diff --git a/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.c b/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.c index 8d2ea09cdf..0e53016490 100644 --- a/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.c +++ b/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.c @@ -207,4 +207,5 @@ NM_UTILS_ENUM2STR_DEFINE (nm_utils_route_type2str, guint8, NM_UTILS_ENUM2STR (RTN_THROW, "throw"), NM_UTILS_ENUM2STR (RTN_UNICAST, "unicast"), NM_UTILS_ENUM2STR (RTN_UNREACHABLE, "unreachable"), + NM_UTILS_ENUM2STR (RTN_UNSPEC, "unspecified"), ); diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 0c1ae60a55..15162dabd1 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -411,8 +411,8 @@ typedef struct _NMDevicePrivate { bool v4_route_table_initialized:1; bool v6_route_table_initialized:1; - bool v4_route_table_full_sync_before:1; - bool v6_route_table_full_sync_before:1; + bool v4_route_table_all_sync_before:1; + bool v6_route_table_all_sync_before:1; NMDeviceAutoconnectBlockedFlags autoconnect_blocked_flags:5; @@ -2737,34 +2737,59 @@ _get_route_table_sync_mode_stateful (NMDevice *self, int addr_family) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gboolean full_sync_now; - gboolean full_sync_eff; + NMDedupMultiIter ipconf_iter; + gboolean all_sync_now; + gboolean all_sync_eff; - full_sync_now = _get_route_table (self, addr_family) != 0u; + all_sync_now = _get_route_table (self, addr_family) != 0u; - if (full_sync_now) - full_sync_eff = TRUE; + if (!all_sync_now) { + /* If there's a local route switch to all-sync in order + * to properly manage the local table */ + if (addr_family == AF_INET) { + const NMPlatformIP4Route *route; + + nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, priv->con_ip_config_4, &route) { + if (nm_platform_route_type_uncoerce (route->type_coerced) == RTN_LOCAL) { + all_sync_now = TRUE; + break; + } + } + } else { + const NMPlatformIP6Route *route; + + nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, priv->con_ip_config_6, &route) { + if (nm_platform_route_type_uncoerce (route->type_coerced) == RTN_LOCAL) { + all_sync_now = TRUE; + break; + } + } + } + } + + if (all_sync_now) + all_sync_eff = TRUE; else { - /* When we change from full-sync to no full-sync, we do a last full-sync one - * more time. For that, we determine the effective full-state based on the - * cached/previous full-sync flag. + /* When we change from all-sync to no all-sync, we do a last all-sync one + * more time. For that, we determine the effective all-state based on the + * cached/previous all-sync flag. * * The purpose of this is to support reapply of route-table (and thus the - * full-sync mode). If reapply toggles from full-sync to no-full-sync, we must + * all-sync mode). If reapply toggles from all-sync to no-all-sync, we must * sync one last time. */ if (addr_family == AF_INET) - full_sync_eff = priv->v4_route_table_full_sync_before; + all_sync_eff = priv->v4_route_table_all_sync_before; else - full_sync_eff = priv->v6_route_table_full_sync_before; + all_sync_eff = priv->v6_route_table_all_sync_before; } if (addr_family == AF_INET) - priv->v4_route_table_full_sync_before = full_sync_now; + priv->v4_route_table_all_sync_before = all_sync_now; else - priv->v6_route_table_full_sync_before = full_sync_now; + priv->v6_route_table_all_sync_before = all_sync_now; - return full_sync_eff - ? NM_IP_ROUTE_TABLE_SYNC_MODE_FULL + return all_sync_eff + ? NM_IP_ROUTE_TABLE_SYNC_MODE_ALL : NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN; } @@ -13244,7 +13269,8 @@ nm_device_set_ip_config (NMDevice *self, if (IS_IPv4) { success = nm_ip4_config_commit (NM_IP4_CONFIG (new_config), nm_device_get_platform (self), - _get_route_table_sync_mode_stateful (self, addr_family)); + _get_route_table_sync_mode_stateful (self, + AF_INET)); nm_platform_ip4_dev_route_blacklist_set (nm_device_get_platform (self), nm_ip_config_get_ifindex (new_config), ip4_dev_route_blacklist); @@ -13253,7 +13279,8 @@ nm_device_set_ip_config (NMDevice *self, success = nm_ip6_config_commit (NM_IP6_CONFIG (new_config), nm_device_get_platform (self), - _get_route_table_sync_mode_stateful (self, addr_family), + _get_route_table_sync_mode_stateful (self, + AF_INET6), &temporary_not_available); if (!_rt6_temporary_not_available_set (self, temporary_not_available)) @@ -15498,8 +15525,8 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) priv->v4_route_table_initialized = FALSE; priv->v6_route_table_initialized = FALSE; - priv->v4_route_table_full_sync_before = FALSE; - priv->v6_route_table_full_sync_before = FALSE; + priv->v4_route_table_all_sync_before = FALSE; + priv->v6_route_table_all_sync_before = FALSE; priv->default_route_metric_penalty_ip4_has = FALSE; priv->default_route_metric_penalty_ip6_has = FALSE; diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index d772d6a255..404b201f87 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -456,6 +456,24 @@ nm_ip6_config_update_routes_metric (NMIP6Config *self, gint64 metric) g_object_thaw_notify (G_OBJECT (self)); } +static void +_add_multicast_route6 (NMIP6Config *self, int ifindex) +{ + nm_auto_nmpobj NMPObject *r = NULL; + NMPlatformIP6Route *route; + + r = nmp_object_new (NMP_OBJECT_TYPE_IP6_ROUTE, NULL); + route = NMP_OBJECT_CAST_IP6_ROUTE (r); + route->ifindex = ifindex; + route->network.s6_addr[0] = 0xffu; + route->plen = 8; + route->table_coerced = nm_platform_route_table_coerce (RT_TABLE_LOCAL); + route->type_coerced = nm_platform_route_type_coerce (RTN_UNICAST); + route->metric = 256; + + _add_route (self, r, NULL, NULL); +} + void nm_ip6_config_add_dependent_routes (NMIP6Config *self, guint32 route_table, @@ -476,6 +494,9 @@ nm_ip6_config_add_dependent_routes (NMIP6Config *self, * * For manually added IPv6 routes, add the device routes explicitly. */ + /* Pre-generate multicast route */ + _add_multicast_route6 (self, ifindex); + nm_ip_config_iter_ip6_address_for_each (&iter, self, &my_addr) { NMPlatformIP6Route *route; gboolean has_peer; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 40451df820..b05c50de48 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -3398,6 +3398,7 @@ rta_multipath_done: obj = nmp_object_new (is_v4 ? NMP_OBJECT_TYPE_IP4_ROUTE : NMP_OBJECT_TYPE_IP6_ROUTE, NULL); + obj->ip_route.type_coerced = nm_platform_route_type_coerce (rtm->rtm_type); obj->ip_route.table_coerced = nm_platform_route_table_coerce ( tb[RTA_TABLE] ? nla_get_u32 (tb[RTA_TABLE]) : (guint32) rtm->rtm_table); diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 880e7b5d27..08822b1cc2 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -4230,9 +4230,18 @@ nm_platform_ip_route_get_prune_list (NMPlatform *self, } else if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN) { if (!nm_platform_route_table_is_main (NMP_OBJECT_CAST_IP_ROUTE (obj)->table_coerced)) continue; - } else + } else { nm_assert (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_ALL); + /* IPv6 routes having metric 0 and routes having rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL + * are entirely managed by kernel, let's not touch them */ + if (addr_family == AF_INET6 && NMP_OBJECT_CAST_IP6_ROUTE (obj)->metric == 0) + continue; + if ( nm_platform_route_table_uncoerce (NMP_OBJECT_CAST_IP_ROUTE (obj)->table_coerced, TRUE) == RT_TABLE_LOCAL + && NMP_OBJECT_CAST_IP_ROUTE (obj)->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) + continue; + } + g_ptr_array_add (routes_prune, (gpointer) nmp_object_ref (obj)); } @@ -6082,11 +6091,11 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi char s_network[INET_ADDRSTRLEN], s_gateway[INET_ADDRSTRLEN]; char s_pref_src[INET_ADDRSTRLEN]; char str_dev[TO_STRING_DEV_BUF_SIZE]; - char str_type[30]; char str_table[30]; char str_scope[30], s_source[50]; char str_tos[32], str_window[32], str_cwnd[32], str_initcwnd[32], str_initrwnd[32], str_mtu[32]; char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN]; + char str_type[30]; if (!nm_utils_to_string_buffer_init_null (route, &buf, &len)) return buf; @@ -6097,7 +6106,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi _to_string_dev (NULL, route->ifindex, str_dev, sizeof (str_dev)); g_snprintf (buf, len, - "%s" /* type */ + "type %s " /* type */ "%s" /* table */ "%s/%d" " via %s" @@ -6115,7 +6124,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi "%s" /* initrwnd */ "%s" /* mtu */ "", - route->type_coerced ? nm_sprintf_buf (str_type, "type %s ", nm_utils_route_type2str (nm_platform_route_type_uncoerce (route->type_coerced), NULL, 0)) : "", + nm_utils_route_type2str (nm_platform_route_type_uncoerce (route->type_coerced), str_type, sizeof (str_type)), route->table_coerced ? nm_sprintf_buf (str_table, "table %u ", nm_platform_route_table_uncoerce (route->table_coerced, FALSE)) : "", s_network, route->plen, @@ -6185,7 +6194,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi _to_string_dev (NULL, route->ifindex, str_dev, sizeof (str_dev)); g_snprintf (buf, len, - "%s" /* type */ + "type %s " /* type */ "%s" /* table */ "%s/%d" " via %s" @@ -6203,7 +6212,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi "%s" /* mtu */ "%s" /* pref */ "", - route->type_coerced ? nm_sprintf_buf (str_type, "type %s ", nm_utils_route_type2str (nm_platform_route_type_uncoerce (route->type_coerced), NULL, 0)) : "", + nm_utils_route_type2str (nm_platform_route_type_uncoerce (route->type_coerced), str_type, sizeof (str_type)), route->table_coerced ? nm_sprintf_buf (str_table, "table %u ", nm_platform_route_table_uncoerce (route->table_coerced, FALSE)) : "", s_network, route->plen,