NetworkManager/0076-rh1059597-route-source...

1006 lines
35 KiB
Diff

From bede7357f6f66c053e5acd59692ed95471dac031 Mon Sep 17 00:00:00 2001
From: Dan Williams <dcbw@redhat.com>
Date: Mon, 6 Jan 2014 14:14:14 -0600
Subject: [PATCH] core/platform: add address/route sources (rh#1005416,
bgo#722843)
Tag addresses and routes with their source. We'll use this later to do
(or not do) operations based on where the item came from.
One thing to note is that when synchronizing items with the kernel, all
items are read as source=KERNEL even when they originally came from
NetworkManager, since the kernel has no way of providing this source
information. This requires the source 'priority', which
nm_ip*_config_add_address() and nm_ip*_config_add_route() must respect
to ensure that NM-owned routes don't have their source overwritten
when merging various IP configs in ip*_config_merge_and_apply().
Also of note is that memcmp() can no longer be used to compare
addresses/routes in nm-platform.c, but this had problems before
anyway with ifindex, so that workaround from nm_platform_ip4_route_sync()
can be removed.
https://bugzilla.gnome.org/show_bug.cgi?id=722843
https://bugzilla.redhat.com/show_bug.cgi?id=1005416
[lkundrak@v3.sk: Backported to f20]
Conflicts:
src/devices/nm-device.c
src/dhcp-manager/nm-dhcp-dhclient-utils.c
src/platform/nm-platform.c
src/tests/test-ip4-config.c
(cherry picked from commit 067db6f8d75fe612a626ce4ee7be910262f438a3)
---
src/devices/nm-device.c | 5 ++
src/dhcp-manager/nm-dhcp-client.c | 5 ++
src/dhcp-manager/nm-dhcp-dhclient-utils.c | 1 -
src/modem-manager/nm-modem-broadband.c | 1 +
src/modem-manager/nm-modem-old.c | 1 +
src/nm-ip4-config.c | 43 +++++++++++
src/nm-ip6-config.c | 43 +++++++++++
src/platform/nm-linux-platform.c | 4 ++
src/platform/nm-platform.c | 75 +++++++++++++++----
src/platform/nm-platform.h | 18 +++++
src/ppp-manager/nm-ppp-manager.c | 1 +
src/tests/test-ip4-config.c | 116 ++++++++++++++++++++++++++++++
src/tests/test-ip6-config.c | 116 ++++++++++++++++++++++++++++++
src/vpn-manager/nm-vpn-connection.c | 12 +++-
14 files changed, 424 insertions(+), 17 deletions(-)
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 5fc6cb7..39b6472 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -2220,12 +2220,14 @@ aipd_get_ip4_config (NMDevice *self, guint32 lla)
memset (&address, 0, sizeof (address));
address.address = lla;
address.plen = 16;
+ address.source = NM_PLATFORM_SOURCE_IP4LL;
nm_ip4_config_add_address (config, &address);
/* Add a multicast route for link-local connections: destination= 224.0.0.0, netmask=240.0.0.0 */
memset (&route, 0, sizeof (route));
route.network = htonl (0xE0000000L);
route.plen = 4;
+ route.source = NM_PLATFORM_SOURCE_IP4LL;
nm_ip4_config_add_route (config, &route);
return config;
@@ -2738,6 +2740,7 @@ shared4_new_config (NMDevice *self, NMDeviceStateReason *reason)
memset (&address, 0, sizeof (address));
address.address = tmp_addr;
address.plen = 24;
+ address.source = NM_PLATFORM_SOURCE_SHARED;
nm_ip4_config_add_address (config, &address);
/* Remove the address lock when the object gets disposed */
@@ -3322,6 +3325,7 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *device
address.lifetime = discovered_address->lifetime;
address.preferred = discovered_address->preferred;
address.flags = ifa_flags;
+ address.source = NM_PLATFORM_SOURCE_RDISC;
nm_ip6_config_add_address (priv->ac_ip6_config, &address);
}
@@ -3344,6 +3348,7 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *device
route.network = discovered_route->network;
route.plen = discovered_route->plen;
route.gateway = discovered_route->gateway;
+ route.source = NM_PLATFORM_SOURCE_RDISC;
nm_ip6_config_add_route (priv->ac_ip6_config, &route);
}
diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c
index 2063049..5c8202e 100644
--- a/src/dhcp-manager/nm-dhcp-client.c
+++ b/src/dhcp-manager/nm-dhcp-client.c
@@ -864,6 +864,7 @@ ip4_process_dhcpcd_rfc3442_routes (const char *str,
route.network = rt_addr;
route.plen = rt_cidr;
route.gateway = rt_route;
+ route.source = NM_PLATFORM_SOURCE_DHCP;
nm_ip4_config_add_route (ip4_config, &route);
}
}
@@ -967,6 +968,7 @@ ip4_process_dhclient_rfc3442_routes (const char *str,
char nh[INET_ADDRSTRLEN + 1];
/* normal route */
+ route.source = NM_PLATFORM_SOURCE_DHCP;
nm_ip4_config_add_route (ip4_config, &route);
inet_ntop (AF_INET, &route.network, addr, sizeof (addr));
@@ -1079,6 +1081,7 @@ process_classful_routes (GHashTable *options, NMIP4Config *ip4_config)
route.network = rt_addr;
route.plen = 32;
route.gateway = rt_route;
+ route.source = NM_PLATFORM_SOURCE_DHCP;
nm_ip4_config_add_route (ip4_config, &route);
nm_log_info (LOGD_DHCP, " static route %s gw %s", *s, *(s + 1));
@@ -1246,6 +1249,7 @@ ip4_options_to_config (NMDHCPClient *self)
nm_log_info (LOGD_DHCP4, " lease time %d", address.lifetime);
}
+ address.source = NM_PLATFORM_SOURCE_DHCP;
nm_ip4_config_add_address (ip4_config, &address);
str = g_hash_table_lookup (priv->options, "new_host_name");
@@ -1413,6 +1417,7 @@ ip6_options_to_config (NMDHCPClient *self)
}
address.address = tmp_addr;
+ address.source = NM_PLATFORM_SOURCE_DHCP;
nm_ip6_config_add_address (ip6_config, &address);
nm_log_info (LOGD_DHCP6, " address %s", str);
} else if (priv->info_only == FALSE) {
diff --git a/src/dhcp-manager/nm-dhcp-dhclient-utils.c b/src/dhcp-manager/nm-dhcp-dhclient-utils.c
index c318e8d..17ecab0 100644
--- a/src/dhcp-manager/nm-dhcp-dhclient-utils.c
+++ b/src/dhcp-manager/nm-dhcp-dhclient-utils.c
@@ -426,4 +426,3 @@ nm_dhcp_dhclient_save_duid (const char *leasefile,
g_string_free (s, TRUE);
return success;
}
-
diff --git a/src/modem-manager/nm-modem-broadband.c b/src/modem-manager/nm-modem-broadband.c
index 508624d..032557d 100644
--- a/src/modem-manager/nm-modem-broadband.c
+++ b/src/modem-manager/nm-modem-broadband.c
@@ -656,6 +656,7 @@ static_stage3_done (NMModemBroadband *self)
memset (&address, 0, sizeof (address));
address.address = address_network;
address.plen = mm_bearer_ip_config_get_prefix (self->priv->ipv4_config);
+ address.source = NM_PLATFORM_SOURCE_WWAN;
nm_ip4_config_add_address (config, &address);
nm_log_info (LOGD_MB, " address %s/%d",
diff --git a/src/modem-manager/nm-modem-old.c b/src/modem-manager/nm-modem-old.c
index 60ddd47..866a94a 100644
--- a/src/modem-manager/nm-modem-old.c
+++ b/src/modem-manager/nm-modem-old.c
@@ -620,6 +620,7 @@ static_stage3_done (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
/* IP address */
address.address = g_value_get_uint (g_value_array_get_nth (ret_array, 0));
address.plen = 32;
+ address.source = NM_PLATFORM_SOURCE_WWAN;
nm_ip4_config_add_address (config, &address);
nm_log_info (LOGD_MB, " address %s/%d",
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c
index 23be6d7..2a3f23d 100644
--- a/src/nm-ip4-config.c
+++ b/src/nm-ip4-config.c
@@ -235,6 +235,7 @@ nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIP4Config *setting)
address.plen = nm_ip4_address_get_prefix (s_addr);
address.lifetime = NM_PLATFORM_LIFETIME_PERMANENT;
address.preferred = NM_PLATFORM_LIFETIME_PERMANENT;
+ address.source = NM_PLATFORM_SOURCE_USER;
nm_ip4_config_add_address (config, &address);
}
@@ -251,6 +252,7 @@ nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIP4Config *setting)
route.plen = nm_ip4_route_get_prefix (s_route);
route.gateway = nm_ip4_route_get_next_hop (s_route);
route.metric = nm_ip4_route_get_metric (s_route);
+ route.source = NM_PLATFORM_SOURCE_USER;
nm_ip4_config_add_route (config, &route);
}
@@ -901,10 +903,21 @@ nm_ip4_config_reset_addresses (NMIP4Config *config)
}
}
+/**
+ * nm_ip4_config_add_address:
+ * @config: the #NMIP4Config
+ * @new: the new address to add to @config
+ *
+ * Adds the new address to @config. If an address with the same basic properties
+ * (address, prefix) already exists in @config, it is overwritten with the
+ * lifetime and preferred of @new. The source is also overwritten by the source
+ * from @new if that source is higher priority.
+ */
void
nm_ip4_config_add_address (NMIP4Config *config, const NMPlatformIP4Address *new)
{
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
+ NMPlatformSource old_source;
int i;
g_return_if_fail (new != NULL);
@@ -915,7 +928,10 @@ nm_ip4_config_add_address (NMIP4Config *config, const NMPlatformIP4Address *new)
if (addresses_are_duplicate (item, new, FALSE)) {
if (nm_platform_ip4_address_cmp (item, new) == 0)
return;
+ old_source = item->source;
memcpy (item, new, sizeof (*item));
+ /* Restore highest priority source */
+ item->source = MAX (old_source, new->source);
goto NOTIFY;
}
}
@@ -965,10 +981,21 @@ nm_ip4_config_reset_routes (NMIP4Config *config)
}
}
+/**
+ * nm_ip4_config_add_route:
+ * @config: the #NMIP4Config
+ * @new: the new route to add to @config
+ *
+ * Adds the new route to @config. If a route with the same basic properties
+ * (network, prefix) already exists in @config, it is overwritten including the
+ * gateway and metric of @new. The source is also overwritten by the source
+ * from @new if that source is higher priority.
+ */
void
nm_ip4_config_add_route (NMIP4Config *config, const NMPlatformIP4Route *new)
{
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
+ NMPlatformSource old_source;
int i;
g_return_if_fail (new != NULL);
@@ -979,7 +1006,10 @@ nm_ip4_config_add_route (NMIP4Config *config, const NMPlatformIP4Route *new)
if (routes_are_duplicate (item, new, FALSE)) {
if (nm_platform_ip4_route_cmp (item, new) == 0)
return;
+ old_source = item->source;
memcpy (item, new, sizeof (*item));
+ /* Restore highest priority source */
+ item->source = MAX (old_source, new->source);
goto NOTIFY;
}
}
@@ -1404,6 +1434,19 @@ nm_ip4_config_hash (const NMIP4Config *config, GChecksum *sum, gboolean dns_only
}
}
+/**
+ * nm_ip4_config_equal:
+ * @a: first config to compare
+ * @b: second config to compare
+ *
+ * Compares two #NMIP4Configs for basic equality. This means that all
+ * attributes must exist in the same order in both configs (addresses, routes,
+ * domains, DNS servers, etc) but some attributes (address lifetimes, and address
+ * and route sources) are ignored.
+ *
+ * Returns: %TRUE if the configurations are basically equal to each other,
+ * %FALSE if not
+ */
gboolean
nm_ip4_config_equal (const NMIP4Config *a, const NMIP4Config *b)
{
diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c
index 58ad2e0..ddbce19 100644
--- a/src/nm-ip6-config.c
+++ b/src/nm-ip6-config.c
@@ -228,6 +228,7 @@ nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIP6Config *setting)
address.plen = nm_ip6_address_get_prefix (s_addr);
address.lifetime = NM_PLATFORM_LIFETIME_PERMANENT;
address.preferred = NM_PLATFORM_LIFETIME_PERMANENT;
+ address.source = NM_PLATFORM_SOURCE_USER;
nm_ip6_config_add_address (config, &address);
}
@@ -244,6 +245,7 @@ nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIP6Config *setting)
route.plen = nm_ip6_route_get_prefix (s_route);
route.gateway = *nm_ip6_route_get_next_hop (s_route);
route.metric = nm_ip6_route_get_metric (s_route);
+ route.source = NM_PLATFORM_SOURCE_USER;
nm_ip6_config_add_route (config, &route);
}
@@ -734,10 +736,21 @@ nm_ip6_config_reset_addresses (NMIP6Config *config)
}
}
+/**
+ * nm_ip6_config_add_address:
+ * @config: the #NMIP6Config
+ * @new: the new address to add to @config
+ *
+ * Adds the new address to @config. If an address with the same basic properties
+ * (address, prefix) already exists in @config, it is overwritten with the
+ * lifetime and preferred of @new. The source is also overwritten by the source
+ * from @new if that source is higher priority.
+ */
void
nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address *new)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
+ NMPlatformSource old_source;
int i;
g_return_if_fail (new != NULL);
@@ -748,8 +761,11 @@ nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address *new)
if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) {
if (nm_platform_ip6_address_cmp (item, new) == 0)
return;
+ old_source = item->source;
/* Copy over old item to get new lifetime, timestamp, preferred */
*item = *new;
+ /* But restore highest priority source */
+ item->source = MAX (old_source, new->source);
goto NOTIFY;
}
}
@@ -799,10 +815,21 @@ nm_ip6_config_reset_routes (NMIP6Config *config)
}
}
+/**
+ * nm_ip6_config_add_route:
+ * @config: the #NMIP6Config
+ * @new: the new route to add to @config
+ *
+ * Adds the new route to @config. If a route with the same basic properties
+ * (network, prefix) already exists in @config, it is overwritten including the
+ * gateway and metric of @new. The source is also overwritten by the source
+ * from @new if that source is higher priority.
+ */
void
nm_ip6_config_add_route (NMIP6Config *config, const NMPlatformIP6Route *new)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
+ NMPlatformSource old_source;
int i;
g_return_if_fail (new != NULL);
@@ -813,7 +840,10 @@ nm_ip6_config_add_route (NMIP6Config *config, const NMPlatformIP6Route *new)
if (routes_are_duplicate (item, new, FALSE)) {
if (nm_platform_ip6_route_cmp (item, new) == 0)
return;
+ old_source = item->source;
*item = *new;
+ /* Restore highest priority source */
+ item->source = MAX (old_source, new->source);
goto NOTIFY;
}
}
@@ -1098,6 +1128,19 @@ nm_ip6_config_hash (const NMIP6Config *config, GChecksum *sum, gboolean dns_only
}
}
+/**
+ * nm_ip6_config_equal:
+ * @a: first config to compare
+ * @b: second config to compare
+ *
+ * Compares two #NMIP6Configs for basic equality. This means that all
+ * attributes must exist in the same order in both configs (addresses, routes,
+ * domains, DNS servers, etc) but some attributes (address lifetimes, and address
+ * and route sources) are ignored.
+ *
+ * Returns: %TRUE if the configurations are basically equal to each other,
+ * %FALSE if not
+ */
gboolean
nm_ip6_config_equal (const NMIP6Config *a, const NMIP6Config *b)
{
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index dacdc16..fc85178 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -2308,6 +2308,7 @@ ip4_address_get_all (NMPlatform *platform, int ifindex)
for (object = nl_cache_get_first (priv->address_cache); object; object = nl_cache_get_next (object)) {
if (nl_object_is_marked (object)) {
init_ip4_address (&address, (struct rtnl_addr *) object);
+ address.source = NM_PLATFORM_SOURCE_KERNEL;
g_array_append_val (addresses, address);
nl_object_unmark (object);
}
@@ -2331,6 +2332,7 @@ ip6_address_get_all (NMPlatform *platform, int ifindex)
for (object = nl_cache_get_first (priv->address_cache); object; object = nl_cache_get_next (object)) {
if (nl_object_is_marked (object)) {
init_ip6_address (&address, (struct rtnl_addr *) object);
+ address.source = NM_PLATFORM_SOURCE_KERNEL;
g_array_append_val (addresses, address);
nl_object_unmark (object);
}
@@ -2533,6 +2535,7 @@ ip4_route_get_all (NMPlatform *platform, int ifindex, gboolean include_default)
for (object = nl_cache_get_first (priv->route_cache); object; object = nl_cache_get_next (object)) {
if (nl_object_is_marked (object)) {
if (init_ip4_route (&route, (struct rtnl_route *) object)) {
+ route.source = NM_PLATFORM_SOURCE_KERNEL;
if (route.plen != 0 || include_default)
g_array_append_val (routes, route);
}
@@ -2558,6 +2561,7 @@ ip6_route_get_all (NMPlatform *platform, int ifindex, gboolean include_default)
for (object = nl_cache_get_first (priv->route_cache); object; object = nl_cache_get_next (object)) {
if (nl_object_is_marked (object)) {
if (init_ip6_route (&route, (struct rtnl_route *) object)) {
+ route.source = NM_PLATFORM_SOURCE_KERNEL;
if (route.plen != 0 || include_default)
g_array_append_val (routes, route);
}
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index 0ac304d..72bbfe6 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -1567,9 +1567,15 @@ array_contains_ip4_route (const GArray *routes, const NMPlatformIP4Route *route)
guint len = routes ? routes->len : 0;
guint i;
- for (i = 0; i < len; i++)
- if (!memcmp (&g_array_index (routes, NMPlatformIP4Route, i), route, sizeof (*route)))
+ for (i = 0; i < len; i++) {
+ NMPlatformIP4Route *c = &g_array_index (routes, NMPlatformIP4Route, i);
+
+ if (route->network == c->network &&
+ route->plen == c->plen &&
+ route->gateway == c->gateway &&
+ route->metric == c->metric)
return TRUE;
+ }
return FALSE;
}
@@ -1580,9 +1586,15 @@ array_contains_ip6_route (const GArray *routes, const NMPlatformIP6Route *route)
guint len = routes ? routes->len : 0;
guint i;
- for (i = 0; i < len; i++)
- if (!memcmp (&g_array_index (routes, NMPlatformIP6Route, i), route, sizeof (*route)))
+ for (i = 0; i < len; i++) {
+ NMPlatformIP6Route *c = &g_array_index (routes, NMPlatformIP6Route, i);
+
+ if (IN6_ARE_ADDR_EQUAL (&route->network, &c->network) &&
+ route->plen == c->plen &&
+ IN6_ARE_ADDR_EQUAL (&route->gateway, &c->gateway) &&
+ route->metric == c->metric)
return TRUE;
+ }
return FALSE;
}
@@ -1611,7 +1623,6 @@ nm_platform_ip4_route_sync (int ifindex, const GArray *known_routes)
routes = nm_platform_ip4_route_get_all (ifindex, FALSE);
for (i = 0; i < routes->len; i++) {
route = &g_array_index (routes, NMPlatformIP4Route, i);
- route->ifindex = 0;
if (!array_contains_ip4_route (known_routes, route))
nm_platform_ip4_route_delete (ifindex, route->network, route->plen, route->metric);
@@ -1725,6 +1736,34 @@ _to_string_dev (int ifindex, char *buf, size_t size)
buf[0] = 0;
}
+static const char *
+source_to_string (NMPlatformSource source)
+{
+ switch (source) {
+ case NM_PLATFORM_SOURCE_KERNEL:
+ return "kernel";
+ case NM_PLATFORM_SOURCE_SHARED:
+ return "shared";
+ case NM_PLATFORM_SOURCE_IP4LL:
+ return "ipv4ll";
+ case NM_PLATFORM_SOURCE_PPP:
+ return "ppp";
+ case NM_PLATFORM_SOURCE_WWAN:
+ return "wwan";
+ case NM_PLATFORM_SOURCE_VPN:
+ return "vpn";
+ case NM_PLATFORM_SOURCE_DHCP:
+ return "dhcp";
+ case NM_PLATFORM_SOURCE_RDISC:
+ return "rdisc";
+ case NM_PLATFORM_SOURCE_USER:
+ return "user";
+ default:
+ break;
+ }
+ return "unknown";
+}
+
/**
* nm_platform_ip4_address_to_string:
* @route: pointer to NMPlatformIP4Address address structure
@@ -1757,11 +1796,12 @@ nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address)
_to_string_dev (address->ifindex, str_dev, sizeof (str_dev));
- g_snprintf (buffer, sizeof (buffer), "%s/%d lft %u pref %u time %u%s%s",
+ g_snprintf (buffer, sizeof (buffer), "%s/%d lft %u pref %u time %u%s%s src %s",
s_address, address->plen, (guint)address->lifetime, (guint)address->preferred,
(guint)address->timestamp,
str_peer ? str_peer : "",
- str_dev);
+ str_dev,
+ source_to_string (address->source));
g_free (str_peer);
return buffer;
}
@@ -1818,12 +1858,13 @@ nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address)
str_flags = s_flags[0] ? g_strconcat (" flags ", s_flags, NULL) : NULL;
- g_snprintf (buffer, sizeof (buffer), "%s/%d lft %u pref %u time %u%s%s%s",
+ g_snprintf (buffer, sizeof (buffer), "%s/%d lft %u pref %u time %u%s%s%s src %s",
s_address, address->plen, (guint)address->lifetime, (guint)address->preferred,
(guint)address->timestamp,
str_peer ? str_peer : "",
str_dev,
- str_flags ? str_flags : "");
+ str_flags ? str_flags : "",
+ source_to_string (address->source));
g_free (str_flags);
g_free (str_peer);
return buffer;
@@ -1855,10 +1896,11 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route)
_to_string_dev (route->ifindex, str_dev, sizeof (str_dev));
- g_snprintf (buffer, sizeof (buffer), "%s/%d via %s%s metric %u mss %u",
+ g_snprintf (buffer, sizeof (buffer), "%s/%d via %s%s metric %u mss %u src %s",
s_network, route->plen, s_gateway,
str_dev,
- route->metric, route->mss);
+ route->metric, route->mss,
+ source_to_string (route->source));
return buffer;
}
@@ -1888,10 +1930,11 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route)
_to_string_dev (route->ifindex, str_dev, sizeof (str_dev));
- g_snprintf (buffer, sizeof (buffer), "%s/%d via %s%s metric %u mss %u",
+ g_snprintf (buffer, sizeof (buffer), "%s/%d via %s%s metric %u mss %u src %s",
s_network, route->plen, s_gateway,
str_dev,
- route->metric, route->mss);
+ route->metric, route->mss,
+ source_to_string (route->source));
return buffer;
}
@@ -1923,9 +1966,10 @@ int
nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b)
{
_CMP_POINTER (a, b);
+ _CMP_FIELD (a, b, ifindex);
+ _CMP_FIELD (a, b, source);
_CMP_FIELD_MEMCMP (a, b, address);
_CMP_FIELD_MEMCMP (a, b, peer_address);
- _CMP_FIELD (a, b, ifindex);
_CMP_FIELD (a, b, plen);
_CMP_FIELD (a, b, timestamp);
_CMP_FIELD (a, b, lifetime);
@@ -1938,6 +1982,7 @@ nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6A
{
_CMP_POINTER (a, b);
_CMP_FIELD (a, b, ifindex);
+ _CMP_FIELD (a, b, source);
_CMP_FIELD_MEMCMP (a, b, address);
_CMP_FIELD_MEMCMP (a, b, peer_address);
_CMP_FIELD (a, b, plen);
@@ -1953,6 +1998,7 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route
{
_CMP_POINTER (a, b);
_CMP_FIELD (a, b, ifindex);
+ _CMP_FIELD (a, b, source);
_CMP_FIELD_MEMCMP (a, b, network);
_CMP_FIELD (a, b, plen);
_CMP_FIELD_MEMCMP (a, b, gateway);
@@ -1966,6 +2012,7 @@ nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route
{
_CMP_POINTER (a, b);
_CMP_FIELD (a, b, ifindex);
+ _CMP_FIELD (a, b, source);
_CMP_FIELD_MEMCMP (a, b, network);
_CMP_FIELD (a, b, plen);
_CMP_FIELD_MEMCMP (a, b, gateway);
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 2725dd9..c4796f1 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -126,8 +126,23 @@ typedef struct {
#define NM_PLATFORM_LIFETIME_PERMANENT G_MAXUINT32
+typedef enum {
+ /* In priority order; higher number == higher priority */
+ NM_PLATFORM_SOURCE_UNKNOWN,
+ NM_PLATFORM_SOURCE_KERNEL,
+ NM_PLATFORM_SOURCE_SHARED,
+ NM_PLATFORM_SOURCE_IP4LL,
+ NM_PLATFORM_SOURCE_PPP,
+ NM_PLATFORM_SOURCE_WWAN,
+ NM_PLATFORM_SOURCE_VPN,
+ NM_PLATFORM_SOURCE_DHCP,
+ NM_PLATFORM_SOURCE_RDISC,
+ NM_PLATFORM_SOURCE_USER,
+} NMPlatformSource;
+
typedef struct {
int ifindex;
+ NMPlatformSource source;
in_addr_t address;
in_addr_t peer_address; /* PTP peer address */
int plen;
@@ -138,6 +153,7 @@ typedef struct {
typedef struct {
int ifindex;
+ NMPlatformSource source;
struct in6_addr address;
struct in6_addr peer_address;
int plen;
@@ -149,6 +165,7 @@ typedef struct {
typedef struct {
int ifindex;
+ NMPlatformSource source;
in_addr_t network;
int plen;
in_addr_t gateway;
@@ -158,6 +175,7 @@ typedef struct {
typedef struct {
int ifindex;
+ NMPlatformSource source;
struct in6_addr network;
int plen;
struct in6_addr gateway;
diff --git a/src/ppp-manager/nm-ppp-manager.c b/src/ppp-manager/nm-ppp-manager.c
index 7b84937..cf085a8 100644
--- a/src/ppp-manager/nm-ppp-manager.c
+++ b/src/ppp-manager/nm-ppp-manager.c
@@ -550,6 +550,7 @@ impl_ppp_manager_set_ip4_config (NMPPPManager *manager,
address.plen = g_value_get_uint (val);
if (address.address && address.plen) {
+ address.source = NM_PLATFORM_SOURCE_PPP;
nm_ip4_config_add_address (config, &address);
} else {
nm_log_err (LOGD_PPP, "invalid IPv4 address received!");
diff --git a/src/tests/test-ip4-config.c b/src/tests/test-ip4-config.c
index 1f2c968..dc3d2a0 100644
--- a/src/tests/test-ip4-config.c
+++ b/src/tests/test-ip4-config.c
@@ -220,6 +220,119 @@ test_merge_subtract_mss_mtu (void)
g_object_unref (cfg3);
}
+static void
+test_compare_with_source (void)
+{
+ NMIP4Config *a, *b;
+ NMPlatformIP4Address addr;
+ NMPlatformIP4Route route;
+
+ a = nm_ip4_config_new ();
+ b = nm_ip4_config_new ();
+
+ /* Address */
+ addr_init (&addr, "1.2.3.4", NULL, 24);
+ addr.source = NM_PLATFORM_SOURCE_USER;
+ nm_ip4_config_add_address (a, &addr);
+
+ addr.source = NM_PLATFORM_SOURCE_VPN;
+ nm_ip4_config_add_address (b, &addr);
+
+ /* Route */
+ route_new (&route, "10.0.0.0", 8, "192.168.1.1");
+ route.source = NM_PLATFORM_SOURCE_USER;
+ nm_ip4_config_add_route (a, &route);
+
+ route.source = NM_PLATFORM_SOURCE_VPN;
+ nm_ip4_config_add_route (b, &route);
+
+ /* Assert that the configs are basically the same, eg that the source is ignored */
+ g_assert (nm_ip4_config_equal (a, b));
+
+ g_object_unref (a);
+ g_object_unref (b);
+}
+
+static void
+test_add_address_with_source (void)
+{
+ NMIP4Config *a;
+ NMPlatformIP4Address addr;
+ const NMPlatformIP4Address *test_addr;
+
+ a = nm_ip4_config_new ();
+
+ /* Test that a higher priority source is not overwritten */
+ addr_init (&addr, "1.2.3.4", NULL, 24);
+ addr.source = NM_PLATFORM_SOURCE_USER;
+ nm_ip4_config_add_address (a, &addr);
+
+ test_addr = nm_ip4_config_get_address (a, 0);
+ g_assert_cmpint (test_addr->source, ==, NM_PLATFORM_SOURCE_USER);
+
+ addr.source = NM_PLATFORM_SOURCE_VPN;
+ nm_ip4_config_add_address (a, &addr);
+
+ test_addr = nm_ip4_config_get_address (a, 0);
+ g_assert_cmpint (test_addr->source, ==, NM_PLATFORM_SOURCE_USER);
+
+ /* Test that a lower priority address source is overwritten */
+ nm_ip4_config_del_address (a, 0);
+ addr.source = NM_PLATFORM_SOURCE_KERNEL;
+ nm_ip4_config_add_address (a, &addr);
+
+ test_addr = nm_ip4_config_get_address (a, 0);
+ g_assert_cmpint (test_addr->source, ==, NM_PLATFORM_SOURCE_KERNEL);
+
+ addr.source = NM_PLATFORM_SOURCE_USER;
+ nm_ip4_config_add_address (a, &addr);
+
+ test_addr = nm_ip4_config_get_address (a, 0);
+ g_assert_cmpint (test_addr->source, ==, NM_PLATFORM_SOURCE_USER);
+
+ g_object_unref (a);
+}
+
+static void
+test_add_route_with_source (void)
+{
+ NMIP4Config *a;
+ NMPlatformIP4Route route;
+ const NMPlatformIP4Route *test_route;
+
+ a = nm_ip4_config_new ();
+
+ /* Test that a higher priority source is not overwritten */
+ route_new (&route, "1.2.3.4", 24, "1.2.3.1");
+ route.source = NM_PLATFORM_SOURCE_USER;
+ nm_ip4_config_add_route (a, &route);
+
+ test_route = nm_ip4_config_get_route (a, 0);
+ g_assert_cmpint (test_route->source, ==, NM_PLATFORM_SOURCE_USER);
+
+ route.source = NM_PLATFORM_SOURCE_VPN;
+ nm_ip4_config_add_route (a, &route);
+
+ test_route = nm_ip4_config_get_route (a, 0);
+ g_assert_cmpint (test_route->source, ==, NM_PLATFORM_SOURCE_USER);
+
+ /* Test that a lower priority address source is overwritten */
+ nm_ip4_config_del_route (a, 0);
+ route.source = NM_PLATFORM_SOURCE_KERNEL;
+ nm_ip4_config_add_route (a, &route);
+
+ test_route = nm_ip4_config_get_route (a, 0);
+ g_assert_cmpint (test_route->source, ==, NM_PLATFORM_SOURCE_KERNEL);
+
+ route.source = NM_PLATFORM_SOURCE_USER;
+ nm_ip4_config_add_route (a, &route);
+
+ test_route = nm_ip4_config_get_route (a, 0);
+ g_assert_cmpint (test_route->source, ==, NM_PLATFORM_SOURCE_USER);
+
+ g_object_unref (a);
+}
+
/*******************************************/
int
@@ -231,6 +344,9 @@ main (int argc, char **argv)
g_test_add_func ("/ip4-config/subtract", test_subtract);
g_test_add_func ("/ip4-config/merge-subtract-mss-mtu", test_merge_subtract_mss_mtu);
+ g_test_add_func ("/ip4-config/compare-with-source", test_compare_with_source);
+ g_test_add_func ("/ip4-config/add-address-with-source", test_add_address_with_source);
+ g_test_add_func ("/ip4-config/add-route-with-source", test_add_route_with_source);
return g_test_run ();
}
diff --git a/src/tests/test-ip6-config.c b/src/tests/test-ip6-config.c
index b8b9c7b..c79ac20 100644
--- a/src/tests/test-ip6-config.c
+++ b/src/tests/test-ip6-config.c
@@ -160,6 +160,119 @@ test_subtract (void)
g_object_unref (dst);
}
+static void
+test_compare_with_source (void)
+{
+ NMIP6Config *a, *b;
+ NMPlatformIP6Address addr;
+ NMPlatformIP6Route route;
+
+ a = nm_ip6_config_new ();
+ b = nm_ip6_config_new ();
+
+ /* Address */
+ addr_init (&addr, "1122:3344:5566::7788", NULL, 64);
+ addr.source = NM_PLATFORM_SOURCE_USER;
+ nm_ip6_config_add_address (a, &addr);
+
+ addr.source = NM_PLATFORM_SOURCE_VPN;
+ nm_ip6_config_add_address (b, &addr);
+
+ /* Route */
+ route_new (&route, "abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2");
+ route.source = NM_PLATFORM_SOURCE_USER;
+ nm_ip6_config_add_route (a, &route);
+
+ route.source = NM_PLATFORM_SOURCE_VPN;
+ nm_ip6_config_add_route (b, &route);
+
+ /* Assert that the configs are basically the same, eg that the source is ignored */
+ g_assert (nm_ip6_config_equal (a, b));
+
+ g_object_unref (a);
+ g_object_unref (b);
+}
+
+static void
+test_add_address_with_source (void)
+{
+ NMIP6Config *a;
+ NMPlatformIP6Address addr;
+ const NMPlatformIP6Address *test_addr;
+
+ a = nm_ip6_config_new ();
+
+ /* Test that a higher priority source is not overwritten */
+ addr_init (&addr, "1122:3344:5566::7788", NULL, 64);
+ addr.source = NM_PLATFORM_SOURCE_USER;
+ nm_ip6_config_add_address (a, &addr);
+
+ test_addr = nm_ip6_config_get_address (a, 0);
+ g_assert_cmpint (test_addr->source, ==, NM_PLATFORM_SOURCE_USER);
+
+ addr.source = NM_PLATFORM_SOURCE_VPN;
+ nm_ip6_config_add_address (a, &addr);
+
+ test_addr = nm_ip6_config_get_address (a, 0);
+ g_assert_cmpint (test_addr->source, ==, NM_PLATFORM_SOURCE_USER);
+
+ /* Test that a lower priority address source is overwritten */
+ nm_ip6_config_del_address (a, 0);
+ addr.source = NM_PLATFORM_SOURCE_KERNEL;
+ nm_ip6_config_add_address (a, &addr);
+
+ test_addr = nm_ip6_config_get_address (a, 0);
+ g_assert_cmpint (test_addr->source, ==, NM_PLATFORM_SOURCE_KERNEL);
+
+ addr.source = NM_PLATFORM_SOURCE_USER;
+ nm_ip6_config_add_address (a, &addr);
+
+ test_addr = nm_ip6_config_get_address (a, 0);
+ g_assert_cmpint (test_addr->source, ==, NM_PLATFORM_SOURCE_USER);
+
+ g_object_unref (a);
+}
+
+static void
+test_add_route_with_source (void)
+{
+ NMIP6Config *a;
+ NMPlatformIP6Route route;
+ const NMPlatformIP6Route *test_route;
+
+ a = nm_ip6_config_new ();
+
+ /* Test that a higher priority source is not overwritten */
+ route_new (&route, "abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2");
+ route.source = NM_PLATFORM_SOURCE_USER;
+ nm_ip6_config_add_route (a, &route);
+
+ test_route = nm_ip6_config_get_route (a, 0);
+ g_assert_cmpint (test_route->source, ==, NM_PLATFORM_SOURCE_USER);
+
+ route.source = NM_PLATFORM_SOURCE_VPN;
+ nm_ip6_config_add_route (a, &route);
+
+ test_route = nm_ip6_config_get_route (a, 0);
+ g_assert_cmpint (test_route->source, ==, NM_PLATFORM_SOURCE_USER);
+
+ /* Test that a lower priority address source is overwritten */
+ nm_ip6_config_del_route (a, 0);
+ route.source = NM_PLATFORM_SOURCE_KERNEL;
+ nm_ip6_config_add_route (a, &route);
+
+ test_route = nm_ip6_config_get_route (a, 0);
+ g_assert_cmpint (test_route->source, ==, NM_PLATFORM_SOURCE_KERNEL);
+
+ route.source = NM_PLATFORM_SOURCE_USER;
+ nm_ip6_config_add_route (a, &route);
+
+ test_route = nm_ip6_config_get_route (a, 0);
+ g_assert_cmpint (test_route->source, ==, NM_PLATFORM_SOURCE_USER);
+
+ g_object_unref (a);
+}
+
/*******************************************/
int
@@ -170,6 +283,9 @@ main (int argc, char **argv)
g_type_init ();
g_test_add_func ("/ip6-config/subtract", test_subtract);
+ g_test_add_func ("/ip6-config/compare-with-source", test_compare_with_source);
+ g_test_add_func ("/ip6-config/add-address-with-source", test_add_address_with_source);
+ g_test_add_func ("/ip6-config/add-route-with-source", test_add_route_with_source);
return g_test_run ();
}
diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c
index 30107a0..e8368a3 100644
--- a/src/vpn-manager/nm-vpn-connection.c
+++ b/src/vpn-manager/nm-vpn-connection.c
@@ -330,6 +330,7 @@ add_ip4_vpn_gateway_route (NMIP4Config *config, NMDevice *parent_device, guint32
if (nm_ip4_config_destination_is_direct (parent_config, vpn_gw, 32))
route.gateway = 0;
+ route.source = NM_PLATFORM_SOURCE_VPN;
nm_ip4_config_add_route (config, &route);
/* Ensure there's a route to the parent device's gateway through the
@@ -340,6 +341,7 @@ add_ip4_vpn_gateway_route (NMIP4Config *config, NMDevice *parent_device, guint32
memset (&route, 0, sizeof (route));
route.network = parent_gw;
route.plen = 32;
+ route.source = NM_PLATFORM_SOURCE_VPN;
nm_ip4_config_add_route (config, &route);
}
@@ -375,6 +377,7 @@ add_ip6_vpn_gateway_route (NMIP6Config *config,
if (nm_ip6_config_destination_is_direct (parent_config, vpn_gw, 128))
route.gateway = in6addr_any;
+ route.source = NM_PLATFORM_SOURCE_VPN;
nm_ip6_config_add_route (config, &route);
/* Ensure there's a route to the parent device's gateway through the
@@ -385,6 +388,7 @@ add_ip6_vpn_gateway_route (NMIP6Config *config,
memset (&route, 0, sizeof (route));
route.network = *parent_gw;
route.plen = 128;
+ route.source = NM_PLATFORM_SOURCE_VPN;
nm_ip6_config_add_route (config, &route);
}
@@ -982,6 +986,7 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
address.plen = g_value_get_uint (val);
if (address.address && address.plen) {
+ address.source = NM_PLATFORM_SOURCE_VPN;
nm_ip4_config_add_address (config, &address);
} else {
nm_log_err (LOGD_VPN, "invalid IP4 config received!");
@@ -1040,6 +1045,7 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
route.network = nm_ip4_route_get_dest (item);
route.plen = nm_ip4_route_get_prefix (item);
route.gateway = nm_ip4_route_get_next_hop (item);
+ route.source = NM_PLATFORM_SOURCE_VPN;
/* Ignore host routes to the VPN gateway since NM adds one itself
* below. Since NM knows more about the routing situation than
@@ -1132,9 +1138,10 @@ nm_vpn_connection_ip6_config_get (DBusGProxy *proxy,
if (val)
address.plen = g_value_get_uint (val);
- if (!IN6_IS_ADDR_UNSPECIFIED (&address.address) && address.plen)
+ if (!IN6_IS_ADDR_UNSPECIFIED (&address.address) && address.plen) {
+ address.source = NM_PLATFORM_SOURCE_VPN;
nm_ip6_config_add_address (config, &address);
- else {
+ } else {
nm_log_err (LOGD_VPN, "invalid IP6 config received!");
g_object_unref (config);
nm_vpn_connection_config_maybe_complete (connection, FALSE);
@@ -1183,6 +1190,7 @@ nm_vpn_connection_ip6_config_get (DBusGProxy *proxy,
route.network = *nm_ip6_route_get_dest (item);
route.plen = nm_ip6_route_get_prefix (item);
route.gateway = *nm_ip6_route_get_next_hop (item);
+ route.source = NM_PLATFORM_SOURCE_VPN;
/* Ignore host routes to the VPN gateway since NM adds one itself
* below. Since NM knows more about the routing situation than
--
1.9.3