network: prevent interfaces to be initialized multiple times
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 15 Apr 2019 08:34:00 +0000 (17:34 +0900)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 25 Apr 2019 08:44:46 +0000 (10:44 +0200)
When a uevent is received during the relevant interface is in
LINK_STATE_PENDING, then the interface may be initialized twice.
To prevent that, this introduces LINK_STATE_INITIALIZED.

src/network/networkd-link.c
src/network/networkd-link.h

index 4936329..3bc7f69 100644 (file)
@@ -1455,7 +1455,7 @@ static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
 
         log_link_debug(link, "Setting MTU done.");
 
-        if (link->state == LINK_STATE_PENDING)
+        if (link->state == LINK_STATE_INITIALIZED)
                 (void) link_configure_after_setting_mtu(link);
 
         return 1;
@@ -2644,7 +2644,7 @@ static int link_enter_join_netdev(Link *link) {
 
         assert(link);
         assert(link->network);
-        assert(link->state == LINK_STATE_PENDING);
+        assert(link->state == LINK_STATE_INITIALIZED);
 
         link_set_state(link, LINK_STATE_CONFIGURING);
 
@@ -3057,7 +3057,7 @@ static int link_configure(Link *link) {
 
         assert(link);
         assert(link->network);
-        assert(link->state == LINK_STATE_PENDING);
+        assert(link->state == LINK_STATE_INITIALIZED);
 
         if (STRPTR_IN_SET(link->kind, "can", "vcan"))
                 return link_configure_can(link);
@@ -3206,7 +3206,7 @@ static int link_configure_after_setting_mtu(Link *link) {
 
         assert(link);
         assert(link->network);
-        assert(link->state == LINK_STATE_PENDING);
+        assert(link->state == LINK_STATE_INITIALIZED);
 
         if (link->setting_mtu)
                 return 0;
@@ -3357,10 +3357,13 @@ static int link_initialized_and_synced(Link *link) {
         assert(link->ifname);
         assert(link->manager);
 
-        if (link->state != LINK_STATE_PENDING)
+        /* We may get called either from the asynchronous netlink callback,
+         * or directly for link_add() if running in a container. See link_add(). */
+        if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_INITIALIZED))
                 return 1;
 
         log_link_debug(link, "Link state is up-to-date");
+        link_set_state(link, LINK_STATE_INITIALIZED);
 
         r = link_new_bound_by_list(link);
         if (r < 0)
@@ -3436,6 +3439,7 @@ int link_initialized(Link *link, sd_device *device) {
                 return 0;
 
         log_link_debug(link, "udev initialized link");
+        link_set_state(link, LINK_STATE_INITIALIZED);
 
         link->sd_device = sd_device_ref(device);
 
@@ -4353,6 +4357,7 @@ void link_clean(Link *link) {
 
 static const char* const link_state_table[_LINK_STATE_MAX] = {
         [LINK_STATE_PENDING] = "pending",
+        [LINK_STATE_INITIALIZED] = "initialized",
         [LINK_STATE_CONFIGURING] = "configuring",
         [LINK_STATE_CONFIGURED] = "configured",
         [LINK_STATE_UNMANAGED] = "unmanaged",
index e65246c..e322ec2 100644 (file)
 #include "set.h"
 
 typedef enum LinkState {
-        LINK_STATE_PENDING,
-        LINK_STATE_CONFIGURING,
-        LINK_STATE_CONFIGURED,
-        LINK_STATE_UNMANAGED,
-        LINK_STATE_FAILED,
-        LINK_STATE_LINGER,
+        LINK_STATE_PENDING,     /* udev has not initialized the link */
+        LINK_STATE_INITIALIZED, /* udev has initialized the link */
+        LINK_STATE_CONFIGURING, /* configuring addresses, routes, etc. */
+        LINK_STATE_CONFIGURED,  /* everything is configured */
+        LINK_STATE_UNMANAGED,   /* Unmanaged=yes is set */
+        LINK_STATE_FAILED,      /* at least one configuration process failed */
+        LINK_STATE_LINGER,      /* RTM_DELLINK for the link has been received */
         _LINK_STATE_MAX,
         _LINK_STATE_INVALID = -1
 } LinkState;