summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2014-10-31 18:46:43 +0100
committerThomas Haller <thaller@redhat.com>2014-10-31 18:46:51 +0100
commit76dd38ecc985f2c16cf837c3f6ed66bb42303efd (patch)
treee44228191cea9c8797f44d492961186b7f147981
parent3d9c8f6b8dd395177063577ce32ff2cabf23cef9 (diff)
parentef663c58aa805432c9aafe3939d0b8844e12b201 (diff)
downloadNetworkManager-76dd38ecc985f2c16cf837c3f6ed66bb42303efd.tar.gz
core: merge branch 'th/bgo738590_dhcp_server_route' (bgo #738590)
https://bugzilla.gnome.org/show_bug.cgi?id=738590 Signed-off-by: Thomas Haller <thaller@redhat.com> (cherry picked from commit 119c0625af2f0ac8e7a4437f8b38ffca584fad17)
-rw-r--r--src/NetworkManagerUtils.c12
-rw-r--r--src/NetworkManagerUtils.h17
-rw-r--r--src/dhcp-manager/nm-dhcp-client.c10
-rw-r--r--src/nm-ip4-config.c30
-rw-r--r--src/nm-ip4-config.h2
-rw-r--r--src/nm-ip6-config.c35
-rw-r--r--src/nm-ip6-config.h2
-rw-r--r--src/platform/nm-platform.h2
8 files changed, 99 insertions, 11 deletions
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index fb273822ea..e6814e32e6 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -104,15 +104,15 @@ nm_utils_ip4_address_clear_host_address (in_addr_t addr, guint8 plen)
* @src: source ip6 address
* @plen: prefix length of network
*
- * Note: this function is self assignment save, to update @src inplace, set both
+ * Note: this function is self assignment safe, to update @src inplace, set both
* @dst and @src to the same destination.
*/
-void
+const struct in6_addr *
nm_utils_ip6_address_clear_host_address (struct in6_addr *dst, const struct in6_addr *src, guint8 plen)
{
- g_return_if_fail (plen <= 128);
- g_return_if_fail (src);
- g_return_if_fail (dst);
+ g_return_val_if_fail (plen <= 128, NULL);
+ g_return_val_if_fail (src, NULL);
+ g_return_val_if_fail (dst, NULL);
if (plen < 128) {
guint nbytes = plen / 8;
@@ -128,6 +128,8 @@ nm_utils_ip6_address_clear_host_address (struct in6_addr *dst, const struct in6_
memset (&dst->s6_addr[nbytes], 0, 16 - nbytes);
} else if (src != dst)
*dst = *src;
+
+ return dst;
}
diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h
index 37e6641702..7be316e16a 100644
--- a/src/NetworkManagerUtils.h
+++ b/src/NetworkManagerUtils.h
@@ -36,7 +36,22 @@
gboolean nm_ethernet_address_is_valid (const struct ether_addr *test_addr);
in_addr_t nm_utils_ip4_address_clear_host_address (in_addr_t addr, guint8 plen);
-void nm_utils_ip6_address_clear_host_address (struct in6_addr *dst, const struct in6_addr *src, guint8 plen);
+const struct in6_addr *nm_utils_ip6_address_clear_host_address (struct in6_addr *dst, const struct in6_addr *src, guint8 plen);
+
+/**
+ * nm_utils_ip6_route_metric_normalize:
+ * @metric: the route metric
+ *
+ * For IPv6 route, kernel treats the value 0 as IP6_RT_PRIO_USER (1024).
+ * Thus, when comparing metric (values), we want to treat zero as NM_PLATFORM_ROUTE_METRIC_DEFAULT.
+ *
+ * Returns: @metric, if @metric is not zero, otherwise 1024.
+ */
+static inline guint32
+nm_utils_ip6_route_metric_normalize (guint32 metric)
+{
+ return metric ? metric : 1024 /*NM_PLATFORM_ROUTE_METRIC_DEFAULT*/;
+}
int nm_spawn_process (const char *args);
diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c
index 1f186f3256..0a541a0ed6 100644
--- a/src/dhcp-manager/nm-dhcp-client.c
+++ b/src/dhcp-manager/nm-dhcp-client.c
@@ -1220,13 +1220,13 @@ ip4_options_to_config (NMDHCPClient *self)
str = g_hash_table_lookup (priv->options, "new_dhcp_server_identifier");
if (str) {
if (inet_pton (AF_INET, str, &tmp_addr) > 0) {
- NMPlatformIP4Route route;
- guint32 mask = nm_utils_ip4_prefix_to_netmask (address.plen);
nm_log_info (LOGD_DHCP4, " server identifier %s", str);
- if ((tmp_addr & mask) != (address.address & mask)) {
- /* DHCP server not on assigned subnet, route needed */
- memset (&route, 0, sizeof (route));
+ if ( nm_utils_ip4_address_clear_host_address(tmp_addr, address.plen) != nm_utils_ip4_address_clear_host_address(address.address, address.plen)
+ && !nm_ip4_config_get_direct_route_for_host (ip4_config, tmp_addr)) {
+ /* DHCP server not on assigned subnet and the no direct route was returned. Add route */
+ NMPlatformIP4Route route = { 0 };
+
route.network = tmp_addr;
route.plen = 32;
/* this will be a device route if gwaddr is 0 */
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c
index caa638c7d4..7645bfd501 100644
--- a/src/nm-ip4-config.c
+++ b/src/nm-ip4-config.c
@@ -1191,6 +1191,36 @@ nm_ip4_config_get_route (const NMIP4Config *config, guint i)
return &g_array_index (priv->routes, NMPlatformIP4Route, i);
}
+const NMPlatformIP4Route *
+nm_ip4_config_get_direct_route_for_host (const NMIP4Config *config, guint32 host)
+{
+ NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
+ int i;
+ NMPlatformIP4Route *best_route = NULL;
+
+ g_return_val_if_fail (host, NULL);
+
+ for (i = 0; i < priv->routes->len; i++ ) {
+ NMPlatformIP4Route *item = &g_array_index (priv->routes, NMPlatformIP4Route, i);
+
+ if (item->gateway != 0)
+ continue;
+
+ if (best_route && best_route->plen > item->plen)
+ continue;
+
+ if (nm_utils_ip4_address_clear_host_address (host, item->plen) != nm_utils_ip4_address_clear_host_address (item->network, item->plen))
+ continue;
+
+ if (best_route && best_route->metric <= item->metric)
+ continue;
+
+ best_route = item;
+ }
+
+ return best_route;
+}
+
/******************************************************************/
void
diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h
index c9096bb389..cbc8e20f9c 100644
--- a/src/nm-ip4-config.h
+++ b/src/nm-ip4-config.h
@@ -92,6 +92,8 @@ void nm_ip4_config_del_route (NMIP4Config *config, guint i);
guint32 nm_ip4_config_get_num_routes (const NMIP4Config *config);
const NMPlatformIP4Route *nm_ip4_config_get_route (const NMIP4Config *config, guint32 i);
+const NMPlatformIP4Route *nm_ip4_config_get_direct_route_for_host (const NMIP4Config *config, guint32 host);
+
/* Nameservers */
void nm_ip4_config_reset_nameservers (NMIP4Config *config);
void nm_ip4_config_add_nameserver (NMIP4Config *config, guint32 nameserver);
diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c
index 142e5a1947..e1a35eeb86 100644
--- a/src/nm-ip6-config.c
+++ b/src/nm-ip6-config.c
@@ -1194,6 +1194,41 @@ nm_ip6_config_get_route (const NMIP6Config *config, guint i)
return &g_array_index (priv->routes, NMPlatformIP6Route, i);
}
+const NMPlatformIP6Route *
+nm_ip6_config_get_direct_route_for_host (const NMIP6Config *config, const struct in6_addr *host)
+{
+ NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
+ int i;
+ struct in6_addr network2, host2;
+ NMPlatformIP6Route *best_route = NULL;
+
+ g_return_val_if_fail (host && !IN6_IS_ADDR_UNSPECIFIED (host), NULL);
+
+ for (i = 0; i < priv->routes->len; i++ ) {
+ NMPlatformIP6Route *item = &g_array_index (priv->routes, NMPlatformIP6Route, i);
+
+ if (!IN6_IS_ADDR_UNSPECIFIED (&item->gateway))
+ continue;
+
+ if (best_route && best_route->plen > item->plen)
+ continue;
+
+ nm_utils_ip6_address_clear_host_address (&host2, host, item->plen);
+ nm_utils_ip6_address_clear_host_address (&network2, &item->network, item->plen);
+
+ if (!IN6_ARE_ADDR_EQUAL (&network2, &host2))
+ continue;
+
+ if (best_route &&
+ nm_utils_ip6_route_metric_normalize (best_route->metric) <= nm_utils_ip6_route_metric_normalize (item->metric))
+ continue;
+
+ best_route = item;
+ }
+
+ return best_route;
+}
+
/******************************************************************/
void
diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h
index b7b9d83ec7..9a7309deb4 100644
--- a/src/nm-ip6-config.h
+++ b/src/nm-ip6-config.h
@@ -93,6 +93,8 @@ void nm_ip6_config_del_route (NMIP6Config *config, guint i);
guint32 nm_ip6_config_get_num_routes (const NMIP6Config *config);
const NMPlatformIP6Route *nm_ip6_config_get_route (const NMIP6Config *config, guint32 i);
+const NMPlatformIP6Route *nm_ip6_config_get_direct_route_for_host (const NMIP6Config *config, const struct in6_addr *host);
+
/* Nameservers */
void nm_ip6_config_reset_nameservers (NMIP6Config *config);
void nm_ip6_config_add_nameserver (NMIP6Config *config, const struct in6_addr *nameserver);
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 348d1fa546..275557cf29 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -230,6 +230,8 @@ G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPAddress, address_ptr) == G_STRUCT_
#undef __NMPlatformIPAddress_COMMON
+/* Adding an IPv6 route with metric 0, kernel translates to IP6_RT_PRIO_USER (1024).
+ * Thus, the value is not choosen arbitraily, but matches kernel IPv6 default. */
#define NM_PLATFORM_ROUTE_METRIC_DEFAULT 1024
#define __NMPlatformIPRoute_COMMON \