summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2014-11-11 14:55:07 +0100
committerDan Williams <dcbw@redhat.com>2014-11-13 16:30:22 -0600
commit3642404f769fe9dc97d6ca653635369bf0fbe403 (patch)
treec06b045d014aa8c0325f6e9a0323a8260733f931
parent4d450a81208d680dd2dd8e8367f0e7bfde7494ee (diff)
downloadNetworkManager-3642404f769fe9dc97d6ca653635369bf0fbe403.tar.gz
core: fix route metrics for subnet routes
For IPv4 addresses, the kernel automatically adds a route when configuring an IP address. Unfortunately, there is no way to control this behavior or to set the route metric. Fix this, by adding our own route and removing the kernel provided one. Note that this adds a major change in that we no longer call nm_ip4_config_commit() for assumed devices. https://bugzilla.gnome.org/show_bug.cgi?id=723178 Signed-off-by: Thomas Haller <thaller@redhat.com>
-rw-r--r--src/devices/nm-device.c16
-rw-r--r--src/nm-iface-helper.c2
-rw-r--r--src/nm-ip4-config.c4
-rw-r--r--src/nm-ip4-config.h2
-rw-r--r--src/platform/nm-platform.c20
-rw-r--r--src/platform/nm-platform.h2
-rw-r--r--src/vpn-manager/nm-vpn-connection.c3
7 files changed, 35 insertions, 14 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 263e1f64d3..59eb9c88bc 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -309,6 +309,7 @@ typedef struct {
static gboolean nm_device_set_ip4_config (NMDevice *self,
NMIP4Config *config,
+ guint32 default_route_metric,
gboolean commit,
NMDeviceStateReason *reason);
static gboolean ip4_config_merge_and_apply (NMDevice *self,
@@ -2752,6 +2753,7 @@ ip4_config_merge_and_apply (NMDevice *self,
NMConnection *connection;
gboolean success;
NMIP4Config *composite;
+ guint32 default_route_metric = nm_device_get_ip4_route_metric (self);
/* Merge all the configs into the composite config */
if (config) {
@@ -2785,7 +2787,7 @@ ip4_config_merge_and_apply (NMDevice *self,
if (!nm_settings_connection_get_nm_generated_assumed (NM_SETTINGS_CONNECTION (connection))) {
nm_ip4_config_merge_setting (composite,
nm_connection_get_setting_ip4_config (connection),
- nm_device_get_ip4_route_metric (self));
+ default_route_metric);
}
/* Add the default route.
@@ -2812,7 +2814,7 @@ ip4_config_merge_and_apply (NMDevice *self,
memset (route, 0, sizeof (*route));
route->source = NM_IP_CONFIG_SOURCE_USER;
route->gateway = gateway;
- route->metric = nm_device_get_ip4_route_metric (self);
+ route->metric = default_route_metric;
route->mss = nm_ip4_config_get_mss (composite);
priv->default_route.v4_has = TRUE;
@@ -2838,7 +2840,7 @@ ip4_config_merge_and_apply (NMDevice *self,
NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit (self, composite);
}
- success = nm_device_set_ip4_config (self, composite, commit, out_reason);
+ success = nm_device_set_ip4_config (self, composite, default_route_metric, commit, out_reason);
g_object_unref (composite);
return success;
}
@@ -5520,6 +5522,7 @@ nm_device_get_ip4_config (NMDevice *self)
static gboolean
nm_device_set_ip4_config (NMDevice *self,
NMIP4Config *new_config,
+ guint32 default_route_metric,
gboolean commit,
NMDeviceStateReason *reason)
{
@@ -5540,8 +5543,9 @@ nm_device_set_ip4_config (NMDevice *self,
old_config = priv->ip4_config;
/* Always commit to nm-platform to update lifetimes */
- if (commit && new_config) {
- success = nm_ip4_config_commit (new_config, ip_ifindex);
+ if ( commit && new_config
+ && !nm_device_uses_assumed_connection (self)) {
+ success = nm_ip4_config_commit (new_config, ip_ifindex, default_route_metric);
if (!success)
reason_local = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
}
@@ -6904,7 +6908,7 @@ _cleanup_generic_post (NMDevice *self, gboolean deconfigure)
/* 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, TRUE, &ignored);
+ nm_device_set_ip4_config (self, NULL, 0, TRUE, &ignored);
nm_device_set_ip6_config (self, NULL, TRUE, &ignored);
g_clear_object (&priv->dev_ip4_config);
g_clear_object (&priv->ext_ip4_config);
diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c
index 62f1b2aba4..20df5160da 100644
--- a/src/nm-iface-helper.c
+++ b/src/nm-iface-helper.c
@@ -79,7 +79,7 @@ dhcp4_state_changed (NMDhcpClient *client,
nm_ip4_config_subtract (existing, last_config);
nm_ip4_config_merge (existing, ip4_config);
- if (!nm_ip4_config_commit (existing, ifindex))
+ if (!nm_ip4_config_commit (existing, ifindex, 0))
nm_log_warn (LOGD_DHCP4, "(%s): failed to apply DHCPv4 config", ifname);
if (last_config) {
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c
index 7b59160a36..955e0eddd9 100644
--- a/src/nm-ip4-config.c
+++ b/src/nm-ip4-config.c
@@ -251,7 +251,7 @@ nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf)
}
gboolean
-nm_ip4_config_commit (const NMIP4Config *config, int ifindex)
+nm_ip4_config_commit (const NMIP4Config *config, int ifindex, guint32 default_route_metric)
{
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
guint32 mtu = nm_ip4_config_get_mtu (config);
@@ -261,7 +261,7 @@ nm_ip4_config_commit (const NMIP4Config *config, int ifindex)
g_return_val_if_fail (config != NULL, FALSE);
/* Addresses */
- nm_platform_ip4_address_sync (ifindex, priv->addresses);
+ nm_platform_ip4_address_sync (ifindex, priv->addresses, default_route_metric);
/* Routes */
{
diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h
index afdd8d09a2..5ac455d84f 100644
--- a/src/nm-ip4-config.h
+++ b/src/nm-ip4-config.h
@@ -64,7 +64,7 @@ const char * nm_ip4_config_get_dbus_path (const NMIP4Config *config);
/* Integration with nm-platform and nm-setting */
NMIP4Config *nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf);
-gboolean nm_ip4_config_commit (const NMIP4Config *config, int ifindex);
+gboolean nm_ip4_config_commit (const NMIP4Config *config, int ifindex, guint32 default_route_metric);
void nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, guint32 default_route_metric);
NMSetting *nm_ip4_config_create_setting (const NMIP4Config *config);
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index aeb84745f0..2e61e184f9 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -1734,6 +1734,8 @@ _address_get_lifetime (const NMPlatformIPAddress *address, guint32 now, guint32
* nm_platform_ip4_address_sync:
* @ifindex: Interface index
* @known_addresses: List of addresses
+ * @route_metric: the route metric for adding subnet routes (overwrites
+ * the kernel added routes).
*
* A convenience function to synchronize addresses for a specific interface
* with the least possible disturbance. It simply removes addresses that are
@@ -1742,12 +1744,13 @@ _address_get_lifetime (const NMPlatformIPAddress *address, guint32 now, guint32
* Returns: %TRUE on success.
*/
gboolean
-nm_platform_ip4_address_sync (int ifindex, const GArray *known_addresses)
+nm_platform_ip4_address_sync (int ifindex, const GArray *known_addresses, guint32 route_metric)
{
GArray *addresses;
NMPlatformIP4Address *address;
guint32 now = nm_utils_get_monotonic_timestamp_s ();
int i;
+ const guint32 METRIC_KERNEL_ROUTE = 0;
/* Delete unknown addresses */
addresses = nm_platform_ip4_address_get_all (ifindex);
@@ -1766,6 +1769,7 @@ nm_platform_ip4_address_sync (int ifindex, const GArray *known_addresses)
for (i = 0; i < known_addresses->len; i++) {
const NMPlatformIP4Address *known_address = &g_array_index (known_addresses, NMPlatformIP4Address, i);
guint32 lifetime, preferred;
+ guint32 network;
/* add a padding of 5 seconds to avoid potential races. */
if (!_address_get_lifetime ((NMPlatformIPAddress *) known_address, now, 5, &lifetime, &preferred))
@@ -1773,6 +1777,18 @@ nm_platform_ip4_address_sync (int ifindex, const GArray *known_addresses)
if (!nm_platform_ip4_address_add (ifindex, known_address->address, known_address->peer_address, known_address->plen, lifetime, preferred, known_address->label))
return FALSE;
+
+ if (known_address->plen == 0)
+ continue;
+
+ if (route_metric == METRIC_KERNEL_ROUTE) {
+ /* Kernel already adds routes for us with this metric. */
+ continue;
+ }
+
+ network = nm_utils_ip4_address_clear_host_address (known_address->address, known_address->plen);
+ nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_KERNEL, network, known_address->plen, 0, known_address->address, route_metric, 0);
+ nm_platform_ip4_route_delete (ifindex, network, known_address->plen, METRIC_KERNEL_ROUTE);
}
return TRUE;
@@ -1835,7 +1851,7 @@ nm_platform_ip6_address_sync (int ifindex, const GArray *known_addresses)
gboolean
nm_platform_address_flush (int ifindex)
{
- return nm_platform_ip4_address_sync (ifindex, NULL)
+ return nm_platform_ip4_address_sync (ifindex, NULL, 0)
&& nm_platform_ip6_address_sync (ifindex, NULL);
}
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index c8a40c8223..126b08555a 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -544,7 +544,7 @@ gboolean nm_platform_ip4_address_delete (int ifindex, in_addr_t address, int ple
gboolean nm_platform_ip6_address_delete (int ifindex, struct in6_addr address, int plen);
gboolean nm_platform_ip4_address_exists (int ifindex, in_addr_t address, int plen);
gboolean nm_platform_ip6_address_exists (int ifindex, struct in6_addr address, int plen);
-gboolean nm_platform_ip4_address_sync (int ifindex, const GArray *known_addresses);
+gboolean nm_platform_ip4_address_sync (int ifindex, const GArray *known_addresses, guint32 route_metric);
gboolean nm_platform_ip6_address_sync (int ifindex, const GArray *known_addresses);
gboolean nm_platform_address_flush (int ifindex);
diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c
index c581874880..fdbc393f95 100644
--- a/src/vpn-manager/nm-vpn-connection.c
+++ b/src/vpn-manager/nm-vpn-connection.c
@@ -939,7 +939,8 @@ nm_vpn_connection_apply_config (NMVpnConnection *connection)
nm_platform_link_set_up (priv->ip_ifindex);
if (priv->ip4_config) {
- if (!nm_ip4_config_commit (priv->ip4_config, priv->ip_ifindex))
+ if (!nm_ip4_config_commit (priv->ip4_config, priv->ip_ifindex,
+ nm_vpn_connection_get_ip4_route_metric (connection)))
return FALSE;
}