summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2021-09-27 07:48:43 +0200
committerThomas Haller <thaller@redhat.com>2021-09-27 07:55:32 +0200
commite47dd2ee224936a197a6bf81e47db49537a13aa9 (patch)
treed24eece3ae8a22db5d2e3200917dfdbb0c69dd95
parented1536c890072ac32a4659c907324b465afa30fa (diff)
downloadNetworkManager-e47dd2ee224936a197a6bf81e47db49537a13aa9.tar.gz
l3cfg: configure dependent routes when creating combined config
-rw-r--r--src/core/nm-l3-config-data.c260
-rw-r--r--src/core/nm-l3-config-data.h12
-rw-r--r--src/core/nm-l3cfg.c33
-rw-r--r--src/core/nm-l3cfg.h2
-rw-r--r--src/libnm-platform/nm-platform.c51
-rw-r--r--src/libnm-platform/nm-platform.h8
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);