diff options
Diffstat (limited to 'src/devices/nm-device.c')
-rw-r--r-- | src/devices/nm-device.c | 216 |
1 files changed, 135 insertions, 81 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 29b20f790a..740f270fa2 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -66,7 +66,6 @@ #include "dns/nm-dns-manager.h" #include "nm-core-internal.h" #include "nm-default-route-manager.h" -#include "nm-route-manager.h" #include "systemd/nm-sd.h" #include "nm-lldp-listener.h" #include "nm-audit-manager.h" @@ -491,16 +490,14 @@ static void nm_device_set_proxy_config (NMDevice *self, const char *pac_url); static gboolean nm_device_set_ip4_config (NMDevice *self, NMIP4Config *config, guint32 default_route_metric, - gboolean commit, - gboolean routes_full_sync); + gboolean commit); static gboolean ip4_config_merge_and_apply (NMDevice *self, NMIP4Config *config, gboolean commit); static gboolean nm_device_set_ip6_config (NMDevice *self, NMIP6Config *config, - gboolean commit, - gboolean routes_full_sync); + gboolean commit); static gboolean ip6_config_merge_and_apply (NMDevice *self, gboolean commit); @@ -2767,6 +2764,99 @@ link_changed_cb (NMPlatform *platform, } } +/*****************************************************************************/ + +typedef struct { + in_addr_t network; + guint8 plen; +} IP4RPFilterData; + +static guint +_v4_has_shadowed_routes_detect_hash (const IP4RPFilterData *d) +{ + guint h = 0; + + h = NM_HASH_COMBINE (h, d->network); + h = NM_HASH_COMBINE (h, d->plen); + return h; +} + +static gboolean +_v4_has_shadowed_routes_detect_equal (const IP4RPFilterData *d1, const IP4RPFilterData *d2) +{ + return d1->network == d2->network && d1->plen == d2->plen; +} + +static gboolean +_v4_has_shadowed_routes_detect (NMDevice *self) +{ + NMPlatform *platform; + int ifindex; + NMPLookup lookup; + const NMDedupMultiHeadEntry *head_entry; + NMDedupMultiIter iter; + const NMPObject *o; + guint data_len; + gs_unref_hashtable GHashTable *data_hash = NULL; + gs_free IP4RPFilterData *data_arr = NULL; + + ifindex = nm_device_get_ip_ifindex (self); + if (ifindex <= 0) + return FALSE; + + platform = nm_device_get_platform (self); + + head_entry = nm_platform_lookup (platform, + nmp_lookup_init_addrroute (&lookup, + NMP_OBJECT_TYPE_IP4_ROUTE, + ifindex)); + if (!head_entry) + return FALSE; + + /* first, create a lookup index @data_hash for all network/plen pairs. */ + data_len = 0; + data_arr = g_new (IP4RPFilterData, head_entry->len); + data_hash = g_hash_table_new ((GHashFunc) _v4_has_shadowed_routes_detect_hash, + (GEqualFunc) _v4_has_shadowed_routes_detect_equal); + + nmp_cache_iter_for_each (&iter, head_entry, &o) { + const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (o); + IP4RPFilterData *d; + + nm_assert (r->ifindex == ifindex); + + if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r)) + continue; + + d = &data_arr[data_len++]; + d->network = nm_utils_ip4_address_clear_host_address (r->network, r->plen); + d->plen = r->plen; + g_hash_table_add (data_hash, d); + } + + /* then, search if there is any route on another interface with the same + * network/plen destination. If yes, we consider this a multihoming + * setup. */ + head_entry = nm_platform_lookup (platform, + nmp_lookup_init_obj_type (&lookup, + NMP_OBJECT_TYPE_IP4_ROUTE)); + nmp_cache_iter_for_each (&iter, head_entry, &o) { + const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (o); + IP4RPFilterData d; + + if ( r->ifindex == ifindex + || NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r)) + continue; + + d.network = nm_utils_ip4_address_clear_host_address (r->network, r->plen); + d.plen = r->plen; + if (g_hash_table_contains (data_hash, &d)) + return TRUE; + } + + return FALSE; +} + static void ip4_rp_filter_update (NMDevice *self) { @@ -2793,20 +2883,6 @@ ip4_rp_filter_update (NMDevice *self) } static void -ip4_routes_changed_changed_cb (NMRouteManager *route_manager, NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - int ifindex = nm_device_get_ip_ifindex (self); - - if (nm_device_sys_iface_state_is_external_or_assume (self)) - return; - - priv->v4_has_shadowed_routes = nm_route_manager_ip4_routes_shadowed (route_manager, - ifindex); - ip4_rp_filter_update (self); -} - -static void link_changed (NMDevice *self, const NMPlatformLink *pllink) { /* stub implementation of virtual function to allow subclasses to chain up. */ @@ -3846,8 +3922,8 @@ nm_device_removed (NMDevice *self, gboolean unconfigure_ip_config) _update_default_route (self, AF_INET6, priv->default_route.v6_has, TRUE); _update_default_route (self, AF_INET, FALSE, TRUE); _update_default_route (self, AF_INET6, FALSE, TRUE); - nm_device_set_ip4_config (self, NULL, 0, FALSE, FALSE); - nm_device_set_ip6_config (self, NULL, FALSE, FALSE); + nm_device_set_ip4_config (self, NULL, 0, FALSE); + nm_device_set_ip6_config (self, NULL, FALSE); } static gboolean @@ -5582,7 +5658,6 @@ ip4_config_merge_and_apply (NMDevice *self, const guint32 default_route_metric = nm_device_get_ip4_route_metric (self); guint32 gateway; gboolean connection_has_default_route, connection_is_never_default; - gboolean routes_full_sync; gboolean ignore_auto_routes = FALSE; gboolean ignore_auto_dns = FALSE; gboolean auto_method = FALSE; @@ -5749,11 +5824,7 @@ END_ADD_DEFAULT_ROUTE: NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit (self, composite); } - routes_full_sync = commit - && priv->v4_commit_first_time - && !nm_device_sys_iface_state_is_external_or_assume (self); - - success = nm_device_set_ip4_config (self, composite, default_route_metric, commit, routes_full_sync); + success = nm_device_set_ip4_config (self, composite, default_route_metric, commit); g_object_unref (composite); if (commit) @@ -6308,7 +6379,6 @@ ip6_config_merge_and_apply (NMDevice *self, gboolean has_direct_route; const struct in6_addr *gateway; gboolean connection_has_default_route, connection_is_never_default; - gboolean routes_full_sync; gboolean ignore_auto_routes = FALSE; gboolean ignore_auto_dns = FALSE; gboolean auto_method = FALSE; @@ -6497,11 +6567,7 @@ END_ADD_DEFAULT_ROUTE: } } - routes_full_sync = commit - && priv->v6_commit_first_time - && !nm_device_sys_iface_state_is_external_or_assume (self); - - success = nm_device_set_ip6_config (self, composite, commit, routes_full_sync); + success = nm_device_set_ip6_config (self, composite, commit); g_object_unref (composite); if (commit) priv->v6_commit_first_time = FALSE; @@ -9853,46 +9919,35 @@ static gboolean nm_device_set_ip4_config (NMDevice *self, NMIP4Config *new_config, guint32 default_route_metric, - gboolean commit, - gboolean routes_full_sync) + gboolean commit) { NMDevicePrivate *priv; NMIP4Config *old_config = NULL; gboolean has_changes = FALSE; gboolean success = TRUE; gboolean def_route_changed; - int ip_ifindex, config_ifindex; + int ip_ifindex = 0; g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - _LOGD (LOGD_IP4, "ip4-config: update (commit=%d, routes-full-sync=%d, new-config=%p)", - commit, routes_full_sync, new_config); + _LOGD (LOGD_IP4, "ip4-config: update (commit=%d, new-config=%p)", + commit, new_config); - priv = NM_DEVICE_GET_PRIVATE (self); - ip_ifindex = nm_device_get_ip_ifindex (self); + nm_assert ( !new_config + || ( new_config + && ((ip_ifindex = nm_device_get_ip_ifindex (self)) > 0) + && ip_ifindex == nm_ip4_config_get_ifindex (new_config))); - if (new_config) { - config_ifindex = nm_ip4_config_get_ifindex (new_config); - if (config_ifindex > 0) - g_return_val_if_fail (ip_ifindex == config_ifindex, FALSE); - } + priv = NM_DEVICE_GET_PRIVATE (self); old_config = priv->ip4_config; /* Always commit to nm-platform to update lifetimes */ if (commit && new_config) { - gboolean assumed = nm_device_sys_iface_state_is_external_or_assume (self); - _commit_mtu (self, new_config); - /* For assumed devices we must not touch the kernel-routes, such as the device-route. - * FIXME: this is wrong in case where "assumed" means "take-over-seamlessly". In this - * case, we should manage the device route, for example on new DHCP lease. */ success = nm_ip4_config_commit (new_config, nm_device_get_platform (self), - nm_netns_get_route_manager (priv->netns), - ip_ifindex, - routes_full_sync, - assumed ? (gint64) -1 : (gint64) default_route_metric); + default_route_metric); } if (new_config) { @@ -10031,29 +10086,26 @@ nm_device_set_wwan_ip4_config (NMDevice *self, NMIP4Config *config) static gboolean nm_device_set_ip6_config (NMDevice *self, NMIP6Config *new_config, - gboolean commit, - gboolean routes_full_sync) + gboolean commit) { NMDevicePrivate *priv; NMIP6Config *old_config = NULL; gboolean has_changes = FALSE; gboolean success = TRUE; gboolean def_route_changed; - int ip_ifindex, config_ifindex; + int ip_ifindex = 0; g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - _LOGD (LOGD_IP6, "ip6-config: update (commit=%d, routes-full-sync=%d, new-config=%p)", - commit, routes_full_sync, new_config); + _LOGD (LOGD_IP6, "ip6-config: update (commit=%d, new-config=%p)", + commit, new_config); - priv = NM_DEVICE_GET_PRIVATE (self); - ip_ifindex = nm_device_get_ip_ifindex (self); + nm_assert ( !new_config + || ( new_config + && ((ip_ifindex = nm_device_get_ip_ifindex (self)) > 0) + && ip_ifindex == nm_ip6_config_get_ifindex (new_config))); - if (new_config) { - config_ifindex = nm_ip6_config_get_ifindex (new_config); - if (config_ifindex > 0) - g_return_val_if_fail (ip_ifindex == config_ifindex, FALSE); - } + priv = NM_DEVICE_GET_PRIVATE (self); old_config = priv->ip6_config; @@ -10061,10 +10113,7 @@ nm_device_set_ip6_config (NMDevice *self, if (commit && new_config) { _commit_mtu (self, priv->ip4_config); success = nm_ip6_config_commit (new_config, - nm_device_get_platform (self), - nm_netns_get_route_manager (priv->netns), - ip_ifindex, - routes_full_sync); + nm_device_get_platform (self)); } if (new_config) { @@ -10900,6 +10949,11 @@ queued_ip4_config_change (gpointer user_data) set_unmanaged_external_down (self, TRUE); + if (!nm_device_sys_iface_state_is_external_or_assume (self)) { + priv->v4_has_shadowed_routes = _v4_has_shadowed_routes_detect (self);; + ip4_rp_filter_update (self); + } + return FALSE; } @@ -12105,8 +12159,8 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) /* Clean up IP configs; this does not actually deconfigure the * interface; the caller must flush routes and addresses explicitly. */ - nm_device_set_ip4_config (self, NULL, 0, TRUE, TRUE); - nm_device_set_ip6_config (self, NULL, TRUE, TRUE); + nm_device_set_ip4_config (self, NULL, 0, TRUE); + nm_device_set_ip6_config (self, NULL, TRUE); g_clear_object (&priv->proxy_config); g_clear_object (&priv->con_ip4_config); g_clear_object (&priv->dev_ip4_config); @@ -12194,18 +12248,24 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean if (NM_DEVICE_GET_CLASS (self)->deactivate) NM_DEVICE_GET_CLASS (self)->deactivate (self); + ifindex = nm_device_get_ip_ifindex (self); + if (cleanup_type == CLEANUP_TYPE_DECONFIGURE) { /* master: release slaves */ nm_device_master_release_slaves (self); /* Take out any entries in the routing table and any IP address the device had. */ - ifindex = nm_device_get_ip_ifindex (self); if (ifindex > 0) { - nm_route_manager_route_flush (nm_netns_get_route_manager (priv->netns), ifindex); - nm_platform_ip_address_flush (nm_device_get_platform (self), AF_UNSPEC, ifindex); + NMPlatform *platform = nm_device_get_platform (self); + + nm_platform_ip_route_flush (platform, AF_UNSPEC, ifindex); + nm_platform_ip_address_flush (platform, AF_UNSPEC, ifindex); } } + if (ifindex > 0) + nm_platform_ip4_dev_route_blacklist_set (nm_device_get_platform (self), ifindex, NULL); + /* slave: mark no longer enslaved */ if ( priv->master && nm_platform_link_get_master (nm_device_get_platform (self), priv->ifindex) <= 0) @@ -13851,9 +13911,6 @@ constructed (GObject *object) g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, G_CALLBACK (device_ipx_changed), self); g_signal_connect (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (link_changed_cb), self); - g_signal_connect (nm_netns_get_route_manager (priv->netns), NM_ROUTE_MANAGER_IP4_ROUTES_CHANGED, - G_CALLBACK (ip4_routes_changed_changed_cb), self); - priv->settings = g_object_ref (NM_SETTINGS_GET); g_assert (priv->settings); @@ -13894,9 +13951,6 @@ dispose (GObject *object) g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (device_ipx_changed), self); g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (link_changed_cb), self); - g_signal_handlers_disconnect_by_func (nm_netns_get_route_manager (priv->netns), - G_CALLBACK (ip4_routes_changed_changed_cb), self); - g_slist_free_full (priv->arping.dad_list, (GDestroyNotify) nm_arping_manager_destroy); priv->arping.dad_list = NULL; |