networkd: link - track state of IPv6LL address
authorTom Gundersen <teg@jklm.no>
Tue, 10 Nov 2015 20:30:59 +0000 (21:30 +0100)
committerTom Gundersen <teg@jklm.no>
Wed, 11 Nov 2015 14:42:38 +0000 (15:42 +0100)
This is managed by the kernel, but we should track whether or not we have
a configured IPv6LL address. This fixes two issues:
 - we now wait for IPv6LL before considering the link ready
 - we now wait for IPv6LL before attempting to do NDisc or DHCPv6
   these protocols relies on an LL address being available.

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

index 5231427..c0562e5 100644 (file)
@@ -329,6 +329,7 @@ static int address_release(Address *address) {
 
 int address_update(Address *address, unsigned char flags, unsigned char scope, struct ifa_cacheinfo *cinfo) {
         bool ready;
+        int r;
 
         assert(address);
         assert(cinfo);
@@ -342,8 +343,17 @@ int address_update(Address *address, unsigned char flags, unsigned char scope, s
         if (address->link) {
                 link_update_operstate(address->link);
 
-                if (!ready && address_is_ready(address))
+                if (!ready && address_is_ready(address)) {
                         link_check_ready(address->link);
+
+                        if (address->family == AF_INET6 &&
+                            in_addr_is_link_local(AF_INET6, &address->in_addr) &&
+                            !address->link->ipv6ll_address) {
+                                r = link_ipv6ll_gained(address->link);
+                                if (r < 0)
+                                        return r;
+                        }
+                }
         }
 
         return 0;
index 19dff89..1194491 100644 (file)
@@ -603,6 +603,10 @@ void link_check_ready(Link *link) {
                     !link->ipv4ll_route)
                         return;
 
+        if (link_ipv6ll_enabled(link))
+                if (!link->ipv6ll_address)
+                        return;
+
         if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) &&
              !link->dhcp4_configured) ||
             (link_dhcp6_enabled(link) && !link_dhcp4_enabled(link) &&
@@ -1238,6 +1242,34 @@ static void lldp_handler(sd_lldp *lldp, int event, void *userdata) {
         }
 }
 
+static int link_acquire_ipv6_conf(Link *link) {
+        int r;
+
+        assert(link);
+
+        if (link_dhcp6_enabled(link)) {
+                assert(link->dhcp6_client);
+
+                log_link_debug(link, "Acquiring DHCPv6 lease");
+
+                r = sd_dhcp6_client_start(link->dhcp6_client);
+                if (r < 0)
+                        return log_link_warning_errno(link, r,  "Could not acquire DHCPv6 lease: %m");
+        }
+
+        if (link_ipv6_accept_ra_enabled(link)) {
+                assert(link->ndisc_router_discovery);
+
+                log_link_debug(link, "Discovering IPv6 routers");
+
+                r = sd_ndisc_router_discovery_start(link->ndisc_router_discovery);
+                if (r < 0)
+                        return log_link_warning_errno(link, r, "Could not start IPv6 Router Discovery: %m");
+        }
+
+        return 0;
+}
+
 static int link_acquire_conf(Link *link) {
         int r;
 
@@ -1266,26 +1298,6 @@ static int link_acquire_conf(Link *link) {
                         return log_link_warning_errno(link, r, "Could not acquire DHCPv4 lease: %m");
         }
 
-        if (link_dhcp6_enabled(link)) {
-                assert(link->dhcp6_client);
-
-                log_link_debug(link, "Acquiring DHCPv6 lease");
-
-                r = sd_dhcp6_client_start(link->dhcp6_client);
-                if (r < 0)
-                        return log_link_warning_errno(link, r,  "Could not acquire DHCPv6 lease: %m");
-        }
-
-        if (link_ipv6_accept_ra_enabled(link)) {
-                assert(link->ndisc_router_discovery);
-
-                log_link_debug(link, "Discovering IPv6 routers");
-
-                r = sd_ndisc_router_discovery_start(link->ndisc_router_discovery);
-                if (r < 0)
-                        return log_link_warning_errno(link, r, "Could not start IPv6 Router Discovery: %m");
-        }
-
         if (link_lldp_enabled(link)) {
                 assert(link->lldp);
 
@@ -2093,6 +2105,12 @@ static int link_configure(Link *link) {
                 r = link_acquire_conf(link);
                 if (r < 0)
                         return r;
+
+                if (link->ipv6ll_address) {
+                        r = link_acquire_ipv6_conf(link);
+                        if (r < 0)
+                                return r;
+                }
         }
 
         return link_enter_join_netdev(link);
@@ -2439,6 +2457,27 @@ failed:
         return r;
 }
 
+int link_ipv6ll_gained(Link *link) {
+        int r;
+
+        assert(link);
+
+        log_link_info(link, "Gained IPv6LL");
+
+        link->ipv6ll_address = true;
+        link_check_ready(link);
+
+        if (link->network) {
+                r = link_acquire_ipv6_conf(link);
+                if (r < 0) {
+                        link_enter_failed(link);
+                        return r;
+                }
+        }
+
+        return 0;
+}
+
 static int link_carrier_gained(Link *link) {
         int r;
 
index 440e332..b564bcb 100644 (file)
@@ -99,8 +99,9 @@ struct Link {
         bool ndisc_configured;
 
         sd_ipv4ll *ipv4ll;
-        bool ipv4ll_address;
-        bool ipv4ll_route;
+        bool ipv4ll_address:1;
+        bool ipv4ll_route:1;
+        bool ipv6ll_address:1;
 
         bool static_configured;
 
@@ -143,6 +144,8 @@ int link_save(Link *link);
 int link_carrier_reset(Link *link);
 bool link_has_carrier(Link *link);
 
+int link_ipv6ll_gained(Link *link);
+
 int link_set_mtu(Link *link, uint32_t mtu);
 int link_set_hostname(Link *link, const char *hostname);
 int link_set_timezone(Link *link, const char *timezone);