ip6: add default gateway to NMIP6Config (bgo #676317)
authorPavel Šimerda <psimerda@redhat.com>
Wed, 23 May 2012 17:07:39 +0000 (19:07 +0200)
committerDan Williams <dcbw@redhat.com>
Thu, 31 May 2012 20:37:49 +0000 (15:37 -0500)
Bug #676317 describes the following error:

  NetworkManager[30151]: <error> [1337348764.559121] [nm-system.c:1121]
  nm_system_replace_default_ip6_route(): (eth1): failed to set IPv6 default
  route: -7

The above error is caused by NetworkManager assuming default gateways
belong to addresses but failing to setup default gateways for addresses
learned through DHCPv6.

This commit doesn't fix the fundamental issue but can be viewed as an ugly
workaround that gets IPv6 connection up and running. It doesn't fix
the fundamental flaw of binding gateways to IP addresses. They are
configured separately in IPv6 and NM should use lifetimes and allow
default gateway reconfiguration.

src/ip6-manager/nm-ip6-manager.c
src/nm-device.c
src/nm-ip6-config.c
src/nm-ip6-config.h
src/nm-policy.c

index 18f78fa..7d58e29 100644 (file)
@@ -1270,8 +1270,6 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex)
        struct rtnl_route *rtnlroute;
        struct nl_addr *nldest, *nlgateway;
        struct in6_addr *dest, *gateway;
-       gboolean defgw_set = FALSE;
-       struct in6_addr defgw;
        uint32_t metric;
        NMIP6Route *ip6route;
        int i;
@@ -1321,11 +1319,9 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex)
                gateway = nl_addr_get_binary_addr (nlgateway);
 
                if (rtnl_route_get_dst_len (rtnlroute) == 0) {
-                       /* Default gateway route; don't add to normal routes but to each address */
-                       if (!defgw_set) {
-                               memcpy (&defgw, gateway, sizeof (defgw));
-                               defgw_set = TRUE;
-                       }
+                       /* Default gateway route; cache the router's address for later */
+                       if (!nm_ip6_config_get_defgw (config))
+                               nm_ip6_config_set_defgw (config, gateway);
                        continue;
                }
 
@@ -1348,6 +1344,8 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex)
 
        /* Add addresses */
        for (rtnladdr = FIRST_ADDR (priv->addr_cache); rtnladdr; rtnladdr = NEXT_ADDR (rtnladdr)) {
+               const struct in6_addr *defgw;
+
                if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex)
                        continue;
 
@@ -1360,8 +1358,9 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex)
                nm_ip6_address_set_prefix (ip6addr, rtnl_addr_get_prefixlen (rtnladdr));
                nm_ip6_address_set_address (ip6addr, addr);
                nm_ip6_config_take_address (config, ip6addr);
-               if (defgw_set)
-                       nm_ip6_address_set_gateway (ip6addr, &defgw);
+               defgw = nm_ip6_config_get_defgw (config);
+               if (defgw)
+                       nm_ip6_address_set_gateway (ip6addr, defgw);
        }
 
        /* Add DNS servers */
index 02509e7..b6359a7 100644 (file)
@@ -1794,6 +1794,10 @@ merge_ip6_configs (NMIP6Config *dst, NMIP6Config *src)
        for (i = 0; i < nm_ip6_config_get_num_nameservers (src); i++)
                nm_ip6_config_add_nameserver (dst, nm_ip6_config_get_nameserver (src, i));
 
+       /* default gateway */
+       if (!nm_ip6_config_get_defgw (dst))
+               nm_ip6_config_set_defgw (dst, nm_ip6_config_get_defgw (src));
+
        /* routes */
        for (i = 0; i < nm_ip6_config_get_num_routes (src); i++)
                nm_ip6_config_add_route (dst, nm_ip6_config_get_route (src, i));
index 0429e30..2fab486 100644 (file)
@@ -53,6 +53,8 @@ typedef struct {
        GPtrArray *domains;
        GPtrArray *searches;
 
+       gboolean defgw_set;
+       struct in6_addr defgw;
        GSList *routes;
 
        gboolean never_default;
@@ -245,6 +247,30 @@ void nm_ip6_config_reset_nameservers (NMIP6Config *config)
 }
 
 void
+nm_ip6_config_set_defgw (NMIP6Config *config, const struct in6_addr *defgw)
+{
+       NMIP6ConfigPrivate *priv;
+
+       g_return_if_fail (NM_IS_IP6_CONFIG (config));
+
+       priv = NM_IP6_CONFIG_GET_PRIVATE (config);
+       if (defgw)
+               memcpy (&priv->defgw, defgw, sizeof (priv->defgw));
+       priv->defgw_set = !!defgw;
+}
+
+const struct in6_addr *
+nm_ip6_config_get_defgw (NMIP6Config *config)
+{
+       NMIP6ConfigPrivate *priv;
+
+       g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL);
+
+       priv = NM_IP6_CONFIG_GET_PRIVATE (config);
+       return priv->defgw_set ? &priv->defgw : NULL;
+}
+
+void
 nm_ip6_config_take_route (NMIP6Config *config, NMIP6Route *route)
 {
        NMIP6ConfigPrivate *priv;
@@ -659,6 +685,7 @@ nm_ip6_config_init (NMIP6Config *config)
        priv->nameservers = g_array_new (FALSE, TRUE, sizeof (struct in6_addr));
        priv->domains = g_ptr_array_sized_new (3);
        priv->searches = g_ptr_array_sized_new (3);
+       priv->defgw_set = FALSE;
 }
 
 static void
index 1e75a12..bc87430 100644 (file)
@@ -67,6 +67,9 @@ const struct in6_addr *nm_ip6_config_get_nameserver      (NMIP6Config *config, g
 guint32       nm_ip6_config_get_num_nameservers (NMIP6Config *config);
 void          nm_ip6_config_reset_nameservers   (NMIP6Config *config);
 
+void                   nm_ip6_config_set_defgw  (NMIP6Config *config, const struct in6_addr *defgw);
+const struct in6_addr *nm_ip6_config_get_defgw  (NMIP6Config *config);
+
 void          nm_ip6_config_take_route          (NMIP6Config *config, NMIP6Route *route);
 void          nm_ip6_config_add_route           (NMIP6Config *config, NMIP6Route *route);
 void          nm_ip6_config_replace_route       (NMIP6Config *config, guint32 i, NMIP6Route *new_route);
index 26b24f9..5420bdf 100644 (file)
@@ -648,7 +648,12 @@ update_ip6_routing_and_dns (NMPolicy *policy, gboolean force_update)
                g_assert (ip6_config);
                addr = nm_ip6_config_get_address (ip6_config, 0);
 
-               nm_system_replace_default_ip6_route (ip_ifindex, nm_ip6_address_get_gateway (addr));
+               if (memcmp (nm_ip6_address_get_gateway (addr)->s6_addr, in6addr_any.s6_addr, sizeof (in6addr_any.s6_addr)) != 0)
+                       nm_system_replace_default_ip6_route (ip_ifindex, nm_ip6_address_get_gateway (addr));
+               else if (nm_ip6_config_get_defgw (ip6_config))
+                       nm_system_replace_default_ip6_route (ip_ifindex, nm_ip6_config_get_defgw (ip6_config));
+               else
+                       nm_log_dbg (LOGD_IP6, "missing default IPv6 route");
 
                dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE;
        }