iface-helper: fix RA processing with more than one router
authorLubomir Rintel <lkundrak@v3.sk>
Thu, 3 Mar 2016 14:35:14 +0000 (15:35 +0100)
committerLubomir Rintel <lkundrak@v3.sk>
Thu, 3 Mar 2016 15:00:56 +0000 (16:00 +0100)
We construct new IP6Config on each rdisc_config_changed(). That's not a smart
thing to do, since that makes us throw away the previous configuration.

In case the two routers on the same network, the first RA triggers
rdisc_config_changed() for changed gateway and addresses. On handling the
second RA rdisc_config_changed() doesn't add the address, resulting in the
address being removed on ip6 config sync.

A side effect of this is that the address is still tentative, resulting in DAD
retry and an new address being added. So the networking still works, but at the
expense of a single DAD failure and an address that's perhaps different from what
was expected.

src/nm-iface-helper.c

index cc59835..225464c 100644 (file)
@@ -130,9 +130,8 @@ dhcp4_state_changed (NMDhcpClient *client,
 static void
 rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, gpointer user_data)
 {
-       static NMIP6Config *last_config = NULL;
+       static NMIP6Config *rdisc_config = NULL;
        NMIP6Config *existing;
-       NMIP6Config *ip6_config;
        static int system_support = -1;
        guint32 ifa_flags = 0x00;
        int i;
@@ -157,21 +156,25 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, gpointer user_da
                ifa_flags |= IFA_F_MANAGETEMPADDR;
        }
 
-       ip6_config = nm_ip6_config_new (ifindex);
+       existing = nm_ip6_config_capture (ifindex, FALSE, global_opt.tempaddr);
+       if (rdisc_config)
+               nm_ip6_config_subtract (existing, rdisc_config);
+       else
+               rdisc_config = nm_ip6_config_new (ifindex);
 
        if (changed & NM_RDISC_CONFIG_GATEWAYS) {
                /* Use the first gateway as ordered in router discovery cache. */
                if (rdisc->gateways->len) {
                        NMRDiscGateway *gateway = &g_array_index (rdisc->gateways, NMRDiscGateway, 0);
 
-                       nm_ip6_config_set_gateway (ip6_config, &gateway->address);
+                       nm_ip6_config_set_gateway (rdisc_config, &gateway->address);
                } else
-                       nm_ip6_config_set_gateway (ip6_config, NULL);
+                       nm_ip6_config_set_gateway (rdisc_config, NULL);
        }
 
        if (changed & NM_RDISC_CONFIG_ADDRESSES) {
                /* Rebuild address list from router discovery cache. */
-               nm_ip6_config_reset_addresses (ip6_config);
+               nm_ip6_config_reset_addresses (rdisc_config);
 
                /* rdisc->addresses contains at most max_addresses entries.
                 * This is different from what the kernel does, which
@@ -193,13 +196,13 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, gpointer user_da
                        address.source = NM_IP_CONFIG_SOURCE_RDISC;
                        address.n_ifa_flags = ifa_flags;
 
-                       nm_ip6_config_add_address (ip6_config, &address);
+                       nm_ip6_config_add_address (rdisc_config, &address);
                }
        }
 
        if (changed & NM_RDISC_CONFIG_ROUTES) {
                /* Rebuild route list from router discovery cache. */
-               nm_ip6_config_reset_routes (ip6_config);
+               nm_ip6_config_reset_routes (rdisc_config);
 
                for (i = 0; i < rdisc->routes->len; i++) {
                        NMRDiscRoute *discovered_route = &g_array_index (rdisc->routes, NMRDiscRoute, i);
@@ -217,7 +220,7 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, gpointer user_da
                                route.source = NM_IP_CONFIG_SOURCE_RDISC;
                                route.metric = global_opt.priority_v6;
 
-                               nm_ip6_config_add_route (ip6_config, &route);
+                               nm_ip6_config_add_route (rdisc_config, &route);
                        }
                }
        }
@@ -236,18 +239,9 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, gpointer user_da
                nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip6_property_path (global_opt.ifname, "mtu"), val);
        }
 
-       existing = nm_ip6_config_capture (ifindex, FALSE, global_opt.tempaddr);
-       if (last_config)
-               nm_ip6_config_subtract (existing, last_config);
-
-       nm_ip6_config_merge (existing, ip6_config, NM_IP_CONFIG_MERGE_DEFAULT);
+       nm_ip6_config_merge (existing, rdisc_config, NM_IP_CONFIG_MERGE_DEFAULT);
        if (!nm_ip6_config_commit (existing, ifindex, TRUE))
                nm_log_warn (LOGD_IP6, "(%s): failed to apply IPv6 config", global_opt.ifname);
-
-       if (last_config)
-               g_object_unref (last_config);
-       last_config = nm_ip6_config_new (ifindex);
-       nm_ip6_config_replace (last_config, ip6_config, NULL);
 }
 
 static void