From 8a059b1496448ffaa1178b35887883e1cf87800b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20=C5=A0imerda?= Date: Wed, 23 May 2012 19:07:39 +0200 Subject: [PATCH] ip6: add default gateway to NMIP6Config (bgo #676317) Bug #676317 describes the following error: NetworkManager[30151]: [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 | 17 ++++++++--------- src/nm-device.c | 4 ++++ src/nm-ip6-config.c | 27 +++++++++++++++++++++++++++ src/nm-ip6-config.h | 3 +++ src/nm-policy.c | 7 ++++++- 5 files changed, 48 insertions(+), 10 deletions(-) diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index 18f78faf06..7d58e29684 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -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 */ diff --git a/src/nm-device.c b/src/nm-device.c index 02509e7015..b6359a7c7a 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -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)); diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 0429e30b26..2fab486383 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -53,6 +53,8 @@ typedef struct { GPtrArray *domains; GPtrArray *searches; + gboolean defgw_set; + struct in6_addr defgw; GSList *routes; gboolean never_default; @@ -244,6 +246,30 @@ void nm_ip6_config_reset_nameservers (NMIP6Config *config) g_array_remove_range (priv->nameservers, 0, priv->nameservers->len); } +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) { @@ -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 diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index 1e75a121c8..bc87430cfc 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -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); diff --git a/src/nm-policy.c b/src/nm-policy.c index 26b24f92ed..5420bdf3f8 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -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; }