diff options
author | Thomas Haller <thaller@redhat.com> | 2021-09-27 07:48:43 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2021-09-27 07:55:32 +0200 |
commit | e47dd2ee224936a197a6bf81e47db49537a13aa9 (patch) | |
tree | d24eece3ae8a22db5d2e3200917dfdbb0c69dd95 | |
parent | ed1536c890072ac32a4659c907324b465afa30fa (diff) | |
download | NetworkManager-e47dd2ee224936a197a6bf81e47db49537a13aa9.tar.gz |
l3cfg: configure dependent routes when creating combined config
-rw-r--r-- | src/core/nm-l3-config-data.c | 260 | ||||
-rw-r--r-- | src/core/nm-l3-config-data.h | 12 | ||||
-rw-r--r-- | src/core/nm-l3cfg.c | 33 | ||||
-rw-r--r-- | src/core/nm-l3cfg.h | 2 | ||||
-rw-r--r-- | src/libnm-platform/nm-platform.c | 51 | ||||
-rw-r--r-- | src/libnm-platform/nm-platform.h | 8 |
6 files changed, 211 insertions, 155 deletions
diff --git a/src/core/nm-l3-config-data.c b/src/core/nm-l3-config-data.c index ca82cd1e31..0670912182 100644 --- a/src/core/nm-l3-config-data.c +++ b/src/core/nm-l3-config-data.c @@ -2100,8 +2100,8 @@ _data_get_direct_route_for_host(const NML3ConfigData *self, NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4)) { const NMPlatformIPXRoute *item = NMP_OBJECT_CAST_IPX_ROUTE(item_obj); - if (nm_ip_addr_is_null(addr_family, - nm_platform_ip_route_get_gateway(addr_family, &item->rx))) + if (!nm_ip_addr_is_null(addr_family, + nm_platform_ip_route_get_gateway(addr_family, &item->rx))) continue; if (best_route && best_route->rx.plen > item->rx.plen) @@ -2159,9 +2159,6 @@ nm_l3_config_data_get_blacklisted_ip4_routes(const NML3ConfigData *self, gboolea in_addr_t network_4; NMPlatformIPXRoute rx; - if (my_addr->external) - continue; - nm_assert(my_addr->plen <= 32); if (my_addr->plen == 0) continue; @@ -2210,120 +2207,137 @@ nm_l3_config_data_get_blacklisted_ip4_routes(const NML3ConfigData *self, gboolea /*****************************************************************************/ void -nm_l3_config_data_add_dependent_routes(NML3ConfigData *self, - int addr_family, - guint32 route_table, - guint32 route_metric, - gboolean is_vrf) +nm_l3_config_data_add_dependent_onlink_routes(NML3ConfigData *self, int addr_family) { - const int IS_IPv4 = NM_IS_IPv4(addr_family); gs_unref_ptrarray GPtrArray *extra_onlink_routes = NULL; - const NMPObject * my_addr_obj; - const NMPObject * my_route_obj; - NMPlatformIPXRoute rx; + const NMPObject * obj_src; NMDedupMultiIter iter; - in_addr_t network_4 = 0; + int IS_IPv4; guint i; + if (addr_family == AF_UNSPEC) { + nm_l3_config_data_add_dependent_onlink_routes(self, AF_INET); + nm_l3_config_data_add_dependent_onlink_routes(self, AF_INET6); + return; + } + + IS_IPv4 = NM_IS_IPv4(addr_family); + nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); - nm_assert_addr_family(addr_family); /* For IPv6 slaac, we explicitly add the device-routes (onlink). * As we don't do that for IPv4 and manual IPv6 addresses. Add them here * as dependent routes. */ - if (!IS_IPv4) { - /* Pre-generate multicast route */ - rx.r6 = (NMPlatformIP6Route){ - .ifindex = self->ifindex, - .network.s6_addr[0] = 0xffu, - .plen = 8, - .table_coerced = nm_platform_route_table_coerce(RT_TABLE_LOCAL), - .type_coerced = nm_platform_route_type_coerce(RTN_UNICAST), - .metric = 256, - }; - nm_l3_config_data_add_route(self, addr_family, NULL, &rx.rx); - } + nm_l3_config_data_iter_obj_for_each (&iter, self, &obj_src, NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4)) { + const NMPlatformIPXRoute *route_src = NMP_OBJECT_CAST_IPX_ROUTE(obj_src); + NMPObject * new_route; + NMPlatformIPXRoute * new_r; + const NMIPAddr * p_gateway; - nm_l3_config_data_iter_obj_for_each (&iter, - self, - &my_addr_obj, - NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4)) { - const NMPlatformIPXAddress *const my_addr = NMP_OBJECT_CAST_IPX_ADDRESS(my_addr_obj); + p_gateway = nm_platform_ip_route_get_gateway(addr_family, &route_src->rx); - if (my_addr->ax.external) + if (nm_ip_addr_is_null(addr_family, p_gateway)) continue; - if (IS_IPv4) { - nm_assert(my_addr->a4.plen <= 32); - if (my_addr->a4.plen == 0) - continue; - } + if (_data_get_direct_route_for_host( + self, + addr_family, + p_gateway, + nm_platform_route_table_uncoerce(route_src->rx.table_coerced, TRUE))) + continue; + new_route = nmp_object_clone(obj_src, FALSE); + new_r = NMP_OBJECT_CAST_IPX_ROUTE(new_route); if (IS_IPv4) { - rx.r4 = (NMPlatformIP4Route){ - .ifindex = self->ifindex, - .rt_source = NM_IP_CONFIG_SOURCE_KERNEL, - .network = my_addr->a4.address, - .plen = 32, - .pref_src = my_addr->a4.address, - .type_coerced = nm_platform_route_type_coerce(RTN_LOCAL), - .scope_inv = nm_platform_route_scope_inv(RT_SCOPE_HOST), - .table_coerced = - nm_platform_route_table_coerce(is_vrf ? route_table : RT_TABLE_LOCAL), - }; + new_r->r4.network = route_src->r4.gateway; + new_r->r4.plen = 32; + new_r->r4.gateway = 0; } else { - rx.r6 = (NMPlatformIP6Route){ - .ifindex = self->ifindex, - .network = my_addr->a6.address, - .plen = 128, - .type_coerced = nm_platform_route_type_coerce(RTN_LOCAL), - .metric = 0, - .table_coerced = - nm_platform_route_table_coerce(is_vrf ? route_table : RT_TABLE_LOCAL), - }; + new_r->r6.network = route_src->r6.gateway; + new_r->r6.plen = 128; + new_r->r6.gateway = in6addr_any; + } + + /* we cannot add the route right away, because that invalidates the iteration. */ + if (!extra_onlink_routes) + extra_onlink_routes = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); + g_ptr_array_add(extra_onlink_routes, new_route); + } + if (extra_onlink_routes) { + for (i = 0; i < extra_onlink_routes->len; i++) { + nm_l3_config_data_add_route_full(self, + addr_family, + extra_onlink_routes->pdata[i], + NULL, + NM_L3_CONFIG_ADD_FLAGS_EXCLUSIVE, + NULL, + NULL); } - nm_l3_config_data_add_route(self, addr_family, NULL, &rx.rx); + } +} + +void +nm_l3_config_data_add_dependent_device_routes(NML3ConfigData * self, + int addr_family, + guint32 route_table, + guint32 route_metric, + const NML3ConfigData *source) +{ + const int IS_IPv4 = NM_IS_IPv4(addr_family); + const NMPObject * obj_src; + NMPlatformIPXRoute rx; + NMDedupMultiIter iter; + + nm_assert_addr_family(addr_family); + nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); + nm_assert(_NM_IS_L3_CONFIG_DATA(source, TRUE)); + nm_assert(self != source); + + /* For IPv6 slaac, we explicitly add the device-routes (onlink) and track them + * as regular routes in NML3ConfigData. + * + * For IPv4 and for manual IPv6 addresses we don't do that. Instead, add those + * routes automatically afterwards. + * + * As route-table/metric is associated with the source l3cd, we need to process + * all source l3cds separately. */ - if (my_addr->ax.plen == 0) + nm_l3_config_data_iter_obj_for_each (&iter, + source, + &obj_src, + NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4)) { + const NMPlatformIPXAddress *const addr_src = NMP_OBJECT_CAST_IPX_ADDRESS(obj_src); + const NMPlatformIPXAddress * addr_dst; + + addr_dst = NMP_OBJECT_CAST_IPX_ADDRESS( + nm_dedup_multi_entry_get_obj(nm_l3_config_data_lookup_obj(self, obj_src))); + if (!addr_dst) continue; if (IS_IPv4) { - network_4 = - nm_utils_ip4_address_clear_host_address(my_addr->a4.peer_address, my_addr->a4.plen); + NMPlatformIPXRoute r_stack; + const NMPlatformIPRoute *r; - if (nm_utils_ip4_address_is_zeronet(network_4)) { - /* Kernel doesn't add device-routes for destinations that - * start with 0.x.y.z. Skip them. */ + if (addr_dst->a4.a_acd_not_ready) continue; - } - if (my_addr->a4.plen == 32 && my_addr->a4.address == my_addr->a4.peer_address) { - /* Kernel doesn't add device-routes for /32 addresses unless - * they have a peer. */ - continue; - } + r = (NMPlatformIPRoute *) nm_platform_ip4_address_generate_device_route(&addr_src->a4, + self->ifindex, + route_table, + route_metric, + &r_stack.r4); + if (r) + nm_l3_config_data_add_route(self, addr_family, NULL, r); } else { - if (NM_FLAGS_HAS(my_addr->a6.n_ifa_flags, IFA_F_NOPREFIXROUTE)) + const gboolean has_peer = !IN6_IS_ADDR_UNSPECIFIED(&addr_src->a6.peer_address); + int routes_i; + + if (addr_src->ax.plen == 0) continue; - } - if (IS_IPv4) { - rx.r4 = (NMPlatformIP4Route){ - .ifindex = self->ifindex, - .rt_source = NM_IP_CONFIG_SOURCE_KERNEL, - .network = network_4, - .plen = my_addr->a4.plen, - .pref_src = my_addr->a4.address, - .table_coerced = nm_platform_route_table_coerce(route_table), - .metric = route_metric, - .scope_inv = nm_platform_route_scope_inv(NM_RT_SCOPE_LINK), - }; - nm_platform_ip_route_normalize(addr_family, &rx.rx); - nm_l3_config_data_add_route(self, addr_family, NULL, &rx.rx); - } else { - const gboolean has_peer = !IN6_IS_ADDR_UNSPECIFIED(&my_addr->a6.peer_address); - int routes_i; + if (NM_FLAGS_HAS(addr_src->a6.n_ifa_flags, IFA_F_NOPREFIXROUTE)) + continue; /* If we have an IPv6 peer, we add two /128 routes * (unless, both addresses are identical). */ @@ -2333,20 +2347,20 @@ nm_l3_config_data_add_dependent_routes(NML3ConfigData *self, guint8 plen; if (routes_i == 1 && has_peer - && IN6_ARE_ADDR_EQUAL(&my_addr->a6.address, &my_addr->a6.peer_address)) + && IN6_ARE_ADDR_EQUAL(&addr_src->a6.address, &addr_src->a6.peer_address)) break; if (has_peer) { if (routes_i == 0) - a6 = &my_addr->a6.address; + a6 = &addr_src->a6.address; else - a6 = &my_addr->a6.peer_address; + a6 = &addr_src->a6.peer_address; plen = 128; } else { a6 = nm_utils_ip6_address_clear_host_address(&a6_stack, - &my_addr->a6.address, - my_addr->a6.plen); - plen = my_addr->a6.plen; + &addr_src->a6.address, + addr_src->a6.plen); + plen = addr_src->a6.plen; } rx.r6 = (NMPlatformIP6Route){ @@ -2362,60 +2376,6 @@ nm_l3_config_data_add_dependent_routes(NML3ConfigData *self, } } } - - nm_l3_config_data_iter_obj_for_each (&iter, - self, - &my_route_obj, - NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4)) { - const NMPlatformIPXRoute *my_route = NMP_OBJECT_CAST_IPX_ROUTE(my_route_obj); - NMPObject * new_route; - NMPlatformIPXRoute * new_r; - const NMIPAddr * p_gateway; - - if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT(my_route) - || NM_IS_IP_CONFIG_SOURCE_RTPROT(my_route->rx.rt_source)) - continue; - - p_gateway = nm_platform_ip_route_get_gateway(addr_family, &my_route->rx); - - if (nm_ip_addr_is_null(addr_family, p_gateway)) - continue; - - if (_data_get_direct_route_for_host( - self, - addr_family, - p_gateway, - nm_platform_route_table_uncoerce(my_route->rx.table_coerced, TRUE))) - continue; - - new_route = nmp_object_clone(my_route_obj, FALSE); - new_r = NMP_OBJECT_CAST_IPX_ROUTE(new_route); - if (IS_IPv4) { - new_r->r4.network = my_route->r4.gateway; - new_r->r4.plen = 32; - new_r->r4.gateway = 0; - } else { - new_r->r6.network = my_route->r6.gateway; - new_r->r6.plen = 128; - new_r->r6.gateway = in6addr_any; - } - - /* we cannot add the route right away, because that invalidates the iteration. */ - if (!extra_onlink_routes) - extra_onlink_routes = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); - g_ptr_array_add(extra_onlink_routes, new_route); - } - if (extra_onlink_routes) { - for (i = 0; i < extra_onlink_routes->len; i++) { - nm_l3_config_data_add_route_full(self, - addr_family, - extra_onlink_routes->pdata[i], - NULL, - NM_L3_CONFIG_ADD_FLAGS_EXCLUSIVE, - NULL, - NULL); - } - } } /*****************************************************************************/ diff --git a/src/core/nm-l3-config-data.h b/src/core/nm-l3-config-data.h index 35b316d162..523b9a0d35 100644 --- a/src/core/nm-l3-config-data.h +++ b/src/core/nm-l3-config-data.h @@ -158,11 +158,13 @@ void nm_l3_config_data_merge(NML3ConfigData * self, GPtrArray *nm_l3_config_data_get_blacklisted_ip4_routes(const NML3ConfigData *self, gboolean is_vrf); -void nm_l3_config_data_add_dependent_routes(NML3ConfigData *self, - int addr_family, - guint32 route_table, - guint32 route_metric, - gboolean is_vrf); +void nm_l3_config_data_add_dependent_onlink_routes(NML3ConfigData *self, int addr_family); + +void nm_l3_config_data_add_dependent_device_routes(NML3ConfigData * self, + int addr_family, + guint32 route_table, + guint32 route_metric, + const NML3ConfigData *source); /*****************************************************************************/ diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c index 3ef4a31125..76c296cc20 100644 --- a/src/core/nm-l3cfg.c +++ b/src/core/nm-l3cfg.c @@ -385,6 +385,17 @@ static NM_UTILS_LOOKUP_DEFINE(_l3_acd_addr_state_to_string, /*****************************************************************************/ +gboolean +nm_l3cfg_is_vrf(const NML3Cfg *self) +{ + const NMPlatformLink *pllink; + + pllink = nm_l3cfg_get_pllink(self, TRUE); + return pllink && pllink->type == NM_LINK_TYPE_VRF; +} + +/*****************************************************************************/ + static const char * _l3_config_notify_data_to_string(const NML3ConfigNotifyData *notify_data, char * sbuf, @@ -3510,6 +3521,28 @@ _l3cfg_update_combined_config(NML3Cfg * self, &hook_data); } + for (i = 0; i < l3_config_datas_len; i++) { + const L3ConfigData *l3cd_data = l3_config_datas_arr[i]; + int IS_IPv4; + + if (NM_FLAGS_HAS(l3cd_data->config_flags, NM_L3CFG_CONFIG_FLAGS_ONLY_FOR_ACD)) + continue; + + for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) { + /* FIXME(l3cfg): VRF needs to be treated specially. */ + nm_assert(!nm_l3cfg_is_vrf(self)); + + nm_l3_config_data_add_dependent_device_routes( + l3cd, + IS_IPv4 ? AF_INET : AF_INET6, + l3cd_data->default_route_table_x[IS_IPv4], + l3cd_data->default_route_metric_x[IS_IPv4], + l3cd_data->l3cd); + } + } + + nm_l3_config_data_add_dependent_onlink_routes(l3cd, AF_UNSPEC); + nm_assert(l3cd); nm_assert(nm_l3_config_data_get_ifindex(l3cd) == self->priv.ifindex); diff --git a/src/core/nm-l3cfg.h b/src/core/nm-l3cfg.h index b5da926ece..c76e9271c1 100644 --- a/src/core/nm-l3cfg.h +++ b/src/core/nm-l3cfg.h @@ -269,6 +269,8 @@ nm_l3cfg_get_ifname(const NML3Cfg *self, gboolean get_next) return nmp_object_link_get_ifname(nm_l3cfg_get_plobj(self, get_next)); } +gboolean nm_l3cfg_is_vrf(const NML3Cfg *self); + static inline NMNetns * nm_l3cfg_get_netns(const NML3Cfg *self) { diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index 0a7b4458b6..5d4ec037ec 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -8578,6 +8578,57 @@ nm_platform_ip4_address_addr_to_hash(NMPlatform *self, int ifindex) /*****************************************************************************/ +NMPlatformIP4Route * +nm_platform_ip4_address_generate_device_route(const NMPlatformIP4Address *addr, + int ifindex, + guint32 route_table, + guint32 route_metric, + NMPlatformIP4Route * dst) +{ + in_addr_t network_4; + + /* When you add an IPv4 address (without "noprefixroute" flag), then kernel will + * automatically add a device route for the IPv4 subnet. This function generates + * such a route for the given address. */ + + nm_assert(addr); + nm_assert(addr->plen <= 32); + if (addr->plen == 0) + return NULL; + + if (addr->plen == 0) + return NULL; + + network_4 = nm_utils_ip4_address_clear_host_address(addr->peer_address, addr->plen); + + if (nm_utils_ip4_address_is_zeronet(network_4)) { + /* Kernel doesn't add device-routes for destinations that + * start with 0.x.y.z. Skip them. */ + return NULL; + } + + if (addr->plen == 32 && addr->address == addr->peer_address) { + /* Kernel doesn't add device-routes for /32 addresses unless + * they have a peer. */ + return NULL; + } + + *dst = (NMPlatformIP4Route){ + .ifindex = ifindex, + .rt_source = NM_IP_CONFIG_SOURCE_KERNEL, + .network = network_4, + .plen = addr->plen, + .pref_src = addr->address, + .table_coerced = nm_platform_route_table_coerce(route_table), + .metric = route_metric, + .scope_inv = nm_platform_route_scope_inv(NM_RT_SCOPE_LINK), + }; + + nm_platform_ip_route_normalize(AF_INET, (NMPlatformIPRoute *) dst); + + return dst; +} + const char * nm_platform_signal_change_type_to_string(NMPlatformSignalChangeType change_type) { diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index a13f921dc7..116efbeec5 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -2422,6 +2422,14 @@ struct _NMDedupMultiIndex *nm_platform_get_multi_idx(NMPlatform *self); /*****************************************************************************/ +NMPlatformIP4Route *nm_platform_ip4_address_generate_device_route(const NMPlatformIP4Address *addr, + int ifindex, + guint32 route_table, + guint32 route_metric, + NMPlatformIP4Route *dst); + +/*****************************************************************************/ + gboolean nm_platform_ip_address_match(int addr_family, const NMPlatformIPAddress *addr, NMPlatformMatchFlags match_flag); |