summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am27
-rw-r--r--shared/nm-utils/nm-dedup-multi.c8
-rw-r--r--shared/nm-utils/nm-dedup-multi.h4
-rw-r--r--src/devices/nm-device.c216
-rw-r--r--src/devices/wwan/nm-modem.c10
-rw-r--r--src/nm-iface-helper.c15
-rw-r--r--src/nm-ip4-config.c181
-rw-r--r--src/nm-ip4-config.h9
-rw-r--r--src/nm-ip6-config.c44
-rw-r--r--src/nm-ip6-config.h5
-rw-r--r--src/nm-netns.c10
-rw-r--r--src/nm-netns.h1
-rw-r--r--src/nm-route-manager.c1380
-rw-r--r--src/nm-route-manager.h49
-rw-r--r--src/nm-types.h1
-rw-r--r--src/platform/nm-platform.c466
-rw-r--r--src/platform/nm-platform.h21
-rw-r--r--src/tests/test-route-manager.c974
-rw-r--r--src/vpn/nm-vpn-connection.c19
19 files changed, 770 insertions, 2670 deletions
diff --git a/Makefile.am b/Makefile.am
index 92ad10c36c..e8a6a8aeea 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1323,9 +1323,6 @@ src_libNetworkManagerBase_la_SOURCES = \
src/nm-ip6-config.c \
src/nm-ip6-config.h \
\
- src/nm-route-manager.c \
- src/nm-route-manager.h \
- \
src/dhcp/nm-dhcp-client.c \
src/dhcp/nm-dhcp-client.h \
src/dhcp/nm-dhcp-client-logging.h \
@@ -2961,8 +2958,6 @@ check_programs += \
src/tests/test-general-with-expect \
src/tests/test-ip4-config \
src/tests/test-ip6-config \
- src/tests/test-route-manager-linux \
- src/tests/test-route-manager-fake \
src/tests/test-dcb \
src/tests/test-systemd \
src/tests/test-resolvconf-capture \
@@ -3010,28 +3005,6 @@ $(src_tests_test_general_with_expect_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
$(src_tests_test_wired_defname_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
$(src_tests_test_utils_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
-src_tests_test_route_manager_ldflags = \
- $(CODE_COVERAGE_LDFLAGS)
-
-src_tests_test_route_manager_ldadd = \
- src/libNetworkManagerTest.la \
- $(GLIB_LIBS) \
- $(LIBUDEV_LIBS) \
- $(LIBNL_LIBS)
-
-src_tests_test_route_manager_fake_SOURCES = src/tests/test-route-manager.c
-src_tests_test_route_manager_fake_CPPFLAGS = $(src_tests_cppflags_fake)
-src_tests_test_route_manager_fake_LDFLAGS = $(src_tests_test_route_manager_ldflags)
-src_tests_test_route_manager_fake_LDADD = $(src_tests_test_route_manager_ldadd)
-
-src_tests_test_route_manager_linux_SOURCES = src/tests/test-route-manager.c
-src_tests_test_route_manager_linux_CPPFLAGS = $(src_tests_cppflags_linux)
-src_tests_test_route_manager_linux_LDFLAGS = $(src_tests_test_route_manager_ldflags)
-src_tests_test_route_manager_linux_LDADD = $(src_tests_test_route_manager_ldadd)
-
-$(src_tests_test_route_manager_fake_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
-$(src_tests_test_route_manager_linux_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
-
src_tests_test_systemd_CPPFLAGS = $(src_libsystemd_nm_la_cppflags)
src_tests_test_systemd_LDADD = \
src/libsystemd-nm.la \
diff --git a/shared/nm-utils/nm-dedup-multi.c b/shared/nm-utils/nm-dedup-multi.c
index 383e40fd72..51a866abca 100644
--- a/shared/nm-utils/nm-dedup-multi.c
+++ b/shared/nm-utils/nm-dedup-multi.c
@@ -77,7 +77,7 @@ nm_dedup_multi_idx_type_init (NMDedupMultiIdxType *idx_type,
/*****************************************************************************/
static NMDedupMultiEntry *
-_entry_lookup_obj (NMDedupMultiIndex *self,
+_entry_lookup_obj (const NMDedupMultiIndex *self,
const NMDedupMultiIdxType *idx_type,
const NMDedupMultiObj *obj)
{
@@ -92,7 +92,7 @@ _entry_lookup_obj (NMDedupMultiIndex *self,
}
static NMDedupMultiHeadEntry *
-_entry_lookup_head (NMDedupMultiIndex *self,
+_entry_lookup_head (const NMDedupMultiIndex *self,
const NMDedupMultiIdxType *idx_type,
const NMDedupMultiObj *obj)
{
@@ -682,7 +682,7 @@ nm_dedup_multi_index_remove_idx (NMDedupMultiIndex *self,
* Returns: the cache entry or %NULL if the entry wasn't found.
*/
const NMDedupMultiEntry *
-nm_dedup_multi_index_lookup_obj (NMDedupMultiIndex *self,
+nm_dedup_multi_index_lookup_obj (const NMDedupMultiIndex *self,
const NMDedupMultiIdxType *idx_type,
/*const NMDedupMultiObj * */ gconstpointer obj)
{
@@ -708,7 +708,7 @@ nm_dedup_multi_index_lookup_obj (NMDedupMultiIndex *self,
* Returns: the cache entry or %NULL if the entry wasn't found.
*/
const NMDedupMultiHeadEntry *
-nm_dedup_multi_index_lookup_head (NMDedupMultiIndex *self,
+nm_dedup_multi_index_lookup_head (const NMDedupMultiIndex *self,
const NMDedupMultiIdxType *idx_type,
/*const NMDedupMultiObj * */ gconstpointer obj)
{
diff --git a/shared/nm-utils/nm-dedup-multi.h b/shared/nm-utils/nm-dedup-multi.h
index c99d6d11e1..ff505b696f 100644
--- a/shared/nm-utils/nm-dedup-multi.h
+++ b/shared/nm-utils/nm-dedup-multi.h
@@ -278,11 +278,11 @@ gboolean nm_dedup_multi_index_add (NMDedupMultiIndex *self,
const NMDedupMultiEntry **out_entry,
/* const NMDedupMultiObj ** */ gpointer out_obj_old);
-const NMDedupMultiEntry *nm_dedup_multi_index_lookup_obj (NMDedupMultiIndex *self,
+const NMDedupMultiEntry *nm_dedup_multi_index_lookup_obj (const NMDedupMultiIndex *self,
const NMDedupMultiIdxType *idx_type,
/*const NMDedupMultiObj * */ gconstpointer obj);
-const NMDedupMultiHeadEntry *nm_dedup_multi_index_lookup_head (NMDedupMultiIndex *self,
+const NMDedupMultiHeadEntry *nm_dedup_multi_index_lookup_head (const NMDedupMultiIndex *self,
const NMDedupMultiIdxType *idx_type,
/*const NMDedupMultiObj * */ gconstpointer obj);
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;
diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c
index b6bcc25fbb..6e2ad7f2e9 100644
--- a/src/devices/wwan/nm-modem.c
+++ b/src/devices/wwan/nm-modem.c
@@ -32,7 +32,6 @@
#include "nm-setting-connection.h"
#include "NetworkManagerUtils.h"
#include "devices/nm-device-private.h"
-#include "nm-route-manager.h"
#include "nm-netns.h"
#include "nm-act-request.h"
#include "nm-ip4-config.h"
@@ -1066,10 +1065,11 @@ deactivate_cleanup (NMModem *self, NMDevice *device)
priv->ip6_method == NM_MODEM_IP_METHOD_AUTO) {
ifindex = nm_device_get_ip_ifindex (device);
if (ifindex > 0) {
- nm_route_manager_route_flush (nm_netns_get_route_manager (nm_device_get_netns (device)),
- ifindex);
- nm_platform_ip_address_flush (nm_device_get_platform (device), AF_UNSPEC, ifindex);
- nm_platform_link_set_down (nm_device_get_platform (device), ifindex);
+ NMPlatform *platform = nm_device_get_platform (device);
+
+ nm_platform_ip_route_flush (platform, AF_UNSPEC, ifindex);
+ nm_platform_ip_address_flush (platform, AF_UNSPEC, ifindex);
+ nm_platform_link_set_down (platform, ifindex);
}
}
}
diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c
index 3b60e0d64f..c695d591f6 100644
--- a/src/nm-iface-helper.c
+++ b/src/nm-iface-helper.c
@@ -42,7 +42,6 @@
#include "nm-utils.h"
#include "nm-setting-ip6-config.h"
#include "systemd/nm-sd.h"
-#include "nm-route-manager.h"
#if !defined(NM_DIST_VERSION)
# define NM_DIST_VERSION VERSION
@@ -98,12 +97,6 @@ static struct {
/*****************************************************************************/
-NMRouteManager *route_manager_get (void);
-
-NM_DEFINE_SINGLETON_GETTER (NMRouteManager, route_manager_get, NM_TYPE_ROUTE_MANAGER);
-
-/*****************************************************************************/
-
static void
dhcp4_state_changed (NMDhcpClient *client,
NMDhcpState state,
@@ -122,13 +115,17 @@ dhcp4_state_changed (NMDhcpClient *client,
switch (state) {
case NM_DHCP_STATE_BOUND:
g_assert (ip4_config);
+ g_assert (nm_ip4_config_get_ifindex (ip4_config) == gl.ifindex);
+
existing = nm_ip4_config_capture (nm_platform_get_multi_idx (NM_PLATFORM_GET),
NM_PLATFORM_GET, gl.ifindex, FALSE);
if (last_config)
nm_ip4_config_subtract (existing, last_config);
nm_ip4_config_merge (existing, ip4_config, NM_IP_CONFIG_MERGE_DEFAULT);
- if (!nm_ip4_config_commit (existing, NM_PLATFORM_GET, route_manager_get (), gl.ifindex, TRUE, global_opt.priority_v4))
+ if (!nm_ip4_config_commit (existing,
+ NM_PLATFORM_GET,
+ global_opt.priority_v4))
_LOGW (LOGD_DHCP4, "failed to apply DHCPv4 config");
if (last_config)
@@ -257,7 +254,7 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
}
nm_ip6_config_merge (existing, ndisc_config, NM_IP_CONFIG_MERGE_DEFAULT);
- if (!nm_ip6_config_commit (existing, NM_PLATFORM_GET, route_manager_get (), gl.ifindex, TRUE))
+ if (!nm_ip6_config_commit (existing, NM_PLATFORM_GET))
_LOGW (LOGD_IP6, "failed to apply IPv6 config");
}
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c
index e94662107d..606bb342fc 100644
--- a/src/nm-ip4-config.c
+++ b/src/nm-ip4-config.c
@@ -33,7 +33,6 @@
#include "platform/nm-platform.h"
#include "platform/nm-platform-utils.h"
#include "NetworkManagerUtils.h"
-#include "nm-route-manager.h"
#include "nm-core-internal.h"
#include "introspection/org.freedesktop.NetworkManager.IP4Config.h"
@@ -284,6 +283,48 @@ append_force_and_out:
return FALSE;
}
+/**
+ * _nm_ip_config_lookup_ip_route:
+ * @multi_idx:
+ * @idx_type:
+ * @needle:
+ * @cmp_type: after lookup, filter the result by comparing with @cmp_type. Only
+ * return the result, if it compares equal to @needle according to this @cmp_type.
+ * Note that the index uses %NM_PLATFORM_IP_ROUTE_CMP_TYPE_DST type, so passing
+ * that compare-type means not to filter any further.
+ *
+ * Returns: the found entry or %NULL.
+ */
+const NMDedupMultiEntry *
+_nm_ip_config_lookup_ip_route (const NMDedupMultiIndex *multi_idx,
+ const NMIPConfigDedupMultiIdxType *idx_type,
+ const NMPObject *needle,
+ NMPlatformIPRouteCmpType cmp_type)
+{
+ const NMDedupMultiEntry *entry;
+
+ nm_assert (multi_idx);
+ nm_assert (idx_type);
+ nm_assert (NM_IN_SET (idx_type->obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
+ nm_assert (NMP_OBJECT_GET_TYPE (needle) == idx_type->obj_type);
+
+ entry = nm_dedup_multi_index_lookup_obj (multi_idx,
+ &idx_type->parent,
+ needle);
+ if (!entry)
+ return NULL;
+
+ if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_DST)
+ nm_assert (nm_platform_ip4_route_cmp (NMP_OBJECT_CAST_IP4_ROUTE (entry->obj), NMP_OBJECT_CAST_IP4_ROUTE (needle), cmp_type) == 0);
+ else {
+ if (nm_platform_ip4_route_cmp (NMP_OBJECT_CAST_IP4_ROUTE (entry->obj),
+ NMP_OBJECT_CAST_IP4_ROUTE (needle),
+ cmp_type) != 0)
+ return NULL;
+ }
+ return entry;
+}
+
/*****************************************************************************/
NM_GOBJECT_PROPERTIES_DEFINE (NMIP4Config,
@@ -352,6 +393,9 @@ G_DEFINE_TYPE (NMIP4Config, nm_ip4_config, NM_TYPE_EXPORTED_OBJECT)
static void _add_address (NMIP4Config *self, const NMPObject *obj_new, const NMPlatformIP4Address *new);
static void _add_route (NMIP4Config *self, const NMPObject *obj_new, const NMPlatformIP4Route *new);
+static const NMDedupMultiEntry *_lookup_route (const NMIP4Config *self,
+ const NMPObject *needle,
+ NMPlatformIPRouteCmpType cmp_type);
/*****************************************************************************/
@@ -669,37 +713,41 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
}
gboolean
-nm_ip4_config_commit (const NMIP4Config *self, NMPlatform *platform, NMRouteManager *route_manager, int ifindex, gboolean routes_full_sync, gint64 default_route_metric)
+nm_ip4_config_commit (const NMIP4Config *self,
+ NMPlatform *platform,
+ guint32 default_route_metric)
{
+ const NMIP4ConfigPrivate *priv;
gs_unref_ptrarray GPtrArray *addresses = NULL;
- const NMDedupMultiHeadEntry *head_entry;
+ gs_unref_ptrarray GPtrArray *routes = NULL;
+ gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL;
+ int ifindex;
guint i;
- gs_unref_array GArray *routes = NULL;
- gs_unref_array GArray *device_route_purge_list = NULL;
- const CList *iter;
+ gboolean success = TRUE;
+
+ g_return_val_if_fail (NM_IS_IP4_CONFIG (self), FALSE);
+
+ priv = NM_IP4_CONFIG_GET_PRIVATE (self);
+ ifindex = nm_ip4_config_get_ifindex (self);
g_return_val_if_fail (ifindex > 0, FALSE);
- g_return_val_if_fail (self != NULL, FALSE);
addresses = nm_dedup_multi_objs_to_ptr_array_head (nm_ip4_config_lookup_addresses (self),
NULL, NULL);
- nm_platform_ip4_address_sync (platform, ifindex, addresses);
-
- /* Routes */
- head_entry = nm_ip4_config_lookup_routes (self);
-
- routes = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP4Route), head_entry ? head_entry->len : 0);
+ routes = nm_dedup_multi_objs_to_ptr_array_head (nm_ip4_config_lookup_routes (self),
+ NULL, NULL);
- if ( default_route_metric >= 0
- && addresses) {
+ if (addresses) {
/* For IPv6, we explicitly add the device-routes (onlink) to NMIP6Config.
* As we don't do that for IPv4, add it here shortly before syncing
- * the routes. For NMRouteManager these routes are very much important. */
+ * the routes. */
for (i = 0; i < addresses->len; i++) {
const NMPObject *o = addresses->pdata[i];
const NMPlatformIP4Address *addr;
- NMPlatformIP4Route route = { 0 };
+ nm_auto_nmpobj NMPObject *r = NULL;
+ NMPlatformIP4Route *route;
+ in_addr_t network;
if (!o)
continue;
@@ -710,48 +758,77 @@ nm_ip4_config_commit (const NMIP4Config *self, NMPlatform *platform, NMRouteMana
nm_assert (addr->plen <= 32);
- route.ifindex = ifindex;
- route.rt_source = NM_IP_CONFIG_SOURCE_KERNEL;
-
/* The destination network depends on the peer-address. */
- route.network = nm_utils_ip4_address_clear_host_address (addr->peer_address, addr->plen);
+ network = nm_utils_ip4_address_clear_host_address (addr->peer_address, addr->plen);
- if (_ipv4_is_zeronet (route.network)) {
+ if (_ipv4_is_zeronet (network)) {
/* Kernel doesn't add device-routes for destinations that
* start with 0.x.y.z. Skip them. */
continue;
}
- route.plen = addr->plen;
- route.pref_src = addr->address;
- route.metric = default_route_metric;
-
- g_array_append_val (routes, route);
+ r = nmp_object_new (NMP_OBJECT_TYPE_IP4_ROUTE, NULL);
+ route = NMP_OBJECT_CAST_IP4_ROUTE (r);
+
+ route->ifindex = ifindex;
+ route->rt_source = NM_IP_CONFIG_SOURCE_KERNEL;
+ route->network = network;
+ route->plen = addr->plen;
+ route->pref_src = addr->address;
+ route->metric = default_route_metric;
+ route->scope_inv = nm_platform_route_scope_inv (NM_RT_SCOPE_LINK);
+
+ nm_platform_ip_route_normalize (AF_INET, (NMPlatformIPRoute *) route);
+
+ if (_lookup_route (self,
+ r,
+ NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID)) {
+ /* we already track this route. Don't add it again. */
+ } else {
+ if (!routes)
+ routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref);
+ g_ptr_array_add (routes, (gpointer) nmp_object_ref (r));
+ }
if (default_route_metric != NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE) {
- if (!device_route_purge_list)
- device_route_purge_list = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route));
- route.metric = NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE;
- g_array_append_val (device_route_purge_list, route);
+ nm_auto_nmpobj NMPObject *r_dev = NULL;
+
+ r_dev = nmp_object_clone (r, FALSE);
+ route = NMP_OBJECT_CAST_IP4_ROUTE (r_dev);
+ route->metric = NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE;
+
+ nm_platform_ip_route_normalize (AF_INET, (NMPlatformIPRoute *) route);
+
+ if (_lookup_route (self,
+ r_dev,
+ NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID)) {
+ /* we track such a route explicitly. Don't blacklist it. */
+ } else {
+ if (!ip4_dev_route_blacklist)
+ ip4_dev_route_blacklist = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref);
+
+ g_ptr_array_add (ip4_dev_route_blacklist,
+ g_steal_pointer (&r_dev));
+ }
}
}
}
- if (head_entry) {
- c_list_for_each (iter, &head_entry->lst_entries_head) {
- g_array_append_vals (routes,
- NMP_OBJECT_CAST_IP4_ROUTE (c_list_entry (iter, NMDedupMultiEntry, lst_entries)->obj),
- 1);
- }
- }
+ nm_platform_ip4_address_sync (platform, ifindex, addresses);
- nm_route_manager_ip4_route_register_device_route_purge_list (route_manager, device_route_purge_list);
+ if (!nm_platform_ip_route_sync (platform,
+ AF_INET,
+ ifindex,
+ routes,
+ nm_platform_lookup_predicate_routes_skip_rtprot_kernel,
+ NULL))
+ success = FALSE;
- if (!nm_route_manager_ip4_route_sync (route_manager, ifindex, routes,
- default_route_metric < 0, routes_full_sync))
- return FALSE;
+ nm_platform_ip4_dev_route_blacklist_set (platform,
+ ifindex,
+ ip4_dev_route_blacklist);
- return TRUE;
+ return success;
}
static void
@@ -1996,6 +2073,24 @@ nm_ip4_config_address_exists (const NMIP4Config *self,
/*****************************************************************************/
+static const NMDedupMultiEntry *
+_lookup_route (const NMIP4Config *self,
+ const NMPObject *needle,
+ NMPlatformIPRouteCmpType cmp_type)
+{
+ const NMIP4ConfigPrivate *priv;
+
+ nm_assert (NM_IS_IP4_CONFIG (self));
+ nm_assert (NMP_OBJECT_GET_TYPE (needle) == NMP_OBJECT_TYPE_IP4_ROUTE);
+
+ priv = NM_IP4_CONFIG_GET_PRIVATE (self);
+
+ return _nm_ip_config_lookup_ip_route (priv->multi_idx,
+ &priv->idx_ip4_routes_,
+ needle,
+ cmp_type);
+}
+
void
nm_ip4_config_reset_routes (NMIP4Config *self)
{
diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h
index 594dcc5bf2..ab8fa51d4d 100644
--- a/src/nm-ip4-config.h
+++ b/src/nm-ip4-config.h
@@ -96,6 +96,11 @@ gboolean _nm_ip_config_add_obj (NMDedupMultiIndex *multi_idx,
gboolean merge,
gboolean append_force);
+const NMDedupMultiEntry *_nm_ip_config_lookup_ip_route (const NMDedupMultiIndex *multi_idx,
+ const NMIPConfigDedupMultiIdxType *idx_type,
+ const NMPObject *needle,
+ NMPlatformIPRouteCmpType cmp_type);
+
/*****************************************************************************/
#define NM_TYPE_IP4_CONFIG (nm_ip4_config_get_type ())
@@ -137,7 +142,9 @@ int nm_ip4_config_get_ifindex (const NMIP4Config *self);
NMDedupMultiIndex *nm_ip4_config_get_multi_idx (const NMIP4Config *self);
NMIP4Config *nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex, gboolean capture_resolv_conf);
-gboolean nm_ip4_config_commit (const NMIP4Config *self, NMPlatform *platform, NMRouteManager *route_manager, int ifindex, gboolean routes_full_sync, gint64 default_route_metric);
+gboolean nm_ip4_config_commit (const NMIP4Config *self,
+ NMPlatform *platform,
+ guint32 default_route_metric);
void nm_ip4_config_merge_setting (NMIP4Config *self, NMSettingIPConfig *setting, guint32 default_route_metric);
NMSetting *nm_ip4_config_create_setting (const NMIP4Config *self);
diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c
index 9fc4c3e2ff..3d42fb7b8a 100644
--- a/src/nm-ip6-config.c
+++ b/src/nm-ip6-config.c
@@ -32,7 +32,6 @@
#include "platform/nmp-object.h"
#include "platform/nm-platform.h"
#include "platform/nm-platform-utils.h"
-#include "nm-route-manager.h"
#include "nm-core-internal.h"
#include "NetworkManagerUtils.h"
#include "nm-ip4-config.h"
@@ -516,42 +515,33 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
gboolean
nm_ip6_config_commit (const NMIP6Config *self,
- NMPlatform *platform,
- NMRouteManager *route_manager,
- int ifindex,
- gboolean routes_full_sync)
+ NMPlatform *platform)
{
gs_unref_ptrarray GPtrArray *addresses = NULL;
- const NMDedupMultiHeadEntry *head_entry;
- gs_unref_array GArray *routes = NULL;
- const CList *iter;
+ gs_unref_ptrarray GPtrArray *routes = NULL;
+ int ifindex;
+ gboolean success = TRUE;
+
+ g_return_val_if_fail (NM_IS_IP6_CONFIG (self), FALSE);
+ ifindex = nm_ip6_config_get_ifindex (self);
g_return_val_if_fail (ifindex > 0, FALSE);
- g_return_val_if_fail (self != NULL, FALSE);
- /* Addresses */
addresses = nm_dedup_multi_objs_to_ptr_array_head (nm_ip6_config_lookup_addresses (self),
NULL, NULL);
-
+ routes = nm_dedup_multi_objs_to_ptr_array_head (nm_ip6_config_lookup_routes (self),
+ NULL, NULL);
nm_platform_ip6_address_sync (platform, ifindex, addresses, TRUE);
- /* Routes */
- head_entry = nm_ip6_config_lookup_routes (self);
-
- routes = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP6Route), head_entry ? head_entry->len : 0);
-
- if (head_entry) {
- c_list_for_each (iter, &head_entry->lst_entries_head) {
- g_array_append_vals (routes,
- NMP_OBJECT_CAST_IP6_ROUTE (c_list_entry (iter, NMDedupMultiEntry, lst_entries)->obj),
- 1);
- }
- }
-
- if (!nm_route_manager_ip6_route_sync (route_manager, ifindex, routes, TRUE, routes_full_sync))
- return FALSE;
+ if (!nm_platform_ip_route_sync (platform,
+ AF_INET6,
+ ifindex,
+ routes,
+ nm_platform_lookup_predicate_routes_skip_rtprot_kernel,
+ NULL))
+ success = FALSE;
- return TRUE;
+ return success;
}
static void
diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h
index f296224fab..6e7b112110 100644
--- a/src/nm-ip6-config.h
+++ b/src/nm-ip6-config.h
@@ -112,10 +112,7 @@ struct _NMDedupMultiIndex *nm_ip6_config_get_multi_idx (const NMIP6Config *self)
NMIP6Config *nm_ip6_config_capture (struct _NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex,
gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary);
gboolean nm_ip6_config_commit (const NMIP6Config *self,
- NMPlatform *platform,
- NMRouteManager *route_manager,
- int ifindex,
- gboolean routes_full_sync);
+ NMPlatform *platform);
void nm_ip6_config_merge_setting (NMIP6Config *self, NMSettingIPConfig *setting, guint32 default_route_metric);
NMSetting *nm_ip6_config_create_setting (const NMIP6Config *self);
diff --git a/src/nm-netns.c b/src/nm-netns.c
index f5e6b0014d..8069cfccc3 100644
--- a/src/nm-netns.c
+++ b/src/nm-netns.c
@@ -26,7 +26,6 @@
#include "platform/nm-platform.h"
#include "platform/nmp-netns.h"
-#include "nm-route-manager.h"
#include "nm-default-route-manager.h"
#include "nm-core-internal.h"
#include "NetworkManagerUtils.h"
@@ -40,7 +39,6 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE (
typedef struct {
NMPlatform *platform;
NMPNetns *platform_netns;
- NMRouteManager *route_manager;
NMDefaultRouteManager *default_route_manager;
bool log_with_ptr;
} NMNetnsPrivate;
@@ -88,12 +86,6 @@ nm_netns_get_default_route_manager (NMNetns *self)
return NM_NETNS_GET_PRIVATE (self)->default_route_manager;
}
-NMRouteManager *
-nm_netns_get_route_manager (NMNetns *self)
-{
- return NM_NETNS_GET_PRIVATE (self)->route_manager;
-}
-
/*****************************************************************************/
static void
@@ -137,7 +129,6 @@ constructed (GObject *object)
log_with_ptr = nm_platform_get_log_with_ptr (priv->platform);
priv->platform_netns = nm_platform_netns_get (priv->platform);
- priv->route_manager = nm_route_manager_new (log_with_ptr, priv->platform);
priv->default_route_manager = nm_default_route_manager_new (log_with_ptr, priv->platform);
G_OBJECT_CLASS (nm_netns_parent_class)->constructed (object);
@@ -157,7 +148,6 @@ dispose (GObject *object)
NMNetns *self = NM_NETNS (object);
NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE (self);
- g_clear_object (&priv->route_manager);
g_clear_object (&priv->default_route_manager);
g_clear_object (&priv->platform);
diff --git a/src/nm-netns.h b/src/nm-netns.h
index ebe9d1f2a8..bc71880400 100644
--- a/src/nm-netns.h
+++ b/src/nm-netns.h
@@ -39,7 +39,6 @@ NMNetns *nm_netns_new (NMPlatform *platform);
NMPlatform *nm_netns_get_platform (NMNetns *self);
NMPNetns *nm_netns_get_platform_netns (NMNetns *self);
-NMRouteManager *nm_netns_get_route_manager (NMNetns *self);
NMDefaultRouteManager *nm_netns_get_default_route_manager (NMNetns *self);
struct _NMDedupMultiIndex *nm_netns_get_multi_idx (NMNetns *self);
diff --git a/src/nm-route-manager.c b/src/nm-route-manager.c
deleted file mode 100644
index 12583e5c06..0000000000
--- a/src/nm-route-manager.c
+++ /dev/null
@@ -1,1380 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright (C) 2015 Red Hat, Inc.
- */
-
-#include "nm-default.h"
-
-#include "nm-route-manager.h"
-
-#include <string.h>
-
-#include "platform/nm-platform.h"
-#include "platform/nmp-object.h"
-#include "nm-core-internal.h"
-#include "NetworkManagerUtils.h"
-
-/* if within half a second after adding an IP address a matching device-route shows
- * up, we delete it. */
-#define IP4_DEVICE_ROUTES_WAIT_TIME_NS (NM_UTILS_NS_PER_SECOND / 2)
-
-#define IP4_DEVICE_ROUTES_GC_INTERVAL_MSEC ((IP4_DEVICE_ROUTES_WAIT_TIME_NS / 1000000) * 3)
-
-/*****************************************************************************/
-
-typedef struct {
- guint len;
- NMPlatformIPXRoute *entries[1];
-} RouteIndex;
-
-typedef struct {
- GArray *entries;
- RouteIndex *index;
-
- /* list of effective metrics. The indexes of the array correspond to @index, not @entries. */
- GArray *effective_metrics;
-
- /* this array contains the effective metrics but using the reversed index that corresponds
- * to @entries, instead of @index. */
- GArray *effective_metrics_reverse;
-} RouteEntries;
-
-typedef struct {
- NMRouteManager *self;
- gint64 scheduled_at_ns;
- guint idle_id;
- const NMPObject *obj;
- const NMPObject *obj_cached;
-} IP4DeviceRoutePurgeEntry;
-
-/*****************************************************************************/
-
-enum {
- IP4_ROUTES_CHANGED,
- LAST_SIGNAL,
-};
-static guint signals[LAST_SIGNAL] = { 0 };
-
-NM_GOBJECT_PROPERTIES_DEFINE_BASE (
- PROP_LOG_WITH_PTR,
- PROP_PLATFORM,
-);
-
-typedef struct {
- NMPlatform *platform;
-
- RouteEntries ip4_routes;
- RouteEntries ip6_routes;
- struct {
- GHashTable *entries;
- guint gc_id;
- } ip4_device_routes;
-
- bool log_with_ptr;
-} NMRouteManagerPrivate;
-
-struct _NMRouteManager {
- GObject parent;
- NMRouteManagerPrivate _priv;
-};
-
-struct _NMRouteManagerClass {
- GObjectClass parent;
-};
-
-G_DEFINE_TYPE (NMRouteManager, nm_route_manager, G_TYPE_OBJECT);
-
-#define NM_ROUTE_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMRouteManager, NM_IS_ROUTE_MANAGER)
-
-/*****************************************************************************/
-
-typedef struct {
- const NMPlatformVTableRoute *vt;
-
- /* a compare function for two routes that considers only the destination fields network/plen.
- * It is a looser comparisong then @route_id_cmp(), that means that if @route_dest_cmp()
- * returns non-zero, also @route_id_cmp() returns the same value. It also means, that
- * sorting by @route_id_cmp() implicitly sorts by @route_dest_cmp() as well. */
- int (*route_dest_cmp) (const NMPlatformIPXRoute *r1, const NMPlatformIPXRoute *r2);
-
- /* a compare function for two routes that considers only the fields network/plen,metric. */
- int (*route_id_cmp) (const NMPlatformIPXRoute *r1, const NMPlatformIPXRoute *r2);
-} VTableIP;
-
-static const VTableIP vtable_v4, vtable_v6;
-
-#define VTABLE_ROUTE_INDEX(vtable, garray, idx) ((NMPlatformIPXRoute *) &((garray)->data[(idx) * (vtable)->vt->sizeof_route]))
-
-#define VTABLE_IS_DEVICE_ROUTE(vtable, route) ((vtable)->vt->is_ip4 \
- ? ((route)->r4.gateway == 0) \
- : IN6_IS_ADDR_UNSPECIFIED (&(route)->r6.gateway) )
-
-#define CMP_AND_RETURN_INT(a, b) \
- G_STMT_START { \
- typeof(a) _a = (a), _b = (b); \
- \
- if (_a < _b) \
- return -1; \
- if (_a > _b) \
- return 1; \
- } G_STMT_END
-
-/*****************************************************************************/
-
-#define _NMLOG_PREFIX_NAME "route-mgr"
-#undef _NMLOG_ENABLED
-#define _NMLOG_ENABLED(level, addr_family) \
- ({ \
- const int __addr_family = (addr_family); \
- const NMLogLevel __level = (level); \
- const NMLogDomain __domain = __addr_family == AF_INET ? LOGD_IP4 : (__addr_family == AF_INET6 ? LOGD_IP6 : LOGD_IP); \
- \
- nm_logging_enabled (__level, __domain); \
- })
-#define _NMLOG(level, addr_family, ...) \
- G_STMT_START { \
- const int __addr_family = (addr_family); \
- const NMLogLevel __level = (level); \
- const NMLogDomain __domain = __addr_family == AF_INET ? LOGD_IP4 : (__addr_family == AF_INET6 ? LOGD_IP6 : LOGD_IP); \
- \
- if (nm_logging_enabled (__level, __domain)) { \
- char __ch = __addr_family == AF_INET ? '4' : (__addr_family == AF_INET6 ? '6' : '-'); \
- char __prefix[30] = _NMLOG_PREFIX_NAME; \
- \
- if (NM_ROUTE_MANAGER_GET_PRIVATE (self)->log_with_ptr) \
- g_snprintf (__prefix, sizeof (__prefix), "%s%c[%p]", _NMLOG_PREFIX_NAME, __ch, (self)); \
- else \
- __prefix[NM_STRLEN (_NMLOG_PREFIX_NAME)] = __ch; \
- _nm_log ((level), (__domain), 0, NULL, NULL, \
- "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
- __prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
- } \
- } G_STMT_END
-
-/*****************************************************************************/
-
-static gboolean _ip4_device_routes_cancel (NMRouteManager *self);
-
-/*****************************************************************************/
-
-#if NM_MORE_ASSERTS && !defined (G_DISABLE_ASSERT)
-static inline void
-ASSERT_route_index_valid (const VTableIP *vtable, const GArray *entries, const RouteIndex *index, gboolean unique_ifindexes)
-{
- guint i, j;
- int c;
- const NMPlatformIPXRoute *r1, *r2;
- gs_unref_hashtable GHashTable *ptrs = g_hash_table_new (NULL, NULL);
- const NMPlatformIPXRoute *r_first = NULL, *r_last = NULL;
-
- g_assert (index);
-
- if (entries)
- g_assert_cmpint (entries->len, ==, index->len);
- else
- g_assert (index->len == 0);
-
- if (index->len > 0) {
- r_first = VTABLE_ROUTE_INDEX (vtable, entries, 0);
- r_last = VTABLE_ROUTE_INDEX (vtable, entries, index->len - 1);
- }
-
- /* assert that the @index is valid for the @entries. */
-
- g_assert (!index->entries[index->len]);
- for (i = 0; i < index->len; i++) {
- r1 = index->entries[i];
-
- g_assert (r1);
- g_assert (r1 >= r_first);
- g_assert (r1 <= r_last);
- g_assert_cmpint ((((char *) r1) - ((char *) entries->data)) % vtable->vt->sizeof_route, ==, 0);
-
- g_assert (!g_hash_table_contains (ptrs, (gpointer) r1));
- g_hash_table_add (ptrs, (gpointer) r1);
-
- for (j = i; j > 0; ) {
- r2 = index->entries[--j];
-
- c = vtable->route_id_cmp (r1, r2);
- g_assert (c >= 0);
- if (c != 0)
- break;
- if (unique_ifindexes)
- g_assert_cmpint (r1->rx.ifindex, !=, r2->rx.ifindex);
- }
- }
-}
-#else
-#define ASSERT_route_index_valid(vtable, entries, index, unique_ifindexes) G_STMT_START { (void) 0; } G_STMT_END
-#endif
-
-/*****************************************************************************/
-
-static int
-_v4_route_dest_cmp (const NMPlatformIP4Route *r1, const NMPlatformIP4Route *r2)
-{
- CMP_AND_RETURN_INT (r1->plen, r2->plen);
- CMP_AND_RETURN_INT (nm_utils_ip4_address_clear_host_address (r1->network, r1->plen),
- nm_utils_ip4_address_clear_host_address (r2->network, r2->plen));
- return 0;
-}
-
-static int
-_v6_route_dest_cmp (const NMPlatformIP6Route *r1, const NMPlatformIP6Route *r2)
-{
- struct in6_addr n1, n2;
-
- CMP_AND_RETURN_INT (r1->plen, r2->plen);
-
- nm_utils_ip6_address_clear_host_address (&n1, &r1->network, r1->plen);
- nm_utils_ip6_address_clear_host_address (&n2, &r2->network, r2->plen );
- return memcmp (&n1, &n2, sizeof (n1));
-}
-
-static int
-_v4_route_id_cmp (const NMPlatformIP4Route *r1, const NMPlatformIP4Route *r2)
-{
- CMP_AND_RETURN_INT (r1->plen, r2->plen);
- CMP_AND_RETURN_INT (nm_utils_ip4_address_clear_host_address (r1->network, r1->plen),
- nm_utils_ip4_address_clear_host_address (r2->network, r2->plen));
- CMP_AND_RETURN_INT (r1->metric, r2->metric);
- return 0;
-}
-
-static int
-_v6_route_id_cmp (const NMPlatformIP6Route *r1, const NMPlatformIP6Route *r2)
-{
- struct in6_addr n1, n2;
- int c;
-
- CMP_AND_RETURN_INT (r1->plen, r2->plen);
-
- nm_utils_ip6_address_clear_host_address (&n1, &r1->network, r1->plen);
- nm_utils_ip6_address_clear_host_address (&n2, &r2->network, r2->plen);
- c = memcmp (&n1, &n2, sizeof (n1));
- if (c != 0)
- return c;
-
- CMP_AND_RETURN_INT (nm_utils_ip6_route_metric_normalize (r1->metric),
- nm_utils_ip6_route_metric_normalize (r2->metric));
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-_route_index_create_sort (const NMPlatformIPXRoute **p1, const NMPlatformIPXRoute ** p2, const VTableIP *vtable)
-{
- return vtable->route_id_cmp (*p1, *p2);
-}
-
-static RouteIndex *
-_route_index_create (const VTableIP *vtable, const GArray *routes)
-{
- RouteIndex *index;
- guint i;
- guint len = routes ? routes->len : 0;
-
- index = g_malloc (sizeof (RouteIndex) + len * sizeof (NMPlatformIPXRoute *));
-
- index->len = len;
- for (i = 0; i < len; i++)
- index->entries[i] = VTABLE_ROUTE_INDEX (vtable, routes, i);
- index->entries[i] = NULL;
-
- /* this is a stable sort, which is very important at this point. */
- g_qsort_with_data (index->entries,
- len,
- sizeof (NMPlatformIPXRoute *),
- (GCompareDataFunc) _route_index_create_sort,
- (gpointer) vtable);
- return index;
-}
-
-static RouteIndex *
-_route_index_create_from_platform (const VTableIP *vtable,
- NMPlatform *platform,
- int ifindex,
- gboolean ignore_kernel_routes,
- GPtrArray **out_storage)
-{
- RouteIndex *index;
- guint i, j, len;
- GPtrArray *storage;
-
- nm_assert (out_storage && !*out_storage);
-
- storage = nm_platform_lookup_addrroute_clone (platform,
- vtable->vt->obj_type,
- ifindex,
- ignore_kernel_routes
- ? nm_platform_lookup_predicate_routes_skip_rtprot_kernel
- : NULL,
- NULL);
- if (!storage)
- return _route_index_create (vtable, NULL);
-
- len = storage->len;
- index = g_malloc (sizeof (RouteIndex) + len * sizeof (NMPlatformIPXRoute *));
-
- j = 0;
- for (i = 0; i < len; i++) {
- const NMPlatformIPXRoute *ipx_route = NMP_OBJECT_CAST_IPX_ROUTE (storage->pdata[i]);
-
- if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (ipx_route))
- continue;
-
- /* we cast away the const-ness of the NMPObjects. The caller must
- * ensure not to modify the object via index->entries. */
- index->entries[j++] = (NMPlatformIPXRoute *) ipx_route;
- }
- index->entries[j] = NULL;
- index->len = j;
-
- /* this is a stable sort, which is very important at this point. */
- g_qsort_with_data (index->entries,
- index->len,
- sizeof (NMPlatformIPXRoute *),
- (GCompareDataFunc) _route_index_create_sort,
- (gpointer) vtable);
- *out_storage = storage;
- return index;
-}
-
-static int
-_vx_route_id_cmp_full (const NMPlatformIPXRoute *r1, const NMPlatformIPXRoute *r2, const VTableIP *vtable)
-{
- return vtable->route_id_cmp (r1, r2);
-}
-
-static gssize
-_route_index_find (const VTableIP *vtable, const RouteIndex *index, const NMPlatformIPXRoute *needle)
-{
- gssize idx, idx2;
-
- idx = _nm_utils_ptrarray_find_binary_search ((gconstpointer *) index->entries, index->len, needle, (GCompareDataFunc) _vx_route_id_cmp_full, (gpointer) vtable);
- if (idx < 0)
- return idx;
-
- /* we only know that the route at index @idx has matching destination. Also find the one with the right
- * ifindex by searching the neighbours */
-
- idx2 = idx;
- do {
- if (index->entries[idx2]->rx.ifindex == needle->rx.ifindex)
- return idx2;
- } while ( idx2 > 0
- && vtable->route_id_cmp (index->entries[--idx2], needle) != 0);
-
- for (idx++; idx < index->len; idx++ ){
- if (vtable->route_id_cmp (index->entries[idx], needle) != 0)
- break;
- if (index->entries[idx]->rx.ifindex == needle->rx.ifindex)
- return idx;
- }
-
- return ~idx;
-}
-
-static guint
-_route_index_reverse_idx (const VTableIP *vtable, const RouteIndex *index, guint idx_idx, const GArray *routes)
-{
- const NMPlatformIPXRoute *r, *r0;
- gssize offset;
-
- /* reverse the @idx_idx that points into @index, to the corresponding index into the unsorted @routes array. */
-
- r = index->entries[idx_idx];
- r0 = VTABLE_ROUTE_INDEX (vtable, routes, 0);
-
- if (vtable->vt->is_ip4)
- offset = &r->r4 - &r0->r4;
- else
- offset = &r->r6 - &r0->r6;
- g_assert (offset >= 0 && offset < index->len);
- g_assert (VTABLE_ROUTE_INDEX (vtable, routes, offset) == r);
- return offset;
-}
-
-/*****************************************************************************/
-
-static gboolean
-_route_equals_ignoring_ifindex (const VTableIP *vtable, const NMPlatformIPXRoute *r1, const NMPlatformIPXRoute *r2, gint64 r2_metric)
-{
- NMPlatformIPXRoute r2_backup;
-
- if ( r1->rx.ifindex != r2->rx.ifindex
- || (r2_metric >= 0 && ((guint32) r2_metric) != r2->rx.metric)) {
- memcpy (&r2_backup, r2, vtable->vt->sizeof_route);
- r2_backup.rx.ifindex = r1->rx.ifindex;
- if (r2_metric >= 0)
- r2_backup.rx.metric = (guint32) r2_metric;
- r2 = &r2_backup;
- }
- return vtable->vt->route_cmp (r1, r2, NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) == 0;
-}
-
-static NMPlatformIPXRoute *
-_get_next_ipx_route (const RouteIndex *index, gboolean start_at_zero, guint *cur_idx, int ifindex)
-{
- guint i;
-
- if (start_at_zero)
- i = 0;
- else
- i = *cur_idx + 1;
- /* Find the next route with matching @ifindex. */
- for (; i < index->len; i++) {
- if (index->entries[i]->rx.ifindex == ifindex) {
- *cur_idx = i;
- return index->entries[i];
- }
- }
- *cur_idx = index->len;
- return NULL;
-}
-
-static const NMPlatformIPXRoute *
-_get_next_known_route (const VTableIP *vtable, const RouteIndex *index, gboolean start_at_zero, guint *cur_idx)
-{
- guint i = 0;
- const NMPlatformIPXRoute *cur = NULL;
-
- if (!start_at_zero) {
- i = *cur_idx;
- cur = index->entries[i];
- i++;
- }
- /* For @known_routes we expect that all routes have the same @ifindex. This is not enforced however,
- * the ifindex value of these routes is ignored. */
- for (; i < index->len; i++) {
- const NMPlatformIPXRoute *r = index->entries[i];
-
- /* skip over default routes. */
- if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r))
- continue;
-
- /* @known_routes should not, but could contain duplicate routes. Skip over them. */
- if (cur && vtable->route_id_cmp (cur, r) == 0)
- continue;
-
- *cur_idx = i;
- return r;
- }
- *cur_idx = index->len;
- return NULL;
-}
-
-static const NMPlatformIPXRoute *
-_get_next_plat_route (const RouteIndex *index, gboolean start_at_zero, guint *cur_idx)
-{
- if (start_at_zero)
- *cur_idx = 0;
- else
- ++*cur_idx;
-
- /* get next route from the platform index. */
- if (*cur_idx < index->len) {
- nm_assert (NMP_OBJECT_UP_CAST (index->entries[*cur_idx]));
- return index->entries[*cur_idx];
- }
- *cur_idx = index->len;
- return NULL;
-}
-
-static int
-_sort_indexes_cmp (guint *a, guint *b)
-{
- CMP_AND_RETURN_INT (*a, *b);
- g_return_val_if_reached (0);
-}
-
-/*****************************************************************************/
-
-static gboolean
-_vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes, gboolean full_sync)
-{
- NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (self);
- gs_unref_ptrarray GPtrArray *plat_routes = NULL;
- RouteEntries *ipx_routes;
- RouteIndex *plat_routes_idx, *known_routes_idx;
- gboolean success = TRUE;
- guint i, i_type;
- GArray *to_delete_indexes = NULL;
- GPtrArray *to_add_routes = NULL;
- guint i_known_routes, i_plat_routes, i_ipx_routes;
- const NMPlatformIPXRoute *cur_known_route, *cur_plat_route;
- NMPlatformIPXRoute *cur_ipx_route;
- gint64 *p_effective_metric = NULL;
- gboolean ipx_routes_changed = FALSE;
- gint64 *effective_metrics = NULL;
-
- nm_platform_process_events (priv->platform);
-
- ipx_routes = vtable->vt->is_ip4 ? &priv->ip4_routes : &priv->ip6_routes;
-
- /* the objects referenced by play_routes_idx are shared from the platform cache. They
- * must not be modified. */
- plat_routes_idx = _route_index_create_from_platform (vtable, priv->platform, ifindex, ignore_kernel_routes, &plat_routes);
-
- known_routes_idx = _route_index_create (vtable, known_routes);
-
- effective_metrics = &g_array_index (ipx_routes->effective_metrics, gint64, 0);
-
- ASSERT_route_index_valid (vtable, known_routes, known_routes_idx, FALSE);
-
- _LOGD (vtable->vt->addr_family, "%3d: sync %u IPv%c routes", ifindex, known_routes_idx->len, vtable->vt->is_ip4 ? '4' : '6');
- if (_LOGt_ENABLED (vtable->vt->addr_family)) {
- for (i = 0; i < known_routes_idx->len; i++) {
- _LOGt (vtable->vt->addr_family, "%3d: sync new route #%u: %s",
- ifindex, i, vtable->vt->route_to_string (VTABLE_ROUTE_INDEX (vtable, known_routes, i), NULL, 0));
- }
- for (i = 0; i < ipx_routes->index->len; i++)
- _LOGt (vtable->vt->addr_family, "%3d: STATE: has #%u - %s (%lld)",
- ifindex, i,
- vtable->vt->route_to_string (ipx_routes->index->entries[i], NULL, 0),
- (long long) g_array_index (ipx_routes->effective_metrics, gint64, i));
- }
-
- /***************************************************************************
- * Check which routes are in @known_routes, and update @ipx_routes.
- *
- * This first part only updates @ipx_routes to find out what routes must
- * be added/deleted.
- **************************************************************************/
-
- /* iterate over @ipx_routes and @known_routes */
- cur_ipx_route = _get_next_ipx_route (ipx_routes->index, TRUE, &i_ipx_routes, ifindex);
- cur_known_route = _get_next_known_route (vtable, known_routes_idx, TRUE, &i_known_routes);
- while (cur_ipx_route || cur_known_route) {
- int route_id_cmp_result = -1;
-
- while ( cur_ipx_route
- && ( !cur_known_route
- || ((route_id_cmp_result = vtable->route_id_cmp (cur_ipx_route, cur_known_route)) < 0))) {
- /* we have @cur_ipx_route, which is less then @cur_known_route. Hence,
- * the route does no longer exist in @known_routes */
- if (!to_delete_indexes)
- to_delete_indexes = g_array_new (FALSE, FALSE, sizeof (guint));
- g_array_append_val (to_delete_indexes, i_ipx_routes);
-
- /* find the next @cur_ipx_route with matching ifindex. */
- cur_ipx_route = _get_next_ipx_route (ipx_routes->index, FALSE, &i_ipx_routes, ifindex);
- }
- if ( cur_ipx_route
- && cur_known_route
- && route_id_cmp_result == 0) {
- if (!_route_equals_ignoring_ifindex (vtable, cur_ipx_route, cur_known_route, -1)) {
- /* The routes match. Update the entry in place. As this is an exact match of primary
- * fields, this only updates possibly modified fields such as @gateway or @mss.
- * Modifiying @cur_ipx_route this way does not invalidate @ipx_routes->index. */
- memcpy (cur_ipx_route, cur_known_route, vtable->vt->sizeof_route);
- cur_ipx_route->rx.ifindex = ifindex;
- cur_ipx_route->rx.metric = vtable->vt->metric_normalize (cur_ipx_route->rx.metric);
- nm_utils_ipx_address_clear_host_address (vtable->vt->addr_family, cur_ipx_route->rx.network_ptr,
- cur_ipx_route->rx.network_ptr, cur_ipx_route->rx.plen);
- ipx_routes_changed = TRUE;
- _LOGt (vtable->vt->addr_family, "%3d: STATE: update #%u - %s", ifindex, i_ipx_routes,
- vtable->vt->route_to_string (cur_ipx_route, NULL, 0));
- }
- } else if (cur_known_route) {
- g_assert (!cur_ipx_route || route_id_cmp_result > 0);
- /* @cur_known_route is new. We cannot immediately add @cur_known_route to @ipx_routes, because
- * it would invalidate @ipx_routes->index. Instead remember to add it later. */
- if (!to_add_routes)
- to_add_routes = g_ptr_array_new ();
- g_ptr_array_add (to_add_routes, (gpointer) cur_known_route);
- }
-
- if (cur_ipx_route && (!cur_known_route || route_id_cmp_result == 0))
- cur_ipx_route = _get_next_ipx_route (ipx_routes->index, FALSE, &i_ipx_routes, ifindex);
- if (cur_known_route)
- cur_known_route = _get_next_known_route (vtable, known_routes_idx, FALSE, &i_known_routes);
- }
-
- if (!full_sync && to_delete_indexes) {
- /***************************************************************************
- * Delete routes in platform, that we are about to remove from @ipx_routes
- *
- * When doing a non-full_sync, we delete routes from platform that were previously
- * known by route-manager, and are now deleted.
- ***************************************************************************/
-
- /* iterate over @to_delete_indexes and @plat_routes.
- * @to_delete_indexes contains the indexes (relative to ipx_routes->index) of items
- * we are about to delete. */
- cur_plat_route = _get_next_plat_route (plat_routes_idx, TRUE, &i_plat_routes);
- for (i = 0; i < to_delete_indexes->len; i++) {
- int route_dest_cmp_result = 0;
- i_ipx_routes = g_array_index (to_delete_indexes, guint, i);
- cur_ipx_route = ipx_routes->index->entries[i_ipx_routes];
- p_effective_metric = &effective_metrics[i_ipx_routes];
-
- nm_assert (cur_ipx_route->rx.ifindex == ifindex);
-
- if (*p_effective_metric == -1)
- continue;
-
- /* skip over @plat_routes that are ordered before our @cur_ipx_route. */
- while ( cur_plat_route
- && (route_dest_cmp_result = vtable->route_dest_cmp (cur_plat_route, cur_ipx_route)) <= 0) {
- if ( route_dest_cmp_result == 0
- && cur_plat_route->rx.metric >= *p_effective_metric)
- break;
- cur_plat_route = _get_next_plat_route (plat_routes_idx, FALSE, &i_plat_routes);
- }
-
- if (!cur_plat_route) {
- /* no more platform routes. Break the loop. */
- break;
- }
-
- if ( route_dest_cmp_result == 0
- && cur_plat_route->rx.metric == *p_effective_metric) {
- /* we are about to delete cur_ipx_route and we have a matching route
- * in platform. Delete it. */
- _LOGt (vtable->vt->addr_family, "%3d: platform rt-rm #%u - %s", ifindex, i_plat_routes,
- vtable->vt->route_to_string (cur_plat_route, NULL, 0));
- nm_assert (ifindex == cur_plat_route->rx.ifindex);
- nm_platform_ip_route_delete (priv->platform, NMP_OBJECT_UP_CAST (cur_plat_route));
- }
- }
- }
-
- /* Update @ipx_routes with the just learned changes. */
- if (to_delete_indexes || to_add_routes) {
- if (to_delete_indexes) {
- for (i = 0; i < to_delete_indexes->len; i++) {
- guint idx = g_array_index (to_delete_indexes, guint, i);
-
- _LOGt (vtable->vt->addr_family, "%3d: STATE: delete #%u - %s", ifindex, idx,
- vtable->vt->route_to_string (ipx_routes->index->entries[idx], NULL, 0));
- g_array_index (to_delete_indexes, guint, i) = _route_index_reverse_idx (vtable, ipx_routes->index, idx, ipx_routes->entries);
- }
- g_array_sort (to_delete_indexes, (GCompareFunc) _sort_indexes_cmp);
- nm_utils_array_remove_at_indexes (ipx_routes->entries, &g_array_index (to_delete_indexes, guint, 0), to_delete_indexes->len);
- nm_utils_array_remove_at_indexes (ipx_routes->effective_metrics_reverse, &g_array_index (to_delete_indexes, guint, 0), to_delete_indexes->len);
- g_array_unref (to_delete_indexes);
- }
- if (to_add_routes) {
- guint j = ipx_routes->effective_metrics_reverse->len;
-
- g_array_set_size (ipx_routes->effective_metrics_reverse, j + to_add_routes->len);
-
- for (i = 0; i < to_add_routes->len; i++) {
- NMPlatformIPXRoute *ipx_route;
-
- g_array_append_vals (ipx_routes->entries, g_ptr_array_index (to_add_routes, i), 1);
-
- ipx_route = VTABLE_ROUTE_INDEX (vtable, ipx_routes->entries, ipx_routes->entries->len - 1);
- ipx_route->rx.ifindex = ifindex;
- ipx_route->rx.metric = vtable->vt->metric_normalize (ipx_route->rx.metric);
- nm_utils_ipx_address_clear_host_address (vtable->vt->addr_family, ipx_route->rx.network_ptr,
- ipx_route->rx.network_ptr, ipx_route->rx.plen);
-
- g_array_index (ipx_routes->effective_metrics_reverse, gint64, j++) = -1;
-
- _LOGt (vtable->vt->addr_family, "%3d: STATE: added #%u - %s", ifindex, ipx_routes->entries->len - 1,
- vtable->vt->route_to_string (ipx_route, NULL, 0));
- }
- g_ptr_array_unref (to_add_routes);
- }
- g_free (ipx_routes->index);
- ipx_routes->index = _route_index_create (vtable, ipx_routes->entries);
- ipx_routes_changed = TRUE;
- ASSERT_route_index_valid (vtable, ipx_routes->entries, ipx_routes->index, TRUE);
- }
-
- if (ipx_routes_changed) {
- /***************************************************************************
- * Rebuild the list of effective metrics. In case of conflicting routes,
- * we configure device routes with a bumped metric. We do this, because non-direct
- * routes might require this direct route to reach the gateway (e.g. the default
- * route).
- *
- * We determine the effective metrics only based on our internal list @ipx_routes
- * and don't consider @plat_routes. That means, we might bump the metric of a route
- * and thereby cause a conflict with an existing route on an unmanaged device (which
- * causes the route on the unmanaged device to be replaced).
- * Still, that is not much different then from messing with unmanaged routes when
- * the effective and the intended metrics equal. The rules is: NM will leave routes
- * on unmanaged devices alone, unless they conflict with what NM wants to configure.
- ***************************************************************************/
-
- g_array_set_size (ipx_routes->effective_metrics, ipx_routes->entries->len);
- effective_metrics = &g_array_index (ipx_routes->effective_metrics, gint64, 0);
-
- /* Completely regenerate the list of effective metrics by walking through
- * ipx_routes->index and determining the effective metric. */
-
- for (i_ipx_routes = 0; i_ipx_routes < ipx_routes->index->len; i_ipx_routes++) {
- gint64 *p_effective_metric_before;
- gboolean is_shadowed;
- guint i_ipx_routes_before;
-
- cur_ipx_route = ipx_routes->index->entries[i_ipx_routes];
- p_effective_metric = &effective_metrics[i_ipx_routes];
-
- is_shadowed = i_ipx_routes > 0
- && vtable->route_dest_cmp (cur_ipx_route, ipx_routes->index->entries[i_ipx_routes - 1]) == 0;
-
- if (!is_shadowed) {
- /* the route is not shadowed, the effective metric is just as specified. */
- *p_effective_metric = cur_ipx_route->rx.metric;
- goto next;
- }
- if (!VTABLE_IS_DEVICE_ROUTE (vtable, cur_ipx_route)) {
- /* The route is not a device route. We want to add redundant device routes, because
- * we might need the direct routes to the gateway. For non-direct routes, there is not much
- * reason to do the metric increment. */
- *p_effective_metric = -1;
- goto next;
- }
-
- /* The current route might be shadowed by several other routes. Find the one with the highest metric,
- * i.e. the one with an effecive metric set and in the index before the current index. */
- i_ipx_routes_before = i_ipx_routes;
- while (TRUE) {
- nm_assert (i_ipx_routes_before > 0);
-
- i_ipx_routes_before--;
-
- p_effective_metric_before = &effective_metrics[i_ipx_routes_before];
-
- if (*p_effective_metric_before == -1) {
- /* this route is also shadowed, continue search. */
- continue;
- }
-
- if (*p_effective_metric_before < cur_ipx_route->rx.metric) {
- /* the previous route has a lower metric. There is no conflict,
- * just use the original metric. */
- *p_effective_metric = cur_ipx_route->rx.metric;
- } else if (*p_effective_metric_before == G_MAXUINT32) {
- /* we cannot bump the metric. Don't configure this route. */
- *p_effective_metric = -1;
- } else {
- /* bump the metric by one. */
- *p_effective_metric = *p_effective_metric_before + 1;
- }
- break;
- }
-next:
- _LOGt (vtable->vt->addr_family, "%3d: new metric #%u - %s (%lld)",
- ifindex, i_ipx_routes,
- vtable->vt->route_to_string (cur_ipx_route, NULL, 0),
- (long long) *p_effective_metric);
- }
- }
-
- if (full_sync) {
- /***************************************************************************
- * Delete all routes in platform, that no longer exist in @ipx_routes
- *
- * Different from the delete action above, we delete every unknown route on
- * the interface.
- ***************************************************************************/
-
- /* iterate over @plat_routes and @ipx_routes */
- cur_plat_route = _get_next_plat_route (plat_routes_idx, TRUE, &i_plat_routes);
- cur_ipx_route = _get_next_ipx_route (ipx_routes->index, TRUE, &i_ipx_routes, ifindex);
- if (cur_ipx_route)
- p_effective_metric = &effective_metrics[i_ipx_routes];
- while (cur_plat_route) {
- int route_dest_cmp_result = 0;
-
- nm_assert (cur_plat_route->rx.ifindex == ifindex);
-
- _LOGt (vtable->vt->addr_family, "%3d: platform rt #%u - %s", ifindex, i_plat_routes, vtable->vt->route_to_string (cur_plat_route, NULL, 0));
-
- /* skip over @cur_ipx_route that are ordered before @cur_plat_route */
- while ( cur_ipx_route
- && ((route_dest_cmp_result = vtable->route_dest_cmp (cur_ipx_route, cur_plat_route)) <= 0)) {
- if ( route_dest_cmp_result == 0
- && *p_effective_metric != -1
- && *p_effective_metric >= cur_plat_route->rx.metric) {
- break;
- }
- cur_ipx_route = _get_next_ipx_route (ipx_routes->index, FALSE, &i_ipx_routes, ifindex);
- if (cur_ipx_route)
- p_effective_metric = &effective_metrics[i_ipx_routes];
- }
-
- /* if @cur_ipx_route is not equal to @plat_route, the route must be deleted. */
- if ( !cur_ipx_route
- || route_dest_cmp_result != 0
- || *p_effective_metric != cur_plat_route->rx.metric) {
- nm_assert (ifindex == cur_plat_route->rx.ifindex);
- nm_platform_ip_route_delete (priv->platform, NMP_OBJECT_UP_CAST (cur_plat_route));
- }
-
- cur_plat_route = _get_next_plat_route (plat_routes_idx, FALSE, &i_plat_routes);
- }
- }
-
- /***************************************************************************
- * Restore shadowed routes. These routes are on an other @ifindex then what
- * we are syncing now. But the current changes make it necessary to add those
- * routes.
- *
- * Only add some routes that might be necessary. We don't delete any routes
- * on other ifindexes here. I.e. we don't do a full sync, but only ~add~ routes
- * that were shadowed previously, but should be now present with a different
- * metric.
- **************************************************************************/
-
- if (ipx_routes_changed) {
- GArray *gateway_routes = NULL;
-
- /* @effective_metrics_reverse contains the list of assigned metrics from the last
- * sync. Walk through it and see what changes there are (and possibly restore a
- * shadowed route).
- * Thereby also update @effective_metrics_reverse to be up-to-date again. */
- for (i_ipx_routes = 0; i_ipx_routes < ipx_routes->entries->len; i_ipx_routes++) {
- guint i_ipx_routes_reverse;
- gint64 *p_effective_metric_reversed;
-
- p_effective_metric = &effective_metrics[i_ipx_routes];
-
- i_ipx_routes_reverse = _route_index_reverse_idx (vtable, ipx_routes->index, i_ipx_routes, ipx_routes->entries);
- p_effective_metric_reversed = &g_array_index (ipx_routes->effective_metrics_reverse, gint64, i_ipx_routes_reverse);
-
- if (*p_effective_metric_reversed == *p_effective_metric) {
- /* The entry is up to date. No change, continue with the next one. */
- continue;
- }
- *p_effective_metric_reversed = *p_effective_metric;
-
- if (*p_effective_metric == -1) {
- /* the entry is shadowed. Nothing to do. */
- continue;
- }
-
- cur_ipx_route = ipx_routes->index->entries[i_ipx_routes];
- if (cur_ipx_route->rx.ifindex == ifindex) {
- /* @cur_ipx_route is on the current @ifindex. No need to special handling them
- * because we are about to do a full sync of the ifindex. */
- continue;
- }
-
- /* the effective metric from previous sync changed. While @cur_ipx_route is not on the
- * ifindex we are about to sync, we still must add this route. Possibly it was shadowed
- * before, and now we want to restore it.
- *
- * Note that we don't do a full sync on the other ifindex. Especially, we don't delete
- * or add any further routes then this. That means there might be some stale routes
- * (with a higher metric!). They will only be removed on the next sync of that other
- * ifindex. */
-
- if (!VTABLE_IS_DEVICE_ROUTE (vtable, cur_ipx_route)) {
- /* the route to restore has a gateway. We can only restore the route
- * when we also have a direct route to the gateway. There can be cases
- * where the direct route is shadowed too, and we cannot restore the gateway
- * route.
- *
- * Restore first the direct-routes, and gateway-routes afterwards.
- * This can avoid some cases where we would fail to add the
- * gateway route. */
- if (!gateway_routes)
- gateway_routes = g_array_new (FALSE, FALSE, sizeof (guint));
- g_array_append_val (gateway_routes, i_ipx_routes);
- } else
- vtable->vt->route_add (priv->platform, NMP_NLM_FLAG_REPLACE,
- cur_ipx_route, 0, *p_effective_metric);
- }
-
- if (gateway_routes) {
- for (i = 0; i < gateway_routes->len; i++) {
- i_ipx_routes = g_array_index (gateway_routes, guint, i);
- vtable->vt->route_add (priv->platform, NMP_NLM_FLAG_REPLACE,
- ipx_routes->index->entries[i_ipx_routes],
- 0, effective_metrics[i_ipx_routes]);
- }
- g_array_unref (gateway_routes);
- }
- }
-
- /***************************************************************************
- * Sync @ipx_routes for @ifindex to platform
- **************************************************************************/
-
- for (i_type = 0; i_type < 2; i_type++) {
- /* iterate (twice) over @ipx_routes and @plat_routes */
- cur_plat_route = _get_next_plat_route (plat_routes_idx, TRUE, &i_plat_routes);
- cur_ipx_route = _get_next_ipx_route (ipx_routes->index, TRUE, &i_ipx_routes, ifindex);
- /* Iterate here over @ipx_routes instead of @known_routes. That is done because
- * we need to know whether a route is shadowed by another route, and that
- * requires to look at @ipx_routes. */
- for (; cur_ipx_route; cur_ipx_route = _get_next_ipx_route (ipx_routes->index, FALSE, &i_ipx_routes, ifindex)) {
- int route_dest_cmp_result = -1;
-
- if ( (i_type == 0 && !VTABLE_IS_DEVICE_ROUTE (vtable, cur_ipx_route))
- || (i_type == 1 && VTABLE_IS_DEVICE_ROUTE (vtable, cur_ipx_route))) {
- /* Make two runs over the list of @ipx_routes. On the first, only add
- * device routes, on the second the others (gateway routes). */
- continue;
- }
-
- p_effective_metric = &effective_metrics[i_ipx_routes];
-
- if (*p_effective_metric == -1) {
- /* @cur_ipx_route is shadewed by another route. */
- continue;
- }
-
- /* skip over @plat_routes that are ordered before our @cur_ipx_route. */
- while ( cur_plat_route
- && (route_dest_cmp_result = vtable->route_dest_cmp (cur_plat_route, cur_ipx_route)) <= 0) {
- if ( route_dest_cmp_result == 0
- && cur_plat_route->rx.metric >= *p_effective_metric)
- break;
- cur_plat_route = _get_next_plat_route (plat_routes_idx, FALSE, &i_plat_routes);
- }
-
- /* only add the route if we don't have an identical route in @plat_routes,
- * i.e. if @cur_plat_route is different from @cur_ipx_route. */
- if ( !cur_plat_route
- || route_dest_cmp_result != 0
- || !_route_equals_ignoring_ifindex (vtable, cur_plat_route, cur_ipx_route, *p_effective_metric)) {
-
- if (!vtable->vt->route_add (priv->platform, NMP_NLM_FLAG_REPLACE,
- cur_ipx_route, ifindex, *p_effective_metric)) {
- if (cur_ipx_route->rx.rt_source < NM_IP_CONFIG_SOURCE_USER) {
- _LOGD (vtable->vt->addr_family,
- "ignore error adding IPv%c route to kernel: %s",
- vtable->vt->is_ip4 ? '4' : '6',
- vtable->vt->route_to_string (cur_ipx_route, NULL, 0));
- } else {
- /* Remember that there was a failure, but for now continue trying
- * to sync the remaining routes. */
- success = FALSE;
- }
- }
- }
- }
- }
-
- if (vtable->vt->is_ip4 && ipx_routes_changed)
- g_signal_emit (self, signals[IP4_ROUTES_CHANGED], 0);
-
- g_free (known_routes_idx);
- g_free (plat_routes_idx);
-
- return success;
-}
-
-/**
- * nm_route_manager_ip4_route_sync:
- * @ifindex: Interface index
- * @known_routes: List of routes
- * @ignore_kernel_routes: if %TRUE, ignore kernel routes.
- * @full_sync: whether to do a full sync and delete routes
- * that are configured on the interface but not currently
- * tracked by route-manager.
- *
- * A convenience function to synchronize routes for a specific interface
- * with the least possible disturbance. It simply removes routes that are
- * not listed and adds routes that are.
- * Default routes are ignored (both in @known_routes and those already
- * configured on the device).
- *
- * Returns: %TRUE on success.
- */
-gboolean
-nm_route_manager_ip4_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes, gboolean full_sync)
-{
- return _vx_route_sync (&vtable_v4, self, ifindex, known_routes, ignore_kernel_routes, full_sync);
-}
-
-/**
- * nm_route_manager_ip6_route_sync:
- * @ifindex: Interface index
- * @known_routes: List of routes
- * @ignore_kernel_routes: if %TRUE, ignore kernel routes.
- * @full_sync: whether to do a full sync and delete routes
- * that are configured on the interface but not currently
- * tracked by route-manager.
- *
- * A convenience function to synchronize routes for a specific interface
- * with the least possible disturbance. It simply removes routes that are
- * not listed and adds routes that are.
- * Default routes are ignored (both in @known_routes and those already
- * configured on the device).
- *
- * Returns: %TRUE on success.
- */
-gboolean
-nm_route_manager_ip6_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes, gboolean full_sync)
-{
- return _vx_route_sync (&vtable_v6, self, ifindex, known_routes, ignore_kernel_routes, full_sync);
-}
-
-gboolean
-nm_route_manager_route_flush (NMRouteManager *self, int ifindex)
-{
- bool success = TRUE;
-
- success &= (bool) nm_route_manager_ip4_route_sync (self, ifindex, NULL, FALSE, TRUE);
- success &= (bool) nm_route_manager_ip6_route_sync (self, ifindex, NULL, FALSE, TRUE);
- return success;
-}
-
-/**
- * nm_route_manager_ip4_routes_shadowed:
- * @ifindex: Interface index
- *
- * Returns: %TRUE if some other link has a route to the same destination
- * with a lower metric.
- */
-gboolean
-nm_route_manager_ip4_routes_shadowed (NMRouteManager *self, int ifindex)
-{
- NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (self);
- RouteIndex *index = priv->ip4_routes.index;
- const NMPlatformIP4Route *route;
- guint i;
-
- for (i = 1; i < index->len; i++) {
- route = (const NMPlatformIP4Route *) index->entries[i];
-
- if (route->ifindex != ifindex)
- continue;
- if (_v4_route_dest_cmp (route, (const NMPlatformIP4Route *) index->entries[i - 1]) == 0)
- return TRUE;
- }
-
- return FALSE;
-}
-
-/*****************************************************************************/
-
-static gboolean
-_ip4_device_routes_entry_expired (const IP4DeviceRoutePurgeEntry *entry, gint64 now)
-{
- return entry->scheduled_at_ns + IP4_DEVICE_ROUTES_WAIT_TIME_NS < now;
-}
-
-static IP4DeviceRoutePurgeEntry *
-_ip4_device_routes_purge_entry_create (NMRouteManager *self, const NMPlatformIP4Route *route, gint64 now_ns)
-{
- IP4DeviceRoutePurgeEntry *entry;
-
- entry = g_slice_new (IP4DeviceRoutePurgeEntry);
-
- entry->self = self;
- entry->scheduled_at_ns = now_ns;
- entry->idle_id = 0;
- entry->obj = nmp_object_new (NMP_OBJECT_TYPE_IP4_ROUTE, (NMPlatformObject *) route);
- entry->obj_cached = NULL;
- return entry;
-}
-
-static void
-_ip4_device_routes_purge_entry_free (IP4DeviceRoutePurgeEntry *entry)
-{
- nmp_object_unref (entry->obj);
- nmp_object_unref (entry->obj_cached);
- nm_clear_g_source (&entry->idle_id);
- g_slice_free (IP4DeviceRoutePurgeEntry, entry);
-}
-
-static gboolean
-_ip4_device_routes_idle_cb (IP4DeviceRoutePurgeEntry *entry)
-{
- NMRouteManager *self;
- NMRouteManagerPrivate *priv;
-
- nm_clear_g_source (&entry->idle_id);
-
- self = entry->self;
- priv = NM_ROUTE_MANAGER_GET_PRIVATE (self);
- if (_route_index_find (&vtable_v4, priv->ip4_routes.index, &entry->obj->ipx_route) >= 0) {
- /* we have an identical route in our list. Don't delete it. */
- return G_SOURCE_REMOVE;
- }
-
- _LOGt (vtable_v4.vt->addr_family, "device-route: delete %s", nmp_object_to_string (entry->obj_cached, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
-
- nm_platform_ip_route_delete (priv->platform, entry->obj_cached);
-
- g_hash_table_remove (priv->ip4_device_routes.entries, entry->obj);
- _ip4_device_routes_cancel (self);
- return G_SOURCE_REMOVE;
-}
-
-static void
-_ip4_device_routes_ip4_route_changed (NMPlatform *platform,
- int obj_type_i,
- int ifindex,
- const NMPlatformIP4Route *route,
- int change_type_i,
- NMRouteManager *self)
-{
- const NMPlatformSignalChangeType change_type = change_type_i;
- NMRouteManagerPrivate *priv;
- const NMPObject *obj;
- IP4DeviceRoutePurgeEntry *entry;
-
- if ( route->rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL
- || route->metric != 0) {
- /* we don't have an automatically created device route at hand. Bail out early. */
- return;
- }
-
- priv = NM_ROUTE_MANAGER_GET_PRIVATE (self);
-
- obj = NMP_OBJECT_UP_CAST (route);
-
- entry = g_hash_table_lookup (priv->ip4_device_routes.entries, obj);
- if (!entry)
- return;
-
- if (_ip4_device_routes_entry_expired (entry, nm_utils_get_monotonic_timestamp_ns ())) {
- _LOGt (vtable_v4.vt->addr_family, "device-route: cleanup-ch %s", nmp_object_to_string (entry->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
- g_hash_table_remove (priv->ip4_device_routes.entries, entry->obj);
- _ip4_device_routes_cancel (self);
- return;
- }
-
- entry->obj_cached = nmp_object_unref (entry->obj_cached);
-
- if (change_type == NM_PLATFORM_SIGNAL_REMOVED) {
- if (nm_clear_g_source (&entry->idle_id))
- _LOGt (vtable_v4.vt->addr_family, "device-route: unschedule %s", nmp_object_to_string (entry->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
- return;
- }
-
- entry->obj_cached = nmp_object_ref (obj);
- if (entry->idle_id == 0) {
- _LOGt (vtable_v4.vt->addr_family, "device-route: schedule %s", nmp_object_to_string (entry->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
- entry->idle_id = g_idle_add ((GSourceFunc) _ip4_device_routes_idle_cb, entry);
- }
-}
-
-static gboolean
-_ip4_device_routes_cancel (NMRouteManager *self)
-{
- NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (self);
-
- if (priv->ip4_device_routes.gc_id) {
- if (g_hash_table_size (priv->ip4_device_routes.entries) > 0)
- return G_SOURCE_CONTINUE;
- _LOGt (vtable_v4.vt->addr_family, "device-route: cancel");
- if (priv->platform)
- g_signal_handlers_disconnect_by_func (priv->platform, G_CALLBACK (_ip4_device_routes_ip4_route_changed), self);
- nm_clear_g_source (&priv->ip4_device_routes.gc_id);
- }
- return G_SOURCE_REMOVE;
-}
-
-static gboolean
-_ip4_device_routes_gc (NMRouteManager *self)
-{
- NMRouteManagerPrivate *priv;
- GHashTableIter iter;
- IP4DeviceRoutePurgeEntry *entry;
- gint64 now = nm_utils_get_monotonic_timestamp_ns ();
-
- priv = NM_ROUTE_MANAGER_GET_PRIVATE (self);
-
- g_hash_table_iter_init (&iter, priv->ip4_device_routes.entries);
- while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &entry)) {
- if (_ip4_device_routes_entry_expired (entry, now)) {
- _LOGt (vtable_v4.vt->addr_family, "device-route: cleanup-gc %s", nmp_object_to_string (entry->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
- g_hash_table_iter_remove (&iter);
- }
- }
-
- return _ip4_device_routes_cancel (self);
-}
-
-/**
- * nm_route_manager_ip4_route_register_device_route_purge_list:
- *
- * When adding an IPv4 address, kernel will automatically add a device route with
- * metric zero. We don't want that route and want to delete it. However, the route
- * by kernel immediately, but some time after. That means during nm_route_manager_ip4_route_sync()
- * such a route doesn't exist yet. We must remember that we expect such a route to appear later
- * and to remove it. */
-void
-nm_route_manager_ip4_route_register_device_route_purge_list (NMRouteManager *self, GArray *device_route_purge_list)
-{
- NMRouteManagerPrivate *priv;
- guint i;
- gint64 now_ns;
-
- if (!device_route_purge_list || device_route_purge_list->len == 0)
- return;
-
- priv = NM_ROUTE_MANAGER_GET_PRIVATE (self);
-
- now_ns = nm_utils_get_monotonic_timestamp_ns ();
- for (i = 0; i < device_route_purge_list->len; i++) {
- IP4DeviceRoutePurgeEntry *entry;
-
- entry = _ip4_device_routes_purge_entry_create (self, &g_array_index (device_route_purge_list, NMPlatformIP4Route, i), now_ns);
- _LOGt (vtable_v4.vt->addr_family, "device-route: watch (%s) %s",
- g_hash_table_contains (priv->ip4_device_routes.entries, entry->obj)
- ? "update" : "new",
- nmp_object_to_string (entry->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
- g_hash_table_replace (priv->ip4_device_routes.entries,
- (NMPObject *) nmp_object_ref (entry->obj),
- entry);
- }
- if (priv->ip4_device_routes.gc_id == 0) {
- g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, G_CALLBACK (_ip4_device_routes_ip4_route_changed), self);
- priv->ip4_device_routes.gc_id = g_timeout_add (IP4_DEVICE_ROUTES_GC_INTERVAL_MSEC, (GSourceFunc) _ip4_device_routes_gc, self);
- }
-}
-
-/*****************************************************************************/
-
-static const VTableIP vtable_v4 = {
- .vt = &nm_platform_vtable_route_v4,
- .route_dest_cmp = (int (*) (const NMPlatformIPXRoute *, const NMPlatformIPXRoute *)) _v4_route_dest_cmp,
- .route_id_cmp = (int (*) (const NMPlatformIPXRoute *, const NMPlatformIPXRoute *)) _v4_route_id_cmp,
-};
-
-static const VTableIP vtable_v6 = {
- .vt = &nm_platform_vtable_route_v6,
- .route_dest_cmp = (int (*) (const NMPlatformIPXRoute *, const NMPlatformIPXRoute *)) _v6_route_dest_cmp,
- .route_id_cmp = (int (*) (const NMPlatformIPXRoute *, const NMPlatformIPXRoute *)) _v6_route_id_cmp,
-};
-
-/*****************************************************************************/
-
-static void
-set_property (GObject *object, guint prop_id,
- const GValue *value, GParamSpec *pspec)
-{
- NMRouteManager *self = NM_ROUTE_MANAGER (object);
- NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (self);
-
- switch (prop_id) {
- case PROP_LOG_WITH_PTR:
- /* construct-only */
- priv->log_with_ptr = g_value_get_boolean (value);
- break;
- case PROP_PLATFORM:
- /* construct-only */
- priv->platform = g_value_get_object (value) ? : NM_PLATFORM_GET;
- if (!priv->platform)
- g_return_if_reached ();
- g_object_ref (priv->platform);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-/*****************************************************************************/
-
-static void
-nm_route_manager_init (NMRouteManager *self)
-{
- NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (self);
-
- priv->ip4_routes.entries = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route));
- priv->ip6_routes.entries = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP6Route));
- priv->ip4_routes.effective_metrics = g_array_new (FALSE, FALSE, sizeof (gint64));
- priv->ip6_routes.effective_metrics = g_array_new (FALSE, FALSE, sizeof (gint64));
- priv->ip4_routes.effective_metrics_reverse = g_array_new (FALSE, FALSE, sizeof (gint64));
- priv->ip6_routes.effective_metrics_reverse = g_array_new (FALSE, FALSE, sizeof (gint64));
- priv->ip4_routes.index = _route_index_create (&vtable_v4, priv->ip4_routes.entries);
- priv->ip6_routes.index = _route_index_create (&vtable_v6, priv->ip6_routes.entries);
- priv->ip4_device_routes.entries = g_hash_table_new_full ((GHashFunc) nmp_object_id_hash,
- (GEqualFunc) nmp_object_id_equal,
- (GDestroyNotify) nmp_object_unref,
- (GDestroyNotify) _ip4_device_routes_purge_entry_free);
-}
-
-NMRouteManager *
-nm_route_manager_new (gboolean log_with_ptr, NMPlatform *platform)
-{
- return g_object_new (NM_TYPE_ROUTE_MANAGER,
- NM_ROUTE_MANAGER_LOG_WITH_PTR, log_with_ptr,
- NM_ROUTE_MANAGER_PLATFORM, platform,
- NULL);
-}
-
-static void
-dispose (GObject *object)
-{
- NMRouteManager *self = NM_ROUTE_MANAGER (object);
- NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (self);
-
- g_hash_table_remove_all (priv->ip4_device_routes.entries);
- _ip4_device_routes_cancel (self);
-
- G_OBJECT_CLASS (nm_route_manager_parent_class)->dispose (object);
-}
-
-static void
-finalize (GObject *object)
-{
- NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE ((NMRouteManager *) object);
-
- g_array_free (priv->ip4_routes.entries, TRUE);
- g_array_free (priv->ip6_routes.entries, TRUE);
- g_array_free (priv->ip4_routes.effective_metrics, TRUE);
- g_array_free (priv->ip6_routes.effective_metrics, TRUE);
- g_array_free (priv->ip4_routes.effective_metrics_reverse, TRUE);
- g_array_free (priv->ip6_routes.effective_metrics_reverse, TRUE);
- g_free (priv->ip4_routes.index);
- g_free (priv->ip6_routes.index);
-
- g_hash_table_unref (priv->ip4_device_routes.entries);
-
- g_clear_object (&priv->platform);
-
- G_OBJECT_CLASS (nm_route_manager_parent_class)->finalize (object);
-}
-
-static void
-nm_route_manager_class_init (NMRouteManagerClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->set_property = set_property;
- object_class->dispose = dispose;
- object_class->finalize = finalize;
-
- obj_properties[PROP_LOG_WITH_PTR] =
- g_param_spec_boolean (NM_ROUTE_MANAGER_LOG_WITH_PTR, "", "",
- TRUE,
- G_PARAM_WRITABLE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS);
-
- obj_properties[PROP_PLATFORM] =
- g_param_spec_object (NM_ROUTE_MANAGER_PLATFORM, "", "",
- NM_TYPE_PLATFORM,
- G_PARAM_WRITABLE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS);
- g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
-
- signals[IP4_ROUTES_CHANGED] =
- g_signal_new (NM_ROUTE_MANAGER_IP4_ROUTES_CHANGED,
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- 0, NULL, NULL, NULL,
- G_TYPE_NONE, 0);
-}
diff --git a/src/nm-route-manager.h b/src/nm-route-manager.h
deleted file mode 100644
index bdf79a09ab..0000000000
--- a/src/nm-route-manager.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright (C) 2015 Red Hat, Inc.
- */
-
-#ifndef __NM_ROUTE_MANAGER_H__
-#define __NM_ROUTE_MANAGER_H__
-
-#define NM_TYPE_ROUTE_MANAGER (nm_route_manager_get_type ())
-#define NM_ROUTE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ROUTE_MANAGER, NMRouteManager))
-#define NM_ROUTE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_ROUTE_MANAGER, NMRouteManagerClass))
-#define NM_IS_ROUTE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_ROUTE_MANAGER))
-#define NM_IS_ROUTE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_ROUTE_MANAGER))
-#define NM_ROUTE_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_ROUTE_MANAGER, NMRouteManagerClass))
-
-#define NM_ROUTE_MANAGER_LOG_WITH_PTR "log-with-ptr"
-#define NM_ROUTE_MANAGER_PLATFORM "platform"
-
-#define NM_ROUTE_MANAGER_IP4_ROUTES_CHANGED "ip4-routes-changed"
-
-typedef struct _NMRouteManagerClass NMRouteManagerClass;
-
-GType nm_route_manager_get_type (void);
-
-gboolean nm_route_manager_ip4_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes, gboolean full_sync);
-gboolean nm_route_manager_ip6_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes, gboolean full_sync);
-gboolean nm_route_manager_route_flush (NMRouteManager *self, int ifindex);
-
-gboolean nm_route_manager_ip4_routes_shadowed (NMRouteManager *self, int ifindex);
-void nm_route_manager_ip4_route_register_device_route_purge_list (NMRouteManager *self, GArray *device_route_purge_list);
-
-NMRouteManager *nm_route_manager_new (gboolean log_with_ptr, NMPlatform *platform);
-
-#endif /* __NM_ROUTE_MANAGER_H__ */
diff --git a/src/nm-types.h b/src/nm-types.h
index 136cc450a8..64d718b1ac 100644
--- a/src/nm-types.h
+++ b/src/nm-types.h
@@ -50,7 +50,6 @@ typedef struct _NMNetns NMNetns;
typedef struct _NMPolicy NMPolicy;
typedef struct _NMRfkillManager NMRfkillManager;
typedef struct _NMPacrunnerManager NMPacrunnerManager;
-typedef struct _NMRouteManager NMRouteManager;
typedef struct _NMSessionMonitor NMSessionMonitor;
typedef struct _NMSleepMonitor NMSleepMonitor;
typedef struct _NMLldpListener NMLldpListener;
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index e906ba3bc6..3b471e2075 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -91,6 +91,9 @@ enum {
typedef struct _NMPlatformPrivate {
bool use_udev:1;
bool log_with_ptr:1;
+ guint ip4_dev_route_blacklist_check_id;
+ guint ip4_dev_route_blacklist_gc_timeout_id;
+ GHashTable *ip4_dev_route_blacklist_hash;
NMDedupMultiIndex *multi_idx;
NMPCache *cache;
} NMPlatformPrivate;
@@ -101,6 +104,10 @@ G_DEFINE_TYPE (NMPlatform, nm_platform, G_TYPE_OBJECT)
/*****************************************************************************/
+static void _ip4_dev_route_blacklist_schedule (NMPlatform *self);
+
+/*****************************************************************************/
+
gboolean
nm_platform_get_use_udev (NMPlatform *self)
{
@@ -3482,6 +3489,153 @@ nm_platform_ip_address_flush (NMPlatform *self,
/*****************************************************************************/
+/**
+ * nm_platform_ip_route_sync:
+ * @self: the #NMPlatform instance.
+ * @addr_family: AF_INET or AF_INET6.
+ * @ifindex: the @ifindex for which the routes are to be added.
+ * @routes: (allow-none): a list of routes to configure. Must contain
+ * NMPObject instances of routes, according to @addr_family.
+ * @kernel_delete_predicate: (allow-none): if not %NULL, previously
+ * existing routes already configured will only be deleted if the
+ * predicate returns TRUE. This allows to preserve/ignore some
+ * routes. For example by passing @nm_platform_lookup_predicate_routes_skip_rtprot_kernel,
+ * routes with "proto kernel" will be left untouched.
+ * @kernel_delete_userdata: user data for @kernel_delete_predicate.
+ *
+ * Returns: %TRUE on success.
+ */
+gboolean
+nm_platform_ip_route_sync (NMPlatform *self,
+ int addr_family,
+ int ifindex,
+ GPtrArray *routes,
+ NMPObjectPredicateFunc kernel_delete_predicate,
+ gpointer kernel_delete_userdata)
+{
+ const NMPlatformVTableRoute *vt;
+ gs_unref_ptrarray GPtrArray *plat_routes = NULL;
+ gs_unref_hashtable GHashTable *routes_idx = NULL;
+ const NMPObject *plat_o;
+ const NMPObject *conf_o;
+ const NMDedupMultiEntry *plat_entry;
+ guint i;
+ int i_type;
+
+ nm_assert (NM_IS_PLATFORM (self));
+ nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
+ nm_assert (ifindex > 0);
+
+ vt = addr_family == AF_INET
+ ? &nm_platform_vtable_route_v4
+ : &nm_platform_vtable_route_v6;
+
+ plat_routes = nm_platform_lookup_addrroute_clone (self,
+ vt->obj_type,
+ ifindex,
+ kernel_delete_predicate,
+ kernel_delete_userdata);
+ /* first delete routes which are in platform (@plat_routes), but not to configure (@routes/@routes_idx). */
+ if (plat_routes) {
+
+ /* create a lookup index. */
+ if (routes && routes->len > 0) {
+ routes_idx = g_hash_table_new ((GHashFunc) nmp_object_id_hash,
+ (GEqualFunc) nmp_object_id_equal);
+ for (i = 0; i < routes->len; i++) {
+ conf_o = routes->pdata[i];
+ if (!nm_g_hash_table_insert (routes_idx, (gpointer) conf_o, (gpointer) conf_o)) {
+ /* we ignore duplicate @routes. */
+ }
+ }
+ }
+
+ for (i = 0; i < plat_routes->len; i++) {
+ plat_o = plat_routes->pdata[i];
+
+ if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (NMP_OBJECT_CAST_IP_ROUTE (plat_o))) {
+ /* don't delete default routes. */
+ continue;
+ }
+
+ conf_o = routes_idx ? g_hash_table_lookup (routes_idx, plat_o) : NULL;
+ if ( !conf_o
+ || vt->route_cmp (NMP_OBJECT_CAST_IPX_ROUTE (conf_o),
+ NMP_OBJECT_CAST_IPX_ROUTE (plat_o),
+ NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) == 0) {
+ /* the route in platform is identical to the one we want to add.
+ * Keep it. */
+ continue;
+ }
+
+ if (!nm_platform_ip_route_delete (self, plat_o)) {
+ /* ignore error... */
+ }
+ }
+ }
+
+ if (!routes)
+ return TRUE;
+
+ for (i_type = 0; i_type < 2; i_type++) {
+ for (i = 0; i < routes->len; i++) {
+ conf_o = routes->pdata[i];
+
+#define VTABLE_IS_DEVICE_ROUTE(vt, o) (vt->is_ip4 \
+ ? (NMP_OBJECT_CAST_IP4_ROUTE (o)->gateway == 0) \
+ : IN6_IS_ADDR_UNSPECIFIED (&NMP_OBJECT_CAST_IP6_ROUTE (o)->gateway) )
+
+ if ( (i_type == 0 && !VTABLE_IS_DEVICE_ROUTE (vt, conf_o))
+ || (i_type == 1 && VTABLE_IS_DEVICE_ROUTE (vt, conf_o))) {
+ /* we add routes in two runs over @i_type.
+ *
+ * First device routes, then gateway routes. */
+ continue;
+ }
+
+ plat_entry = nm_platform_lookup_entry (self,
+ NMP_CACHE_ID_TYPE_OBJECT_TYPE,
+ conf_o);
+ if (plat_entry) {
+ /* we alreay have a route with the same ID in the platform cache.
+ * Skip adding it again. It should identical already, otherwise we would
+ * have deleted it in the previous step. */
+ continue;
+ }
+
+ if (!nm_platform_ip_route_add (self,
+ NMP_NLM_FLAG_APPEND,
+ conf_o)) {
+ /* ignore error adding route. */
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+gboolean
+nm_platform_ip_route_flush (NMPlatform *self,
+ int addr_family,
+ int ifindex)
+{
+ gboolean success = TRUE;
+
+ _CHECK_SELF (self, klass, FALSE);
+
+ nm_assert (NM_IN_SET (addr_family, AF_UNSPEC,
+ AF_INET,
+ AF_INET6));
+
+ if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET))
+ success &= nm_platform_ip_route_sync (self, AF_INET, ifindex, NULL, NULL, NULL);
+ if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET6))
+ success &= nm_platform_ip_route_sync (self, AF_INET6, ifindex, NULL, NULL, NULL);
+ return success;
+}
+
+/*****************************************************************************/
+
static guint8
_ip_route_scope_inv_get_normalized (const NMPlatformIP4Route *route)
{
@@ -3616,6 +3770,274 @@ nm_platform_ip_route_delete (NMPlatform *self,
/*****************************************************************************/
+#define IP4_DEV_ROUTE_BLACKLIST_TIMEOUT_MS ((int) 1500)
+#define IP4_DEV_ROUTE_BLACKLIST_GC_TIMEOUT_S ((int) (((IP4_DEV_ROUTE_BLACKLIST_TIMEOUT_MS + 999) * 3) / 1000))
+
+static gint64
+_ip4_dev_route_blacklist_timeout_ms_get (gint64 timeout_ms)
+{
+ return timeout_ms >> 1;
+}
+
+static gint64
+_ip4_dev_route_blacklist_timeout_ms_marked (gint64 timeout_ms)
+{
+ return !!(timeout_ms & ((gint64) 1));
+}
+
+static gboolean
+_ip4_dev_route_blacklist_check_cb (gpointer user_data)
+{
+ NMPlatform *self = user_data;
+ NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE (self);
+ GHashTableIter iter;
+ const NMPObject *p_obj;
+ gint64 *p_timeout_ms;
+ gint64 now_ms;
+
+ priv->ip4_dev_route_blacklist_check_id = 0;
+
+again:
+ if (!priv->ip4_dev_route_blacklist_hash)
+ goto out;
+
+ now_ms = nm_utils_get_monotonic_timestamp_ms ();
+
+ g_hash_table_iter_init (&iter, priv->ip4_dev_route_blacklist_hash);
+ while (g_hash_table_iter_next (&iter, (gpointer *) &p_obj, (gpointer *) &p_timeout_ms)) {
+ if (!_ip4_dev_route_blacklist_timeout_ms_marked (*p_timeout_ms))
+ continue;
+
+ /* unmark because we checked it. */
+ *p_timeout_ms = *p_timeout_ms & ~((gint64) 1);
+
+ if (now_ms > _ip4_dev_route_blacklist_timeout_ms_get (*p_timeout_ms))
+ continue;
+
+ if (!nm_platform_lookup_entry (self,
+ NMP_CACHE_ID_TYPE_OBJECT_TYPE,
+ p_obj))
+ continue;
+
+ _LOGT ("ip4-dev-route: delete %s",
+ nmp_object_to_string (p_obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
+ nm_platform_ip_route_delete (self, p_obj);
+ goto again;
+ }
+
+out:
+ return G_SOURCE_REMOVE;
+}
+
+static void
+_ip4_dev_route_blacklist_check_schedule (NMPlatform *self)
+{
+ NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE (self);
+
+ if (!priv->ip4_dev_route_blacklist_check_id) {
+ priv->ip4_dev_route_blacklist_check_id = g_idle_add_full (G_PRIORITY_HIGH,
+ _ip4_dev_route_blacklist_check_cb,
+ self,
+ NULL);
+ }
+}
+
+static void
+_ip4_dev_route_blacklist_notify_route (NMPlatform *self,
+ const NMPObject *obj)
+{
+ NMPlatformPrivate *priv;
+ const NMPObject *p_obj;
+ gint64 *p_timeout_ms;
+ gint64 now_ms;
+
+ nm_assert (NM_IS_PLATFORM (self));
+ nm_assert (NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_IP4_ROUTE);
+
+ priv = NM_PLATFORM_GET_PRIVATE (self);
+
+ nm_assert (priv->ip4_dev_route_blacklist_gc_timeout_id);
+
+ if (!g_hash_table_lookup_extended (priv->ip4_dev_route_blacklist_hash,
+ obj,
+ (gpointer *) &p_obj,
+ (gpointer *) &p_timeout_ms))
+ return;
+
+ now_ms = nm_utils_get_monotonic_timestamp_ms ();
+ if (now_ms > _ip4_dev_route_blacklist_timeout_ms_get (*p_timeout_ms)) {
+ /* already expired. Wait for gc. */
+ return;
+ }
+
+ if (_ip4_dev_route_blacklist_timeout_ms_marked (*p_timeout_ms)) {
+ nm_assert (priv->ip4_dev_route_blacklist_check_id);
+ return;
+ }
+
+ /* We cannot delete it right away because we are in the process of receiving netlink messages.
+ * It may be possible to do so, but complicated and error prone.
+ *
+ * Instead, we mark the entry and schedule an idle action (with high priority). */
+ *p_timeout_ms = (*p_timeout_ms) | ((gint64) 1);
+ _ip4_dev_route_blacklist_check_schedule (self);
+}
+
+static gboolean
+_ip4_dev_route_blacklist_gc_timeout_handle (gpointer user_data)
+{
+ NMPlatform *self = user_data;
+ NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE (self);
+ GHashTableIter iter;
+ const NMPObject *p_obj;
+ gint64 *p_timeout_ms;
+ gint64 now_ms;
+
+ nm_assert (priv->ip4_dev_route_blacklist_gc_timeout_id);
+
+ now_ms = nm_utils_get_monotonic_timestamp_ms ();
+
+ g_hash_table_iter_init (&iter, priv->ip4_dev_route_blacklist_hash);
+ while (g_hash_table_iter_next (&iter, (gpointer *) &p_obj, (gpointer *) &p_timeout_ms)) {
+ if (now_ms > _ip4_dev_route_blacklist_timeout_ms_get (*p_timeout_ms)) {
+ _LOGT ("ip4-dev-route: cleanup %s",
+ nmp_object_to_string (p_obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
+ g_hash_table_iter_remove (&iter);
+ }
+ }
+
+ _ip4_dev_route_blacklist_schedule (self);
+ return G_SOURCE_CONTINUE;
+}
+
+static void
+_ip4_dev_route_blacklist_schedule (NMPlatform *self)
+{
+ NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE (self);
+
+ if ( !priv->ip4_dev_route_blacklist_hash
+ || g_hash_table_size (priv->ip4_dev_route_blacklist_hash) == 0) {
+ g_clear_pointer (&priv->ip4_dev_route_blacklist_hash, g_hash_table_unref);
+ nm_clear_g_source (&priv->ip4_dev_route_blacklist_gc_timeout_id);
+ } else {
+ if (!priv->ip4_dev_route_blacklist_gc_timeout_id) {
+ /* this timeout is only to garbage collect the expired entries from priv->ip4_dev_route_blacklist_hash.
+ * It can run infrequently, and it doesn't hurt if expired entries linger around a bit
+ * longer then necessary. */
+ priv->ip4_dev_route_blacklist_gc_timeout_id = g_timeout_add_seconds (IP4_DEV_ROUTE_BLACKLIST_GC_TIMEOUT_S,
+ _ip4_dev_route_blacklist_gc_timeout_handle,
+ self);
+ }
+ }
+}
+
+/**
+ * nm_platform_ip4_dev_route_blacklist_set:
+ * @self:
+ * @ifindex:
+ * @ip4_dev_route_blacklist:
+ *
+ * When adding an IP address, kernel automatically adds a device route.
+ * This can be suppressed via the IFA_F_NOPREFIXROUTE address flag. For IPv6
+ * addresses, we require kernel support for IFA_F_NOPREFIXROUTE and always
+ * add the device route manually.
+ *
+ * For IPv4, this flag is rather new and we don't rely on it yet. We want to use
+ * it (but currently still don't). So, for IPv4, kernel possibly adds a device
+ * route, however it has a wrong metric of zero. We add our own device route (with
+ * proper metric), but need to delete the route that kernel adds.
+ *
+ * The problem is, that kernel does not immidiately add the route, when adding
+ * the address. It only shows up some time later. So, we register here a list
+ * of blacklisted routes, and when they show up within a time out, we assume it's
+ * the kernel generated one, and we delete it.
+ *
+ * Eventually, we want to get rid of this and use IFA_F_NOPREFIXROUTE for IPv4
+ * routes as well.
+ */
+void
+nm_platform_ip4_dev_route_blacklist_set (NMPlatform *self,
+ int ifindex,
+ GPtrArray *ip4_dev_route_blacklist)
+{
+ NMPlatformPrivate *priv;
+ GHashTableIter iter;
+ const NMPObject *p_obj;
+ guint i;
+ gint64 timeout_ms;
+ gint64 timeout_ms_val;
+ gint64 *p_timeout_ms;
+ gboolean needs_check = FALSE;
+
+ nm_assert (NM_IS_PLATFORM (self));
+ nm_assert (ifindex > 0);
+
+ priv = NM_PLATFORM_GET_PRIVATE (self);
+
+ /* first, expire all for current ifindex... */
+ if (priv->ip4_dev_route_blacklist_hash) {
+ g_hash_table_iter_init (&iter, priv->ip4_dev_route_blacklist_hash);
+ while (g_hash_table_iter_next (&iter, (gpointer *) &p_obj, (gpointer *) &p_timeout_ms)) {
+ if (NMP_OBJECT_CAST_IP4_ROUTE (p_obj)->ifindex == ifindex) {
+ /* we could g_hash_table_iter_remove(&iter) the current entry.
+ * Instead, just expire it and let _ip4_dev_route_blacklist_gc_timeout_handle()
+ * handle it.
+ *
+ * The assumption is, that ip4_dev_route_blacklist contains the very same entry
+ * again, with a new timeout. So, we can un-expire it below. */
+ *p_timeout_ms = 0;
+ }
+ }
+ }
+
+ if ( ip4_dev_route_blacklist
+ && ip4_dev_route_blacklist->len > 0) {
+
+ if (!priv->ip4_dev_route_blacklist_hash) {
+ priv->ip4_dev_route_blacklist_hash = g_hash_table_new_full ((GHashFunc) nmp_object_id_hash,
+ (GEqualFunc) nmp_object_id_equal,
+ (GDestroyNotify) nmp_object_unref,
+ nm_g_slice_free_fcn_gint64);
+ }
+
+ timeout_ms = nm_utils_get_monotonic_timestamp_ms () + IP4_DEV_ROUTE_BLACKLIST_TIMEOUT_MS;
+ timeout_ms_val = (timeout_ms << 1) | ((gint64) 1);
+ for (i = 0; i < ip4_dev_route_blacklist->len; i++) {
+ const NMPObject *o;
+
+ needs_check = TRUE;
+ o = ip4_dev_route_blacklist->pdata[i];
+ if (g_hash_table_lookup_extended (priv->ip4_dev_route_blacklist_hash,
+ o,
+ (gpointer *) &p_obj,
+ (gpointer *) &p_timeout_ms)) {
+ if (nmp_object_equal (p_obj, o)) {
+ /* un-expire and reuse the entry. */
+ _LOGT ("ip4-dev-route: register %s (update)",
+ nmp_object_to_string (p_obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
+ *p_timeout_ms = timeout_ms_val;
+ continue;
+ }
+ }
+
+ _LOGT ("ip4-dev-route: register %s",
+ nmp_object_to_string (o, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
+ p_timeout_ms = g_slice_new (gint64);
+ *p_timeout_ms = timeout_ms_val;
+ g_hash_table_replace (priv->ip4_dev_route_blacklist_hash,
+ (gpointer) nmp_object_ref (o),
+ p_timeout_ms);
+ }
+ }
+
+ _ip4_dev_route_blacklist_schedule (self);
+
+ if (needs_check)
+ _ip4_dev_route_blacklist_check_schedule (self);
+}
+
+/*****************************************************************************/
+
const char *
nm_platform_vlan_qos_mapping_to_string (const char *name,
const NMVlanQosMapping *map,
@@ -5235,6 +5657,11 @@ nm_platform_cache_update_emit_signal (NMPlatform *self,
klass = NMP_OBJECT_GET_CLASS (o);
+ if ( klass->obj_type == NMP_OBJECT_TYPE_IP4_ROUTE
+ && NM_PLATFORM_GET_PRIVATE (self)->ip4_dev_route_blacklist_gc_timeout_id
+ && NM_IN_SET (cache_op, NMP_CACHE_OPS_ADDED, NMP_CACHE_OPS_UPDATED))
+ _ip4_dev_route_blacklist_notify_route (self, o);
+
_LOGt ("emit signal %s %s: %s",
klass->signal_type,
nm_platform_signal_change_type_to_string ((NMPlatformSignalChangeType) cache_op),
@@ -5284,40 +5711,6 @@ nm_platform_netns_push (NMPlatform *self, NMPNetns **netns)
/*****************************************************************************/
-static gboolean
-_vtr_v4_route_add (NMPlatform *self,
- NMPNlmFlags flags,
- const NMPlatformIPXRoute *route,
- int ifindex,
- gint64 metric)
-{
- NMPlatformIP4Route rt = route->r4;
-
- if (ifindex > 0)
- rt.ifindex = ifindex;
- if (metric >= 0)
- rt.metric = metric;
-
- return nm_platform_ip4_route_add (self, flags, &rt);
-}
-
-static gboolean
-_vtr_v6_route_add (NMPlatform *self,
- NMPNlmFlags flags,
- const NMPlatformIPXRoute *route,
- int ifindex,
- gint64 metric)
-{
- NMPlatformIP6Route rt = route->r6;
-
- if (ifindex > 0)
- rt.ifindex = ifindex;
- if (metric >= 0)
- rt.metric = metric;
-
- return nm_platform_ip6_route_add (self, flags, &rt);
-}
-
static guint32
_vtr_v4_metric_normalize (guint32 metric)
{
@@ -5333,7 +5726,6 @@ const NMPlatformVTableRoute nm_platform_vtable_route_v4 = {
.sizeof_route = sizeof (NMPlatformIP4Route),
.route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, NMPlatformIPRouteCmpType cmp_type)) nm_platform_ip4_route_cmp,
.route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip4_route_to_string,
- .route_add = _vtr_v4_route_add,
.metric_normalize = _vtr_v4_metric_normalize,
};
@@ -5344,7 +5736,6 @@ const NMPlatformVTableRoute nm_platform_vtable_route_v6 = {
.sizeof_route = sizeof (NMPlatformIP6Route),
.route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, NMPlatformIPRouteCmpType cmp_type)) nm_platform_ip6_route_cmp,
.route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip6_route_to_string,
- .route_add = _vtr_v6_route_add,
.metric_normalize = nm_utils_ip6_route_metric_normalize,
};
@@ -5416,6 +5807,9 @@ finalize (GObject *object)
NMPlatform *self = NM_PLATFORM (object);
NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE (self);
+ nm_clear_g_source (&priv->ip4_dev_route_blacklist_check_id);
+ nm_clear_g_source (&priv->ip4_dev_route_blacklist_gc_timeout_id);
+ g_clear_pointer (&priv->ip4_dev_route_blacklist_hash, g_hash_table_unref);
g_clear_object (&self->_netns);
nm_dedup_multi_index_unref (priv->multi_idx);
nmp_cache_free (priv->cache);
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 315fcd5c5e..112d894fed 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -63,6 +63,8 @@ typedef gboolean (*NMPObjectPredicateFunc) (const NMPObject *obj,
#define IFA_F_NOPREFIXROUTE 0x200
#endif
+#define NM_RT_SCOPE_LINK 253 /* RT_SCOPE_LINK */
+
/* Define of the IN6_ADDR_GEN_MODE_* values to workaround old kernel headers
* that don't define it. */
#define NM_IN6_ADDR_GEN_MODE_UNKNOWN 255 /* no corresponding value. */
@@ -521,11 +523,6 @@ typedef struct {
gsize sizeof_route;
int (*route_cmp) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, NMPlatformIPRouteCmpType cmp_type);
const char *(*route_to_string) (const NMPlatformIPXRoute *route, char *buf, gsize len);
- gboolean (*route_add) (NMPlatform *self,
- NMPNlmFlags flags,
- const NMPlatformIPXRoute *route,
- int ifindex,
- gint64 metric);
guint32 (*metric_normalize) (guint32 metric);
} NMPlatformVTableRoute;
@@ -1128,6 +1125,16 @@ gboolean nm_platform_ip6_route_add (NMPlatform *self, NMPNlmFlags flags, const N
gboolean nm_platform_ip_route_delete (NMPlatform *self, const NMPObject *route);
+gboolean nm_platform_ip_route_sync (NMPlatform *self,
+ int addr_family,
+ int ifindex,
+ GPtrArray *routes,
+ NMPObjectPredicateFunc kernel_delete_predicate,
+ gpointer kernel_delete_userdata);
+gboolean nm_platform_ip_route_flush (NMPlatform *self,
+ int addr_family,
+ int ifindex);
+
const char *nm_platform_link_to_string (const NMPlatformLink *link, char *buf, gsize len);
const char *nm_platform_lnk_gre_to_string (const NMPlatformLnkGre *lnk, char *buf, gsize len);
const char *nm_platform_lnk_infiniband_to_string (const NMPlatformLnkInfiniband *lnk, char *buf, gsize len);
@@ -1218,6 +1225,10 @@ gboolean nm_platform_ethtool_set_wake_on_lan (NMPlatform *self, int ifindex, NMS
gboolean nm_platform_ethtool_set_link_settings (NMPlatform *self, int ifindex, gboolean autoneg, guint32 speed, NMPlatformLinkDuplexType duplex);
gboolean nm_platform_ethtool_get_link_settings (NMPlatform *self, int ifindex, gboolean *out_autoneg, guint32 *out_speed, NMPlatformLinkDuplexType *out_duplex);
+void nm_platform_ip4_dev_route_blacklist_set (NMPlatform *self,
+ int ifindex,
+ GPtrArray *ip4_dev_route_blacklist);
+
struct _NMDedupMultiIndex *nm_platform_get_multi_idx (NMPlatform *self);
#endif /* __NETWORKMANAGER_PLATFORM_H__ */
diff --git a/src/tests/test-route-manager.c b/src/tests/test-route-manager.c
deleted file mode 100644
index 2778cfcc82..0000000000
--- a/src/tests/test-route-manager.c
+++ /dev/null
@@ -1,974 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright (C) 2015 Red Hat, Inc.
- *
- */
-
-#include "nm-default.h"
-
-#include <arpa/inet.h>
-#include <linux/rtnetlink.h>
-
-#include "platform/nm-platform.h"
-#include "platform/nm-platform-utils.h"
-#include "nm-route-manager.h"
-
-#include "platform/tests/test-common.h"
-
-typedef struct {
- int ifindex0, ifindex1;
-} test_fixture;
-
-NMRouteManager *route_manager_get (void);
-
-NM_DEFINE_SINGLETON_GETTER (NMRouteManager, route_manager_get, NM_TYPE_ROUTE_MANAGER);
-
-/*****************************************************************************/
-
-static void
-setup_dev0_ip4 (int ifindex, guint mss_of_first_route, guint32 metric_of_second_route)
-{
- GArray *routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route));
- NMPlatformIP4Route route = { 0 };
-
- route.ifindex = ifindex;
- route.mss = 0;
-
- route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
- inet_pton (AF_INET, "6.6.6.0", &route.network);
- route.plen = 24;
- route.gateway = INADDR_ANY;
- route.metric = 20;
- route.mss = mss_of_first_route;
- g_array_append_val (routes, route);
-
- route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
- inet_pton (AF_INET, "7.0.0.0", &route.network);
- route.plen = 8;
- inet_pton (AF_INET, "6.6.6.1", &route.gateway);
- route.metric = metric_of_second_route;
- route.mss = 0;
- g_array_append_val (routes, route);
-
- nm_route_manager_ip4_route_sync (route_manager_get (), ifindex, routes, TRUE, TRUE);
- g_array_free (routes, TRUE);
-}
-
-static void
-setup_dev1_ip4 (int ifindex)
-{
- GArray *routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route));
- NMPlatformIP4Route route = { 0 };
-
- route.ifindex = ifindex;
- route.mss = 0;
-
- /* Add some route outside of route manager. The route manager
- * should get rid of it upon sync. */
- nmtstp_ip4_route_add (NM_PLATFORM_GET,
- route.ifindex,
- NM_IP_CONFIG_SOURCE_USER,
- nmtst_inet4_from_string ("9.0.0.0"),
- 8,
- INADDR_ANY,
- 0,
- 10,
- route.mss);
-
- route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
- inet_pton (AF_INET, "6.6.6.0", &route.network);
- route.plen = 24;
- route.gateway = INADDR_ANY;
- route.metric = 20;
- g_array_append_val (routes, route);
-
- route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
- inet_pton (AF_INET, "7.0.0.0", &route.network);
- route.plen = 8;
- route.gateway = INADDR_ANY;
- route.metric = 22;
- g_array_append_val (routes, route);
-
- route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
- inet_pton (AF_INET, "8.0.0.0", &route.network);
- route.plen = 8;
- inet_pton (AF_INET, "6.6.6.2", &route.gateway);
- route.metric = 22;
- g_array_append_val (routes, route);
-
- nm_route_manager_ip4_route_sync (route_manager_get (), ifindex, routes, TRUE, TRUE);
- g_array_free (routes, TRUE);
-}
-
-static void
-update_dev0_ip4 (int ifindex)
-{
- GArray *routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route));
- NMPlatformIP4Route route = { 0 };
-
- route.ifindex = ifindex;
- route.mss = 0;
-
- route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
- inet_pton (AF_INET, "6.6.6.0", &route.network);
- route.plen = 24;
- route.gateway = INADDR_ANY;
- route.metric = 20;
- g_array_append_val (routes, route);
-
- route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
- inet_pton (AF_INET, "7.0.0.0", &route.network);
- route.plen = 8;
- route.gateway = INADDR_ANY;
- route.metric = 21;
- g_array_append_val (routes, route);
-
- nm_route_manager_ip4_route_sync (route_manager_get (), ifindex, routes, TRUE, TRUE);
- g_array_free (routes, TRUE);
-}
-
-
-static GArray *
-ip_routes (test_fixture *fixture, NMPObjectType obj_type)
-{
- const NMPClass *klass;
- GArray *routes;
- const NMDedupMultiHeadEntry *pl_head_entry;
- NMDedupMultiIter iter;
- const NMPObject *plobj = NULL;
- guint i;
-
- g_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
-
- klass = nmp_class_from_type (obj_type);
-
- routes = g_array_new (FALSE, FALSE, klass->sizeof_public);
-
- for (i = 0; i < 2; i++) {
- int ifindex;
-
- if (i == 0)
- ifindex = fixture->ifindex0;
- else
- ifindex = fixture->ifindex1;
-
- pl_head_entry = nm_platform_lookup_addrroute (NM_PLATFORM_GET,
- obj_type,
- ifindex);
- nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) {
- const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE (plobj);
-
- if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r))
- continue;
- if (r->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL)
- continue;
- g_assert (r->ifindex == ifindex);
- g_assert (nmp_object_is_visible (plobj));
- g_array_append_vals (routes, r, 1);
- }
- }
-
- return routes;
-}
-
-static void
-test_ip4 (test_fixture *fixture, gconstpointer user_data)
-{
- GArray *routes;
-
- NMPlatformIP4Route state1[] = {
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = nmtst_inet4_from_string ("6.6.6.0"),
- .plen = 24,
- .ifindex = fixture->ifindex0,
- .gateway = INADDR_ANY,
- .metric = 20,
- .mss = 1000,
- .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = nmtst_inet4_from_string ("7.0.0.0"),
- .plen = 8,
- .ifindex = fixture->ifindex0,
- .gateway = nmtst_inet4_from_string ("6.6.6.1"),
- .metric = 21021,
- .mss = 0,
- .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_UNIVERSE),
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = nmtst_inet4_from_string ("7.0.0.0"),
- .plen = 8,
- .ifindex = fixture->ifindex1,
- .gateway = INADDR_ANY,
- .metric = 22,
- .mss = 0,
- .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = nmtst_inet4_from_string ("6.6.6.0"),
- .plen = 24,
- .ifindex = fixture->ifindex1,
- .gateway = INADDR_ANY,
- .metric = 21,
- .mss = 0,
- .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = nmtst_inet4_from_string ("8.0.0.0"),
- .plen = 8,
- .ifindex = fixture->ifindex1,
- .gateway = nmtst_inet4_from_string ("6.6.6.2"),
- .metric = 22,
- .mss = 0,
- .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_UNIVERSE),
- },
- };
-
- NMPlatformIP4Route state2[] = {
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = nmtst_inet4_from_string ("6.6.6.0"),
- .plen = 24,
- .ifindex = fixture->ifindex0,
- .gateway = INADDR_ANY,
- .metric = 20,
- .mss = 0,
- .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = nmtst_inet4_from_string ("7.0.0.0"),
- .plen = 8,
- .ifindex = fixture->ifindex0,
- .gateway = INADDR_ANY,
- .metric = 21,
- .mss = 0,
- .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = nmtst_inet4_from_string ("7.0.0.0"),
- .plen = 8,
- .ifindex = fixture->ifindex1,
- .gateway = INADDR_ANY,
- .metric = 22,
- .mss = 0,
- .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = nmtst_inet4_from_string ("6.6.6.0"),
- .plen = 24,
- .ifindex = fixture->ifindex1,
- .gateway = INADDR_ANY,
- .metric = 21,
- .mss = 0,
- .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = nmtst_inet4_from_string ("8.0.0.0"),
- .plen = 8,
- .ifindex = fixture->ifindex1,
- .gateway = nmtst_inet4_from_string ("6.6.6.2"),
- .metric = 22,
- .mss = 0,
- .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_UNIVERSE),
- },
- };
-
- NMPlatformIP4Route state3[] = {
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = nmtst_inet4_from_string ("7.0.0.0"),
- .plen = 8,
- .ifindex = fixture->ifindex1,
- .gateway = INADDR_ANY,
- .metric = 22,
- .mss = 0,
- .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = nmtst_inet4_from_string ("6.6.6.0"),
- .plen = 24,
- .ifindex = fixture->ifindex1,
- .gateway = INADDR_ANY,
- .metric = 20,
- .mss = 0,
- .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = nmtst_inet4_from_string ("8.0.0.0"),
- .plen = 8,
- .ifindex = fixture->ifindex1,
- .gateway = nmtst_inet4_from_string ("6.6.6.2"),
- .metric = 22,
- .mss = 0,
- .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_UNIVERSE),
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = nmtst_inet4_from_string ("6.6.6.0"),
- .plen = 24,
- .ifindex = fixture->ifindex1,
- .gateway = INADDR_ANY,
- /* this is a ghost entry because we synced ifindex0 and restore the route
- * with metric 20 (above). But we don't remove the metric 21. */
- .metric = 21,
- .mss = 0,
- .scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
- },
- };
-
- setup_dev0_ip4 (fixture->ifindex0, 1000, 21021);
- setup_dev1_ip4 (fixture->ifindex1);
- g_test_assert_expected_messages ();
-
- /* - 6.6.6.0/24 on dev0 won over 6.6.6.0/24 on dev1
- * - 6.6.6.0/24 on dev1 has metric bumped.
- * - 7.0.0.0/8 route, metric 21021 added
- * - 7.0.0.0/8 route, metric 22 added
- * - 8.0.0.0/8 could be added. */
- routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP4_ROUTE);
- g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state1));
- nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, state1, routes->len, TRUE);
- g_array_free (routes, TRUE);
-
- setup_dev1_ip4 (fixture->ifindex1);
- g_test_assert_expected_messages ();
-
- setup_dev0_ip4 (fixture->ifindex0, 0, 21);
-
- /* Ensure nothing changed. */
- routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP4_ROUTE);
- g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state1));
- state1[0].mss = 0;
- state1[1].metric = 21;
- nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, state1, routes->len, TRUE);
- g_array_free (routes, TRUE);
-
- update_dev0_ip4 (fixture->ifindex0);
-
- /* minor changes in the routes. Quite similar to state1. */
- routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP4_ROUTE);
- g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state2));
- nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, state2, routes->len, TRUE);
- g_array_free (routes, TRUE);
-
- nm_route_manager_route_flush (route_manager_get (), fixture->ifindex0);
-
- /* 6.6.6.0/24 is now on dev1
- * 6.6.6.0/24 is also still on dev1 with bumped metric 21.
- * 7.0.0.0/8 gone from dev0, still present on dev1
- * 8.0.0.0/8 is present on dev1
- * No dev0 routes left. */
- routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP4_ROUTE);
- g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state3));
- nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, state3, routes->len, TRUE);
- g_array_free (routes, TRUE);
-
- nm_route_manager_route_flush (route_manager_get (), fixture->ifindex1);
-
- /* No routes left. */
- routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP4_ROUTE);
- g_assert_cmpint (routes->len, ==, 0);
- g_array_free (routes, TRUE);
-}
-
-static void
-setup_dev0_ip6 (int ifindex)
-{
- GArray *routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP6Route));
- NMPlatformIP6Route *route;
-
- /* Add an address so that a route to the gateway below gets added. */
- nm_platform_ip6_address_add (NM_PLATFORM_GET,
- ifindex,
- *nmtst_inet6_from_string ("2001:db8:8086::666"),
- 64,
- in6addr_any,
- 3600,
- 3600,
- 0);
-
- route = nmtst_platform_ip6_route_full ("2001:db8:8086::",
- 48,
- NULL,
- ifindex,
- NM_IP_CONFIG_SOURCE_USER,
- 20,
- 0);
- g_array_append_val (routes, *route);
-
- route = nmtst_platform_ip6_route_full ("2001:db8:1337::",
- 48,
- NULL,
- ifindex,
- NM_IP_CONFIG_SOURCE_USER,
- 0,
- 0);
- g_array_append_val (routes, *route);
-
- route = nmtst_platform_ip6_route_full ("2001:db8:abad:c0de::",
- 64,
- "2001:db8:8086::1",
- ifindex,
- NM_IP_CONFIG_SOURCE_USER,
- 21,
- 0);
- g_array_append_val (routes, *route);
-
- nm_route_manager_ip6_route_sync (route_manager_get (), ifindex, routes, TRUE, TRUE);
- g_array_free (routes, TRUE);
-}
-
-static void
-setup_dev1_ip6 (int ifindex)
-{
- GArray *routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP6Route));
- NMPlatformIP6Route *route;
-
- /* Add some route outside of route manager. The route manager
- * should get rid of it upon sync. */
- nmtstp_ip6_route_add (NM_PLATFORM_GET,
- ifindex,
- NM_IP_CONFIG_SOURCE_USER,
- *nmtst_inet6_from_string ("2001:db8:8088::"),
- 48,
- in6addr_any,
- in6addr_any,
- 10,
- 0);
-
- route = nmtst_platform_ip6_route_full ("2001:db8:8086::",
- 48,
- NULL,
- ifindex,
- NM_IP_CONFIG_SOURCE_USER,
- 20,
- 0);
- g_array_append_val (routes, *route);
-
- route = nmtst_platform_ip6_route_full ("2001:db8:1337::",
- 48,
- NULL,
- ifindex,
- NM_IP_CONFIG_SOURCE_USER,
- 1024,
- 0);
- g_array_append_val (routes, *route);
-
- route = nmtst_platform_ip6_route_full ("2001:db8:d34d::",
- 64,
- "2001:db8:8086::2",
- ifindex,
- NM_IP_CONFIG_SOURCE_USER,
- 20,
- 0);
- g_array_append_val (routes, *route);
-
- route = nmtst_platform_ip6_route_full ("2001:db8:abad:c0de::",
- 64,
- NULL,
- ifindex,
- NM_IP_CONFIG_SOURCE_USER,
- 22,
- 0);
- g_array_append_val (routes, *route);
-
- nm_route_manager_ip6_route_sync (route_manager_get (), ifindex, routes, TRUE, TRUE);
- g_array_free (routes, TRUE);
-}
-
-static void
-update_dev0_ip6 (int ifindex)
-{
- GArray *routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP6Route));
- NMPlatformIP6Route *route;
-
- /* Add an address so that a route to the gateway below gets added. */
- nm_platform_ip6_address_add (NM_PLATFORM_GET,
- ifindex,
- *nmtst_inet6_from_string ("2001:db8:8086::2"),
- 64,
- in6addr_any,
- 3600,
- 3600,
- 0);
-
- route = nmtst_platform_ip6_route_full ("2001:db8:8086::",
- 48,
- NULL,
- ifindex,
- NM_IP_CONFIG_SOURCE_USER,
- 20,
- 0);
- g_array_append_val (routes, *route);
-
- route = nmtst_platform_ip6_route_full ("2001:db8:1337::",
- 48,
- NULL,
- ifindex,
- NM_IP_CONFIG_SOURCE_USER,
- 0,
- 0);
- g_array_append_val (routes, *route);
-
- route = nmtst_platform_ip6_route_full ("2001:db8:abad:c0de::",
- 64,
- NULL,
- ifindex,
- NM_IP_CONFIG_SOURCE_USER,
- 21,
- 0);
- g_array_append_val (routes, *route);
-
- nm_route_manager_ip6_route_sync (route_manager_get (), ifindex, routes, TRUE, TRUE);
- g_array_free (routes, TRUE);
-}
-
-static void
-test_ip6 (test_fixture *fixture, gconstpointer user_data)
-{
- GArray *routes;
- int i;
-
- NMPlatformIP6Route state1[] = {
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = *nmtst_inet6_from_string ("2001:db8:8086::"),
- .plen = 48,
- .ifindex = fixture->ifindex0,
- .gateway = in6addr_any,
- .metric = 20,
- .mss = 0,
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = *nmtst_inet6_from_string ("2001:db8:1337::"),
- .plen = 48,
- .ifindex = fixture->ifindex0,
- .gateway = in6addr_any,
- .metric = 1024,
- .mss = 0,
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = *nmtst_inet6_from_string ("2001:db8:abad:c0de::"),
- .plen = 64,
- .ifindex = fixture->ifindex0,
- .gateway = *nmtst_inet6_from_string ("2001:db8:8086::1"),
- .metric = 21,
- .mss = 0,
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = *nmtst_inet6_from_string ("2001:db8:abad:c0de::"),
- .plen = 64,
- .ifindex = fixture->ifindex1,
- .gateway = in6addr_any,
- .metric = 22,
- .mss = 0,
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = *nmtst_inet6_from_string ("2001:db8:1337::"),
- .plen = 48,
- .ifindex = fixture->ifindex1,
- .gateway = in6addr_any,
- .metric = 1025,
- .mss = 0,
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = *nmtst_inet6_from_string ("2001:db8:8086::"),
- .plen = 48,
- .ifindex = fixture->ifindex1,
- .gateway = in6addr_any,
- .metric = 21,
- .mss = 0,
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = *nmtst_inet6_from_string ("2001:db8:d34d::"),
- .plen = 64,
- .ifindex = fixture->ifindex1,
- .gateway = *nmtst_inet6_from_string ("2001:db8:8086::2"),
- .metric = 20,
- .mss = 0,
- },
- };
-
- NMPlatformIP6Route state2[] = {
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = *nmtst_inet6_from_string ("2001:db8:8086::"),
- .plen = 48,
- .ifindex = fixture->ifindex0,
- .gateway = in6addr_any,
- .metric = 20,
- .mss = 0,
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = *nmtst_inet6_from_string ("2001:db8:1337::"),
- .plen = 48,
- .ifindex = fixture->ifindex0,
- .gateway = in6addr_any,
- .metric = 1024,
- .mss = 0,
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = *nmtst_inet6_from_string ("2001:db8:abad:c0de::"),
- .plen = 64,
- .ifindex = fixture->ifindex0,
- .gateway = in6addr_any,
- .metric = 21,
- .mss = 0,
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = *nmtst_inet6_from_string ("2001:db8:abad:c0de::"),
- .plen = 64,
- .ifindex = fixture->ifindex1,
- .gateway = in6addr_any,
- .metric = 22,
- .mss = 0,
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = *nmtst_inet6_from_string ("2001:db8:1337::"),
- .plen = 48,
- .ifindex = fixture->ifindex1,
- .gateway = in6addr_any,
- .metric = 1025,
- .mss = 0,
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = *nmtst_inet6_from_string ("2001:db8:8086::"),
- .plen = 48,
- .ifindex = fixture->ifindex1,
- .gateway = in6addr_any,
- .metric = 21,
- .mss = 0,
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = *nmtst_inet6_from_string ("2001:db8:d34d::"),
- .plen = 64,
- .ifindex = fixture->ifindex1,
- .gateway = *nmtst_inet6_from_string ("2001:db8:8086::2"),
- .metric = 20,
- .mss = 0,
- },
- };
-
- NMPlatformIP6Route state3[] = {
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = *nmtst_inet6_from_string ("2001:db8:abad:c0de::"),
- .plen = 64,
- .ifindex = fixture->ifindex1,
- .gateway = in6addr_any,
- .metric = 22,
- .mss = 0,
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = *nmtst_inet6_from_string ("2001:db8:8086::"),
- .plen = 48,
- .ifindex = fixture->ifindex1,
- .gateway = in6addr_any,
- .metric = 20,
- .mss = 0,
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = *nmtst_inet6_from_string ("2001:db8:1337::"),
- .plen = 48,
- .ifindex = fixture->ifindex1,
- .gateway = in6addr_any,
- .metric = 1024,
- .mss = 0,
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = *nmtst_inet6_from_string ("2001:db8:1337::"),
- .plen = 48,
- .ifindex = fixture->ifindex1,
- .gateway = in6addr_any,
- .metric = 1025,
- .mss = 0,
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = *nmtst_inet6_from_string ("2001:db8:8086::"),
- .plen = 48,
- .ifindex = fixture->ifindex1,
- .gateway = in6addr_any,
- .metric = 21,
- .mss = 0,
- },
- {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = *nmtst_inet6_from_string ("2001:db8:d34d::"),
- .plen = 64,
- .ifindex = fixture->ifindex1,
- .gateway = *nmtst_inet6_from_string ("2001:db8:8086::2"),
- .metric = 20,
- .mss = 0,
- },
- };
-
- setup_dev0_ip6 (fixture->ifindex0);
- setup_dev1_ip6 (fixture->ifindex1);
- g_test_assert_expected_messages ();
-
- /* 2001:db8:8086::/48 on dev0 won over 2001:db8:8086::/48 on dev1
- * 2001:db8:d34d::/64 on dev1 could not be added
- * 2001:db8:1337::/48 on dev0 won over 2001:db8:1337::/48 on dev1 and has metric 1024
- * 2001:db8:abad:c0de::/64 routes did not clash */
- routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP6_ROUTE);
- g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state1));
- nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, state1, routes->len, TRUE);
- g_array_free (routes, TRUE);
-
-
- setup_dev1_ip6 (fixture->ifindex1);
- g_test_assert_expected_messages ();
- setup_dev0_ip6 (fixture->ifindex0);
-
- /* Ensure nothing changed. */
- routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP6_ROUTE);
- g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state1));
- nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, state1, routes->len, TRUE);
- g_array_free (routes, TRUE);
-
- update_dev0_ip6 (fixture->ifindex0);
-
- /* 2001:db8:abad:c0de::/64 on dev0 was updated for gateway removal*/
- routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP6_ROUTE);
- if (routes->len != G_N_ELEMENTS (state2)) {
- NMPlatformIP6Route rr;
-
- /* hm, seems kernel may wrongly treat IPv6 gateway for `ip route replace`.
- * See rh#1480427.
- *
- * We would expect that `ip route replace` replaces an existing route.
- * However, kernel may not do so, and instead prepend it.
- *
- * Work around that, by checking if such a route exists and accept
- * it. */
- g_assert (nmtstp_is_root_test ());
- g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state2) + 1);
- rr = ((NMPlatformIP6Route) {
- .rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
- .network = *nmtst_inet6_from_string ("2001:db8:abad:c0de::"),
- .plen = 64,
- .ifindex = fixture->ifindex0,
- .gateway = *nmtst_inet6_from_string ("2001:db8:8086::1"),
- .metric = 21,
- .mss = 0,
- });
- for (i = 0; i < routes->len; i++) {
- if (nm_platform_ip6_route_cmp (&rr,
- &g_array_index (routes, NMPlatformIP6Route, i),
- NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL) != 0)
- continue;
- g_array_remove_index (routes, i);
- break;
- }
- }
- nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, state2, routes->len, TRUE);
- g_array_free (routes, TRUE);
-
- nm_route_manager_route_flush (route_manager_get (), fixture->ifindex0);
-
- /* 2001:db8:abad:c0de::/64 on dev1 is still there, went away from dev0
- * 2001:db8:8086::/48 is now on dev1
- * 2001:db8:1337::/48 is now on dev1, metric of 1024 still applies
- * 2001:db8:d34d::/64 is present now that 2001:db8:8086::/48 is on dev1
- * No dev0 routes left. */
- routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP6_ROUTE);
- g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state3));
- nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, state3, routes->len, TRUE);
- g_array_free (routes, TRUE);
-
- nm_route_manager_route_flush (route_manager_get (), fixture->ifindex1);
-
- /* No routes left. */
- routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP6_ROUTE);
- g_assert_cmpint (routes->len, ==, 0);
- g_array_free (routes, TRUE);
-}
-
-/*****************************************************************************/
-
-static void
-_assert_route_check (const NMPlatformVTableRoute *vtable, gboolean has, const NMPlatformIPXRoute *route)
-{
- const NMPlatformIPXRoute *r;
- NMPlatformIPXRoute c;
-
- g_assert (route);
-
- if (vtable->is_ip4)
- r = (const NMPlatformIPXRoute *) nmtstp_ip4_route_get (NM_PLATFORM_GET, route->rx.ifindex, route->r4.network, route->rx.plen, route->rx.metric, route->r4.tos);
- else
- r = (const NMPlatformIPXRoute *) nmtstp_ip6_route_get (NM_PLATFORM_GET, route->rx.ifindex, &route->r6.network, route->rx.plen, route->rx.metric, &route->r6.src, route->r6.src_plen);
-
- if (!has) {
- g_assert (!r);
- } else {
- char buf[sizeof (_nm_utils_to_string_buffer)];
-
- if (r) {
- if (vtable->is_ip4)
- c.r4 = route->r4;
- else
- c.r6 = route->r6;
- c.rx.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (c.rx.rt_source);
- }
- if (!r || vtable->route_cmp (r, &c, NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL) != 0) {
- g_error ("Invalid route. Expect %s, has %s",
- vtable->route_to_string (&c, NULL, 0),
- vtable->route_to_string (r, buf, sizeof (buf)));
- }
- }
-}
-
-static void
-test_ip4_full_sync (test_fixture *fixture, gconstpointer user_data)
-{
- const NMPlatformVTableRoute *vtable = &nm_platform_vtable_route_v4;
- gs_unref_array GArray *routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route));
- NMPlatformIP4Route r01, r02, r03;
-
- nm_log_dbg (LOGD_CORE, "TEST start test_ip4_full_sync(): start");
-
- r01 = *nmtst_platform_ip4_route_full ("12.3.4.0", 24, NULL,
- fixture->ifindex0, NM_IP_CONFIG_SOURCE_USER,
- 100, 0, RT_SCOPE_LINK, NULL);
- r02 = *nmtst_platform_ip4_route_full ("13.4.5.6", 32, "12.3.4.1",
- fixture->ifindex0, NM_IP_CONFIG_SOURCE_USER,
- 100, 0, RT_SCOPE_UNIVERSE, NULL);
- r03 = *nmtst_platform_ip4_route_full ("14.5.6.7", 32, "12.3.4.1",
- fixture->ifindex0, NM_IP_CONFIG_SOURCE_USER,
- 110, 0, RT_SCOPE_UNIVERSE, NULL);
- g_array_set_size (routes, 2);
- g_array_index (routes, NMPlatformIP4Route, 0) = r01;
- g_array_index (routes, NMPlatformIP4Route, 1) = r02;
- nm_route_manager_ip4_route_sync (route_manager_get (), fixture->ifindex0, routes, TRUE, TRUE);
-
- _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r01);
- _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r02);
- _assert_route_check (vtable, FALSE, (const NMPlatformIPXRoute *) &r03);
-
- vtable->route_add (NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, (const NMPlatformIPXRoute *) &r03, 0, -1);
-
- _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r01);
- _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r02);
- _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r03);
-
- nm_route_manager_ip4_route_sync (route_manager_get (), fixture->ifindex0, routes, TRUE, FALSE);
-
- _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r01);
- _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r02);
- _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r03);
-
- g_array_set_size (routes, 1);
-
- nm_route_manager_ip4_route_sync (route_manager_get (), fixture->ifindex0, routes, TRUE, FALSE);
-
- _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r01);
- _assert_route_check (vtable, FALSE, (const NMPlatformIPXRoute *) &r02);
- _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r03);
-
- nm_route_manager_ip4_route_sync (route_manager_get (), fixture->ifindex0, routes, TRUE, TRUE);
-
- _assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r01);
- _assert_route_check (vtable, FALSE, (const NMPlatformIPXRoute *) &r02);
- _assert_route_check (vtable, FALSE, (const NMPlatformIPXRoute *) &r03);
-
- nm_log_dbg (LOGD_CORE, "TEST test_ip4_full_sync(): done");
-}
-
-/*****************************************************************************/
-
-static void
-fixture_setup (test_fixture *fixture, gconstpointer user_data)
-{
- SignalData *link_added;
-
- link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED,
- NM_PLATFORM_SIGNAL_ADDED,
- link_callback,
- "nm-test-device0");
- nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device0"));
- g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "nm-test-device0"));
- g_assert (nm_platform_link_dummy_add (NM_PLATFORM_GET, "nm-test-device0", NULL) == NM_PLATFORM_ERROR_SUCCESS);
- accept_signal (link_added);
- free_signal (link_added);
- fixture->ifindex0 = nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device0");
- g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, fixture->ifindex0, NULL));
-
- link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED,
- NM_PLATFORM_SIGNAL_ADDED,
- link_callback,
- "nm-test-device1");
- nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device1"));
- g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "nm-test-device1"));
- g_assert (nm_platform_link_dummy_add (NM_PLATFORM_GET, "nm-test-device1", NULL) == NM_PLATFORM_ERROR_SUCCESS);
- accept_signal (link_added);
- free_signal (link_added);
- fixture->ifindex1 = nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device1");
- g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, fixture->ifindex1, NULL));
-}
-
-static void
-fixture_teardown (test_fixture *fixture, gconstpointer user_data)
-{
- nm_platform_link_delete (NM_PLATFORM_GET, fixture->ifindex0);
- nm_platform_link_delete (NM_PLATFORM_GET, fixture->ifindex1);
-}
-
-/*****************************************************************************/
-
-NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP;
-
-void
-_nmtstp_init_tests (int *argc, char ***argv)
-{
- nmtst_init_assert_logging (argc, argv, "WARN", "ALL");
-}
-
-void
-_nmtstp_setup_tests (void)
-{
- g_test_add ("/route-manager/ip4", test_fixture, NULL, fixture_setup, test_ip4, fixture_teardown);
- g_test_add ("/route-manager/ip6", test_fixture, NULL, fixture_setup, test_ip6, fixture_teardown);
- g_test_add ("/route-manager/ip4-full-sync", test_fixture, NULL, fixture_setup, test_ip4_full_sync, fixture_teardown);
-}
diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c
index 912df081e4..562867545e 100644
--- a/src/vpn/nm-vpn-connection.c
+++ b/src/vpn/nm-vpn-connection.c
@@ -45,7 +45,6 @@
#include "nm-core-internal.h"
#include "nm-pacrunner-manager.h"
#include "nm-default-route-manager.h"
-#include "nm-route-manager.h"
#include "nm-firewall-manager.h"
#include "nm-config.h"
#include "nm-vpn-plugin-info.h"
@@ -394,9 +393,11 @@ vpn_cleanup (NMVpnConnection *self, NMDevice *parent_dev)
NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
if (priv->ip_ifindex) {
- nm_platform_link_set_down (nm_netns_get_platform (priv->netns), priv->ip_ifindex);
- nm_route_manager_route_flush (nm_netns_get_route_manager (priv->netns), priv->ip_ifindex);
- nm_platform_ip_address_flush (nm_netns_get_platform (priv->netns), AF_UNSPEC, priv->ip_ifindex);
+ NMPlatform *platform = nm_netns_get_platform (priv->netns);
+
+ nm_platform_link_set_down (platform, priv->ip_ifindex);
+ nm_platform_ip_route_flush (platform, AF_UNSPEC, priv->ip_ifindex);
+ nm_platform_ip_address_flush (platform, AF_UNSPEC, priv->ip_ifindex);
}
remove_parent_device_config (self, parent_dev);
@@ -1104,21 +1105,17 @@ nm_vpn_connection_apply_config (NMVpnConnection *self)
nm_platform_link_set_up (nm_netns_get_platform (priv->netns), priv->ip_ifindex, NULL);
if (priv->ip4_config) {
+ nm_assert (priv->ip_ifindex == nm_ip4_config_get_ifindex (priv->ip4_config));
if (!nm_ip4_config_commit (priv->ip4_config,
nm_netns_get_platform (priv->netns),
- nm_netns_get_route_manager (priv->netns),
- priv->ip_ifindex,
- TRUE,
nm_vpn_connection_get_ip4_route_metric (self)))
return FALSE;
}
if (priv->ip6_config) {
+ nm_assert (priv->ip_ifindex == nm_ip6_config_get_ifindex (priv->ip6_config));
if (!nm_ip6_config_commit (priv->ip6_config,
- nm_netns_get_platform (priv->netns),
- nm_netns_get_route_manager (priv->netns),
- priv->ip_ifindex,
- TRUE))
+ nm_netns_get_platform (priv->netns)))
return FALSE;
}