From 7fadadb8f33675d0a12c94f5c0f5c6ecef4a98cf Mon Sep 17 00:00:00 2001 From: Antonio Cardace Date: Tue, 14 Jul 2020 11:35:35 +0200 Subject: [PATCH] core: fix generation of dependent local routes for VRFs When using VRF devices we must pre-generate dependent local routes in the VRF's table otherwise they will be incorrectly added to the local table instead. https://bugzilla.redhat.com/show_bug.cgi?id=1857133 Fixes: a199cd2a7d92 ('core: add dependent local routes configured by kernel') (cherry picked from commit d342af1925223cf8d117750c91f35f3041f05570) (cherry picked from commit ad64da5e85757eeb729fea377bb92ac41c8b92bd) --- src/devices/nm-device.c | 9 ++++++++- src/nm-iface-helper.c | 11 ++++++++++- src/nm-ip4-config.c | 19 +++++++++++-------- src/nm-ip4-config.h | 7 ++++--- src/nm-ip6-config.c | 17 +++++++++++------ src/nm-ip6-config.h | 5 +++-- src/vpn/nm-vpn-connection.c | 19 ++++++++++++++++--- 7 files changed, 63 insertions(+), 24 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index de09e4807..57c32cef8 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -68,6 +68,7 @@ #include "nm-device-generic.h" #include "nm-device-vlan.h" +#include "nm-device-vrf.h" #include "nm-device-wireguard.h" #include "nm-device-logging.h" @@ -8097,15 +8098,21 @@ ip_config_merge_and_apply (NMDevice *self, } if (commit) { + gboolean is_vrf; + + is_vrf = priv->master && nm_device_get_device_type (priv->master) == NM_DEVICE_TYPE_VRF; + if (IS_IPv4) { nm_ip4_config_add_dependent_routes (NM_IP4_CONFIG (composite), nm_device_get_route_table (self, addr_family), nm_device_get_route_metric (self, addr_family), + is_vrf, &ip4_dev_route_blacklist); } else { nm_ip6_config_add_dependent_routes (NM_IP6_CONFIG (composite), nm_device_get_route_table (self, addr_family), - nm_device_get_route_metric (self, addr_family)); + nm_device_get_route_metric (self, addr_family), + is_vrf); } } diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c index 6320e722c..c7d65d2a6 100644 --- a/src/nm-iface-helper.c +++ b/src/nm-iface-helper.c @@ -41,11 +41,13 @@ static struct { GMainLoop *main_loop; int ifindex; + gboolean is_vrf_device; guint dad_failed_id; CList dad_failed_lst_head; } gl/*obal*/ = { .ifindex = -1, + .is_vrf_device = FALSE, }; static struct { @@ -120,6 +122,7 @@ dhcp4_state_changed (NMDhcpClient *client, nm_ip4_config_add_dependent_routes (existing, RT_TABLE_MAIN, global_opt.priority_v4, + gl.is_vrf_device, &ip4_dev_route_blacklist); if (!nm_ip4_config_commit (existing, NM_PLATFORM_GET, @@ -236,7 +239,8 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in nm_ip6_config_merge (existing, ndisc_config, NM_IP_CONFIG_MERGE_DEFAULT, 0); nm_ip6_config_add_dependent_routes (existing, RT_TABLE_MAIN, - global_opt.priority_v6); + global_opt.priority_v6, + gl.is_vrf_device); if (!nm_ip6_config_commit (existing, NM_PLATFORM_GET, NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN, @@ -480,6 +484,11 @@ main (int argc, char *argv[]) if (pllink) { hwaddr = nmp_link_address_get_as_bytes (&pllink->l_address); bcast_hwaddr = nmp_link_address_get_as_bytes (&pllink->l_broadcast); + + if (pllink->master > 0) { + gl.is_vrf_device + = nm_platform_link_get_type (NM_PLATFORM_GET, pllink->master) == NM_LINK_TYPE_VRF; + } } if (global_opt.iid_str) { diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 490296c8d..f017a3e80 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -672,9 +672,11 @@ nm_ip4_config_update_routes_metric (NMIP4Config *self, gint64 metric) } static void -_add_local_route_from_addr4 (NMIP4Config *self, - const NMPlatformIP4Address *addr, - int ifindex) +_add_local_route_from_addr4 (NMIP4Config * self, + const NMPlatformIP4Address *addr, + int ifindex, + guint32 route_table, + gboolean is_vrf) { nm_auto_nmpobj NMPObject *r = NULL; NMPlatformIP4Route *route; @@ -686,18 +688,19 @@ _add_local_route_from_addr4 (NMIP4Config *self, route->network = addr->address; route->plen = 32; route->pref_src = addr->address; - route->table_coerced = nm_platform_route_table_coerce (RT_TABLE_LOCAL); route->type_coerced = nm_platform_route_type_coerce (RTN_LOCAL); route->scope_inv = nm_platform_route_scope_inv (RT_SCOPE_HOST); + route->table_coerced = nm_platform_route_table_coerce (is_vrf ? route_table : RT_TABLE_LOCAL); _add_route (self, r, NULL, NULL); } void nm_ip4_config_add_dependent_routes (NMIP4Config *self, - guint32 route_table, - guint32 route_metric, - GPtrArray **out_ip4_dev_route_blacklist) + guint32 route_table, + guint32 route_metric, + gboolean is_vrf, + GPtrArray ** out_ip4_dev_route_blacklist) { GPtrArray *ip4_dev_route_blacklist = NULL; const NMPlatformIP4Address *my_addr; @@ -729,7 +732,7 @@ nm_ip4_config_add_dependent_routes (NMIP4Config *self, if (my_addr->external) continue; - _add_local_route_from_addr4 (self, my_addr, ifindex); + _add_local_route_from_addr4 (self, my_addr, ifindex, route_table, is_vrf); if (_ipv4_is_zeronet (network)) { /* Kernel doesn't add device-routes for destinations that diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index d4694d936..dc8222fd5 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -157,9 +157,10 @@ NMDedupMultiIndex *nm_ip4_config_get_multi_idx (const NMIP4Config *self); NMIP4Config *nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex); void nm_ip4_config_add_dependent_routes (NMIP4Config *self, - guint32 route_table, - guint32 route_metric, - GPtrArray **out_ip4_dev_route_blacklist); + guint32 route_table, + guint32 route_metric, + gboolean is_vrf, + GPtrArray ** out_ip4_dev_route_blacklist); gboolean nm_ip4_config_commit (const NMIP4Config *self, NMPlatform *platform, diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 4911ec1d1..1589cad00 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -475,27 +475,32 @@ _add_multicast_route6 (NMIP6Config *self, int ifindex) } static void -_add_local_route_from_addr6 (NMIP6Config *self, const NMPlatformIP6Address *addr, int ifindex) +_add_local_route_from_addr6 (NMIP6Config * self, + const NMPlatformIP6Address *addr, + int ifindex, + guint32 route_table, + gboolean is_vrf) { nm_auto_nmpobj NMPObject *r = NULL; - NMPlatformIP6Route *route; + NMPlatformIP6Route * route; r = nmp_object_new (NMP_OBJECT_TYPE_IP6_ROUTE, NULL); route = NMP_OBJECT_CAST_IP6_ROUTE (r); route->ifindex = ifindex; route->network = addr->address; route->plen = 128; - route->table_coerced = nm_platform_route_table_coerce (RT_TABLE_LOCAL); route->type_coerced = nm_platform_route_type_coerce (RTN_LOCAL); route->metric = 0; + route->table_coerced = nm_platform_route_table_coerce (is_vrf ? route_table : RT_TABLE_LOCAL); _add_route (self, r, NULL, NULL); } void nm_ip6_config_add_dependent_routes (NMIP6Config *self, - guint32 route_table, - guint32 route_metric) + guint32 route_table, + guint32 route_metric, + gboolean is_vrf) { const NMPlatformIP6Address *my_addr; const NMPlatformIP6Route *my_route; @@ -524,7 +529,7 @@ nm_ip6_config_add_dependent_routes (NMIP6Config *self, continue; /* Pre-generate local route added by kernel */ - _add_local_route_from_addr6 (self, my_addr, ifindex); + _add_local_route_from_addr6 (self, my_addr, ifindex, route_table, is_vrf); if (NM_FLAGS_HAS (my_addr->n_ifa_flags, IFA_F_NOPREFIXROUTE)) continue; diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index 36e8518a8..b6f461b29 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -93,8 +93,9 @@ NMIP6Config *nm_ip6_config_capture (struct _NMDedupMultiIndex *multi_idx, NMPlat NMSettingIP6ConfigPrivacy use_temporary); void nm_ip6_config_add_dependent_routes (NMIP6Config *self, - guint32 route_table, - guint32 route_metric); + guint32 route_table, + guint32 route_metric, + gboolean is_vrf); gboolean nm_ip6_config_commit (const NMIP6Config *self, NMPlatform *platform, diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c index 6d995dc48..ff6b8e00c 100644 --- a/src/vpn/nm-vpn-connection.c +++ b/src/vpn/nm-vpn-connection.c @@ -1447,6 +1447,20 @@ get_route_table (NMVpnConnection *self, return route_table ?: (fallback_main ? RT_TABLE_MAIN : 0); } +static gboolean +_is_device_vrf (NMVpnConnection *self) +{ + NMDevice *parent; + NMDevice *master; + + parent = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (self)); + if (!parent) + return FALSE; + + master = nm_device_get_master (parent); + return master && nm_device_get_link_type (master) == NM_LINK_TYPE_VRF; +} + static void nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict) { @@ -1646,6 +1660,7 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict) nm_ip4_config_add_dependent_routes (config, route_table, nm_vpn_connection_get_ip4_route_metric (self), + _is_device_vrf (self), &priv->ip4_dev_route_blacklist); if (priv->ip4_config) { @@ -1840,9 +1855,7 @@ next: nm_ip6_config_add_route (config, &r, NULL); } - nm_ip6_config_add_dependent_routes (config, - route_table, - route_metric); + nm_ip6_config_add_dependent_routes (config, route_table, route_metric, _is_device_vrf (self)); if (priv->ip6_config) { nm_ip6_config_replace (priv->ip6_config, config, NULL); -- 2.26.2