From 45af44d47da6933b260c734ad9ff721f63f80a4d Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Mon, 8 Dec 2014 19:54:06 +0100 Subject: [PATCH] networkd: manager - enumerate addresses globally, rather than per-link The kernel always returns all addresses, rather than only for the given link, so let's only enumerate once. --- src/libsystemd/sd-rtnl/rtnl-message.c | 9 +++- src/network/networkd-dhcp4.c | 7 +-- src/network/networkd-ipv4ll.c | 7 +-- src/network/networkd-link.c | 63 +++++++-------------------- src/network/networkd-link.h | 1 - src/network/networkd-manager.c | 61 ++++++++++++++++++++------ src/network/networkd.c | 6 +++ src/network/networkd.h | 1 + src/systemd/sd-rtnl.h | 1 + 9 files changed, 84 insertions(+), 72 deletions(-) diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c index ac920b2d3..5c627f96a 100644 --- a/src/libsystemd/sd-rtnl/rtnl-message.c +++ b/src/libsystemd/sd-rtnl/rtnl-message.c @@ -1194,13 +1194,20 @@ uint32_t rtnl_message_get_serial(sd_rtnl_message *m) { return m->hdr->nlmsg_seq; } +int sd_rtnl_message_is_error(sd_rtnl_message *m) { + assert_return(m, 0); + assert_return(m->hdr, 0); + + return m->hdr->nlmsg_type == NLMSG_ERROR; +} + int sd_rtnl_message_get_errno(sd_rtnl_message *m) { struct nlmsgerr *err; assert_return(m, -EINVAL); assert_return(m->hdr, -EINVAL); - if (m->hdr->nlmsg_type != NLMSG_ERROR) + if (!sd_rtnl_message_is_error(m)) return 0; err = NLMSG_DATA(m->hdr); diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index ac59fd48c..1c2edc5b8 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -296,11 +296,8 @@ static int dhcp4_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, log_link_error(link, "could not set DHCPv4 address: %s", strerror(-r)); link_enter_failed(link); - } else if (r >= 0) { - /* calling handler directly so take a ref */ - link_ref(link); - link_get_address_handler(rtnl, m, link); - } + } else if (r >= 0) + link_rtnl_process_address(rtnl, m, link->manager); link_set_dhcp_routes(link); diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index beac939b3..339bf4d19 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -105,11 +105,8 @@ static int ipv4ll_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userd if (r < 0 && r != -EEXIST) { log_link_error(link, "could not set ipv4ll address: %s", strerror(-r)); link_enter_failed(link); - } else if (r >= 0) { - /* calling handler directly so take a ref */ - link_ref(link); - link_get_address_handler(rtnl, m, link); - } + } else if (r >= 0) + link_rtnl_process_address(rtnl, m, link->manager); link->ipv4ll_address = true; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 4ad0bb47f..b9f1b992d 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -576,32 +576,6 @@ int link_route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { return 1; } -int link_get_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { - _cleanup_link_unref_ Link *link = userdata; - int r; - - assert(rtnl); - assert(m); - assert(link); - assert(link->manager); - - for (; m; m = sd_rtnl_message_next(m)) { - r = sd_rtnl_message_get_errno(m); - if (r < 0) { - log_link_debug(link, "getting address failed: %s", - strerror(-r)); - continue; - } - - r = link_rtnl_process_address(rtnl, m, link->manager); - if (r < 0) - log_link_warning(link, "could not process address: %s", - strerror(-r)); - } - - return 1; -} - static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { _cleanup_link_unref_ Link *link = userdata; int r; @@ -622,11 +596,8 @@ static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { r = sd_rtnl_message_get_errno(m); if (r < 0 && r != -EEXIST) log_link_warning_errno(link, -r, "%-*s: could not set address: %m", IFNAMSIZ, link->ifname); - else if (r >= 0) { - /* calling handler directly so take a ref */ - link_ref(link); - link_get_address_handler(rtnl, m, link); - } + else if (r >= 0) + link_rtnl_process_address(rtnl, m, link->manager); if (link->link_messages == 0) { log_link_debug(link, "addresses set"); @@ -1417,8 +1388,7 @@ int link_initialized(Link *link, struct udev_device *device) { return 0; } -int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, - void *userdata) { +int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) { Manager *m = userdata; Link *link = NULL; uint16_t type; @@ -1434,6 +1404,14 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, assert(message); assert(m); + if (sd_rtnl_message_is_error(message)) { + r = sd_rtnl_message_get_errno(message); + if (r < 0) + log_warning_errno(r, "rtnl: failed to receive address: %m"); + + return 0; + } + r = sd_rtnl_message_get_type(message, &type); if (r < 0) { log_warning("rtnl: could not get message type"); @@ -1441,8 +1419,11 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, } r = sd_rtnl_message_addr_get_ifindex(message, &ifindex); - if (r < 0 || ifindex <= 0) { - log_warning("rtnl: received address message without valid ifindex, ignoring"); + if (r < 0) { + log_warning_errno(r, "rtnl: could not get ifindex: %m"); + return 0; + } else if (ifindex <= 0) { + log_warning("rtnl: received address message with invalid ifindex: %d", ifindex); return 0; } else { r = link_get(m, ifindex, &link); @@ -1594,18 +1575,6 @@ int link_add(Manager *m, sd_rtnl_message *message, Link **ret) { log_link_debug(link, "link %d added", link->ifindex); - r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, link->ifindex, - 0); - if (r < 0) - return r; - - r = sd_rtnl_call_async(m->rtnl, req, link_get_address_handler, link, 0, - NULL); - if (r < 0) - return r; - - link_ref(link); - if (detect_container(NULL) <= 0) { /* not in a container, udev will be around */ sprintf(ifindex_str, "n%d", link->ifindex); diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 56631757a..31688c3ba 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -99,7 +99,6 @@ int link_get(Manager *m, int ifindex, Link **ret); int link_add(Manager *manager, sd_rtnl_message *message, Link **ret); void link_drop(Link *link); -int link_get_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata); int link_address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata); int link_route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata); diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index a708e905f..fe9008a3d 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -236,22 +236,33 @@ static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, vo assert(message); assert(m); + if (sd_rtnl_message_is_error(message)) { + r = sd_rtnl_message_get_errno(message); + if (r < 0) + log_warning_errno(r, "rtnl: could not receive link: %m"); + + return 0; + } + r = sd_rtnl_message_get_type(message, &type); if (r < 0) { - log_warning("rtnl: could not get message type"); + log_warning_errno(r, "rtnl: could not get message type: %m"); return 0; } r = sd_rtnl_message_link_get_ifindex(message, &ifindex); - if (r < 0 || ifindex <= 0) { - log_warning("rtnl: received link message without valid ifindex"); + if (r < 0) { + log_warning_errno(r, "rtnl: could not get ifindex: %m"); + return 0; + } else if (ifindex <= 0) { + log_warning("rtnl: received link message with invalid ifindex: %d", ifindex); return 0; } else link_get(m, ifindex, &link); r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &name); - if (r < 0 || !name) { - log_warning("rtnl: received link message without valid ifname"); + if (r < 0) { + log_warning_errno(r, "rtnl: received link message without ifname: %m"); return 0; } else netdev_get(m, name, &netdev); @@ -271,7 +282,7 @@ static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, vo /* netdev exists, so make sure the ifindex matches */ r = netdev_set_ifindex(netdev, message); if (r < 0) { - log_debug("could not set ifindex on netdev"); + log_debug_errno(r, "could not set ifindex on netdev: %m"); return 0; } } @@ -298,7 +309,7 @@ static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, vo int manager_rtnl_enumerate_links(Manager *m) { _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL; sd_rtnl_message *link; - int r, k; + int r; assert(m); assert(m->rtnl); @@ -316,16 +327,40 @@ int manager_rtnl_enumerate_links(Manager *m) { return r; for (link = reply; link; link = sd_rtnl_message_next(link)) { - uint16_t type; + int k; - k = sd_rtnl_message_get_type(link, &type); + k = manager_rtnl_process_link(m->rtnl, link, m); if (k < 0) - return k; + r = k; + } - if (type != RTM_NEWLINK) - continue; + return r; +} - k = manager_rtnl_process_link(m->rtnl, link, m); +int manager_rtnl_enumerate_addresses(Manager *m) { + _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL; + sd_rtnl_message *addr; + int r; + + assert(m); + assert(m->rtnl); + + r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0); + if (r < 0) + return r; + + r = sd_rtnl_message_request_dump(req, true); + if (r < 0) + return r; + + r = sd_rtnl_call(m->rtnl, req, 0, &reply); + if (r < 0) + return r; + + for (addr = reply; addr; addr = sd_rtnl_message_next(addr)) { + int k; + + k = link_rtnl_process_address(m->rtnl, addr, m); if (k < 0) r = k; } diff --git a/src/network/networkd.c b/src/network/networkd.c index 430d615f9..0b386d406 100644 --- a/src/network/networkd.c +++ b/src/network/networkd.c @@ -110,6 +110,12 @@ int main(int argc, char *argv[]) { goto out; } + r = manager_rtnl_enumerate_addresses(m); + if (r < 0) { + log_error_errno(r, "Could not enumerate links: %m"); + goto out; + } + sd_notify(false, "READY=1\n" "STATUS=Processing requests..."); diff --git a/src/network/networkd.h b/src/network/networkd.h index 5f553fb3b..4cdcd73c5 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -203,6 +203,7 @@ int manager_load_config(Manager *m); bool manager_should_reload(Manager *m); int manager_rtnl_enumerate_links(Manager *m); +int manager_rtnl_enumerate_addresses(Manager *m); int manager_rtnl_listen(Manager *m); int manager_udev_listen(Manager *m); diff --git a/src/systemd/sd-rtnl.h b/src/systemd/sd-rtnl.h index da8610c0a..b05f83ce4 100644 --- a/src/systemd/sd-rtnl.h +++ b/src/systemd/sd-rtnl.h @@ -81,6 +81,7 @@ sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m); sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m); int sd_rtnl_message_request_dump(sd_rtnl_message *m, int dump); +int sd_rtnl_message_is_error(sd_rtnl_message *m); int sd_rtnl_message_get_errno(sd_rtnl_message *m); int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type); int sd_rtnl_message_is_broadcast(sd_rtnl_message *m); -- 2.30.2