[systemd-commits] 14 commits - src/libsystemd-network src/network

Tom Gundersen tomegun at kemper.freedesktop.org
Fri May 9 05:41:32 PDT 2014


 src/libsystemd-network/sd-dhcp-client.c  |    2 
 src/network/networkd-link.c              |  219 +++++++++++++++++++++++--------
 src/network/networkd-manager.c           |   35 +++-
 src/network/networkd-netdev.c            |   67 ++++++++-
 src/network/networkd-network-gperf.gperf |    8 -
 src/network/networkd-network.c           |  166 +++++++----------------
 src/network/networkd.h                   |   37 ++---
 7 files changed, 330 insertions(+), 204 deletions(-)

New commits:
commit b90b025af151eb4e07121f86495d9362e54b3455
Author: Tom Gundersen <teg at jklm.no>
Date:   Fri May 9 14:23:17 2014 +0200

    networkd: link - don't log errors when missing routes/addresses are dropped
    
    We were ignoring the wrong errno.

diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index d23be9c..f1f04a3 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -420,7 +420,7 @@ static int route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata)
         }
 
         r = sd_rtnl_message_get_errno(m);
-        if (r < 0 && r != -ENOENT)
+        if (r < 0 && r != -ESRCH)
                 log_struct_link(LOG_WARNING, link,
                                 "MESSAGE=%s: could not drop route: %s",
                                 link->ifname, strerror(-r),
@@ -623,7 +623,7 @@ static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdat
         }
 
         r = sd_rtnl_message_get_errno(m);
-        if (r < 0 && r != -ENOENT)
+        if (r < 0 && r != -EADDRNOTAVAIL)
                 log_struct_link(LOG_WARNING, link,
                                 "MESSAGE=%s: could not drop address: %s",
                                 link->ifname, strerror(-r),

commit 7619683b46bddcf753786fd20581322da9825f99
Author: Tom Gundersen <teg at jklm.no>
Date:   Fri May 9 12:11:15 2014 +0200

    networkd: link - handle links coming back to life
    
    When enslaving devices, we may receieve DELLINK/NEWLINK for the same ifindex,
    let's not be confused by this.

diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 7cb9ee6..d23be9c 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -160,7 +160,7 @@ void link_drop(Link *link) {
 
         link->state = LINK_STATE_LINGER;
 
-        log_debug_link(link, "dropped");
+        log_debug_link(link, "link removed");
 
         link_unref(link);
 
@@ -1733,6 +1733,12 @@ int link_update(Link *link, sd_rtnl_message *m) {
         assert(link->ifname);
         assert(m);
 
+        if (link->state == LINK_STATE_LINGER) {
+                link_ref(link);
+                log_info_link(link, "link readded");
+                link->state = LINK_STATE_ENSLAVING;
+        }
+
         r = sd_rtnl_message_read_string(m, IFLA_IFNAME, &ifname);
         if (r >= 0 && !streq(ifname, link->ifname)) {
                 log_info_link(link, "renamed to %s", ifname);

commit d9c67ea112724e271c39553d966eae612e272e34
Author: Tom Gundersen <teg at jklm.no>
Date:   Fri May 9 12:20:21 2014 +0200

    networkd: reorder bonding and bridging
    
    A link should only ever be part of one, but if we accidentally do both, let's do it
    in the right order so the failure is more obvious in the logs.

diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 0a228b2..7cb9ee6 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -1490,19 +1490,19 @@ static int link_enter_enslave(Link *link) {
             hashmap_isempty(link->network->macvlans))
                 return link_enslaved(link);
 
-        if (link->network->bridge) {
+        if (link->network->bond) {
                 log_struct_link(LOG_DEBUG, link,
                                 "MESSAGE=%s: enslaving by '%s'",
-                                link->ifname, link->network->bridge->name,
-                                NETDEV(link->network->bridge),
+                                link->ifname, link->network->bond->name,
+                                NETDEV(link->network->bond),
                                 NULL);
 
-                r = netdev_enslave(link->network->bridge, link, &enslave_handler);
+                r = netdev_enslave(link->network->bond, link, &enslave_handler);
                 if (r < 0) {
                         log_struct_link(LOG_WARNING, link,
                                         "MESSAGE=%s: could not enslave by '%s': %s",
-                                        link->ifname, link->network->bridge->name, strerror(-r),
-                                        NETDEV(link->network->bridge),
+                                        link->ifname, link->network->bond->name, strerror(-r),
+                                        NETDEV(link->network->bond),
                                         NULL);
                         link_enter_failed(link);
                         return r;
@@ -1512,19 +1512,19 @@ static int link_enter_enslave(Link *link) {
                 link->enslaving ++;
         }
 
-        if (link->network->bond) {
+        if (link->network->bridge) {
                 log_struct_link(LOG_DEBUG, link,
                                 "MESSAGE=%s: enslaving by '%s'",
-                                link->ifname, link->network->bond->name,
-                                NETDEV(link->network->bond),
+                                link->ifname, link->network->bridge->name,
+                                NETDEV(link->network->bridge),
                                 NULL);
 
-                r = netdev_enslave(link->network->bond, link, &enslave_handler);
+                r = netdev_enslave(link->network->bridge, link, &enslave_handler);
                 if (r < 0) {
                         log_struct_link(LOG_WARNING, link,
                                         "MESSAGE=%s: could not enslave by '%s': %s",
-                                        link->ifname, link->network->bond->name, strerror(-r),
-                                        NETDEV(link->network->bond),
+                                        link->ifname, link->network->bridge->name, strerror(-r),
+                                        NETDEV(link->network->bridge),
                                         NULL);
                         link_enter_failed(link);
                         return r;

commit 699370c98d37e4b373795f62cba9ff7bade5f2a1
Author: Tom Gundersen <teg at jklm.no>
Date:   Fri May 9 00:26:22 2014 +0200

    sd-dhcp-client: improve logging when stopping client
    
    'Requested by user' was confusing, just drop it.

diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index b69927d..94235cf 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -237,7 +237,7 @@ static sd_dhcp_client *client_stop(sd_dhcp_client *client, int error) {
         else {
                 switch(error) {
                 case DHCP_EVENT_STOP:
-                        log_dhcp_client(client, "STOPPED: Requested by user");
+                        log_dhcp_client(client, "STOPPED");
                         break;
                 case DHCP_EVENT_NO_LEASE:
                         log_dhcp_client(client, "STOPPED: No lease");

commit f22364691bafc834a41cbe106f73f3da1a78d57f
Author: Tom Gundersen <teg at jklm.no>
Date:   Thu May 8 18:55:11 2014 +0200

    networkd: manager - drop links and netdevs when we receive DELLINK

diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index 71c5425..40a088b 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -219,6 +219,7 @@ static int manager_udev_process_link(Manager *m, struct udev_device *device) {
 static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
         Manager *m = userdata;
         Link *link = NULL;
+        uint16_t type;
         char *name;
         int r, ifindex;
 
@@ -226,6 +227,12 @@ static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, vo
         assert(message);
         assert(m);
 
+        r = sd_rtnl_message_get_type(message, &type);
+        if (r < 0) {
+                log_warning("rtnl: could not get message type");
+                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");
@@ -233,7 +240,9 @@ static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, vo
         }
 
         link_get(m, ifindex, &link);
-        if (!link) {
+        if (type == RTM_DELLINK)
+                link_drop(link);
+        else if (!link) {
                 /* link is new, so add it */
                 r = link_add(m, message, &link);
                 if (r < 0) {
@@ -246,10 +255,12 @@ static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, vo
         if (r < 0)
                 log_warning("rtnl: received link message without valid ifname");
         else {
-                NetDev *netdev;
+                NetDev *netdev = NULL;
 
-                r = netdev_get(m, name, &netdev);
-                if (r >= 0) {
+                netdev_get(m, name, &netdev);
+                if (type == RTM_DELLINK)
+                        netdev_drop(netdev);
+                else if (netdev) {
                         r = netdev_set_ifindex(netdev, message);
                         if (r < 0) {
                                 log_debug("could not set ifindex on netdev");
@@ -258,9 +269,11 @@ static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, vo
                 }
         }
 
-        r = link_update(link, message);
-        if (r < 0)
-                return 0;
+        if (type == RTM_NEWLINK) {
+                r = link_update(link, message);
+                if (r < 0)
+                        return 0;
+        }
 
         return 1;
 }
@@ -358,6 +371,10 @@ int manager_rtnl_listen(Manager *m) {
         if (r < 0)
                 return r;
 
+        r = sd_rtnl_add_match(m->rtnl, RTM_DELLINK, &manager_rtnl_process_link, m);
+        if (r < 0)
+                return r;
+
         return 0;
 }
 

commit 37ebeb77cf94ef0222cbe3b19eaad8a0a53702f1
Author: Tom Gundersen <teg at jklm.no>
Date:   Thu May 8 21:08:12 2014 +0200

    networkd: netdev - drop if creation fails
    
    This ensures that all links waiting to be enslaved are notified that the netdev does not exist.

diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index 36decf4..7962cc6 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -219,8 +219,8 @@ static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userda
         if (r == -EEXIST)
                 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);
+                log_warning_netdev(netdev, "netdev could not be greated: %s", strerror(-r));
+                netdev_drop(netdev);
 
                 return 1;
         }

commit 370e9930c3260cc58984ec70e44b1e2ab7676496
Author: Tom Gundersen <teg at jklm.no>
Date:   Thu May 8 20:50:05 2014 +0200

    networkd: link - introduce LINGER state and link_drop()
    
    We need the LINGER state in case we still have references to the link after it has been dropped.

diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index e3fb094..0a228b2 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -154,6 +154,19 @@ int link_get(Manager *m, int ifindex, Link **ret) {
         return 0;
 }
 
+void link_drop(Link *link) {
+        if (!link || link->state == LINK_STATE_LINGER)
+                return;
+
+        link->state = LINK_STATE_LINGER;
+
+        log_debug_link(link, "dropped");
+
+        link_unref(link);
+
+        return;
+}
+
 static int link_enter_configured(Link *link) {
         assert(link);
         assert(link->state == LINK_STATE_SETTING_ROUTES);
@@ -213,7 +226,7 @@ static int link_stop_clients(Link *link) {
 static void link_enter_failed(Link *link) {
         assert(link);
 
-        if (link->state == LINK_STATE_FAILED)
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                 return;
 
         log_warning_link(link, "failed");
@@ -230,13 +243,13 @@ static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
         int r;
 
         assert(link->route_messages > 0);
-        assert(link->state == LINK_STATE_SETTING_ADDRESSES ||
-               link->state == LINK_STATE_SETTING_ROUTES ||
-               link->state == LINK_STATE_FAILED);
+        assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
+                      LINK_STATE_SETTING_ROUTES, LINK_STATE_FAILED,
+                      LINK_STATE_LINGER));
 
         link->route_messages --;
 
-        if (link->state == LINK_STATE_FAILED) {
+        if (IN_SET(LINK_STATE_FAILED, LINK_STATE_LINGER)) {
                 link_unref(link);
                 return 1;
         }
@@ -272,7 +285,7 @@ static int link_enter_set_routes(Link *link) {
         link->state = LINK_STATE_SETTING_ROUTES;
 
         if (!link->network->static_routes && !link->dhcp_lease &&
-                (!link->ipv4ll || ipv4ll_is_bound(link->ipv4ll) == false))
+            (!link->ipv4ll || ipv4ll_is_bound(link->ipv4ll) == false))
                 return link_enter_configured(link);
 
         log_debug_link(link, "setting routes");
@@ -401,7 +414,7 @@ static int route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata)
         assert(link);
         assert(link->ifname);
 
-        if (link->state == LINK_STATE_FAILED) {
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) {
                 link_unref(link);
                 return 1;
         }
@@ -427,11 +440,12 @@ static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
         assert(link);
         assert(link->ifname);
         assert(link->addr_messages > 0);
-        assert(link->state == LINK_STATE_SETTING_ADDRESSES || link->state == LINK_STATE_FAILED);
+        assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
+               LINK_STATE_FAILED, LINK_STATE_LINGER));
 
         link->addr_messages --;
 
-        if (link->state == LINK_STATE_FAILED) {
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) {
                 link_unref(link);
                 return 1;
         }
@@ -577,7 +591,7 @@ static int address_update_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userd
         assert(link);
         assert(link->ifname);
 
-        if (link->state == LINK_STATE_FAILED) {
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) {
                 link_unref(link);
                 return 1;
         }
@@ -603,7 +617,7 @@ static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdat
         assert(link);
         assert(link->ifname);
 
-        if (link->state == LINK_STATE_FAILED) {
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) {
                 link_unref(link);
                 return 1;
         }
@@ -627,6 +641,11 @@ static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata,
 
         assert(link);
 
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) {
+                link_unref(link);
+                return 1;
+        }
+
         r = sd_bus_message_get_errno(m);
         if (r < 0)
                 log_warning("Could not set hostname: %s", strerror(-r));
@@ -682,7 +701,7 @@ static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
         assert(link);
         assert(link->ifname);
 
-        if (link->state == LINK_STATE_FAILED) {
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) {
                 link_unref(link);
                 return 1;
         }
@@ -933,7 +952,7 @@ static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
         assert(link->network);
         assert(link->manager);
 
-        if (link->state == LINK_STATE_FAILED)
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                 return;
 
         switch (event) {
@@ -1128,6 +1147,9 @@ static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){
         assert(link->network);
         assert(link->manager);
 
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+                return;
+
         switch(event) {
                 case IPV4LL_EVENT_STOP:
                 case IPV4LL_EVENT_CONFLICT:
@@ -1335,7 +1357,7 @@ static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
 
         assert(link);
 
-        if (link->state == LINK_STATE_FAILED) {
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) {
                 link_unref(link);
                 return 1;
         }
@@ -1417,12 +1439,13 @@ static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
         int r;
 
         assert(link);
-        assert(link->state == LINK_STATE_ENSLAVING || link->state == LINK_STATE_FAILED);
+        assert(IN_SET(link->state, LINK_STATE_ENSLAVING, LINK_STATE_FAILED,
+                      LINK_STATE_LINGER));
         assert(link->network);
 
         link->enslaving --;
 
-        if (link->state == LINK_STATE_FAILED) {
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) {
                 link_unref(link);
                 return 1;
         }
@@ -1784,6 +1807,11 @@ int link_save(Link *link) {
         if (r < 0)
                 return r;
 
+        if (link->state == LINK_STATE_LINGER) {
+                unlink(link->state_file);
+                return 0;
+        }
+
         admin_state = link_state_to_string(link->state);
         assert(admin_state);
 
@@ -1837,6 +1865,7 @@ static const char* const link_state_table[_LINK_STATE_MAX] = {
         [LINK_STATE_CONFIGURED] = "configured",
         [LINK_STATE_UNMANAGED] = "unmanaged",
         [LINK_STATE_FAILED] = "failed",
+        [LINK_STATE_LINGER] = "linger",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(link_state, LinkState);
diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index c7bec74..36decf4 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -114,6 +114,8 @@ void netdev_drop(NetDev *netdev) {
 
         netdev->state = NETDEV_STATE_LINGER;
 
+        log_debug_netdev(netdev, "dropped");
+
         netdev_cancel_callbacks(netdev);
 
         netdev_unref(netdev);
diff --git a/src/network/networkd.h b/src/network/networkd.h
index bdf9808..692b3df 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -195,6 +195,7 @@ typedef enum LinkState {
         LINK_STATE_CONFIGURED,
         LINK_STATE_UNMANAGED,
         LINK_STATE_FAILED,
+        LINK_STATE_LINGER,
         _LINK_STATE_MAX,
         _LINK_STATE_INVALID = -1
 } LinkState;
@@ -370,6 +371,7 @@ Link *link_unref(Link *link);
 Link *link_ref(Link *link);
 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_update(Link *link, sd_rtnl_message *message);
 

commit 2cc7e981af27b12a6a3d4f08728281febeb450c9
Author: Tom Gundersen <teg at jklm.no>
Date:   Thu May 8 20:42:22 2014 +0200

    networkd: netdev - introduce LINGER state and netdev_drop()
    
    We need the LINGER state in case we still have references to the netdev after it has been dropped.

diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index ed4bc19..c7bec74 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -108,6 +108,19 @@ NetDev *netdev_ref(NetDev *netdev) {
         return netdev;
 }
 
+void netdev_drop(NetDev *netdev) {
+        if (!netdev || netdev->state == NETDEV_STATE_LINGER)
+                return;
+
+        netdev->state = NETDEV_STATE_LINGER;
+
+        netdev_cancel_callbacks(netdev);
+
+        netdev_unref(netdev);
+
+        return;
+}
+
 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
         NetDev *netdev;
 
diff --git a/src/network/networkd.h b/src/network/networkd.h
index cff0136..bdf9808 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -76,6 +76,7 @@ typedef enum NetDevState {
         NETDEV_STATE_FAILED,
         NETDEV_STATE_CREATING,
         NETDEV_STATE_READY,
+        NETDEV_STATE_LINGER,
         _NETDEV_STATE_MAX,
         _NETDEV_STATE_INVALID = -1,
 } NetDevState;
@@ -271,6 +272,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
 /* NetDev */
 
 int netdev_load(Manager *manager);
+void netdev_drop(NetDev *netdev);
 
 NetDev *netdev_unref(NetDev *netdev);
 NetDev *netdev_ref(NetDev *netdev);

commit 59cb64e6253e445c78b9e78be5e27bae0015ea38
Author: Tom Gundersen <teg at jklm.no>
Date:   Thu May 8 20:40:56 2014 +0200

    networkd: netdev - cancel all callbacks when freeing
    
    This notifies the link that the netdev no longer exists.

diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index 5ee257f..ed4bc19 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -48,16 +48,35 @@ static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
 DEFINE_STRING_TABLE_LOOKUP(macvlan_mode, MacVlanMode);
 DEFINE_CONFIG_PARSE_ENUM(config_parse_macvlan_mode, macvlan_mode, MacVlanMode, "Failed to parse macvlan mode");
 
-static void netdev_free(NetDev *netdev) {
+static void netdev_cancel_callbacks(NetDev *netdev) {
+        _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
         netdev_enslave_callback *callback;
 
         if (!netdev)
                 return;
 
+        rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
+
         while ((callback = netdev->callbacks)) {
+                if (m) {
+                        assert(callback->link);
+                        assert(callback->callback);
+                        assert(netdev->manager);
+                        assert(netdev->manager->rtnl);
+
+                        callback->callback(netdev->manager->rtnl, m, link);
+                }
+
                 LIST_REMOVE(callbacks, netdev->callbacks, callback);
                 free(callback);
         }
+}
+
+static void netdev_free(NetDev *netdev) {
+        if (!netdev)
+                return;
+
+        netdev_cancel_callbacks(netdev);
 
         if (netdev->name)
                 hashmap_remove(netdev->manager->netdevs, netdev->name);

commit b226d99b044222739dccfa9cf9f7a9d79576c407
Author: Tom Gundersen <teg at jklm.no>
Date:   Thu May 8 19:46:06 2014 +0200

    networkd: link - take refcounts on links
    
    We need to take a refcount on the link whenever we expect a callback. The exceptions
    are the ipv4ll/dhcp clients as their lifetimes are guaranteed to be shorter than that
    of the link.

diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 525fe14..e3fb094 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -236,8 +236,10 @@ static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
 
         link->route_messages --;
 
-        if (link->state == LINK_STATE_FAILED)
+        if (link->state == LINK_STATE_FAILED) {
+                link_unref(link);
                 return 1;
+        }
 
         r = sd_rtnl_message_get_errno(m);
         if (r < 0 && r != -EEXIST)
@@ -254,6 +256,8 @@ static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
                 link_enter_configured(link);
         }
 
+        link_unref(link);
+
         return 1;
 }
 
@@ -282,6 +286,7 @@ static int link_enter_set_routes(Link *link) {
                         return r;
                 }
 
+                link_ref(link);
                 link->route_messages ++;
         }
 
@@ -316,6 +321,7 @@ static int link_enter_set_routes(Link *link) {
                                 return r;
                         }
 
+                        link_ref(link);
                         link->route_messages ++;
                 }
         }
@@ -361,6 +367,7 @@ static int link_enter_set_routes(Link *link) {
                                 return r;
                         }
 
+                        link_ref(link);
                         link->route_messages ++;
 
                         route->family = AF_INET;
@@ -374,6 +381,7 @@ static int link_enter_set_routes(Link *link) {
                                 return r;
                         }
 
+                        link_ref(link);
                         link->route_messages ++;
                 }
         }
@@ -393,8 +401,10 @@ static int route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata)
         assert(link);
         assert(link->ifname);
 
-        if (link->state == LINK_STATE_FAILED)
+        if (link->state == LINK_STATE_FAILED) {
+                link_unref(link);
                 return 1;
+        }
 
         r = sd_rtnl_message_get_errno(m);
         if (r < 0 && r != -ENOENT)
@@ -404,6 +414,8 @@ static int route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata)
                                 "ERRNO=%d", -r,
                                 NULL);
 
+        link_unref(link);
+
         return 0;
 }
 
@@ -419,8 +431,10 @@ static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
 
         link->addr_messages --;
 
-        if (link->state == LINK_STATE_FAILED)
+        if (link->state == LINK_STATE_FAILED) {
+                link_unref(link);
                 return 1;
+        }
 
         r = sd_rtnl_message_get_errno(m);
         if (r < 0 && r != -EEXIST)
@@ -435,6 +449,8 @@ static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
                 link_enter_set_routes(link);
         }
 
+        link_unref(link);
+
         return 1;
 }
 
@@ -463,6 +479,7 @@ static int link_enter_set_addresses(Link *link) {
                         return r;
                 }
 
+                link_ref(link);
                 link->addr_messages ++;
         }
 
@@ -498,6 +515,7 @@ static int link_enter_set_addresses(Link *link) {
                                 return r;
                         }
 
+                        link_ref(link);
                         link->addr_messages ++;
                 }
         }
@@ -544,6 +562,7 @@ static int link_enter_set_addresses(Link *link) {
                         return r;
                 }
 
+                link_ref(link);
                 link->addr_messages ++;
         }
 
@@ -558,8 +577,10 @@ static int address_update_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userd
         assert(link);
         assert(link->ifname);
 
-        if (link->state == LINK_STATE_FAILED)
+        if (link->state == LINK_STATE_FAILED) {
+                link_unref(link);
                 return 1;
+        }
 
         r = sd_rtnl_message_get_errno(m);
         if (r < 0 && r != -ENOENT)
@@ -569,6 +590,8 @@ static int address_update_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userd
                                 "ERRNO=%d", -r,
                                 NULL);
 
+        link_unref(link);
+
         return 0;
 }
 
@@ -580,8 +603,10 @@ static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdat
         assert(link);
         assert(link->ifname);
 
-        if (link->state == LINK_STATE_FAILED)
+        if (link->state == LINK_STATE_FAILED) {
+                link_unref(link);
                 return 1;
+        }
 
         r = sd_rtnl_message_get_errno(m);
         if (r < 0 && r != -ENOENT)
@@ -591,34 +616,43 @@ static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdat
                                 "ERRNO=%d", -r,
                                 NULL);
 
+        link_unref(link);
+
         return 0;
 }
 
 static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+        Link *link = userdata;
         int r;
 
+        assert(link);
+
         r = sd_bus_message_get_errno(m);
         if (r < 0)
                 log_warning("Could not set hostname: %s", strerror(-r));
 
+        link_unref(link);
+
         return 1;
 }
 
-static int set_hostname(sd_bus *bus, const char *hostname) {
+static int link_set_hostname(Link *link, const char *hostname) {
         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
         int r = 0;
 
+        assert(link);
+        assert(link->manager);
         assert(hostname);
 
-        log_debug("Setting transient hostname: '%s'", hostname);
+        log_debug_link(link, "Setting transient hostname: '%s'", hostname);
 
-        if (!bus) { /* TODO: replace by assert when we can rely on kdbus */
-                log_info("Not connected to system bus, ignoring transient hostname.");
+        if (!link->manager->bus) { /* TODO: replace by assert when we can rely on kdbus */
+                log_info_link(link, "Not connected to system bus, ignoring transient hostname.");
                 return 0;
         }
 
         r = sd_bus_message_new_method_call(
-                        bus,
+                        link->manager->bus,
                         &m,
                         "org.freedesktop.hostname1",
                         "/org/freedesktop/hostname1",
@@ -631,9 +665,11 @@ static int set_hostname(sd_bus *bus, const char *hostname) {
         if (r < 0)
                 return r;
 
-        r = sd_bus_call_async(bus, m, set_hostname_handler, NULL, 0, NULL);
+        r = sd_bus_call_async(link->manager->bus, m, set_hostname_handler, link, 0, NULL);
         if (r < 0)
-                log_error("Could not set transient hostname: %s", strerror(-r));
+                log_error_link(link, "Could not set transient hostname: %s", strerror(-r));
+
+        link_ref(link);
 
         return r;
 }
@@ -646,8 +682,10 @@ static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
         assert(link);
         assert(link->ifname);
 
-        if (link->state == LINK_STATE_FAILED)
+        if (link->state == LINK_STATE_FAILED) {
+                link_unref(link);
                 return 1;
+        }
 
         r = sd_rtnl_message_get_errno(m);
         if (r < 0)
@@ -657,6 +695,8 @@ static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
                                 "ERRNO=%d", -r,
                                 NULL);
 
+        link_unref(link);
+
         return 1;
 }
 
@@ -690,6 +730,8 @@ static int link_set_mtu(Link *link, uint32_t mtu) {
                 return r;
         }
 
+        link_unref(link);
+
         return 0;
 }
 
@@ -720,6 +762,7 @@ static int dhcp_lease_lost(Link *link) {
                                 route_gw->scope = RT_SCOPE_LINK;
 
                                 route_drop(route_gw, link, &route_drop_handler);
+                                link_ref(link);
                         }
 
                         r = route_new_dynamic(&route);
@@ -728,6 +771,7 @@ static int dhcp_lease_lost(Link *link) {
                                 route->in_addr.in = gateway;
 
                                 route_drop(route, link, &route_drop_handler);
+                                link_ref(link);
                         }
                 }
 
@@ -740,6 +784,7 @@ static int dhcp_lease_lost(Link *link) {
                 address->prefixlen = prefixlen;
 
                 address_drop(address, link, &address_drop_handler);
+                link_ref(link);
         }
 
         if (link->network->dhcp_mtu) {
@@ -761,7 +806,7 @@ static int dhcp_lease_lost(Link *link) {
 
                 r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
                 if (r >= 0 && hostname) {
-                        r = set_hostname(link->manager->bus, "");
+                        r = link_set_hostname(link, "");
                         if (r < 0)
                                 log_error("Failed to reset transient hostname");
                 }
@@ -868,7 +913,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
 
                 r = sd_dhcp_lease_get_hostname(lease, &hostname);
                 if (r >= 0) {
-                        r = set_hostname(link->manager->bus, hostname);
+                        r = link_set_hostname(link, hostname);
                         if (r < 0)
                                 log_error("Failed to set transient hostname "
                                           "to '%s'", hostname);
@@ -988,6 +1033,7 @@ static int ipv4ll_address_update(Link *link, bool deprecate) {
                 address->broadcast.s_addr = address->in_addr.in.s_addr | htonl(0xfffffffflu >> address->prefixlen);
 
                 address_update(address, link, &address_update_handler);
+                link_ref(link);
         }
 
         return 0;
@@ -1020,6 +1066,7 @@ static int ipv4ll_address_lost(Link *link) {
                 address->scope = RT_SCOPE_LINK;
 
                 address_drop(address, link, &address_drop_handler);
+                link_ref(link);
 
                 r = route_new_dynamic(&route);
                 if (r < 0) {
@@ -1033,6 +1080,7 @@ static int ipv4ll_address_lost(Link *link) {
                 route->metrics = 99;
 
                 route_drop(route, link, &route_drop_handler);
+                link_ref(link);
         }
 
         return 0;
@@ -1287,8 +1335,10 @@ static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
 
         assert(link);
 
-        if (link->state == LINK_STATE_FAILED)
+        if (link->state == LINK_STATE_FAILED) {
+                link_unref(link);
                 return 1;
+        }
 
         r = sd_rtnl_message_get_errno(m);
         if (r < 0) {
@@ -1301,6 +1351,8 @@ static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
                                 NULL);
         }
 
+        link_unref(link);
+
         return 1;
 }
 
@@ -1334,6 +1386,8 @@ static int link_up(Link *link) {
                 return r;
         }
 
+        link_ref(link);
+
         return 0;
 }
 
@@ -1368,8 +1422,10 @@ static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
 
         link->enslaving --;
 
-        if (link->state == LINK_STATE_FAILED)
+        if (link->state == LINK_STATE_FAILED) {
+                link_unref(link);
                 return 1;
+        }
 
         r = sd_rtnl_message_get_errno(m);
         if (r < 0) {
@@ -1379,6 +1435,7 @@ static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
                                 "ERRNO=%d", -r,
                                 NULL);
                 link_enter_failed(link);
+                link_unref(link);
                 return 1;
         }
 
@@ -1387,6 +1444,8 @@ static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
         if (link->enslaving == 0)
                 link_enslaved(link);
 
+        link_unref(link);
+
         return 1;
 }
 
@@ -1426,6 +1485,7 @@ static int link_enter_enslave(Link *link) {
                         return r;
                 }
 
+                link_ref(link);
                 link->enslaving ++;
         }
 
@@ -1447,6 +1507,7 @@ static int link_enter_enslave(Link *link) {
                         return r;
                 }
 
+                link_ref(link);
                 link->enslaving ++;
         }
 
@@ -1465,6 +1526,7 @@ static int link_enter_enslave(Link *link) {
                         return r;
                 }
 
+                link_ref(link);
                 link->enslaving ++;
         }
 
@@ -1483,6 +1545,7 @@ static int link_enter_enslave(Link *link) {
                         return r;
                 }
 
+                link_ref(link);
                 link->enslaving ++;
         }
 
diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index 9614042..5ee257f 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -168,7 +168,7 @@ static int netdev_enter_ready(NetDev *netdev) {
         log_info_netdev(netdev, "netdev ready");
 
         LIST_FOREACH(callbacks, callback, netdev->callbacks) {
-                /* enslave the links that were attempted to be enslaved befor the
+                /* enslave the links that were attempted to be enslaved before the
                  * link was ready */
                 netdev_enslave_ready(netdev, callback->link, callback->callback);
         }
@@ -308,11 +308,15 @@ static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t c
 }
 
 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
+        int r;
+
         if (netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN)
                 return netdev_create(netdev, link, callback);
 
         if (netdev->state == NETDEV_STATE_READY) {
-                netdev_enslave_ready(netdev, link, callback);
+                r = netdev_enslave_ready(netdev, link, callback);
+                if (r < 0)
+                        return r;
         } else {
                 /* the netdev is not yet read, save this request for when it is*/
                 netdev_enslave_callback *cb;

commit 47e2dc3168cb0509d8d61f5dbeffaa3c252685b5
Author: Tom Gundersen <teg at jklm.no>
Date:   Thu May 8 19:28:17 2014 +0200

    networkd: network - do reference counting on netdevs

diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 4493359..a452096 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -145,6 +145,7 @@ int network_load(Manager *manager) {
 }
 
 void network_free(Network *network) {
+        NetDev *netdev;
         Route *route;
         Address *address;
         Iterator i;
@@ -167,8 +168,16 @@ void network_free(Network *network) {
 
         set_free(network->dns);
 
+        netdev_unref(network->bridge);
+
+        netdev_unref(network->bond);
+
+        HASHMAP_FOREACH(netdev, network->vlans, i)
+                netdev_unref(netdev);
         hashmap_free(network->vlans);
 
+        HASHMAP_FOREACH(netdev, network->macvlans, i)
+                netdev_unref(netdev);
         hashmap_free(network->macvlans);
 
         while ((route = network->static_routes))
@@ -317,5 +326,7 @@ int config_parse_netdev(const char *unit,
                 assert_not_reached("Can not parse NetDev");
         }
 
+        netdev_ref(netdev);
+
         return 0;
 }

commit 69a93e7db47addc4495a6ec9dc0fc74092a6ebee
Author: Tom Gundersen <teg at jklm.no>
Date:   Thu May 8 19:22:53 2014 +0200

    networkd: network - merge all netdev parsing into one function

diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 6ba890f..bfe44e0 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -25,10 +25,10 @@ Match.Virtualization,        config_parse_net_condition,         CONDITION_VIRTU
 Match.KernelCommandLine,     config_parse_net_condition,         CONDITION_KERNEL_COMMAND_LINE, offsetof(Network, match_kernel)
 Match.Architecture,          config_parse_net_condition,         CONDITION_ARCHITECTURE,        offsetof(Network, match_arch)
 Network.Description,         config_parse_string,                0,                             offsetof(Network, description)
-Network.Bridge,              config_parse_bridge,                0,                             offsetof(Network, bridge)
-Network.Bond,                config_parse_bond,                  0,                             offsetof(Network, bond)
-Network.VLAN,                config_parse_vlan,                  0,                             offsetof(Network, vlans)
-Network.MACVLAN,             config_parse_macvlan,               0,                             offsetof(Network, macvlans)
+Network.Bridge,              config_parse_netdev,                0,                             offsetof(Network, bridge)
+Network.Bond,                config_parse_netdev,                0,                             offsetof(Network, bond)
+Network.VLAN,                config_parse_netdev,                0,                             offsetof(Network, vlans)
+Network.MACVLAN,             config_parse_netdev,                0,                             offsetof(Network, macvlans)
 Network.DHCP,                config_parse_bool,                  0,                             offsetof(Network, dhcp)
 Network.IPv4LL,              config_parse_bool,                  0,                             offsetof(Network, ipv4ll)
 Network.Address,             config_parse_address,               0,                             0
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 4d01e55..4493359 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -19,6 +19,8 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <ctype.h>
+
 #include "networkd.h"
 #include "network-internal.h"
 #include "path-util.h"
@@ -235,7 +237,7 @@ int network_apply(Manager *manager, Network *network, Link *link) {
         return 0;
 }
 
-int config_parse_bridge(const char *unit,
+int config_parse_netdev(const char *unit,
                 const char *filename,
                 unsigned line,
                 const char *section,
@@ -246,7 +248,9 @@ int config_parse_bridge(const char *unit,
                 void *data,
                 void *userdata) {
         Network *network = userdata;
+        char *kind_string, *p;
         NetDev *netdev;
+        NetDevKind kind;
         int r;
 
         assert(filename);
@@ -254,140 +258,63 @@ int config_parse_bridge(const char *unit,
         assert(rvalue);
         assert(data);
 
-        r = netdev_get(network->manager, rvalue, &netdev);
-        if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
-                           "Bridge is invalid, ignoring assignment: %s", rvalue);
-                return 0;
-        }
-
-        if (netdev->kind != NETDEV_KIND_BRIDGE) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
-                           "NetDev is not a bridge, ignoring assignment: %s", rvalue);
-                return 0;
-        }
-
-        network->bridge = netdev;
-
-        return 0;
-}
-
-int config_parse_bond(const char *unit,
-                const char *filename,
-                unsigned line,
-                const char *section,
-                unsigned section_line,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-        Network *network = userdata;
-        NetDev *netdev;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
+        kind_string = strdup(lvalue);
+        if (!kind_string)
+                return log_oom();
 
-        r = netdev_get(network->manager, rvalue, &netdev);
-        if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
-                           "Bond is invalid, ignoring assignment: %s", rvalue);
-                return 0;
-        }
+        /* the keys are CamelCase versions of the kind */
+        for (p = kind_string; *p; p++)
+                *p = tolower(*p);
 
-        if (netdev->kind != NETDEV_KIND_BOND) {
+        kind = netdev_kind_from_string(kind_string);
+        if (kind == _NETDEV_KIND_INVALID) {
                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
-                           "NetDev is not a bond, ignoring assignment: %s", rvalue);
+                           "Invalid NetDev kind: %s", lvalue);
                 return 0;
         }
 
-        network->bond = netdev;
-
-        return 0;
-}
-
-int config_parse_vlan(const char *unit,
-                const char *filename,
-                unsigned line,
-                const char *section,
-                unsigned section_line,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-        Network *network = userdata;
-        NetDev *netdev;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
         r = netdev_get(network->manager, rvalue, &netdev);
         if (r < 0) {
                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
-                           "VLAN is invalid, ignoring assignment: %s", rvalue);
+                           "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
                 return 0;
         }
 
-        if (netdev->kind != NETDEV_KIND_VLAN) {
+        if (netdev->kind != kind) {
                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
-                           "NetDev is not a VLAN, ignoring assignment: %s", rvalue);
+                           "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
                 return 0;
         }
 
-        r = hashmap_put(network->vlans, &netdev->vlanid, netdev);
-        if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
-                           "Can not add VLAN to network: %s", rvalue);
-                return 0;
-        }
+        switch (kind) {
+        case NETDEV_KIND_BRIDGE:
+                network->bridge = netdev;
 
-        return 0;
-}
+                break;
+        case NETDEV_KIND_BOND:
+                network->bond = netdev;
 
-int config_parse_macvlan(const char *unit,
-                const char *filename,
-                unsigned line,
-                const char *section,
-                unsigned section_line,
-                const char *lvalue,
-                int ltype,
-                const char *rvalue,
-                void *data,
-                void *userdata) {
-        Network *network = userdata;
-        NetDev *netdev;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        r = netdev_get(network->manager, rvalue, &netdev);
-        if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
-                           "MACVLAN is invalid, ignoring assignment: %s", rvalue);
-                return 0;
-        }
+                break;
+        case NETDEV_KIND_VLAN:
+                r = hashmap_put(network->vlans, &netdev->vlanid, netdev);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                                   "Can not add VLAN to network: %s", rvalue);
+                        return 0;
+                }
 
-        if (netdev->kind != NETDEV_KIND_MACVLAN) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
-                           "NetDev is not a MACVLAN, ignoring assignment: %s", rvalue);
-                return 0;
-        }
+                break;
+        case NETDEV_KIND_MACVLAN:
+                r = hashmap_put(network->macvlans, netdev->name, netdev);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                                   "Can not add MACVLAN to network: %s", rvalue);
+                        return 0;
+                }
 
-        r = hashmap_put(network->macvlans, netdev->name, netdev);
-        if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
-                           "Can not add MACVLAN to network: %s", rvalue);
-                return 0;
+                break;
+        default:
+                assert_not_reached("Can not parse NetDev");
         }
 
         return 0;
diff --git a/src/network/networkd.h b/src/network/networkd.h
index b2794ba..cff0136 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -309,22 +309,10 @@ int network_get(Manager *manager, struct udev_device *device,
                 Network **ret);
 int network_apply(Manager *manager, Network *network, Link *link);
 
-int config_parse_bridge(const char *unit, const char *filename, unsigned line,
+int config_parse_netdev(const char *unit, const char *filename, unsigned line,
                         const char *section, unsigned section_line, const char *lvalue,
                         int ltype, const char *rvalue, void *data, void *userdata);
 
-int config_parse_bond(const char *unit, const char *filename, unsigned line,
-                      const char *section, unsigned section_line, const char *lvalue,
-                      int ltype, const char *rvalue, void *data, void *userdata);
-
-int config_parse_vlan(const char *unit, const char *filename, unsigned line,
-                      const char *section, unsigned section_line, const char *lvalue,
-                      int ltype, const char *rvalue, void *data, void *userdata);
-
-int config_parse_macvlan(const char *unit, const char *filename, unsigned line,
-                         const char *section, unsigned section_line, const char *lvalue,
-                         int ltype, const char *rvalue, void *data, void *userdata);
-
 /* gperf */
 const struct ConfigPerfItem* network_network_gperf_lookup(const char *key, unsigned length);
 

commit 14b746f72132324e637c4e39694bd474f85e19f7
Author: Tom Gundersen <teg at jklm.no>
Date:   Thu May 8 18:54:26 2014 +0200

    networkd: introduce refcounting for Links and NetDevs

diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 7486019..525fe14 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -37,7 +37,7 @@ static int ipv4ll_address_update(Link *link, bool deprecate);
 static bool ipv4ll_is_bound(sd_ipv4ll *ll);
 
 static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) {
-        _cleanup_link_free_ Link *link = NULL;
+        _cleanup_link_unref_ Link *link = NULL;
         uint16_t type;
         char *ifname;
         int r, ifindex;
@@ -67,6 +67,7 @@ static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) {
         if (!link)
                 return -ENOMEM;
 
+        link->n_ref = 1;
         link->manager = manager;
         link->state = LINK_STATE_INITIALIZING;
         link->ifindex = ifindex;
@@ -94,7 +95,7 @@ static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) {
         return 0;
 }
 
-void link_free(Link *link) {
+static void link_free(Link *link) {
         if (!link)
                 return;
 
@@ -120,6 +121,20 @@ void link_free(Link *link) {
         free(link);
 }
 
+Link *link_unref(Link *link) {
+        if (link && (-- link->n_ref <= 0))
+                link_free(link);
+
+        return NULL;
+}
+
+Link *link_ref(Link *link) {
+        if (link)
+                assert_se(++ link->n_ref >= 2);
+
+        return link;
+}
+
 int link_get(Manager *m, int ifindex, Link **ret) {
         Link *link;
         uint64_t ifindex_64;
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index 4b29553..71c5425 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -151,14 +151,14 @@ void manager_free(Manager *m) {
         sd_event_unref(m->event);
 
         while ((link = hashmap_first(m->links)))
-                link_free(link);
+                link_unref(link);
         hashmap_free(m->links);
 
         while ((network = m->networks))
                 network_free(network);
 
         while ((netdev = hashmap_first(m->netdevs)))
-                netdev_free(netdev);
+                netdev_unref(netdev);
         hashmap_free(m->netdevs);
 
         sd_rtnl_unref(m->rtnl);
diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index a8a629b..9614042 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -48,7 +48,7 @@ static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
 DEFINE_STRING_TABLE_LOOKUP(macvlan_mode, MacVlanMode);
 DEFINE_CONFIG_PARSE_ENUM(config_parse_macvlan_mode, macvlan_mode, MacVlanMode, "Failed to parse macvlan mode");
 
-void netdev_free(NetDev *netdev) {
+static void netdev_free(NetDev *netdev) {
         netdev_enslave_callback *callback;
 
         if (!netdev)
@@ -75,6 +75,20 @@ void netdev_free(NetDev *netdev) {
         free(netdev);
 }
 
+NetDev *netdev_unref(NetDev *netdev) {
+        if (netdev && (-- netdev->n_ref <= 0))
+                netdev_free(netdev);
+
+        return NULL;
+}
+
+NetDev *netdev_ref(NetDev *netdev) {
+        if (netdev)
+                assert_se(++ netdev->n_ref >= 2);
+
+        return netdev;
+}
+
 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
         NetDev *netdev;
 
@@ -413,7 +427,7 @@ int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
 }
 
 static int netdev_load_one(Manager *manager, const char *filename) {
-        _cleanup_netdev_free_ NetDev *netdev = NULL;
+        _cleanup_netdev_unref_ NetDev *netdev = NULL;
         _cleanup_fclose_ FILE *file = NULL;
         int r;
 
@@ -437,6 +451,7 @@ static int netdev_load_one(Manager *manager, const char *filename) {
         if (!netdev)
                 return log_oom();
 
+        netdev->n_ref = 1;
         netdev->manager = manager;
         netdev->state = _NETDEV_STATE_INVALID;
         netdev->kind = _NETDEV_KIND_INVALID;
@@ -517,7 +532,7 @@ int netdev_load(Manager *manager) {
         assert(manager);
 
         while ((netdev = hashmap_first(manager->netdevs)))
-                netdev_free(netdev);
+                netdev_unref(netdev);
 
         r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
         if (r < 0) {
diff --git a/src/network/networkd.h b/src/network/networkd.h
index 57eecf4..b2794ba 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -83,6 +83,8 @@ typedef enum NetDevState {
 struct NetDev {
         Manager *manager;
 
+        int n_ref;
+
         char *filename;
 
         Condition *match_host;
@@ -199,6 +201,8 @@ typedef enum LinkState {
 struct Link {
         Manager *manager;
 
+        int n_ref;
+
         uint64_t ifindex;
         char *ifname;
         char *state_file;
@@ -268,10 +272,11 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
 
 int netdev_load(Manager *manager);
 
-void netdev_free(NetDev *netdev);
+NetDev *netdev_unref(NetDev *netdev);
+NetDev *netdev_ref(NetDev *netdev);
 
-DEFINE_TRIVIAL_CLEANUP_FUNC(NetDev*, netdev_free);
-#define _cleanup_netdev_free_ _cleanup_(netdev_freep)
+DEFINE_TRIVIAL_CLEANUP_FUNC(NetDev*, netdev_unref);
+#define _cleanup_netdev_unref_ _cleanup_(netdev_unrefp)
 
 int netdev_get(Manager *manager, const char *name, NetDev **ret);
 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *newlink);
@@ -371,7 +376,8 @@ int config_parse_label(const char *unit, const char *filename, unsigned line,
 
 /* Link */
 
-void link_free(Link *link);
+Link *link_unref(Link *link);
+Link *link_ref(Link *link);
 int link_get(Manager *m, int ifindex, Link **ret);
 int link_add(Manager *manager, sd_rtnl_message *message, Link **ret);
 
@@ -386,8 +392,8 @@ bool link_has_carrier(unsigned flags, uint8_t operstate);
 const char* link_state_to_string(LinkState s) _const_;
 LinkState link_state_from_string(const char *s) _pure_;
 
-DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_free);
-#define _cleanup_link_free_ _cleanup_(link_freep)
+DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_unref);
+#define _cleanup_link_unref_ _cleanup_(link_unrefp)
 
 /* Macros which append INTERFACE= to the message */
 

commit 68a8723c8592c06b2c978f391cb47db266d9d6de
Author: Tom Gundersen <teg at jklm.no>
Date:   Thu May 8 18:53:32 2014 +0200

    networkd: link - clean up state files
    
    Also keep the path to the lease file around rather than regenarating it all the time.

diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index ab31583..7486019 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -79,6 +79,11 @@ static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) {
         if (r < 0)
                 return -ENOMEM;
 
+        r = asprintf(&link->lease_file, "/run/systemd/network/leases/%"PRIu64,
+                     link->ifindex);
+        if (r < 0)
+                return -ENOMEM;
+
         r = hashmap_put(manager->links, &link->ifindex, link);
         if (r < 0)
                 return r;
@@ -98,11 +103,16 @@ void link_free(Link *link) {
         sd_dhcp_client_unref(link->dhcp_client);
         sd_dhcp_lease_unref(link->dhcp_lease);
 
+        unlink(link->lease_file);
+        free(link->lease_file);
+
         sd_ipv4ll_unref(link->ipv4ll);
 
         hashmap_remove(link->manager->links, &link->ifindex);
 
         free(link->ifname);
+
+        unlink(link->state_file);
         free(link->state_file);
 
         udev_device_unref(link->udev_device);
@@ -1682,13 +1692,14 @@ int link_update(Link *link, sd_rtnl_message *m) {
 }
 
 int link_save(Link *link) {
-        _cleanup_free_ char *temp_path = NULL, *lease_file = NULL;
+        _cleanup_free_ char *temp_path = NULL;
         _cleanup_fclose_ FILE *f = NULL;
         const char *admin_state, *oper_state = "unknown";
         int r;
 
         assert(link);
         assert(link->state_file);
+        assert(link->lease_file);
         assert(link->manager);
 
         r = manager_save(link->manager);
@@ -1703,11 +1714,6 @@ int link_save(Link *link) {
         else if (link_has_carrier(link->flags, link->operstate))
                 oper_state = "carrier";
 
-        r = asprintf(&lease_file, "/run/systemd/network/leases/%"PRIu64,
-                             link->ifindex);
-        if (r < 0)
-                return -ENOMEM;
-
         r = fopen_temporary(link->state_file, &f, &temp_path);
         if (r < 0)
                 goto finish;
@@ -1722,13 +1728,13 @@ int link_save(Link *link) {
                 admin_state, oper_state, link->flags);
 
         if (link->dhcp_lease) {
-                r = dhcp_lease_save(link->dhcp_lease, lease_file);
+                r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
                 if (r < 0)
                         goto finish;
 
-                fprintf(f, "DHCP_LEASE=%s\n", lease_file);
+                fprintf(f, "DHCP_LEASE=%s\n", link->lease_file);
         } else
-                unlink(lease_file);
+                unlink(link->lease_file);
 
         fflush(f);
 
diff --git a/src/network/networkd.h b/src/network/networkd.h
index aebb285..57eecf4 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -218,6 +218,7 @@ struct Link {
 
         sd_dhcp_client *dhcp_client;
         sd_dhcp_lease *dhcp_lease;
+        char *lease_file;
         uint16_t original_mtu;
         sd_ipv4ll *ipv4ll;
 };



More information about the systemd-commits mailing list