networkd: address - distinguish between addresses added by us and by others
authorTom Gundersen <teg@jklm.no>
Wed, 30 Sep 2015 12:01:44 +0000 (14:01 +0200)
committerTom Gundersen <teg@jklm.no>
Wed, 21 Oct 2015 00:35:31 +0000 (02:35 +0200)
We only keep the addresses that we added ourselves in link->addresses, and
introduce a new set link->addresses_foreign to keep addresses of unknown
origin.

Only functional change is that "foreign" addresses no longer prevent a link
from entering "configured" state.

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

index c6de89a..da458dc 100644 (file)
@@ -95,8 +95,10 @@ void address_free(Address *address) {
                                        UINT_TO_PTR(address->section));
         }
 
-        if (address->link)
+        if (address->link) {
                 set_remove(address->link->addresses, address);
+                set_remove(address->link->addresses_foreign, address);
+        }
 
         free(address);
 }
@@ -225,13 +227,17 @@ static int address_establish(Address *address, Link *link) {
         return 0;
 }
 
-int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
+static int address_add_internal(Link *link, Set **addresses,
+                                int family,
+                                const union in_addr_union *in_addr,
+                                unsigned char prefixlen,
+                                Address **ret) {
         _cleanup_address_free_ Address *address = NULL;
         int r;
 
         assert(link);
+        assert(addresses);
         assert(in_addr);
-        assert(ret);
 
         r = address_new(&address);
         if (r < 0)
@@ -241,22 +247,32 @@ int address_add(Link *link, int family, const union in_addr_union *in_addr, unsi
         address->in_addr = *in_addr;
         address->prefixlen = prefixlen;
 
-        r = set_ensure_allocated(&link->addresses, &address_hash_ops);
+        r = set_ensure_allocated(addresses, &address_hash_ops);
         if (r < 0)
                 return r;
 
-        r = set_put(link->addresses, address);
+        r = set_put(*addresses, address);
         if (r < 0)
                 return r;
 
         address->link = link;
 
-        *ret = address;
+        if (ret)
+                *ret = address;
+
         address = NULL;
 
         return 0;
 }
 
+int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
+        return address_add_internal(link, &link->addresses_foreign, family, in_addr, prefixlen, ret);
+}
+
+static int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
+        return address_add_internal(link, &link->addresses, family, in_addr, prefixlen, ret);
+}
+
 static int address_release(Address *address) {
         int r;
 
@@ -286,6 +302,7 @@ int address_update(Address *address, unsigned char flags, unsigned char scope, s
 
         ready = address_is_ready(address);
 
+        address->added = true;
         address->flags = flags;
         address->scope = scope;
         address->cinfo = *cinfo;
@@ -326,8 +343,11 @@ int address_get(Link *link, int family, const union in_addr_union *in_addr, unsi
         address.prefixlen = prefixlen;
 
         existing = set_get(link->addresses, &address);
-        if (!existing)
-                return -ENOENT;
+        if (!existing) {
+                existing = set_get(link->addresses_foreign, &address);
+                if (!existing)
+                        return -ENOENT;
+        }
 
         *ret = existing;
 
@@ -519,6 +539,12 @@ int address_configure(Address *address, Link *link, sd_netlink_message_handler_t
 
         link_ref(link);
 
+        r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
+        if (r < 0) {
+                address_release(address);
+                return log_error_errno(r, "Could not add address: %m");
+        }
+
         return 0;
 }
 
@@ -702,5 +728,5 @@ int config_parse_label(const char *unit,
 bool address_is_ready(const Address *a) {
         assert(a);
 
-        return !(a->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED));
+        return a->added && !(a->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED));
 }
index cb29acc..fd309be 100644 (file)
@@ -52,7 +52,8 @@ struct Address {
         union in_addr_union in_addr;
         union in_addr_union in_addr_peer;
 
-        bool ip_masquerade_done;
+        bool added:1;
+        bool ip_masquerade_done:1;
 
         LIST_FIELDS(Address, addresses);
 };
@@ -60,7 +61,7 @@ struct Address {
 int address_new_static(Network *network, unsigned section, Address **ret);
 int address_new(Address **ret);
 void address_free(Address *address);
-int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
+int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
 int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
 int address_update(Address *address, unsigned char flags, unsigned char scope, struct ifa_cacheinfo *cinfo);
 int address_drop(Address *address);
index 1ac76c4..c0f27aa 100644 (file)
@@ -297,6 +297,11 @@ static void link_free(Link *link) {
 
         set_free(link->addresses);
 
+        while (!set_isempty(link->addresses_foreign))
+                address_free(set_first(link->addresses_foreign));
+
+        set_free(link->addresses_foreign);
+
         while ((address = link->pool_addresses)) {
                 LIST_REMOVE(addresses, link->pool_addresses, address);
                 address_free(address);
@@ -508,7 +513,9 @@ void link_check_ready(Link *link) {
         Iterator i;
 
         assert(link);
-        assert(link->network);
+
+        if (!link->network)
+                return;
 
         if (!link->static_configured)
                 return;
@@ -2324,6 +2331,15 @@ static void link_update_operstate(Link *link) {
                                 scope = address->scope;
                 }
 
+                /* for operstate we also take foreign addresses into account */
+                SET_FOREACH(address, link->addresses_foreign, i) {
+                        if (!address_is_ready(address))
+                                continue;
+
+                        if (address->scope < scope)
+                                scope = address->scope;
+                }
+
                 if (scope < RT_SCOPE_SITE)
                         /* universally accessible addresses found */
                         operstate = LINK_OPERSTATE_ROUTABLE;
index a94bb2f..90ad08a 100644 (file)
@@ -84,6 +84,7 @@ struct Link {
         unsigned enslaving;
 
         Set *addresses;
+        Set *addresses_foreign;
 
         sd_dhcp_client *dhcp_client;
         sd_dhcp_lease *dhcp_lease;
index 9a7e71f..2b83ee8 100644 (file)
@@ -400,7 +400,8 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
                 if (address)
                         log_link_debug(link, "Updating address: %s/%u (valid for %s)", buf, prefixlen, valid_str);
                 else {
-                        r = address_add(link, family, &in_addr, prefixlen, &address);
+                        /* An address appeared that we did not request */
+                        r = address_add_foreign(link, family, &in_addr, prefixlen, &address);
                         if (r < 0) {
                                 log_link_warning_errno(link, r, "Failed to add address %s/%u: %m", buf, prefixlen);
                                 return 0;