[systemd-commits] 10 commits - Makefile.am src/libsystemd src/libsystemd-network src/network src/nss-myhostname src/systemd src/udev

Tom Gundersen tomegun at kemper.freedesktop.org
Sat Apr 19 09:55:59 PDT 2014


 Makefile.am                               |    4 
 src/libsystemd-network/network-internal.c |    4 
 src/libsystemd-network/network-internal.h |    2 
 src/libsystemd/sd-rtnl/rtnl-internal.h    |    5 
 src/libsystemd/sd-rtnl/rtnl-message.c     |  116 +++++++++----
 src/libsystemd/sd-rtnl/sd-rtnl.c          |   17 ++
 src/libsystemd/sd-rtnl/test-rtnl.c        |   30 +++
 src/network/networkd-link.c               |  253 +++++++++++++++---------------
 src/network/networkd-manager.c            |  184 +++++++++++----------
 src/network/networkd-netdev.c             |  171 +++++++++++---------
 src/network/networkd-network.c            |   30 +--
 src/network/networkd.c                    |    2 
 src/network/networkd.h                    |   14 +
 src/network/test-network.c                |   14 -
 src/nss-myhostname/netlink.c              |  245 ++++++++++-------------------
 src/systemd/sd-rtnl.h                     |    1 
 src/udev/net/link-config.c                |    2 
 17 files changed, 586 insertions(+), 508 deletions(-)

New commits:
commit a21df104887552e8558d6c11388dff466641a031
Author: Tom Gundersen <teg at jklm.no>
Date:   Sat Apr 19 17:14:36 2014 +0200

    networkd: netdev - give up early when setting already set ifindex
    
    We may receive RTM_NEWLINK messages with missing LINKINFO after the initial NEWLINK message,
    don't bother verifying these, just drop out early after checking that the ifindex is not in conflict.

diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index 30cb74b..717ecdf 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -392,6 +392,29 @@ int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
                 return -EINVAL;
         }
 
+        r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
+        if (r < 0) {
+                log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
+                netdev_enter_failed(netdev);
+                return r;
+        } else if (ifindex <= 0) {
+                log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
+                netdev_enter_failed(netdev);
+                return r;
+        }
+
+
+        if (netdev->ifindex > 0) {
+                if (netdev->ifindex != ifindex) {
+                        log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
+                                         ifindex, netdev->ifindex);
+                        netdev_enter_failed(netdev);
+                        return -EEXIST;
+                } else
+                        /* ifindex already set to the same for this netdev */
+                        return 0;
+        }
+
         r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
         if (r < 0) {
                 log_error_netdev(netdev, "Could not get IFNAME");
@@ -437,24 +460,6 @@ int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
                 return r;
         }
 
-        r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
-        if (r < 0) {
-                log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
-                netdev_enter_failed(netdev);
-                return r;
-        } else if (ifindex <= 0) {
-                log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
-                netdev_enter_failed(netdev);
-                return r;
-        }
-
-        if (netdev->ifindex > 0 && netdev->ifindex != ifindex) {
-                log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
-                                 ifindex, netdev->ifindex);
-                netdev_enter_failed(netdev);
-                return -EEXIST;
-        }
-
         netdev->ifindex = ifindex;
 
         netdev_enter_ready(netdev);

commit c6315a7afc905c0b41901cf8e204306296ebb640
Author: Tom Gundersen <teg at jklm.no>
Date:   Fri Apr 18 10:28:42 2014 +0200

    networkd: netdev - verify name of newlink messages

diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index 075a879..30cb74b 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -375,6 +375,7 @@ int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
         uint16_t type;
         const char *kind;
         char *received_kind;
+        char *received_name;
         int r, ifindex;
 
         assert(netdev);
@@ -391,6 +392,19 @@ int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
                 return -EINVAL;
         }
 
+        r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
+        if (r < 0) {
+                log_error_netdev(netdev, "Could not get IFNAME");
+                return r;
+        }
+
+        if (!streq(netdev->name, received_name)) {
+                log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
+                                 received_name);
+                netdev_enter_failed(netdev);
+                return r;
+        }
+
         r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
         if (r < 0) {
                 log_error_netdev(netdev, "Could not get LINKINFO");
@@ -417,7 +431,8 @@ int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
         }
 
         if (!streq(kind, received_kind)) {
-                log_error_netdev(netdev, "Received newlink with wrong KIND");
+                log_error_netdev(netdev, "Received newlink with wrong KIND %s, "
+                                 "expected %s", received_kind, kind);
                 netdev_enter_failed(netdev);
                 return r;
         }

commit cdc85c875b842b9309f72caefc51c262f521cf92
Author: Tom Gundersen <teg at jklm.no>
Date:   Fri Apr 18 00:50:40 2014 +0200

    networkd: netdev - set predictable mac address when creating netdev

diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index b7fc48d..075a879 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -25,6 +25,7 @@
 #include "conf-files.h"
 #include "conf-parser.h"
 #include "list.h"
+#include "siphash24.h"
 
 #define VLANID_MAX 4094
 
@@ -180,8 +181,48 @@ static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userda
         return 1;
 }
 
+#define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
+
+static int netdev_get_mac(NetDev *netdev, struct ether_addr *mac) {
+        uint8_t result[8];
+        size_t l, sz;
+        uint8_t *v;
+        int r;
+
+        assert(netdev);
+        assert(netdev->name);
+        assert(mac);
+
+        l = strlen(netdev->name);
+        sz = sizeof(sd_id128_t) + l;
+        v = alloca(sz);
+
+        /* fetch some persistent data unique to the machine */
+        r = sd_id128_get_machine((sd_id128_t*) v);
+        if (r < 0)
+                return r;
+
+        /* combine with some data unique (on this machine) to this
+         * netdev */
+        memcpy(v + sizeof(sd_id128_t), netdev->name, l);
+
+        /* Let's hash the host machine ID plus the container name. We
+         * use a fixed, but originally randomly created hash key here. */
+        siphash24(result, v, sz, HASH_KEY.bytes);
+
+        assert_cc(ETH_ALEN <= sizeof(result));
+        memcpy(mac->ether_addr_octet, result, ETH_ALEN);
+
+        /* see eth_random_addr in the kernel */
+        mac->ether_addr_octet[0] &= 0xfe;        /* clear multicast bit */
+        mac->ether_addr_octet[0] |= 0x02;        /* set local assignment bit (IEEE802) */
+
+        return 0;
+}
+
 static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
+        struct ether_addr mac;
         const char *kind;
         int r;
 
@@ -192,6 +233,12 @@ static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t c
         assert(netdev->manager);
         assert(netdev->manager->rtnl);
 
+        r = netdev_get_mac(netdev, &mac);
+        if (r < 0) {
+                log_error("Failed to generate predictable MAC address for %s", netdev->name);
+                return r;
+        }
+
         r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, 0);
         if (r < 0) {
                 log_error_netdev(netdev,
@@ -218,6 +265,14 @@ static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t c
                 return r;
         }
 
+        r = sd_rtnl_message_append_ether_addr(req, IFLA_ADDRESS, &mac);
+        if (r < 0) {
+                log_error_netdev(netdev,
+                                 "Colud not append IFLA_ADDRESS attribute: %s",
+                                 strerror(-r));
+                return r;
+        }
+
         r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
         if (r < 0) {
                 log_error_netdev(netdev,

commit 505f8da7325591defe5f751f328bd26915267602
Author: Tom Gundersen <teg at jklm.no>
Date:   Tue Apr 15 14:21:44 2014 +0200

    networkd: tie links to rtnl rather than udev
    
    This essentially swaps the roles of rtnl and udev in networkd. After this
    change libudev is only used for waiting for udev to initialize devices and
    to get udev-specific information needed for some [Match] attributes.
    
    This in particular simplifies the code in containers where udev is not really
    useful, but also simplifies things and reduces round-trips in the non-container
    case.

diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c
index 3686267..52e614c 100644
--- a/src/libsystemd-network/network-internal.c
+++ b/src/libsystemd-network/network-internal.c
@@ -79,7 +79,7 @@ bool net_match_config(const struct ether_addr *match_mac,
                       Condition *match_virt,
                       Condition *match_kernel,
                       Condition *match_arch,
-                      const char *dev_mac,
+                      const struct ether_addr *dev_mac,
                       const char *dev_path,
                       const char *dev_parent_driver,
                       const char *dev_driver,
@@ -98,7 +98,7 @@ bool net_match_config(const struct ether_addr *match_mac,
         if (match_arch && !condition_test_architecture(match_arch))
                 return 0;
 
-        if (match_mac && (!dev_mac || memcmp(match_mac, ether_aton(dev_mac), ETH_ALEN)))
+        if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
                 return 0;
 
         if (match_path && (!dev_path || fnmatch(match_path, dev_path, 0)))
diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h
index 65cd0d7..836472a 100644
--- a/src/libsystemd-network/network-internal.h
+++ b/src/libsystemd-network/network-internal.h
@@ -37,7 +37,7 @@ bool net_match_config(const struct ether_addr *match_mac,
                       Condition *match_virt,
                       Condition *match_kernel,
                       Condition *match_arch,
-                      const char *dev_mac,
+                      const struct ether_addr *dev_mac,
                       const char *dev_path,
                       const char *dev_parent_driver,
                       const char *dev_driver,
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index f179af3..319f290 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -24,7 +24,9 @@
 
 #include "networkd.h"
 #include "libudev-private.h"
+#include "udev-util.h"
 #include "util.h"
+#include "virt.h"
 #include "bus-util.h"
 #include "network-internal.h"
 
@@ -33,41 +35,53 @@
 static int ipv4ll_address_update(Link *link, bool deprecate);
 static bool ipv4ll_is_bound(sd_ipv4ll *ll);
 
-int link_new(Manager *manager, struct udev_device *device, Link **ret) {
+static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) {
         _cleanup_link_free_ Link *link = NULL;
-        const char *ifname;
-        int r;
+        uint16_t type;
+        char *ifname;
+        int r, ifindex;
 
         assert(manager);
         assert(manager->links);
-        assert(device);
+        assert(message);
         assert(ret);
 
+        r = sd_rtnl_message_get_type(message, &type);
+        if (r < 0)
+                return r;
+        else if (type != RTM_NEWLINK)
+                return -EINVAL;
+
+        r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
+        if (r < 0)
+                return r;
+        else if (ifindex <= 0)
+                return -EINVAL;
+
+        r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &ifname);
+        if (r < 0)
+                return r;
+
         link = new0(Link, 1);
         if (!link)
                 return -ENOMEM;
 
         link->manager = manager;
-        link->state = _LINK_STATE_INVALID;
-
-        link->ifindex = udev_device_get_ifindex(device);
-        if (link->ifindex <= 0)
-                return -EINVAL;
+        link->state = LINK_STATE_INITIALIZING;
+        link->ifindex = ifindex;
+        link->ifname = strdup(ifname);
+        if (!link->ifname)
+                return -ENOMEM;
 
         r = asprintf(&link->state_file, "/run/systemd/network/links/%"PRIu64,
                      link->ifindex);
         if (r < 0)
                 return -ENOMEM;
 
-        ifname = udev_device_get_sysname(device);
-        link->ifname = strdup(ifname);
-
         r = hashmap_put(manager->links, &link->ifindex, link);
         if (r < 0)
                 return r;
 
-        link->udev_device = udev_device_ref(device);
-
         *ret = link;
         link = NULL;
 
@@ -1036,7 +1050,6 @@ static int link_update_flags(Link *link, unsigned flags) {
         int r;
 
         assert(link);
-        assert(link->network);
 
         if (link->state == LINK_STATE_FAILED)
                 return 0;
@@ -1060,13 +1073,12 @@ static int link_update_flags(Link *link, unsigned flags) {
 
         link->flags = flags;
 
-        if (flags_added & generic_flags)
-                log_debug_link(link, "link flags gained: %#.8x",
-                               flags_added & generic_flags);
-
-        if (flags_removed & generic_flags)
-                log_debug_link(link, "link flags lost: %#.8x",
-                                flags_removed & generic_flags);
+        if (!link->network)
+                /* not currently managing this link
+                   we track state changes, but don't log them
+                   they will be logged if and when a network is
+                   applied */
+                return 0;
 
         if (flags_added & IFF_UP)
                 log_info_link(link, "link is up");
@@ -1083,6 +1095,14 @@ static int link_update_flags(Link *link, unsigned flags) {
         else if (flags_removed & IFF_RUNNING)
                 log_debug_link(link, "link is not running");
 
+        if (flags_added & generic_flags)
+                log_debug_link(link, "ignored link flags gained: %#.8x",
+                               flags_added & generic_flags);
+
+        if (flags_removed & generic_flags)
+                log_debug_link(link, "ignored link flags lost: %#.8x",
+                                flags_removed & generic_flags);
+
         if (carrier_gained) {
                 log_info_link(link, "gained carrier");
 
@@ -1180,10 +1200,12 @@ static int link_enslaved(Link *link) {
         assert(link->state == LINK_STATE_ENSLAVING);
         assert(link->network);
 
-        r = link_up(link);
-        if (r < 0) {
-                link_enter_failed(link);
-                return r;
+        if (!(link->flags & IFF_UP)) {
+                r = link_up(link);
+                if (r < 0) {
+                        link_enter_failed(link);
+                        return r;
+                }
         }
 
         if (!link->network->dhcp && !link->network->ipv4ll)
@@ -1231,7 +1253,7 @@ static int link_enter_enslave(Link *link) {
 
         assert(link);
         assert(link->network);
-        assert(link->state == _LINK_STATE_INVALID);
+        assert(link->state == LINK_STATE_INITIALIZING);
 
         link->state = LINK_STATE_ENSLAVING;
 
@@ -1323,95 +1345,11 @@ static int link_enter_enslave(Link *link) {
         return 0;
 }
 
-static int link_getlink_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
-                                void *userdata) {
-        Link *link = userdata;
-        int r;
-
-        assert(link);
-        assert(link->ifname);
-
-        if (link->state == LINK_STATE_FAILED)
-                return 1;
-
-        r = sd_rtnl_message_get_errno(m);
-        if (r < 0) {
-                log_struct_link(LOG_ERR, link,
-                                "MESSAGE=%s: could not get state: %s",
-                                link->ifname, strerror(-r),
-                                "ERRNO=%d", -r,
-                                NULL);
-                link_enter_failed(link);
-                return 1;
-        }
-
-        link_update(link, m);
-
-        return 1;
-}
-
-static int link_getlink(Link *link) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
-        int r;
-
-        assert(link);
-        assert(link->manager);
-        assert(link->manager->rtnl);
-
-        log_debug_link(link, "requesting link status");
-
-        r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
-                                     RTM_GETLINK, link->ifindex);
-        if (r < 0) {
-                log_error_link(link, "Could not allocate RTM_GETLINK message");
-                return r;
-        }
-
-        r = sd_rtnl_call_async(link->manager->rtnl, req, link_getlink_handler,
-                               link, 0, NULL);
-        if (r < 0) {
-                log_error_link(link,
-                               "Could not send rtnetlink message: %s", strerror(-r));
-                return r;
-        }
-
-        return 0;
-}
-
 static int link_configure(Link *link) {
         int r;
 
         assert(link);
-        assert(link->state == _LINK_STATE_INVALID);
-
-        r = link_getlink(link);
-        if (r < 0)
-                return r;
-
-        return link_enter_enslave(link);
-}
-
-int link_add(Manager *m, struct udev_device *device, Link **ret) {
-        Link *link = NULL;
-        Network *network;
-        int r;
-
-        assert(m);
-        assert(device);
-
-        r = link_new(m, device, &link);
-        if (r < 0)
-                return r;
-
-        *ret = link;
-
-        r = network_get(m, device, &network);
-        if (r < 0)
-                return r == -ENOENT ? 0 : r;
-
-        r = network_apply(m, network, link);
-        if (r < 0)
-                return r;
+        assert(link->state == LINK_STATE_INITIALIZING);
 
         if (link->network->ipv4ll) {
                 uint8_t seed[8];
@@ -1419,11 +1357,13 @@ int link_add(Manager *m, struct udev_device *device, Link **ret) {
                 if (r < 0)
                         return r;
 
-                r = net_get_unique_predictable_data(link->udev_device, seed);
-                if (r >= 0) {
-                        r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
-                        if (r < 0)
-                                return r;
+                if (link->udev_device) {
+                        r = net_get_unique_predictable_data(link->udev_device, seed);
+                        if (r >= 0) {
+                                r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
+                                if (r < 0)
+                                        return r;
+                        }
                 }
 
                 r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0);
@@ -1463,10 +1403,84 @@ int link_add(Manager *m, struct udev_device *device, Link **ret) {
                 }
         }
 
+        return link_enter_enslave(link);
+}
+
+int link_initialized(Link *link, struct udev_device *device) {
+        Network *network;
+        unsigned flags;
+        int r;
+
+        assert(link);
+        assert(link->ifname);
+        assert(link->manager);
+
+        if (link->state != LINK_STATE_INITIALIZING)
+                return 0;
+
+        if (device)
+                link->udev_device = udev_device_ref(device);
+
+        log_debug_link(link, "link initialized");
+
+        r = network_get(link->manager, device, link->ifname, &link->mac, &network);
+        if (r < 0)
+                return r == -ENOENT ? 0 : r;
+
+        r = network_apply(link->manager, network, link);
+        if (r < 0)
+                return r;
+
         r = link_configure(link);
         if (r < 0)
                 return r;
 
+        /* re-trigger all state updates */
+        flags = link->flags;
+        link->flags = 0;
+        r = link_update_flags(link, flags);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int link_add(Manager *m, sd_rtnl_message *message, Link **ret) {
+        Link *link;
+        _cleanup_udev_device_unref_ struct udev_device *device = NULL;
+        char ifindex_str[2 + DECIMAL_STR_MAX(int)];
+        int r;
+
+        assert(m);
+        assert(message);
+        assert(ret);
+
+        r = link_new(m, message, ret);
+        if (r < 0)
+                return r;
+
+        link = *ret;
+
+        log_info_link(link, "link added");
+
+        if (detect_container(NULL) <= 0) {
+                /* not in a container, udev will be around */
+                sprintf(ifindex_str, "n%"PRIu64, link->ifindex);
+                device = udev_device_new_from_device_id(m->udev, ifindex_str);
+                if (!device) {
+                        log_warning_link(link, "could not find udev device");
+                        return -errno;
+                }
+
+                if (udev_device_get_is_initialized(device) <= 0)
+                        /* not yet ready */
+                        return 0;
+        }
+
+        r = link_initialized(link, device);
+        if (r < 0)
+                return r;
+
         return 0;
 }
 
@@ -1476,14 +1490,12 @@ int link_update(Link *link, sd_rtnl_message *m) {
         int r;
 
         assert(link);
-        assert(link->network);
         assert(m);
 
         if (link->state == LINK_STATE_FAILED)
                 return 0;
 
-        if (link->network->dhcp && link->network->dhcp_mtu &&
-            !link->original_mtu) {
+        if (!link->original_mtu) {
                 r = sd_rtnl_message_read_u16(m, IFLA_MTU, &link->original_mtu);
                 if (r >= 0)
                         log_debug_link(link, "saved original MTU: %"
@@ -1591,6 +1603,7 @@ finish:
 }
 
 static const char* const link_state_table[_LINK_STATE_MAX] = {
+        [LINK_STATE_INITIALIZING] = "configuring",
         [LINK_STATE_ENSLAVING] = "configuring",
         [LINK_STATE_SETTING_ADDRESSES] = "configuring",
         [LINK_STATE_SETTING_ROUTES] = "configuring",
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index d903d0d..4c1987d 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -29,6 +29,8 @@
 #include "mkdir.h"
 #include "virt.h"
 
+#include "sd-rtnl.h"
+
 const char* const network_dirs[] = {
         "/etc/systemd/network",
         "/run/systemd/network",
@@ -96,18 +98,14 @@ int manager_new(Manager **ret) {
         if (r < 0)
                 return r;
 
-        m->udev = udev_new();
-        if (!m->udev)
-                return -ENOMEM;
-
         /* udev does not initialize devices inside containers,
          * so we rely on them being already initialized before
          * entering the container */
-        if (detect_container(NULL) > 0) {
-                m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "kernel");
-                if (!m->udev_monitor)
+        if (detect_container(NULL) <= 0) {
+                m->udev = udev_new();
+                if (!m->udev)
                         return -ENOMEM;
-        } else {
+
                 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
                 if (!m->udev_monitor)
                         return -ENOMEM;
@@ -182,15 +180,30 @@ bool manager_should_reload(Manager *m) {
         return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
 }
 
-static int manager_process_link(Manager *m, struct udev_device *device) {
+static int manager_udev_process_link(Manager *m, struct udev_device *device) {
         Link *link = NULL;
         int r;
 
         assert(m);
         assert(device);
 
-        link_get(m, udev_device_get_ifindex(device), &link);
+        if (!streq_ptr(udev_device_get_action(device), "add"))
+                return 0;
+
+        r = link_get(m, udev_device_get_ifindex(device), &link);
+        if (r < 0)
+                return r;
+
+        if (!link)
+                return 0;
+
+        r = link_initialized(link, device);
+        if (r < 0)
+                return r;
 
+        return 0;
+}
+/*
         if (streq_ptr(udev_device_get_action(device), "remove")) {
                 log_debug("%s: link removed", udev_device_get_sysname(device));
 
@@ -215,45 +228,87 @@ static int manager_process_link(Manager *m, struct udev_device *device) {
 
         return 0;
 }
+*/
+static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
+        Manager *m = userdata;
+        Link *link = NULL;
+        char *name;
+        int r, ifindex;
 
-int manager_udev_enumerate_links(Manager *m) {
-        _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
-        struct udev_list_entry *item = NULL, *first = NULL;
-        int r;
-
+        assert(rtnl);
+        assert(message);
         assert(m);
 
-        e = udev_enumerate_new(m->udev);
-        if (!e)
-                return -ENOMEM;
+        r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
+        if (r < 0 || ifindex <= 0) {
+                log_warning("rtnl: received link message without valid ifindex");
+                return 0;
+        }
+
+        link_get(m, ifindex, &link);
+        if (!link) {
+                /* link is new, so add it */
+                r = link_add(m, message, &link);
+                if (r < 0) {
+                        log_debug("could not add new link");
+                        return 0;
+                }
+        }
 
-        r = udev_enumerate_add_match_subsystem(e, "net");
+        r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &name);
         if (r < 0)
-                return r;
+                log_warning("rtnl: received link message without valid ifname");
+        else {
+                NetDev *netdev;
 
-        /* udev does not initialize devices inside containers,
-         * so we rely on them being already initialized before
-         * entering the container */
-        if (detect_container(NULL) <= 0) {
-                r = udev_enumerate_add_match_is_initialized(e);
-                if (r < 0)
-                        return r;
+                r = netdev_get(m, name, &netdev);
+                if (r >= 0) {
+                        r = netdev_set_ifindex(netdev, message);
+                        if (r < 0) {
+                                log_debug("could not set ifindex on netdev");
+                                return 0;
+                        }
+                }
         }
 
-        r = udev_enumerate_scan_devices(e);
+        r = link_update(link, message);
+        if (r < 0)
+                return 0;
+
+        return 1;
+}
+
+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;
+
+        assert(m);
+        assert(m->rtnl);
+
+        r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
+        if (r < 0)
+                return r;
+
+        r = sd_rtnl_message_request_dump(req, true);
         if (r < 0)
                 return r;
 
-        first = udev_enumerate_get_list_entry(e);
-        udev_list_entry_foreach(item, first) {
-                _cleanup_udev_device_unref_ struct udev_device *d = NULL;
-                int k;
+        r = sd_rtnl_call(m->rtnl, req, 0, &reply);
+        if (r < 0)
+                return r;
 
-                d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
-                if (!d)
-                        return -ENOMEM;
+        for (link = reply; link; link = sd_rtnl_message_next(link)) {
+                uint16_t type;
+
+                k = sd_rtnl_message_get_type(link, &type);
+                if (k < 0)
+                        return k;
+
+                if (type != RTM_NEWLINK)
+                        continue;
 
-                k = manager_process_link(m, d);
+                k = manager_rtnl_process_link(m->rtnl, link, m);
                 if (k < 0)
                         r = k;
         }
@@ -270,13 +325,18 @@ static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t
         if (!device)
                 return -ENOMEM;
 
-        manager_process_link(m, device);
+        manager_udev_process_link(m, device);
         return 0;
 }
 
 int manager_udev_listen(Manager *m) {
         int r;
 
+        if (detect_container(NULL) > 0)
+                return 0;
+
+        assert(m->udev_monitor);
+
         r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
         if (r < 0) {
                 log_error("Could not add udev monitor filter: %s", strerror(-r));
@@ -300,56 +360,6 @@ int manager_udev_listen(Manager *m) {
         return 0;
 }
 
-static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
-        Manager *m = userdata;
-        Link *link;
-        char *name;
-        int r, ifindex;
-
-        assert(rtnl);
-        assert(message);
-        assert(m);
-
-        r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
-        if (r < 0 || ifindex <= 0) {
-                log_warning("received RTM_NEWLINK message without valid ifindex");
-                return 0;
-        }
-
-        r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &name);
-        if (r < 0)
-                log_warning("received RTM_NEWLINK message without valid ifname");
-        else {
-                NetDev *netdev;
-
-                r = netdev_get(m, name, &netdev);
-                if (r >= 0) {
-                        netdev_set_ifindex(netdev, message);
-                        r = sd_rtnl_message_rewind(message);
-                        if (r < 0) {
-                                log_debug("could not rewind rtnl message");
-                                return 0;
-                        }
-                }
-        }
-
-        r = link_get(m, ifindex, &link);
-        if (r < 0) {
-                log_debug("received RTM_NEWLINK message for untracked ifindex %d", ifindex);
-                return 0;
-        }
-
-        /* only track the status of links we want to manage */
-        if (link->network) {
-                r = link_update(link, message);
-                if (r < 0)
-                        return 0;
-        } else
-                log_debug("%s: received RTM_NEWLINK message for unmanaged link", link->ifname);
-
-        return 1;
-}
-
 int manager_rtnl_listen(Manager *m) {
         int r;
 
diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index 92548d9..b7fc48d 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -161,67 +161,6 @@ static int netdev_enter_ready(NetDev *netdev) {
 
         return 0;
 }
-
-static int netdev_getlink_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
-                                void *userdata) {
-        NetDev *netdev = userdata;
-        int r;
-
-        assert(netdev);
-
-        if (netdev->state == NETDEV_STATE_FAILED)
-                return 1;
-
-        r = sd_rtnl_message_get_errno(m);
-        if (r < 0) {
-                log_struct_netdev(LOG_ERR, netdev,
-                                "MESSAGE=%s: could not get link: %s",
-                                netdev->name, strerror(-r),
-                                "ERRNO=%d", -r,
-                                NULL);
-                return 1;
-        }
-
-        netdev_set_ifindex(netdev, m);
-
-        return 1;
-}
-
-static int netdev_getlink(NetDev *netdev) {
-        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
-        int r;
-
-        assert(netdev->manager);
-        assert(netdev->manager->rtnl);
-        assert(netdev->name);
-
-        log_debug_netdev(netdev, "requesting netdev status");
-
-        r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
-                                     RTM_GETLINK, 0);
-        if (r < 0) {
-                log_error_netdev(netdev, "Could not allocate RTM_GETLINK message");
-                return r;
-        }
-
-        r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->name);
-        if (r < 0) {
-                log_error_netdev(netdev, "Colud not append ifname to message: %s",
-                                 strerror(-r));
-                return r;
-        }
-
-        r = sd_rtnl_call_async(netdev->manager->rtnl, req, netdev_getlink_handler,
-                               netdev, 0, NULL);
-        if (r < 0) {
-                log_error_netdev(netdev,
-                               "Could not send rtnetlink message: %s", strerror(-r));
-                return r;
-        }
-
-        return 0;
-}
-
 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
         NetDev *netdev = userdata;
         int r;
@@ -230,9 +169,8 @@ static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userda
 
         r = sd_rtnl_message_get_errno(m);
         if (r == -EEXIST)
-                r = netdev_getlink(netdev);
-
-        if (r < 0) {
+                log_debug_netdev(netdev, "netdev exists, using existing");
+        else if (r < 0) {
                 log_warning_netdev(netdev, "netdev failed: %s", strerror(-r));
                 netdev_enter_failed(netdev);
 
@@ -410,6 +348,12 @@ int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
                 return r;
         }
 
+        r = sd_rtnl_message_exit_container(message);
+        if (r < 0) {
+                log_error_netdev(netdev, "Could not exit container");
+                return r;
+        }
+
         kind = netdev_kind_to_string(netdev->kind);
         if (!kind) {
                 log_error_netdev(netdev, "Could not get kind");
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index bdf71e8..048017e 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -184,28 +184,28 @@ void network_free(Network *network) {
         free(network);
 }
 
-int network_get(Manager *manager, struct udev_device *device, Network **ret) {
+int network_get(Manager *manager, struct udev_device *device,
+                const char *ifname, const struct ether_addr *address,
+                Network **ret) {
         Network *network;
 
         assert(manager);
-        assert(device);
         assert(ret);
 
         LIST_FOREACH(networks, network, manager->networks) {
                 if (net_match_config(network->match_mac, network->match_path,
-                                        network->match_driver, network->match_type,
-                                        network->match_name, network->match_host,
-                                        network->match_virt, network->match_kernel,
-                                        network->match_arch,
-                                        udev_device_get_sysattr_value(device, "address"),
-                                        udev_device_get_property_value(device, "ID_PATH"),
-                                        udev_device_get_driver(udev_device_get_parent(device)),
-                                        udev_device_get_property_value(device, "ID_NET_DRIVER"),
-                                        udev_device_get_devtype(device),
-                                        udev_device_get_sysname(device))) {
-                        log_debug("%s: found matching network '%s'",
-                                        udev_device_get_sysname(device),
-                                        network->filename);
+                                     network->match_driver, network->match_type,
+                                     network->match_name, network->match_host,
+                                     network->match_virt, network->match_kernel,
+                                     network->match_arch,
+                                     address,
+                                     udev_device_get_property_value(device, "ID_PATH"),
+                                     udev_device_get_driver(udev_device_get_parent(device)),
+                                     udev_device_get_property_value(device, "ID_NET_DRIVER"),
+                                     udev_device_get_devtype(device),
+                                     ifname)) {
+                        log_debug("%s: found matching network '%s'", ifname,
+                                  network->filename);
                         *ret = network;
                         return 0;
                 }
diff --git a/src/network/networkd.c b/src/network/networkd.c
index f0e6ad5..6b3bf12 100644
--- a/src/network/networkd.c
+++ b/src/network/networkd.c
@@ -87,7 +87,7 @@ int main(int argc, char *argv[]) {
                 goto out;
         }
 
-        r = manager_udev_enumerate_links(m);
+        r = manager_rtnl_enumerate_links(m);
         if (r < 0) {
                 log_error("Could not enumerate links: %s", strerror(-r));
                 goto out;
diff --git a/src/network/networkd.h b/src/network/networkd.h
index 36902e3..4a62fb8 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -185,6 +185,7 @@ struct Route {
 };
 
 typedef enum LinkState {
+        LINK_STATE_INITIALIZING,
         LINK_STATE_ENSLAVING,
         LINK_STATE_SETTING_ADDRESSES,
         LINK_STATE_SETTING_ROUTES,
@@ -246,10 +247,10 @@ void manager_free(Manager *m);
 int manager_load_config(Manager *m);
 bool manager_should_reload(Manager *m);
 
-int manager_udev_enumerate_links(Manager *m);
-int manager_udev_listen(Manager *m);
+int manager_rtnl_enumerate_links(Manager *m);
 
 int manager_rtnl_listen(Manager *m);
+int manager_udev_listen(Manager *m);
 int manager_bus_listen(Manager *m);
 
 int manager_update_resolv_conf(Manager *m);
@@ -292,7 +293,9 @@ void network_free(Network *network);
 DEFINE_TRIVIAL_CLEANUP_FUNC(Network*, network_free);
 #define _cleanup_network_free_ _cleanup_(network_freep)
 
-int network_get(Manager *manager, struct udev_device *device, Network **ret);
+int network_get(Manager *manager, struct udev_device *device,
+                const char *ifname, const struct ether_addr *mac,
+                Network **ret);
 int network_apply(Manager *manager, Network *network, Link *link);
 
 int config_parse_bridge(const char *unit, const char *filename, unsigned line,
@@ -362,13 +365,14 @@ int config_parse_label(const char *unit, const char *filename, unsigned line,
 
 /* Link */
 
-int link_new(Manager *manager, struct udev_device *device, Link **ret);
 void link_free(Link *link);
 int link_get(Manager *m, int ifindex, Link **ret);
-int link_add(Manager *manager, struct udev_device *device, Link **ret);
+int link_add(Manager *manager, sd_rtnl_message *message, Link **ret);
 
 int link_update(Link *link, sd_rtnl_message *message);
 
+int link_initialized(Link *link, struct udev_device *device);
+
 int link_save(Link *link);
 
 const char* link_state_to_string(LinkState s) _const_;
diff --git a/src/network/test-network.c b/src/network/test-network.c
index 9c372c7..38d57cc 100644
--- a/src/network/test-network.c
+++ b/src/network/test-network.c
@@ -21,13 +21,6 @@
 
 #include "networkd.h"
 
-static void test_link(Manager *manager, struct udev_device *loopback) {
-        Link *link = NULL;
-
-        assert_se(link_new(manager, loopback, &link) >= 0);
-        assert_se(link);
-}
-
 static void test_load_config(Manager *manager) {
 /*  TODO: should_reload, is false if the config dirs do not exist, so
  *        so we can't do this test here, move it to a test for paths_check_timestamps
@@ -41,10 +34,11 @@ static void test_load_config(Manager *manager) {
 
 static void test_network_get(Manager *manager, struct udev_device *loopback) {
         Network *network;
+        const struct ether_addr mac = {};
 
         /* let's assume that the test machine does not have a .network file
            that applies to the loopback device... */
-        assert_se(network_get(manager, loopback, &network) == -ENOENT);
+        assert_se(network_get(manager, loopback, "lo", &mac, &network) == -ENOENT);
         assert_se(!network);
 }
 
@@ -66,11 +60,9 @@ int main(void) {
 
         test_network_get(manager, loopback);
 
-        test_link(manager, loopback);
-
         assert_se(manager_udev_listen(manager) >= 0);
-        assert_se(manager_udev_enumerate_links(manager) >= 0);
         assert_se(manager_rtnl_listen(manager) >= 0);
+        assert_se(manager_rtnl_enumerate_links(manager) >= 0);
 
         udev_device_unref(loopback);
         udev_unref(udev);
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index 0c563b2..8215c40 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -238,7 +238,7 @@ int link_config_get(link_config_ctx *ctx, struct udev_device *device, link_confi
                 if (net_match_config(link->match_mac, link->match_path, link->match_driver,
                                      link->match_type, NULL, link->match_host,
                                      link->match_virt, link->match_kernel, link->match_arch,
-                                     udev_device_get_sysattr_value(device, "address"),
+                                     ether_aton(udev_device_get_sysattr_value(device, "address")),
                                      udev_device_get_property_value(device, "ID_PATH"),
                                      udev_device_get_driver(udev_device_get_parent(device)),
                                      udev_device_get_property_value(device, "ID_NET_DRIVER"),

commit d1ca51b153d7854d49400289ddedc7d493458f71
Author: Tom Gundersen <teg at jklm.no>
Date:   Mon Apr 14 12:46:09 2014 +0200

    nss-myhostname: port to sd-rtnl

diff --git a/Makefile.am b/Makefile.am
index 451e53a..90b9b93 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4062,6 +4062,10 @@ libnss_myhostname_la_LDFLAGS = \
 	-shared \
 	-shrext .so.2
 
+libnss_myhostname_la_LIBADD = \
+	libsystemd-shared.la \
+	libsystemd-internal.la
+
 lib_LTLIBRARIES += \
 	libnss_myhostname.la
 endif
diff --git a/src/nss-myhostname/netlink.c b/src/nss-myhostname/netlink.c
index d61ecdf..b4a464c 100644
--- a/src/nss-myhostname/netlink.c
+++ b/src/nss-myhostname/netlink.c
@@ -4,6 +4,7 @@
   This file is part of systemd.
 
   Copyright 2008-2011 Lennart Poettering
+  Copyright 2014 Tom Gundersen
 
   systemd is free software; you can redistribute it and/or modify it
   under the terms of the GNU Lesser General Public License as published by
@@ -19,188 +20,122 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <asm/types.h>
-#include <inttypes.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-#include <limits.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <stdlib.h>
+#include "sd-rtnl.h"
+#include "rtnl-util.h"
+#include "macro.h"
 
 #include "ifconf.h"
 
-#define SEQ 4711
-
-static int read_reply(int fd, struct address **list, unsigned *n_list) {
-        ssize_t bytes;
-        struct cmsghdr *cmsg;
-        struct ucred *ucred;
-        struct nlmsghdr *p;
-        uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
-        struct {
-                struct nlmsghdr hdr;
-                struct ifaddrmsg ifaddrmsg;
-                uint8_t payload[16*1024];
-        } resp;
-        struct iovec iov = {
-                .iov_base = &resp,
-                .iov_len = sizeof(resp),
-        };
-        struct msghdr msg = {
-                .msg_name = NULL,
-                .msg_namelen = 0,
-                .msg_iov = &iov,
-                .msg_iovlen = 1,
-                .msg_control = cred_buffer,
-                .msg_controllen = sizeof(cred_buffer),
-                .msg_flags = 0,
-        };
-
-        assert(fd >= 0);
-        assert(list);
-
-        bytes = recvmsg(fd, &msg, 0);
-        if (bytes < 0)
-                return -errno;
-
-        cmsg = CMSG_FIRSTHDR(&msg);
-        if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS)
-                return -EIO;
-
-        ucred = (struct ucred*) CMSG_DATA(cmsg);
-        if (ucred->uid != 0 || ucred->pid != 0)
-                return 0;
-
-        for (p = &resp.hdr; bytes > 0; p = NLMSG_NEXT(p, bytes)) {
-                struct ifaddrmsg *ifaddrmsg;
-                struct rtattr *a;
-                size_t l;
-                void *local = NULL, *address = NULL;
-
-                if (!NLMSG_OK(p, (size_t) bytes))
-                        return -EIO;
-
-                if (p->nlmsg_seq != SEQ)
-                        continue;
-
-                if (p->nlmsg_type == NLMSG_DONE)
-                        return 1;
+int ifconf_acquire_addresses(struct address **_list, unsigned *_n_list) {
+        _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
+        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
+        sd_rtnl_message *m;
+        _cleanup_free_ struct address *list = NULL;
+        struct address *new_list = NULL;
+        unsigned n_list = 0;
+        int r;
 
-                if (p->nlmsg_type == NLMSG_ERROR) {
-                        struct nlmsgerr *nlmsgerr;
+        r = sd_rtnl_open(&rtnl, 0);
+        if (r < 0)
+                return r;
 
-                        nlmsgerr = NLMSG_DATA(p);
-                        return -nlmsgerr->error;
-                }
+        r = sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC);
+        if (r < 0)
+                return r;
 
-                if (p->nlmsg_type != RTM_NEWADDR)
+        r = sd_rtnl_call(rtnl, req, 0, &reply);
+        if (r < 0)
+                return r;
+        m = reply;
+
+        do {
+                uint16_t type;
+                unsigned char scope;
+                unsigned char flags;
+                unsigned char family;
+                int ifindex;
+                union {
+                        struct in_addr in;
+                        struct in6_addr in6;
+                } address;
+
+                r = sd_rtnl_message_get_errno(m);
+                if (r < 0)
+                        return r;
+
+                r = sd_rtnl_message_get_type(m, &type);
+                if (r < 0)
+                        return r;
+
+                if (type != RTM_NEWADDR)
                         continue;
 
-                ifaddrmsg = NLMSG_DATA(p);
+                r = sd_rtnl_message_addr_get_scope(m, &scope);
+                if (r < 0)
+                        return r;
 
-                if (ifaddrmsg->ifa_family != AF_INET &&
-                    ifaddrmsg->ifa_family != AF_INET6)
+                if (scope == RT_SCOPE_HOST || scope == RT_SCOPE_NOWHERE)
                         continue;
 
-                if (ifaddrmsg->ifa_scope == RT_SCOPE_HOST ||
-                    ifaddrmsg->ifa_scope == RT_SCOPE_NOWHERE)
-                        continue;
+                r = sd_rtnl_message_addr_get_flags(m, &flags);
+                if (r < 0)
+                        return r;
 
-                if (ifaddrmsg->ifa_flags & IFA_F_DEPRECATED)
+                if (flags & IFA_F_DEPRECATED)
                         continue;
 
-                l = NLMSG_PAYLOAD(p, sizeof(struct ifaddrmsg));
-                a = IFA_RTA(ifaddrmsg);
-
-                while (RTA_OK(a, l)) {
-
-                        if (a->rta_type == IFA_ADDRESS)
-                                address = RTA_DATA(a);
-                        else if (a->rta_type == IFA_LOCAL)
-                                local = RTA_DATA(a);
-
-                        a = RTA_NEXT(a, l);
-                }
-
-                if (local)
-                        address = local;
-
-                if (!address)
+                r = sd_rtnl_message_addr_get_family(m, &family);
+                if (r < 0)
+                        return r;
+
+                switch (family) {
+                case AF_INET:
+                        r = sd_rtnl_message_read_in_addr(m, IFA_LOCAL, &address.in);
+                        if (r < 0) {
+                                r = sd_rtnl_message_read_in_addr(m, IFA_ADDRESS, &address.in);
+                                if (r < 0)
+                                        continue;
+                        }
+                        break;
+                case AF_INET6:
+                        r = sd_rtnl_message_read_in6_addr(m, IFA_LOCAL, &address.in6);
+                        if (r < 0) {
+                                r = sd_rtnl_message_read_in6_addr(m, IFA_ADDRESS, &address.in6);
+                                if (r < 0)
+                                        continue;
+                        }
+                        break;
+                default:
                         continue;
-
-                *list = realloc(*list, (*n_list+1) * sizeof(struct address));
-                if (!*list)
-                        return -ENOMEM;
-
-                (*list)[*n_list].family = ifaddrmsg->ifa_family;
-                (*list)[*n_list].scope = ifaddrmsg->ifa_scope;
-                memcpy((*list)[*n_list].address,
-                       address, ifaddrmsg->ifa_family == AF_INET ? 4 : 16);
-                (*list)[*n_list].ifindex = ifaddrmsg->ifa_index;
-
-                (*n_list)++;
-        }
-
-        return 0;
-}
-
-
-int ifconf_acquire_addresses(struct address **_list, unsigned *_n_list) {
-
-        struct {
-                struct nlmsghdr hdr;
-                struct rtgenmsg gen;
-        } req = { {
-                        .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
-                        .nlmsg_type = RTM_GETADDR,
-                        .nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP|NLM_F_ACK,
-                        .nlmsg_seq = SEQ,
-                        .nlmsg_pid = 0,
-                }, {
-                        .rtgen_family = AF_UNSPEC,
                 }
-        };
-        int r, on = 1;
-        struct address *list = NULL;
-        unsigned n_list = 0;
-        int fd;
 
-        fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
-        if (fd < 0)
-                return -errno;
+                r = sd_rtnl_message_addr_get_ifindex(m, &ifindex);
+                if (r < 0)
+                        return r;
 
-        if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
-                r = -errno;
-                goto finish;
-        }
+                new_list = realloc(list, (n_list+1) * sizeof(struct address));
+                if (!new_list)
+                        return -ENOMEM;
+                else
+                        list = new_list;
 
-        if (send(fd, &req, req.hdr.nlmsg_len, 0) < 0) {
-                r = -errno;
-                goto finish;
-        }
+                assert_cc(sizeof(address) <= 16);
 
-        while((r = read_reply(fd, &list, &n_list)) == 0)
-                ;
+                list[n_list].family = family;
+                list[n_list].scope = scope;
+                memcpy(list[n_list].address, &address, sizeof(address));
+                list[n_list].ifindex = ifindex;
 
-finish:
-        close(fd);
+                n_list++;
 
-        if (r < 0) {
-                free(list);
-                return r;
-        }
+        } while ((m = sd_rtnl_message_next(m)));
 
         if (n_list)
                 qsort(list, n_list, sizeof(struct address), address_compare);
 
-        *_list = list;
         *_n_list = n_list;
+        *_list = list;
+        list = NULL;
 
         return 0;
 }

commit 6e20c8f8fa095b28ef4e08d9dae494abed6f275f
Author: Tom Gundersen <teg at jklm.no>
Date:   Mon Apr 14 18:07:34 2014 +0200

    sd-rtnl: message - expose DUMP flag in the api

diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c
index 17b9280..3362958 100644
--- a/src/libsystemd/sd-rtnl/rtnl-message.c
+++ b/src/libsystemd/sd-rtnl/rtnl-message.c
@@ -213,6 +213,22 @@ int sd_rtnl_message_new_link(sd_rtnl *rtnl, sd_rtnl_message **ret,
         return 0;
 }
 
+int sd_rtnl_message_request_dump(sd_rtnl_message *m, int dump) {
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(m->hdr->nlmsg_type == RTM_GETLINK ||
+                      m->hdr->nlmsg_type == RTM_GETADDR ||
+                      m->hdr->nlmsg_type == RTM_GETROUTE,
+                      -EINVAL);
+
+        if (dump)
+                m->hdr->nlmsg_flags |= NLM_F_DUMP;
+        else
+                m->hdr->nlmsg_flags &= ~NLM_F_DUMP;
+
+        return 0;
+}
+
 int sd_rtnl_message_addr_set_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
         struct ifaddrmsg *ifa;
 
diff --git a/src/systemd/sd-rtnl.h b/src/systemd/sd-rtnl.h
index 6fbaee0..93f5ab9 100644
--- a/src/systemd/sd-rtnl.h
+++ b/src/systemd/sd-rtnl.h
@@ -77,6 +77,7 @@ int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t nlm
 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_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);

commit 7182867e7970741d294237aa83022fcb2774af69
Author: Tom Gundersen <teg at jklm.no>
Date:   Thu Apr 17 11:12:41 2014 +0200

    sd-rtnl: add multi-part message test

diff --git a/src/libsystemd/sd-rtnl/test-rtnl.c b/src/libsystemd/sd-rtnl/test-rtnl.c
index 529231a..78f5cca 100644
--- a/src/libsystemd/sd-rtnl/test-rtnl.c
+++ b/src/libsystemd/sd-rtnl/test-rtnl.c
@@ -322,6 +322,34 @@ static void test_match(void) {
         assert_se((rtnl = sd_rtnl_unref(rtnl)) == NULL);
 }
 
+static void test_get_addresses(sd_rtnl *rtnl) {
+        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
+        sd_rtnl_message *m;
+
+        assert_se(sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC) >= 0);
+
+        assert_se(sd_rtnl_call(rtnl, req, 0, &reply) >= 0);
+
+        for (m = reply; m; m = sd_rtnl_message_next(m)) {
+                uint16_t type;
+                unsigned char family, scope, flags;
+                int ifindex;
+
+                assert_se(sd_rtnl_message_get_type(m, &type) >= 0);
+                assert_se(type == RTM_NEWADDR);
+
+                assert_se(sd_rtnl_message_addr_get_ifindex(m, &ifindex) >= 0);
+                assert_se(sd_rtnl_message_addr_get_family(m, &family) >= 0);
+                assert_se(sd_rtnl_message_addr_get_scope(m, &scope) >= 0);
+                assert_se(sd_rtnl_message_addr_get_flags(m, &flags) >= 0);
+
+                assert_se(ifindex > 0);
+                assert_se(family == AF_INET || family == AF_INET6);
+
+                log_info("got IPv%u address on ifindex %i", family == AF_INET ? 4: 6, ifindex);
+        }
+}
+
 int main(void) {
         sd_rtnl *rtnl;
         sd_rtnl_message *m;
@@ -352,6 +380,8 @@ int main(void) {
 
         test_link_configure(rtnl, if_loopback);
 
+        test_get_addresses(rtnl);
+
         assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, if_loopback) >= 0);
         assert_se(m);
 

commit 4e996881b2a24390b534d84aa89ba70401cc7e69
Author: Tom Gundersen <teg at jklm.no>
Date:   Thu Apr 17 21:32:25 2014 +0200

    sd-rtnl: message - concatenate multi-part messages from different packets

diff --git a/src/libsystemd/sd-rtnl/rtnl-internal.h b/src/libsystemd/sd-rtnl/rtnl-internal.h
index 6dd65b2..a192198 100644
--- a/src/libsystemd/sd-rtnl/rtnl-internal.h
+++ b/src/libsystemd/sd-rtnl/rtnl-internal.h
@@ -68,6 +68,10 @@ struct sd_rtnl {
         unsigned rqueue_size;
         size_t rqueue_allocated;
 
+        sd_rtnl_message **rqueue_partial;
+        unsigned rqueue_partial_size;
+        size_t rqueue_partial_allocated;
+
         sd_rtnl_message **wqueue;
         unsigned wqueue_size;
         size_t wqueue_allocated;
@@ -115,6 +119,7 @@ int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m);
 int socket_read_message(sd_rtnl *nl);
 
 int rtnl_rqueue_make_room(sd_rtnl *rtnl);
+int rtnl_rqueue_partial_make_room(sd_rtnl *rtnl);
 
 int rtnl_message_read_internal(sd_rtnl_message *m, unsigned short type, void **data);
 int rtnl_message_parse(sd_rtnl_message *m,
diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c
index ffc19f1..17b9280 100644
--- a/src/libsystemd/sd-rtnl/rtnl-message.c
+++ b/src/libsystemd/sd-rtnl/rtnl-message.c
@@ -1063,7 +1063,6 @@ int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
  */
 int socket_read_message(sd_rtnl *rtnl) {
         _cleanup_rtnl_message_unref_ sd_rtnl_message *first = NULL;
-        sd_rtnl_message *previous = NULL;
         uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
         struct iovec iov = {};
         struct msghdr msg = {
@@ -1073,10 +1072,11 @@ int socket_read_message(sd_rtnl *rtnl) {
                 .msg_controllen = sizeof(cred_buffer),
         };
         struct cmsghdr *cmsg;
-        bool auth = false;
+        bool auth = false, multi_part = false, done = false;
         struct nlmsghdr *new_msg;
         size_t len;
-        int r, ret = 0;
+        int r;
+        unsigned i;
 
         assert(rtnl);
         assert(rtnl->rbuffer);
@@ -1134,6 +1134,18 @@ int socket_read_message(sd_rtnl *rtnl) {
                 /* not from the kernel, ignore */
                 return 0;
 
+        if (NLMSG_OK(rtnl->rbuffer, len) && rtnl->rbuffer->nlmsg_flags & NLM_F_MULTI) {
+                multi_part = true;
+
+                for (i = 0; i < rtnl->rqueue_partial_size; i++) {
+                        if (rtnl_message_get_serial(rtnl->rqueue_partial[i]) ==
+                            rtnl->rbuffer->nlmsg_seq) {
+                                first = rtnl->rqueue_partial[i];
+                                break;
+                        }
+                }
+        }
+
         for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len); new_msg = NLMSG_NEXT(new_msg, len)) {
                 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
                 const NLType *nl_type;
@@ -1142,13 +1154,15 @@ int socket_read_message(sd_rtnl *rtnl) {
                         /* not broadcast and not for us */
                         continue;
 
-                /* silently drop noop messages */
                 if (new_msg->nlmsg_type == NLMSG_NOOP)
+                        /* silently drop noop messages */
                         continue;
 
-                /* finished reading multi-part message */
-                if (new_msg->nlmsg_type == NLMSG_DONE)
+                if (new_msg->nlmsg_type == NLMSG_DONE) {
+                        /* finished reading multi-part message */
+                        done = true;
                         break;
+                }
 
                 /* check that we support this message type */
                 r = type_system_get_type(NULL, &nl_type, new_msg->nlmsg_type);
@@ -1177,36 +1191,52 @@ int socket_read_message(sd_rtnl *rtnl) {
                 if (r < 0)
                         return r;
 
-                if (!first)
-                        first = m;
-                else {
-                        assert(previous);
-
-                        previous->next = m;
-                }
-                previous = m;
+                /* push the message onto the multi-part message stack */
+                if (first)
+                        m->next = first;
+                first = m;
                 m = NULL;
+        }
 
-                ret += new_msg->nlmsg_len;
+        if (len)
+                log_debug("sd-rtnl: discarding %zu bytes of incoming message", len);
 
-                /* not a multi-part message, so stop reading*/
-                if (!(new_msg->nlmsg_flags & NLM_F_MULTI))
-                        break;
-        }
+        if (!first)
+                return 0;
 
-        if (first) {
+        if (!multi_part || done) {
+                /* we got a complete message, push it on the read queue */
                 r = rtnl_rqueue_make_room(rtnl);
                 if (r < 0)
                         return r;
 
+                if (i < rtnl->rqueue_partial_size) {
+                        /* remove the message form the partial read queue */
+                        memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1,
+                                sizeof(sd_rtnl_message*) * (rtnl->rqueue_partial_size - i - 1));
+                        rtnl->rqueue_partial_size --;
+                }
+
                 rtnl->rqueue[rtnl->rqueue_size ++] = first;
                 first = NULL;
-        }
 
-        if (len)
-                log_debug("sd-rtnl: discarding %zu bytes of incoming message", len);
+                return 1;
+        } else {
+                /* we only got a partial multi-part message, push it on the
+                   partial read queue */
+                if (i < rtnl->rqueue_partial_size) {
+                        rtnl->rqueue_partial[i] = first;
+                } else {
+                        r = rtnl_rqueue_partial_make_room(rtnl);
+                        if (r < 0)
+                                return r;
+
+                        rtnl->rqueue_partial[rtnl->rqueue_partial_size ++] = first;
+                }
+                first = NULL;
 
-        return ret;
+                return 0;
+        }
 }
 
 int sd_rtnl_message_rewind(sd_rtnl_message *m) {
diff --git a/src/libsystemd/sd-rtnl/sd-rtnl.c b/src/libsystemd/sd-rtnl/sd-rtnl.c
index e4d436b..8650f55 100644
--- a/src/libsystemd/sd-rtnl/sd-rtnl.c
+++ b/src/libsystemd/sd-rtnl/sd-rtnl.c
@@ -135,6 +135,10 @@ sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
                         sd_rtnl_message_unref(rtnl->rqueue[i]);
                 free(rtnl->rqueue);
 
+                for (i = 0; i < rtnl->rqueue_partial_size; i++)
+                        sd_rtnl_message_unref(rtnl->rqueue_partial[i]);
+                free(rtnl->rqueue_partial);
+
                 for (i = 0; i < rtnl->wqueue_size; i++)
                         sd_rtnl_message_unref(rtnl->wqueue[i]);
                 free(rtnl->wqueue);
@@ -226,6 +230,19 @@ int rtnl_rqueue_make_room(sd_rtnl *rtnl) {
         return 0;
 }
 
+int rtnl_rqueue_partial_make_room(sd_rtnl *rtnl) {
+        assert(rtnl);
+
+        if (rtnl->rqueue_partial_size >= RTNL_RQUEUE_MAX)
+                return -ENOBUFS;
+
+        if (!GREEDY_REALLOC(rtnl->rqueue_partial, rtnl->rqueue_partial_allocated,
+                            rtnl->rqueue_partial_size + 1))
+                return -ENOMEM;
+
+        return 0;
+}
+
 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
         int r;
 

commit 24a026737da3f108ba56c1c9fe7786b8173376d5
Author: Tom Gundersen <teg at jklm.no>
Date:   Wed Apr 16 18:17:24 2014 +0200

    sd-rtnl: message - don't put NULL message on rqueue
    
    If nothing interesting was receieved we should not put anything on
    the queue.

diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c
index 47dcd4a..ffc19f1 100644
--- a/src/libsystemd/sd-rtnl/rtnl-message.c
+++ b/src/libsystemd/sd-rtnl/rtnl-message.c
@@ -1194,12 +1194,17 @@ int socket_read_message(sd_rtnl *rtnl) {
                         break;
         }
 
-        r = rtnl_rqueue_make_room(rtnl);
-        if (r < 0)
-                return r;
+        if (first) {
+                r = rtnl_rqueue_make_room(rtnl);
+                if (r < 0)
+                        return r;
+
+                rtnl->rqueue[rtnl->rqueue_size ++] = first;
+                first = NULL;
+        }
 
-        rtnl->rqueue[rtnl->rqueue_size ++] = first;
-        first = NULL;
+        if (len)
+                log_debug("sd-rtnl: discarding %zu bytes of incoming message", len);
 
         return ret;
 }

commit 6fc518838cd717f2f8258f8a0cca37797c187a06
Author: Tom Gundersen <teg at jklm.no>
Date:   Tue Apr 15 12:01:39 2014 +0200

    sd-rtnl: message - make room for all pending messages, not just the first
    
    Also, don't actually read any of the message when peeking, just get its length.

diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c
index 1afba8f..47dcd4a 100644
--- a/src/libsystemd/sd-rtnl/rtnl-message.c
+++ b/src/libsystemd/sd-rtnl/rtnl-message.c
@@ -1080,26 +1080,23 @@ int socket_read_message(sd_rtnl *rtnl) {
 
         assert(rtnl);
         assert(rtnl->rbuffer);
+        assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
 
-        iov.iov_base = rtnl->rbuffer;
-        iov.iov_len = rtnl->rbuffer_allocated;
-
-        /* peek at the pending message header to get the message size */
-        r = recvmsg(rtnl->fd, &msg, MSG_PEEK);
+        /* read nothing, just get the pending message size */
+        r = recvmsg(rtnl->fd, &msg, MSG_PEEK | MSG_TRUNC);
         if (r < 0)
                 /* no data */
                 return (errno == EAGAIN) ? 0 : -errno;
         else if (r == 0)
                 /* connection was closed by the kernel */
                 return -ECONNRESET;
-        else if ((size_t)r < sizeof(struct nlmsghdr))
-                return -EIO;
+        else
+                len = (size_t)r;
 
         /* make room for the pending message */
         if (!greedy_realloc((void **)&rtnl->rbuffer,
                             &rtnl->rbuffer_allocated,
-                            rtnl->rbuffer->nlmsg_len,
-                            sizeof(uint8_t)))
+                            len, sizeof(uint8_t)))
                 return -ENOMEM;
 
         iov.iov_base = rtnl->rbuffer;



More information about the systemd-commits mailing list