]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: fix DHCPv4 address renewal with IPv4ACD
authorYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 18 Aug 2022 05:15:23 +0000 (14:15 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 18 Aug 2022 06:44:23 +0000 (15:44 +0900)
Previously, when a DHCP address is renewed and if the IPv4ACD for the
address is enabled, the address will never drop the probing flag, thus
the lifetime of the address will never be updated.

This drops NETWORK_CONFIG_STATE_PROBING, and the IPv4ACD status is
managed another bit, Address.acd_bound. And, the flag is updated only
when the IPv4ACD announced the address or detects conflict.

src/network/networkd-address.c
src/network/networkd-address.h
src/network/networkd-ipv4acd.c
src/network/networkd-ipv4acd.h
src/network/networkd-util.c
src/network/networkd-util.h

index ccb4a426faea04c1d915401532dff8c6810fcd0e..9122c644e8c7a5997f6bce4d135ce0a20e6628c3 100644 (file)
@@ -143,13 +143,13 @@ Address *address_free(Address *address) {
 bool address_is_ready(const Address *a) {
         assert(a);
 
-        if (FLAGS_SET(a->flags, IFA_F_TENTATIVE))
+        if (!ipv4acd_bound(a))
                 return false;
 
-        if (FLAGS_SET(a->state, NETWORK_CONFIG_STATE_REMOVING))
+        if (FLAGS_SET(a->flags, IFA_F_TENTATIVE))
                 return false;
 
-        if (FLAGS_SET(a->state, NETWORK_CONFIG_STATE_PROBING))
+        if (FLAGS_SET(a->state, NETWORK_CONFIG_STATE_REMOVING))
                 return false;
 
         if (!FLAGS_SET(a->state, NETWORK_CONFIG_STATE_CONFIGURED))
@@ -1089,7 +1089,7 @@ static bool address_is_ready_to_configure(Link *link, const Address *address) {
         if (!link_is_ready_to_configure(link, false))
                 return false;
 
-        if (FLAGS_SET(address->state, NETWORK_CONFIG_STATE_PROBING))
+        if (!ipv4acd_bound(address))
                 return false;
 
         /* Refuse adding more than the limit */
index 0237c1cb98c51d42cf8b1967d1d66d501f8ca444..f97342504cf452cae5fe50638b433d9d0e521d92 100644 (file)
@@ -58,6 +58,7 @@ struct Address {
          * To control DAD for IPv6 dynamic addresses, set IFA_F_NODAD to flags. */
         AddressFamily duplicate_address_detection;
         sd_ipv4acd *acd;
+        bool acd_bound;
 
         /* Called when address become ready */
         address_ready_callback_t callback;
@@ -118,12 +119,6 @@ int network_drop_invalid_addresses(Network *network);
 int address_compare_func(const Address *a1, const Address *a2);
 
 DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(Address, address);
-static inline void address_enter_probing(Address *address) {
-        address_update_state(address, NETWORK_CONFIG_STATE_PROBING, NETWORK_CONFIG_STATE_PROBING);
-}
-static inline void address_cancel_probing(Address *address) {
-        address_update_state(address, NETWORK_CONFIG_STATE_PROBING, 0);
-}
 
 void link_mark_addresses(Link *link, NetworkConfigSource source, const struct in6_addr *router);
 
index 4f2563ff9cf8e45e55a7ca3dd112f6f04014c839..f55e998f233766b013bbf153ff8db47caf63bbcd 100644 (file)
@@ -39,15 +39,21 @@ bool link_ipv4acd_supported(Link *link) {
         return true;
 }
 
+bool ipv4acd_bound(const Address *address) {
+        assert(address);
+
+        if (!address->acd)
+                return true;
+
+        return address->acd_bound;
+}
+
 static int static_ipv4acd_address_remove(Link *link, Address *address, bool on_conflict) {
         int r;
 
         assert(link);
         assert(address);
 
-        /* Prevent form the address being freed. */
-        address_enter_probing(address);
-
         if (!address_exists(address))
                 return 0; /* Not assigned. */
 
@@ -85,9 +91,6 @@ static int dhcp4_address_on_conflict(Link *link, Address *address) {
         if (r < 0)
                 return log_link_warning_errno(link, r, "Failed to drop DHCPv4 lease: %m");
 
-        /* make the address will be freed. */
-        address_cancel_probing(address);
-
         /* It is not necessary to call address_remove() here, as dhcp4_lease_lost() removes it. */
         return 0;
 }
@@ -108,6 +111,8 @@ static void on_acd(sd_ipv4acd *acd, int event, void *userdata) {
 
         switch (event) {
         case SD_IPV4ACD_EVENT_STOP:
+                address->acd_bound = false;
+
                 if (address->source == NETWORK_CONFIG_SOURCE_STATIC) {
                         r = static_ipv4acd_address_remove(link, address, /* on_conflict = */ false);
                         if (r < 0)
@@ -119,13 +124,15 @@ static void on_acd(sd_ipv4acd *acd, int event, void *userdata) {
                 break;
 
         case SD_IPV4ACD_EVENT_BIND:
+                address->acd_bound = true;
+
                 log_link_debug(link, "Successfully claimed address "IPV4_ADDRESS_FMT_STR,
                                IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
-
-                address_cancel_probing(address);
                 break;
 
         case SD_IPV4ACD_EVENT_CONFLICT:
+                address->acd_bound = false;
+
                 log_link_warning(link, "Dropping address "IPV4_ADDRESS_FMT_STR", as an address conflict was detected.",
                                  IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
 
@@ -157,6 +164,22 @@ static int ipv4acd_check_mac(sd_ipv4acd *acd, const struct ether_addr *mac, void
         return link_get_by_hw_addr(m, &hw_addr, NULL) >= 0;
 }
 
+static int address_ipv4acd_start(Address *address) {
+        assert(address);
+        assert(address->link);
+
+        if (!address->acd)
+                return 0;
+
+        if (sd_ipv4acd_is_running(address->acd))
+                return 0;
+
+        if (!link_has_carrier(address->link))
+                return 0;
+
+        return sd_ipv4acd_start(address->acd, true);
+}
+
 int ipv4acd_configure(Address *address) {
         Link *link;
         int r;
@@ -177,10 +200,8 @@ int ipv4acd_configure(Address *address) {
         /* Currently, only static and DHCP4 addresses are supported. */
         assert(IN_SET(address->source, NETWORK_CONFIG_SOURCE_STATIC, NETWORK_CONFIG_SOURCE_DHCP4));
 
-        if (address->acd) {
-                address_enter_probing(address);
-                return 0;
-        }
+        if (address->acd)
+                return address_ipv4acd_start(address);
 
         log_link_debug(link, "Configuring IPv4ACD for address "IPV4_ADDRESS_FMT_STR,
                        IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
@@ -213,14 +234,7 @@ int ipv4acd_configure(Address *address) {
         if (r < 0)
                 return r;
 
-        if (link_has_carrier(link)) {
-                r = sd_ipv4acd_start(address->acd, true);
-                if (r < 0)
-                        return r;
-        }
-
-        address_enter_probing(address);
-        return 0;
+        return address_ipv4acd_start(address);
 }
 
 int ipv4acd_update_mac(Link *link) {
@@ -255,13 +269,7 @@ int ipv4acd_start(Link *link) {
         assert(link);
 
         SET_FOREACH(address, link->addresses) {
-                if (!address->acd)
-                        continue;
-
-                if (sd_ipv4acd_is_running(address->acd))
-                        continue;
-
-                r = sd_ipv4acd_start(address->acd, true);
+                r = address_ipv4acd_start(address);
                 if (r < 0)
                         return r;
         }
index 7bd6a26b40a67abdd44cb47fbe315efff5926fd3..1ec9481b99e0256c124ece1a2f2166f78e24f457 100644 (file)
@@ -5,6 +5,7 @@ typedef struct Address Address;
 typedef struct Link Link;
 
 bool link_ipv4acd_supported(Link *link);
+bool ipv4acd_bound(const Address *address);
 int ipv4acd_configure(Address *address);
 int ipv4acd_update_mac(Link *link);
 int ipv4acd_start(Link *link);
index 1c0987bc3370c1049359e039171c2984face2681..aa1b5ed17207304385bf150dffb126b24590cd9c 100644 (file)
@@ -26,7 +26,6 @@ DEFINE_STRING_TABLE_LOOKUP_TO_STRING(network_config_source, NetworkConfigSource)
 
 int network_config_state_to_string_alloc(NetworkConfigState s, char **ret) {
         static const char* states[] = {
-                [LOG2U(NETWORK_CONFIG_STATE_PROBING)]     = "probing",
                 [LOG2U(NETWORK_CONFIG_STATE_REQUESTING)]  = "requesting",
                 [LOG2U(NETWORK_CONFIG_STATE_CONFIGURING)] = "configuring",
                 [LOG2U(NETWORK_CONFIG_STATE_CONFIGURED)]  = "configured",
index 373184a3ed71b903fd78797619faa355db03c7d8..84fdc99958ffc0fa501483dbb19c77f93c63fcae 100644 (file)
@@ -27,14 +27,13 @@ typedef enum NetworkConfigSource {
 } NetworkConfigSource;
 
 typedef enum NetworkConfigState {
-        NETWORK_CONFIG_STATE_PROBING     = 1 << 0, /* address is probing by IPv4ACD */
-        NETWORK_CONFIG_STATE_REQUESTING  = 1 << 1, /* request is queued */
-        NETWORK_CONFIG_STATE_CONFIGURING = 1 << 2, /* e.g. address_configure() is called, but no response is received yet */
-        NETWORK_CONFIG_STATE_CONFIGURED  = 1 << 3, /* e.g. address_configure() is called and received a response from kernel.
+        NETWORK_CONFIG_STATE_REQUESTING  = 1 << 0, /* request is queued */
+        NETWORK_CONFIG_STATE_CONFIGURING = 1 << 1, /* e.g. address_configure() is called, but no response is received yet */
+        NETWORK_CONFIG_STATE_CONFIGURED  = 1 << 2, /* e.g. address_configure() is called and received a response from kernel.
                                                     * Note that address may not be ready yet, so please use address_is_ready()
                                                     * to check whether the address can be usable or not. */
-        NETWORK_CONFIG_STATE_MARKED      = 1 << 4, /* used GC'ing the old config */
-        NETWORK_CONFIG_STATE_REMOVING    = 1 << 5, /* e.g. address_remove() is called, but no response is received yet */
+        NETWORK_CONFIG_STATE_MARKED      = 1 << 3, /* used GC'ing the old config */
+        NETWORK_CONFIG_STATE_REMOVING    = 1 << 4, /* e.g. address_remove() is called, but no response is received yet */
 } NetworkConfigState;
 
 static inline usec_t sec16_to_usec(uint16_t sec, usec_t timestamp_usec) {