diff options
author | Thomas Haller <thaller@redhat.com> | 2017-10-09 10:58:47 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-10-11 15:59:30 +0200 |
commit | 9836c3d682226311f4729d6852d1cf7fcb8a2252 (patch) | |
tree | dc58db8985a1351851243ca0df9b3505ed61a6e0 | |
parent | f97151e23bf59278c379bb90f9292f7dfe10c977 (diff) | |
download | NetworkManager-th/ndisc-route-preference-rh1445417.tar.gz |
core: use router preference for IPv6 routesth/ndisc-route-preference-rh1445417
For routes and the default-route from NDisc, set the router preference
RTA_PREF.
Also, previously, we would only configure one IPv6 default-route. That by itself
was not really a problem, as long as NetworkManager would always make sure that
it configured the route to the ~best~ router.
Actually, NM should have done that already. It keeps the list of gateways
sorted, and prefers them according to their preference. But maybe
it didn't, so we have bug rh#1445417 (??).
Change that by configuring a default-route for all gateways, with
appropriate router prefrence. In case, kernel doesn't support RTA_PREF
yet, only configure all routes that share the same maxiumum preference.
https://bugzilla.redhat.com/show_bug.cgi?id=1445417
-rw-r--r-- | src/devices/nm-device.c | 4 | ||||
-rw-r--r-- | src/nm-iface-helper.c | 4 | ||||
-rw-r--r-- | src/nm-ip6-config.c | 45 | ||||
-rw-r--r-- | src/nm-ip6-config.h | 3 |
4 files changed, 38 insertions, 18 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 0e9833bd3d..3000adb32f 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -7397,7 +7397,9 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in rdata->routes, rdata->routes_n, nm_device_get_route_table (self, AF_INET6, TRUE), - nm_device_get_route_metric (self, AF_INET6)); + nm_device_get_route_metric (self, AF_INET6), + nm_platform_check_kernel_support (nm_device_get_platform (self), + NM_PLATFORM_KERNEL_SUPPORT_RTA_PREF)); } if (changed & NM_NDISC_CONFIG_DNS_SERVERS) { diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c index 8f6331e3c9..38a8a8afef 100644 --- a/src/nm-iface-helper.c +++ b/src/nm-iface-helper.c @@ -208,7 +208,9 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in rdata->routes, rdata->routes_n, RT_TABLE_MAIN, - global_opt.priority_v6); + global_opt.priority_v6, + nm_platform_check_kernel_support (NM_PLATFORM_GET, + NM_PLATFORM_KERNEL_SUPPORT_RTA_PREF)); } if (changed & NM_NDISC_CONFIG_DHCP_LEVEL) { diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 8eeabca223..3f0bbfe75c 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -1769,7 +1769,8 @@ nm_ip6_config_reset_routes_ndisc (NMIP6Config *self, const NMNDiscRoute *routes, guint routes_n, guint32 route_table, - guint32 route_metric) + guint32 route_metric, + gboolean kernel_support_rta_pref) { NMIP6ConfigPrivate *priv; guint i; @@ -1800,6 +1801,8 @@ nm_ip6_config_reset_routes_ndisc (NMIP6Config *self, r->rt_source = NM_IP_CONFIG_SOURCE_NDISC; r->table_coerced = nm_platform_route_table_coerce (route_table); r->metric = route_metric; + r->rt_pref = ndisc_route->preference; + nm_assert ((NMIcmpv6RouterPref) r->rt_pref == ndisc_route->preference); if (_nm_ip_config_add_obj (priv->multi_idx, &priv->idx_ip6_routes_, @@ -1814,28 +1817,40 @@ nm_ip6_config_reset_routes_ndisc (NMIP6Config *self, new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, obj_new); } - /* Use the first gateway as ordered in neighbor discovery cache. */ if (gateways_n) { const NMPObject *obj_new; - const NMPlatformIP6Route r = { + NMPlatformIP6Route r = { .rt_source = NM_IP_CONFIG_SOURCE_NDISC, .ifindex = priv->ifindex, - .gateway = gateways[0].address, .table_coerced = nm_platform_route_table_coerce (route_table), .metric = route_metric, }; + const NMIcmpv6RouterPref first_pref = gateways[0].preference; + + for (i = 0; i < gateways_n; i++) { + r.gateway = gateways[i].address; + r.rt_pref = gateways[i].preference; + nm_assert ((NMIcmpv6RouterPref) r.rt_pref == gateways[i].preference); + if (_nm_ip_config_add_obj (priv->multi_idx, + &priv->idx_ip6_routes_, + priv->ifindex, + NULL, + (const NMPlatformObject *) &r, + FALSE, + TRUE, + NULL, + &obj_new)) + changed = TRUE; + new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, obj_new); - if (_nm_ip_config_add_obj (priv->multi_idx, - &priv->idx_ip6_routes_, - priv->ifindex, - NULL, - (const NMPlatformObject *) &r, - FALSE, - TRUE, - NULL, - &obj_new)) - changed = TRUE; - new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, obj_new); + if ( first_pref != gateways[i].preference + && !kernel_support_rta_pref) { + /* We are unable to configure a router preference. Hence, we skip all gateways + * with a different preference from the first gateway. Note, that the gateways + * are sorted in order of highest to lowest preference. */ + break; + } + } } if (nm_dedup_multi_index_dirty_remove_idx (priv->multi_idx, &priv->idx_ip6_routes, FALSE) > 0) diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index c55ee31ea9..2fb8b8a4ad 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -219,6 +219,7 @@ void nm_ip6_config_reset_routes_ndisc (NMIP6Config *self, const struct _NMNDiscRoute *routes, guint routes_n, guint32 route_table, - guint32 route_metric); + guint32 route_metric, + gboolean kernel_support_rta_pref); #endif /* __NETWORKMANAGER_IP6_CONFIG_H__ */ |