summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2017-09-28 08:40:41 +0200
committerThomas Haller <thaller@redhat.com>2017-10-09 22:05:36 +0200
commitcc1ee1d286a3de84fcebc33088d12fee21145d8a (patch)
treeef33eea1683d5230e3534869fb4d0225538315d3
parent17ca5c4c0c08116e3d2309b7f25b903440d66194 (diff)
downloadNetworkManager-cc1ee1d286a3de84fcebc33088d12fee21145d8a.tar.gz
all: rework configuring route table support by adding "route-table" setting
We added "ipv4.route-table-sync" and "ipv6.route-table-sync" to not change behavior for users that configured policy routing outside of NetworkManager, for example, via a dispatcher script. Users had to explicitly opt-in for NetworkManager to fully manage all routing tables. These settings were awkward. Replace them with new settings "ipv4.route-table" and "ipv6.route-table". Note that this commit breaks API/ABI on the unstable development branch by removing recently added API. As before, a connection will have no route-table set by default. This has the meaning that policy-routing is not enabled and only the main table will be fully synced. Once the user sets a table, we recognize that and NetworkManager manages all routing tables. The new route-table setting has other important uses: analog to "ipv4.route-metric", it is the default that applies to all routes. Currently it only works for static routes, not DHCP, SLAAC, default-route, etc. That will be implemented later. For static routes, each route still can explicitly set a table, and overwrite the per-connection setting in "ipv4.route-table" and "ipv6.route-table".
-rw-r--r--clients/common/nm-meta-setting-desc.c35
-rw-r--r--clients/common/settings-docs.c.in4
-rw-r--r--libnm-core/nm-dbus-interface.h21
-rw-r--r--libnm-core/nm-setting-ip-config.c90
-rw-r--r--libnm-core/nm-setting-ip-config.h8
-rw-r--r--libnm-core/nm-setting-ip4-config.c7
-rw-r--r--libnm-core/nm-setting-ip6-config.c7
-rw-r--r--libnm-core/tests/test-general.c2
-rw-r--r--libnm/libnm.ver3
-rw-r--r--man/NetworkManager.conf.xml14
-rw-r--r--src/devices/nm-device.c108
-rw-r--r--src/devices/nm-device.h1
-rw-r--r--src/nm-core-utils.h2
-rw-r--r--src/nm-ip4-config.c29
-rw-r--r--src/nm-ip4-config.h7
-rw-r--r--src/nm-ip6-config.c27
-rw-r--r--src/nm-ip6-config.h7
-rw-r--r--src/nm-types.h17
-rw-r--r--src/platform/nm-platform.c8
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c8
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c20
-rw-r--r--src/vpn/nm-vpn-connection.c28
22 files changed, 274 insertions, 179 deletions
diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c
index b6abd666d9..c429f4d41c 100644
--- a/clients/common/nm-meta-setting-desc.c
+++ b/clients/common/nm-meta-setting-desc.c
@@ -5353,11 +5353,18 @@ static const NMMetaPropertyInfo *const property_infos_IP4_CONFIG[] = {
PROPERTY_INFO (NM_SETTING_IP_CONFIG_ROUTE_METRIC, DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTE_METRIC,
.property_type = &_pt_gobject_int,
),
- PROPERTY_INFO (NM_SETTING_IP_CONFIG_ROUTE_TABLE_SYNC, DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTE_TABLE_SYNC,
- .property_type = &_pt_gobject_enum,
- .property_typ_data = DEFINE_PROPERTY_TYP_DATA (
- PROPERTY_TYP_DATA_SUBTYPE (gobject_enum,
- .get_gtype = nm_ip_route_table_sync_mode_get_type,
+ PROPERTY_INFO (NM_SETTING_IP_CONFIG_ROUTE_TABLE, DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTE_TABLE,
+ .property_type = &_pt_gobject_int,
+ .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int,
+ .value_infos = INT_VALUE_INFOS (
+ {
+ .value = 0,
+ .nick = "unspec",
+ },
+ {
+ .value = 254,
+ .nick = "main",
+ }
),
),
),
@@ -5384,7 +5391,6 @@ static const NMMetaPropertyInfo *const property_infos_IP4_CONFIG[] = {
}
),
),
-
),
PROPERTY_INFO (NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_SEND_HOSTNAME,
.property_type = &_pt_gobject_bool,
@@ -5510,11 +5516,18 @@ static const NMMetaPropertyInfo *const property_infos_IP6_CONFIG[] = {
PROPERTY_INFO (NM_SETTING_IP_CONFIG_ROUTE_METRIC, DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ROUTE_METRIC,
.property_type = &_pt_gobject_int,
),
- PROPERTY_INFO (NM_SETTING_IP_CONFIG_ROUTE_TABLE_SYNC, DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ROUTE_TABLE_SYNC,
- .property_type = &_pt_gobject_enum,
- .property_typ_data = DEFINE_PROPERTY_TYP_DATA (
- PROPERTY_TYP_DATA_SUBTYPE (gobject_enum,
- .get_gtype = nm_ip_route_table_sync_mode_get_type,
+ PROPERTY_INFO (NM_SETTING_IP_CONFIG_ROUTE_TABLE, DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ROUTE_TABLE,
+ .property_type = &_pt_gobject_int,
+ .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int,
+ .value_infos = INT_VALUE_INFOS (
+ {
+ .value = 0,
+ .nick = "unspec",
+ },
+ {
+ .value = 254,
+ .nick = "main",
+ }
),
),
),
diff --git a/clients/common/settings-docs.c.in b/clients/common/settings-docs.c.in
index 9de91f2e6b..4860de10ad 100644
--- a/clients/common/settings-docs.c.in
+++ b/clients/common/settings-docs.c.in
@@ -224,7 +224,7 @@
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_NAME N_("The setting's name, which uniquely identifies the setting within the connection. Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".")
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_NEVER_DEFAULT N_("If TRUE, this connection will never be the default connection for this IP type, meaning it will never be assigned the default route by NetworkManager.")
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTE_METRIC N_("The default metric for routes that don't explicitly specify a metric. The default value -1 means that the metric is chosen automatically based on the device type. The metric applies to dynamic routes, manual (static) routes that don't have an explicit metric setting, address prefix routes, and the default route. Note that for IPv6, the kernel accepts zero (0) but coerces it to 1024 (user default). Hence, setting this property to zero effectively mean setting it to 1024. For IPv4, zero is a regular value for the metric.")
-#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTE_TABLE_SYNC N_("The mode how to sync the routes per table. In general, when NetworkManager manages a device it will remove extraneous routes from the routing tables. The sync parameter specifies which tables are synced this way. That means, from which routing table NetworkManager will remove those unexpected, extraneous routes. A value of 1 (none) means that no route tables will not be synced and no routes are removed by NetworkManager. 2 (main) means that only the main table will be synced. 3 (full) will sync all the route tables, except the local table. A value of zero is the default value and allows to be overwritten via global configuration. In absence of global configuration, the default value is 2 (main).")
+#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTE_TABLE N_("Enable policy routing (source routing) and set the routing table used when adding routes. This currently only affects static routes (ipv4.routes and ipv6.routes). However, each static route can individually overwrite the table setting by explicitly specifying a non-zero routing table. If the table setting is left at zero, it is eligible to be overwritten via global configuration. If the property is zero even after applying the global configuration value, policy routing is disabled for the address family of this connection. Policy routing disabled means that NetworkManager will add all routes to the main table (except static routes that explicitly configure a different table). Additionally, NetworkManager will not delete any extraneous routes from tables except the main table. This is to preserve backward compatibility for users who manage routing tables outside of NetworkManager.")
#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTES N_("Array of IP routes.")
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE N_("Configure method for creating the address for use with RFC4862 IPv6 Stateless Address Autoconfiguration. The permitted values are: \"eui64\", or \"stable-privacy\". If the property is set to \"eui64\", the addresses will be generated using the interface tokens derived from hardware address. This makes the host part of the address to stay constant, making it possible to track host's presence when it changes networks. The address changes when the interface hardware is replaced. The value of \"stable-privacy\" enables use of cryptographically secure hash of a secret host-specific key along with the connection's stable-id and the network address as specified by RFC7217. This makes it impossible to use the address track host's presence, and makes the address stable when the network interface hardware is replaced. On D-Bus, the absence of an addr-gen-mode setting equals enabling \"stable-privacy\". For keyfile plugin, the absence of the setting on disk means \"eui64\" so that the property doesn't change on upgrade from older versions. Note that this setting is distinct from the Privacy Extensions as configured by \"ip6-privacy\" property and it does not affect the temporary addresses configured with this option.")
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDRESSES N_("Array of IP addresses.")
@@ -245,7 +245,7 @@
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_NAME N_("The setting's name, which uniquely identifies the setting within the connection. Each setting type has a name unique to that type, for example \"ppp\" or \"wireless\" or \"wired\".")
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_NEVER_DEFAULT N_("If TRUE, this connection will never be the default connection for this IP type, meaning it will never be assigned the default route by NetworkManager.")
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ROUTE_METRIC N_("The default metric for routes that don't explicitly specify a metric. The default value -1 means that the metric is chosen automatically based on the device type. The metric applies to dynamic routes, manual (static) routes that don't have an explicit metric setting, address prefix routes, and the default route. Note that for IPv6, the kernel accepts zero (0) but coerces it to 1024 (user default). Hence, setting this property to zero effectively mean setting it to 1024. For IPv4, zero is a regular value for the metric.")
-#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ROUTE_TABLE_SYNC N_("The mode how to sync the routes per table. In general, when NetworkManager manages a device it will remove extraneous routes from the routing tables. The sync parameter specifies which tables are synced this way. That means, from which routing table NetworkManager will remove those unexpected, extraneous routes. A value of 1 (none) means that no route tables will not be synced and no routes are removed by NetworkManager. 2 (main) means that only the main table will be synced. 3 (full) will sync all the route tables, except the local table. A value of zero is the default value and allows to be overwritten via global configuration. In absence of global configuration, the default value is 2 (main).")
+#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ROUTE_TABLE N_("Enable policy routing (source routing) and set the routing table used when adding routes. This currently only affects static routes (ipv4.routes and ipv6.routes). However, each static route can individually overwrite the table setting by explicitly specifying a non-zero routing table. If the table setting is left at zero, it is eligible to be overwritten via global configuration. If the property is zero even after applying the global configuration value, policy routing is disabled for the address family of this connection. Policy routing disabled means that NetworkManager will add all routes to the main table (except static routes that explicitly configure a different table). Additionally, NetworkManager will not delete any extraneous routes from tables except the main table. This is to preserve backward compatibility for users who manage routing tables outside of NetworkManager.")
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ROUTES N_("Array of IP routes.")
#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_TOKEN N_("Configure the token for draft-chown-6man-tokenised-ipv6-identifiers-02 IPv6 tokenized interface identifiers. Useful with eui64 addr-gen-mode.")
#define DESCRIBE_DOC_NM_SETTING_MACSEC_ENCRYPT N_("Whether the transmitted traffic must be encrypted.")
diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h
index 229c5d253f..8b92dbe7e6 100644
--- a/libnm-core/nm-dbus-interface.h
+++ b/libnm-core/nm-dbus-interface.h
@@ -857,27 +857,6 @@ typedef enum { /*< skip >*/
} NMRollbackResult;
/**
- * NMIPRouteTableSyncMode:
- * @NM_IP_ROUTE_TABLE_SYNC_MODE_DEFAULT: the default value, meaning the value
- * is subject to global configuration default.
- * @NM_IP_ROUTE_TABLE_SYNC_MODE_NONE: no route table is synced. This means,
- * NetworkManager will only add routes for a particular interface to the
- * routing tables, but not delete any routes.
- * @NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN: only the main table is synced. For all
- * other tables, NM won't delete any extra routes.
- * @NM_IP_ROUTE_TABLE_SYNC_MODE_FULL: NM will sync all tables, except the
- * local table (255).
- *
- * Since: 1.10
- */
-typedef enum {
- NM_IP_ROUTE_TABLE_SYNC_MODE_DEFAULT = 0,
- NM_IP_ROUTE_TABLE_SYNC_MODE_NONE = 1,
- NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN = 2,
- NM_IP_ROUTE_TABLE_SYNC_MODE_FULL = 3,
-} NMIPRouteTableSyncMode;
-
-/**
* NMActivationStateFlags:
* @NM_ACTIVATION_STATE_FLAG_NONE: an alias for numeric zero, no flags set.
* @NM_ACTIVATION_STATE_FLAG_IS_MASTER: the device is a master.
diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c
index 69dd91b40b..1ca7a0f976 100644
--- a/libnm-core/nm-setting-ip-config.c
+++ b/libnm-core/nm-setting-ip-config.c
@@ -1378,6 +1378,7 @@ typedef struct {
GPtrArray *addresses; /* array of NMIPAddress */
GPtrArray *routes; /* array of NMIPRoute */
gint64 route_metric;
+ guint32 route_table;
char *gateway;
gboolean ignore_auto_routes;
gboolean ignore_auto_dns;
@@ -1387,7 +1388,6 @@ typedef struct {
gboolean may_fail;
gint dad_timeout;
gint dhcp_timeout;
- int route_table_sync;
} NMSettingIPConfigPrivate;
enum {
@@ -1401,6 +1401,7 @@ enum {
PROP_GATEWAY,
PROP_ROUTES,
PROP_ROUTE_METRIC,
+ PROP_ROUTE_TABLE,
PROP_IGNORE_AUTO_ROUTES,
PROP_IGNORE_AUTO_DNS,
PROP_DHCP_HOSTNAME,
@@ -1409,7 +1410,6 @@ enum {
PROP_MAY_FAIL,
PROP_DAD_TIMEOUT,
PROP_DHCP_TIMEOUT,
- PROP_ROUTE_TABLE_SYNC,
LAST_PROP
};
@@ -2270,22 +2270,22 @@ nm_setting_ip_config_get_route_metric (NMSettingIPConfig *setting)
}
/**
- * nm_setting_ip_config_get_route_table_sync:
+ * nm_setting_ip_config_get_route_table:
* @setting: the #NMSettingIPConfig
*
- * Returns the value contained in the #NMSettingIPConfig:route-table-sync
+ * Returns the value contained in the #NMSettingIPConfig:route-table
* property.
*
- * Returns: the configured route-table-sync mode.
+ * Returns: the configured route-table.
*
* Since: 1.10
**/
-NMIPRouteTableSyncMode
-nm_setting_ip_config_get_route_table_sync (NMSettingIPConfig *setting)
+guint32
+nm_setting_ip_config_get_route_table (NMSettingIPConfig *setting)
{
g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), 0);
- return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->route_table_sync;
+ return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->route_table;
}
/**
@@ -2550,17 +2550,6 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
}
}
- if ( priv->route_table_sync < NM_IP_ROUTE_TABLE_SYNC_MODE_DEFAULT
- || priv->route_table_sync > NM_IP_ROUTE_TABLE_SYNC_MODE_FULL) {
- g_set_error (error,
- NM_CONNECTION_ERROR,
- NM_CONNECTION_ERROR_INVALID_PROPERTY,
- _("invalid route table sync value %d"),
- priv->route_table_sync);
- g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_ROUTE_TABLE_SYNC);
- return FALSE;
- }
-
/* Validate routes */
for (i = 0; i < priv->routes->len; i++) {
NMIPRoute *route = (NMIPRoute *) priv->routes->pdata[i];
@@ -2739,6 +2728,9 @@ set_property (GObject *object, guint prop_id,
case PROP_ROUTE_METRIC:
priv->route_metric = g_value_get_int64 (value);
break;
+ case PROP_ROUTE_TABLE:
+ priv->route_table = g_value_get_uint (value);
+ break;
case PROP_IGNORE_AUTO_ROUTES:
priv->ignore_auto_routes = g_value_get_boolean (value);
break;
@@ -2764,9 +2756,6 @@ set_property (GObject *object, guint prop_id,
case PROP_DHCP_TIMEOUT:
priv->dhcp_timeout = g_value_get_int (value);
break;
- case PROP_ROUTE_TABLE_SYNC:
- priv->route_table_sync = g_value_get_int (value);
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -2812,6 +2801,9 @@ get_property (GObject *object, guint prop_id,
case PROP_ROUTE_METRIC:
g_value_set_int64 (value, priv->route_metric);
break;
+ case PROP_ROUTE_TABLE:
+ g_value_set_uint (value, priv->route_table);
+ break;
case PROP_IGNORE_AUTO_ROUTES:
g_value_set_boolean (value, nm_setting_ip_config_get_ignore_auto_routes (setting));
break;
@@ -2836,9 +2828,6 @@ get_property (GObject *object, guint prop_id,
case PROP_DHCP_TIMEOUT:
g_value_set_int (value, nm_setting_ip_config_get_dhcp_timeout (setting));
break;
- case PROP_ROUTE_TABLE_SYNC:
- g_value_set_int (value, priv->route_table_sync);
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -3064,6 +3053,34 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *setting_class)
G_PARAM_STATIC_STRINGS));
/**
+ * NMSettingIPConfig:route-table:
+ *
+ * Enable policy routing (source routing) and set the routing table used when adding routes.
+ *
+ * This currently only affects static routes (ipv4.routes and ipv6.routes). However,
+ * each static route can individually overwrite the table setting by explicitly
+ * specifying a non-zero routing table.
+ *
+ * If the table setting is left at zero, it is eligible to be overwritten via global
+ * configuration. If the property is zero even after applying the global configuration
+ * value, policy routing is disabled for the address family of this connection.
+ *
+ * Policy routing disabled means that NetworkManager will add all routes to the main
+ * table (except static routes that explicitly configure a different table). Additionally,
+ * NetworkManager will not delete any extraneous routes from tables except the main table.
+ * This is to preserve backward compatibility for users who manage routing tables outside
+ * of NetworkManager.
+ *
+ * Since: 1.10
+ **/
+ g_object_class_install_property
+ (object_class, PROP_ROUTE_TABLE,
+ g_param_spec_uint (NM_SETTING_IP_CONFIG_ROUTE_TABLE, "", "",
+ 0, G_MAXUINT32, 0,
+ G_PARAM_READWRITE |
+ NM_SETTING_PARAM_FUZZY_IGNORE |
+ G_PARAM_STATIC_STRINGS));
+ /**
* NMSettingIPConfig:ignore-auto-routes:
*
* When #NMSettingIPConfig:method is set to "auto" and this property to
@@ -3194,27 +3211,4 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *setting_class)
G_PARAM_READWRITE |
NM_SETTING_PARAM_FUZZY_IGNORE |
G_PARAM_STATIC_STRINGS));
-
- /**
- * NMSettingIPConfig:route-table-sync:
- *
- * The mode how to sync the routes per table. In general, when NetworkManager manages
- * a device it will remove extraneous routes from the routing tables. The
- * sync parameter specifies which tables are synced this way. That means, from
- * which routing table NetworkManager will remove those unexpected, extraneous routes.
- * A value of 1 (none) means that no route tables will not be synced and no routes
- * are removed by NetworkManager. 2 (main) means that only the main table will be synced.
- * 3 (full) will sync all the route tables, except the local table. A value of zero is
- * the default value and allows to be overwritten via global configuration. In absence of
- * global configuration, the default value is 2 (main).
- *
- * Since: 1.10
- **/
- g_object_class_install_property
- (object_class, PROP_ROUTE_TABLE_SYNC,
- g_param_spec_int (NM_SETTING_IP_CONFIG_ROUTE_TABLE_SYNC, "", "",
- G_MININT32, G_MAXINT32, NM_IP_ROUTE_TABLE_SYNC_MODE_DEFAULT,
- G_PARAM_READWRITE |
- NM_SETTING_PARAM_FUZZY_IGNORE |
- G_PARAM_STATIC_STRINGS));
}
diff --git a/libnm-core/nm-setting-ip-config.h b/libnm-core/nm-setting-ip-config.h
index 16aa415684..84ce84657a 100644
--- a/libnm-core/nm-setting-ip-config.h
+++ b/libnm-core/nm-setting-ip-config.h
@@ -175,6 +175,7 @@ gboolean nm_ip_route_attribute_validate (const char *name,
#define NM_SETTING_IP_CONFIG_GATEWAY "gateway"
#define NM_SETTING_IP_CONFIG_ROUTES "routes"
#define NM_SETTING_IP_CONFIG_ROUTE_METRIC "route-metric"
+#define NM_SETTING_IP_CONFIG_ROUTE_TABLE "route-table"
#define NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES "ignore-auto-routes"
#define NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS "ignore-auto-dns"
#define NM_SETTING_IP_CONFIG_DHCP_HOSTNAME "dhcp-hostname"
@@ -183,7 +184,6 @@ gboolean nm_ip_route_attribute_validate (const char *name,
#define NM_SETTING_IP_CONFIG_MAY_FAIL "may-fail"
#define NM_SETTING_IP_CONFIG_DAD_TIMEOUT "dad-timeout"
#define NM_SETTING_IP_CONFIG_DHCP_TIMEOUT "dhcp-timeout"
-#define NM_SETTING_IP_CONFIG_ROUTE_TABLE_SYNC "route-table-sync"
#define NM_SETTING_DNS_OPTION_DEBUG "debug"
#define NM_SETTING_DNS_OPTION_NDOTS "ndots"
@@ -284,6 +284,9 @@ void nm_setting_ip_config_clear_routes (NMSettingIPConfig
gint64 nm_setting_ip_config_get_route_metric (NMSettingIPConfig *setting);
+NM_AVAILABLE_IN_1_10
+guint32 nm_setting_ip_config_get_route_table (NMSettingIPConfig *setting);
+
gboolean nm_setting_ip_config_get_ignore_auto_routes (NMSettingIPConfig *setting);
gboolean nm_setting_ip_config_get_ignore_auto_dns (NMSettingIPConfig *setting);
@@ -297,9 +300,6 @@ gint nm_setting_ip_config_get_dad_timeout (NMSettingIPConfig
NM_AVAILABLE_IN_1_2
gint nm_setting_ip_config_get_dhcp_timeout (NMSettingIPConfig *setting);
-NM_AVAILABLE_IN_1_10
-NMIPRouteTableSyncMode nm_setting_ip_config_get_route_table_sync (NMSettingIPConfig *setting);
-
G_END_DECLS
#endif /* NM_SETTING_IP_CONFIG_H */
diff --git a/libnm-core/nm-setting-ip4-config.c b/libnm-core/nm-setting-ip4-config.c
index 7c3cddd6f3..db3a12be41 100644
--- a/libnm-core/nm-setting-ip4-config.c
+++ b/libnm-core/nm-setting-ip4-config.c
@@ -681,11 +681,10 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *ip4_class)
*/
/* ---ifcfg-rh---
- * property: route-table-sync
- * variable: IPV4_ROUTE_TABLE_SYNC(+)
+ * property: route-table
+ * variable: IPV4_ROUTE_TABLE(+)
* default: 0
- * description: IPV4_ROUTE_TABLE_SYNC controls how NetworkManager removes extraneous
- * routes from the routing tables.
+ * description: IPV4_ROUTE_TABLE enables policy-routing and sets the default routing table.
* ---end---
*/
diff --git a/libnm-core/nm-setting-ip6-config.c b/libnm-core/nm-setting-ip6-config.c
index 7ebb3df8c9..11d9c54793 100644
--- a/libnm-core/nm-setting-ip6-config.c
+++ b/libnm-core/nm-setting-ip6-config.c
@@ -653,11 +653,10 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *ip6_class)
*/
/* ---ifcfg-rh---
- * property: route-table-sync
- * variable: IPV6_ROUTE_TABLE_SYNC(+)
+ * property: route-table
+ * variable: IPV6_ROUTE_TABLE(+)
* default: 0
- * description: IPV6_ROUTE_TABLE_SYNC controls how NetworkManager removes extraneous
- * routes from the routing tables.
+ * description: IPV6_ROUTE_TABLE enables policy-routing and sets the default routing table.
* ---end---
*/
diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c
index 257fdad5a1..b95e307cd7 100644
--- a/libnm-core/tests/test-general.c
+++ b/libnm-core/tests/test-general.c
@@ -2479,7 +2479,7 @@ test_connection_diff_a_only (void)
{ NM_SETTING_IP_CONFIG_GATEWAY, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP_CONFIG_ROUTES, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP_CONFIG_ROUTE_METRIC, NM_SETTING_DIFF_RESULT_IN_A },
- { NM_SETTING_IP_CONFIG_ROUTE_TABLE_SYNC, NM_SETTING_DIFF_RESULT_IN_A },
+ { NM_SETTING_IP_CONFIG_ROUTE_TABLE, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, NM_SETTING_DIFF_RESULT_IN_A },
diff --git a/libnm/libnm.ver b/libnm/libnm.ver
index 72c6224b3a..0fd28beecd 100644
--- a/libnm/libnm.ver
+++ b/libnm/libnm.ver
@@ -1188,9 +1188,8 @@ global:
nm_device_dummy_get_hw_address;
nm_device_ppp_get_type;
nm_ip_route_equal_full;
- nm_ip_route_table_sync_mode_get_type;
nm_setting_bridge_get_group_forward_mask;
- nm_setting_ip_config_get_route_table_sync;
+ nm_setting_ip_config_get_route_table;
nm_setting_pppoe_get_parent;
nm_setting_wireless_security_get_pmf;
nm_setting_wireless_security_get_wps_method;
diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml
index 94465a019f..611c7d0798 100644
--- a/man/NetworkManager.conf.xml
+++ b/man/NetworkManager.conf.xml
@@ -684,8 +684,11 @@ ipv6.ip6-privacy=0
<term><varname>ipv4.route-metric</varname></term>
</varlistentry>
<varlistentry>
- <term><varname>ipv4.route-table-sync</varname></term>
- <listitem><para>If left unspecified, the default value is 2 (main).</para></listitem>
+ <term><varname>ipv4.route-table</varname></term>
+ <listitem><para>If left unspecified, routes are only added to the main table. Note that this
+ is different from explicitly selecting the main table 254, because of how NetworkManager
+ removes extraneous routes from the tables.
+ </para></listitem>
</varlistentry>
<varlistentry>
<term><varname>ipv6.dhcp-timeout</varname></term>
@@ -702,8 +705,11 @@ ipv6.ip6-privacy=0
<term><varname>ipv6.route-metric</varname></term>
</varlistentry>
<varlistentry>
- <term><varname>ipv6.route-table-sync</varname></term>
- <listitem><para>If left unspecified, the default value is 2 (main).</para></listitem>
+ <term><varname>ipv6.route-table</varname></term>
+ <listitem><para>If left unspecified, routes are only added to the main table. Note that this
+ is different from explicitly selecting the main table 254, because of how NetworkManager
+ removes extraneous routes from the tables.
+ </para></listitem>
</varlistentry>
<varlistentry>
<term><varname>vpn.timeout</varname></term>
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index e10dc7be53..04b0d0923b 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -34,6 +34,7 @@
#include <arpa/inet.h>
#include <fcntl.h>
#include <linux/if_addr.h>
+#include <linux/rtnetlink.h>
#include "nm-utils/nm-dedup-multi.h"
@@ -317,6 +318,9 @@ typedef struct _NMDevicePrivate {
guint32 mtu_initial;
guint32 ip6_mtu_initial;
+ guint32 v4_route_table;
+ guint32 v6_route_table;
+
/* when carrier goes away, we give a grace period of CARRIER_WAIT_TIME_MS
* until taking action.
*
@@ -337,6 +341,9 @@ typedef struct _NMDevicePrivate {
NMDeviceSysIfaceState sys_iface_state:2;
+ bool v4_route_table_initalized:1;
+ bool v6_route_table_initalized:1;
+
/* Generic DHCP stuff */
char * dhcp_anycast_address;
@@ -1724,15 +1731,28 @@ out:
return nm_utils_ip_route_metric_normalize (addr_family, route_metric);
}
-static NMIPRouteTableSyncMode
-get_route_table_sync (NMDevice *self, int addr_family)
+guint32
+nm_device_get_route_table (NMDevice *self,
+ int addr_family,
+ gboolean fallback_main)
{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMConnection *connection;
NMSettingIPConfig *s_ip;
- NMIPRouteTableSyncMode route_table_sync = NM_IP_ROUTE_TABLE_SYNC_MODE_DEFAULT;
+ guint32 route_table = 0;
nm_assert_addr_family (addr_family);
+ /* the route table setting affects how we sync routes. We shall
+ * not change it while the device is active, hence, cache it. */
+ if (addr_family == AF_INET) {
+ if (priv->v4_route_table_initalized)
+ return priv->v4_route_table ?: (fallback_main ? RT_TABLE_MAIN : 0);
+ } else {
+ if (priv->v6_route_table_initalized)
+ return priv->v6_route_table ?: (fallback_main ? RT_TABLE_MAIN : 0);
+ }
+
connection = nm_device_get_applied_connection (self);
if (connection) {
if (addr_family == AF_INET)
@@ -1741,27 +1761,38 @@ get_route_table_sync (NMDevice *self, int addr_family)
s_ip = nm_connection_get_setting_ip6_config (connection);
if (s_ip)
- route_table_sync = nm_setting_ip_config_get_route_table_sync (s_ip);
- }
+ route_table = nm_setting_ip_config_get_route_table (s_ip);
- if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_DEFAULT) {
- gs_free char *value = NULL;
+ /* we only lookup the global default if we also have an applied
+ * connection. Otherwise, the connection is not active, and the
+ * connection default doesn't matter. */
+ if (route_table == 0) {
+ gs_free char *value = NULL;
- value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA,
- addr_family == AF_INET
- ? "ipv4.route-table-sync"
- : "ipv6.route-table-sync",
- self);
- route_table_sync = _nm_utils_ascii_str_to_int64 (value, 10,
- NM_IP_ROUTE_TABLE_SYNC_MODE_NONE,
- NM_IP_ROUTE_TABLE_SYNC_MODE_FULL,
- NM_IP_ROUTE_TABLE_SYNC_MODE_DEFAULT);
+ value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA,
+ addr_family == AF_INET
+ ? "ipv4.route-table"
+ : "ipv6.route-table",
+ self);
+ route_table = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT32, 0);
+ }
+ }
- if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_DEFAULT)
- route_table_sync = NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN;
+ if (addr_family == AF_INET) {
+ priv->v4_route_table_initalized = TRUE;
+ priv->v4_route_table = route_table;
+ } else {
+ priv->v6_route_table_initalized = TRUE;
+ priv->v6_route_table = route_table;
}
- return route_table_sync;
+ _LOGT (LOGD_DEVICE,
+ "ipv%c.route-table = %u%s",
+ addr_family == AF_INET ? '4' : '6',
+ (guint) (route_table ?: RT_TABLE_MAIN),
+ route_table ? "" : " (policy routing not enabled)");
+
+ return route_table ?: (fallback_main ? RT_TABLE_MAIN : 0);
}
const NMPObject *
@@ -5661,6 +5692,7 @@ ensure_con_ip4_config (NMDevice *self)
priv->con_ip4_config = _ip4_config_new (self);
nm_ip4_config_merge_setting (priv->con_ip4_config,
nm_connection_get_setting_ip4_config (connection),
+ nm_device_get_route_table (self, AF_INET, TRUE),
nm_device_get_route_metric (self, AF_INET));
if (nm_device_sys_iface_state_is_external_or_assume (self)) {
@@ -5686,6 +5718,7 @@ ensure_con_ip6_config (NMDevice *self)
priv->con_ip6_config = _ip6_config_new (self);
nm_ip6_config_merge_setting (priv->con_ip6_config,
nm_connection_get_setting_ip6_config (connection),
+ nm_device_get_route_table (self, AF_INET6, TRUE),
nm_device_get_route_metric (self, AF_INET6));
if (nm_device_sys_iface_state_is_external_or_assume (self)) {
@@ -6007,6 +6040,7 @@ dhcp4_state_changed (NMDhcpClient *client,
manual = _ip4_config_new (self);
nm_ip4_config_merge_setting (manual,
nm_connection_get_setting_ip4_config (connection),
+ nm_device_get_route_table (self, AF_INET, TRUE),
nm_device_get_route_metric (self, AF_INET));
configs = g_new0 (NMIP4Config *, 3);
@@ -6377,6 +6411,7 @@ act_stage3_ip4_config_start (NMDevice *self,
config = _ip4_config_new (self);
nm_ip4_config_merge_setting (config,
nm_connection_get_setting_ip4_config (connection),
+ nm_device_get_route_table (self, AF_INET, TRUE),
nm_device_get_route_metric (self, AF_INET));
configs = g_new0 (NMIP4Config *, 2);
@@ -9084,6 +9119,7 @@ nm_device_reactivate_ip4_config (NMDevice *self,
priv->con_ip4_config = _ip4_config_new (self);
nm_ip4_config_merge_setting (priv->con_ip4_config,
s_ip4_new,
+ nm_device_get_route_table (self, AF_INET, TRUE),
nm_device_get_route_metric (self, AF_INET));
if (!force_restart) {
@@ -9126,6 +9162,7 @@ nm_device_reactivate_ip6_config (NMDevice *self,
priv->con_ip6_config = _ip6_config_new (self);
nm_ip6_config_merge_setting (priv->con_ip6_config,
s_ip6_new,
+ nm_device_get_route_table (self, AF_INET6, TRUE),
nm_device_get_route_metric (self, AF_INET6));
if (!force_restart) {
@@ -9206,7 +9243,27 @@ can_reapply_change (NMDevice *self, const char *setting_name,
NM_SETTING_IP4_CONFIG_SETTING_NAME,
NM_SETTING_IP6_CONFIG_SETTING_NAME,
NM_SETTING_PROXY_SETTING_NAME)) {
- /* accept all */
+ if (g_hash_table_contains (diffs, NM_SETTING_IP_CONFIG_ROUTE_TABLE)) {
+ /* changing the route-table setting is complicated, because it affects
+ * how we sync the routes. Don't support changing it without full
+ * re-activation.
+ *
+ * The problem is really that changing the setting also affects the sync
+ * mode. So, switching from NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN to
+ * NM_IP_ROUTE_TABLE_SYNC_MODE_FULL would somehow require us to get rid
+ * of additional routes, but we don't know which routes were added by NM
+ * and which should be removed.
+ *
+ * Note how nm_device_get_route_table() caches the value for the duration of the
+ * activation. */
+ g_set_error (error,
+ NM_DEVICE_ERROR,
+ NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
+ "Can't reapply changes to '%s.%s' setting",
+ setting_name,
+ NM_SETTING_IP_CONFIG_ROUTE_TABLE);
+ return FALSE;
+ }
return TRUE;
} else {
g_set_error (error,
@@ -10064,7 +10121,9 @@ nm_device_set_ip4_config (NMDevice *self,
_commit_mtu (self, new_config);
success = nm_ip4_config_commit (new_config,
nm_device_get_platform (self),
- get_route_table_sync (self, AF_INET));
+ nm_device_get_route_table (self, AF_INET, FALSE)
+ ? NM_IP_ROUTE_TABLE_SYNC_MODE_FULL
+ : NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN);
nm_platform_ip4_dev_route_blacklist_set (nm_device_get_platform (self),
nm_ip4_config_get_ifindex (new_config),
ip4_dev_route_blacklist);
@@ -10237,7 +10296,9 @@ nm_device_set_ip6_config (NMDevice *self,
success = nm_ip6_config_commit (new_config,
nm_device_get_platform (self),
- get_route_table_sync (self, AF_INET6),
+ nm_device_get_route_table (self, AF_INET6, FALSE)
+ ? NM_IP_ROUTE_TABLE_SYNC_MODE_FULL
+ : NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN,
&temporary_not_available);
if (!_rt6_temporary_not_available_set (self, temporary_not_available))
@@ -12332,6 +12393,9 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type)
priv->v4_commit_first_time = TRUE;
priv->v6_commit_first_time = TRUE;
+ priv->v4_route_table_initalized = FALSE;
+ priv->v6_route_table_initalized = FALSE;
+
priv->linklocal6_dad_counter = 0;
/* Clean up IP configs; this does not actually deconfigure the
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index b02b8d923b..ef83f1b53e 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -447,6 +447,7 @@ NMDeviceType nm_device_get_device_type (NMDevice *dev);
NMLinkType nm_device_get_link_type (NMDevice *dev);
NMMetered nm_device_get_metered (NMDevice *dev);
+guint32 nm_device_get_route_table (NMDevice *self, int addr_family, gboolean fallback_main);
guint32 nm_device_get_route_metric (NMDevice *dev, int addr_family);
const char * nm_device_get_hw_address (NMDevice *dev);
diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h
index d94fba9df0..21ff111a33 100644
--- a/src/nm-core-utils.h
+++ b/src/nm-core-utils.h
@@ -31,8 +31,6 @@
#define NM_PLATFORM_LIFETIME_PERMANENT G_MAXUINT32
-#define NM_IP_ROUTE_TABLE_SYNC_MODE_ALL ((NMIPRouteTableSyncMode) -1)
-
#define NM_DEFINE_SINGLETON_INSTANCE(TYPE) \
static TYPE *singleton_instance
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c
index 9727ace126..498d60dbec 100644
--- a/src/nm-ip4-config.c
+++ b/src/nm-ip4-config.c
@@ -26,6 +26,7 @@
#include <string.h>
#include <arpa/inet.h>
#include <resolv.h>
+#include <linux/rtnetlink.h>
#include "nm-utils/nm-dedup-multi.h"
@@ -674,7 +675,7 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
void
nm_ip4_config_add_device_routes (NMIP4Config *self,
- guint32 default_route_metric,
+ guint32 route_metric,
GPtrArray **out_ip4_dev_route_blacklist)
{
const NMIP4ConfigPrivate *priv;
@@ -720,7 +721,7 @@ nm_ip4_config_add_device_routes (NMIP4Config *self,
route->network = network;
route->plen = addr->plen;
route->pref_src = addr->address;
- route->metric = default_route_metric;
+ route->metric = route_metric;
route->scope_inv = nm_platform_route_scope_inv (NM_RT_SCOPE_LINK);
nm_platform_ip_route_normalize (AF_INET, (NMPlatformIPRoute *) route);
@@ -733,7 +734,7 @@ nm_ip4_config_add_device_routes (NMIP4Config *self,
_add_route (self, nmp_object_ref (r), NULL, NULL);
if ( out_ip4_dev_route_blacklist
- && default_route_metric != NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE) {
+ && route_metric != NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE) {
nm_auto_nmpobj NMPObject *r_dev = NULL;
r_dev = nmp_object_clone (r, FALSE);
@@ -800,9 +801,12 @@ nm_ip4_config_commit (const NMIP4Config *self,
}
static void
-merge_route_attributes (NMIPRoute *s_route, NMPlatformIP4Route *r)
+merge_route_attributes (NMIPRoute *s_route,
+ NMPlatformIP4Route *r,
+ guint32 route_table)
{
GVariant *variant;
+ guint32 u32;
in_addr_t addr;
#define GET_ATTR(name, field, variant_type, type) \
@@ -810,9 +814,11 @@ merge_route_attributes (NMIPRoute *s_route, NMPlatformIP4Route *r)
if (variant && g_variant_is_of_type (variant, G_VARIANT_TYPE_ ## variant_type)) \
r->field = g_variant_get_ ## type (variant);
- r->table_coerced = 254 /* RT_TABLE_MAIN */;
- GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TABLE, table_coerced, UINT32, uint32);
- r->table_coerced = nm_platform_route_table_coerce (r->table_coerced);
+ variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_TABLE);
+ u32 = variant && g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32)
+ ? g_variant_get_uint32 (variant)
+ : 0;
+ r->table_coerced = nm_platform_route_table_coerce (u32 ?: (route_table ?: RT_TABLE_MAIN));
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TOS, tos, BYTE, byte);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, window, UINT32, uint32);
@@ -836,7 +842,10 @@ merge_route_attributes (NMIPRoute *s_route, NMPlatformIP4Route *r)
}
void
-nm_ip4_config_merge_setting (NMIP4Config *self, NMSettingIPConfig *setting, guint32 default_route_metric)
+nm_ip4_config_merge_setting (NMIP4Config *self,
+ NMSettingIPConfig *setting,
+ guint32 route_table,
+ guint32 route_metric)
{
NMIP4ConfigPrivate *priv;
guint naddresses, nroutes, nnameservers, nsearches;
@@ -915,14 +924,14 @@ nm_ip4_config_merge_setting (NMIP4Config *self, NMSettingIPConfig *setting, guin
nm_ip_route_get_next_hop_binary (s_route, &route.gateway);
if (nm_ip_route_get_metric (s_route) == -1)
- route.metric = default_route_metric;
+ route.metric = route_metric;
else
route.metric = nm_ip_route_get_metric (s_route);
route.rt_source = NM_IP_CONFIG_SOURCE_USER;
route.network = nm_utils_ip4_address_clear_host_address (route.network, route.plen);
- merge_route_attributes (s_route, &route);
+ merge_route_attributes (s_route, &route, route_table);
_add_route (self, NULL, &route, NULL);
}
diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h
index a6df1e9db9..68c9ef30a8 100644
--- a/src/nm-ip4-config.h
+++ b/src/nm-ip4-config.h
@@ -152,14 +152,17 @@ 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);
void nm_ip4_config_add_device_routes (NMIP4Config *self,
- guint32 default_route_metric,
+ guint32 route_metric,
GPtrArray **out_ip4_dev_route_blacklist);
gboolean nm_ip4_config_commit (const NMIP4Config *self,
NMPlatform *platform,
NMIPRouteTableSyncMode route_table_sync);
-void nm_ip4_config_merge_setting (NMIP4Config *self, NMSettingIPConfig *setting, guint32 default_route_metric);
+void nm_ip4_config_merge_setting (NMIP4Config *self,
+ NMSettingIPConfig *setting,
+ guint32 route_table,
+ guint32 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 923d2da9bb..a5fb3a3c23 100644
--- a/src/nm-ip6-config.c
+++ b/src/nm-ip6-config.c
@@ -26,6 +26,7 @@
#include <string.h>
#include <arpa/inet.h>
#include <resolv.h>
+#include <linux/rtnetlink.h>
#include "nm-utils/nm-dedup-multi.h"
@@ -469,7 +470,7 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
void
nm_ip6_config_add_device_routes (NMIP6Config *self,
- guint32 default_route_metric)
+ guint32 route_metric)
{
const NMIP6ConfigPrivate *priv;
const NMPlatformIP6Address *addr;
@@ -512,7 +513,7 @@ nm_ip6_config_add_device_routes (NMIP6Config *self,
route->ifindex = ifindex;
route->rt_source = NM_IP_CONFIG_SOURCE_KERNEL;
- route->metric = default_route_metric;
+ route->metric = route_metric;
if (has_peer) {
if (routes_i == 0)
@@ -580,9 +581,12 @@ nm_ip6_config_commit (const NMIP6Config *self,
}
static void
-merge_route_attributes (NMIPRoute *s_route, NMPlatformIP6Route *r)
+merge_route_attributes (NMIPRoute *s_route,
+ NMPlatformIP6Route *r,
+ guint32 route_table)
{
GVariant *variant;
+ guint32 u32;
struct in6_addr addr;
#define GET_ATTR(name, field, variant_type, type) \
@@ -590,9 +594,11 @@ merge_route_attributes (NMIPRoute *s_route, NMPlatformIP6Route *r)
if (variant && g_variant_is_of_type (variant, G_VARIANT_TYPE_ ## variant_type)) \
r->field = g_variant_get_ ## type (variant);
- r->table_coerced = 254 /* RT_TABLE_MAIN */;
- GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TABLE, table_coerced, UINT32, uint32);
- r->table_coerced = nm_platform_route_table_coerce (r->table_coerced);
+ variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_TABLE);
+ u32 = variant && g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32)
+ ? g_variant_get_uint32 (variant)
+ : 0;
+ r->table_coerced = nm_platform_route_table_coerce (u32 ?: (route_table ?: RT_TABLE_MAIN));
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, window, UINT32, uint32);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_CWND, cwnd, UINT32, uint32);
@@ -634,7 +640,10 @@ merge_route_attributes (NMIPRoute *s_route, NMPlatformIP6Route *r)
}
void
-nm_ip6_config_merge_setting (NMIP6Config *self, NMSettingIPConfig *setting, guint32 default_route_metric)
+nm_ip6_config_merge_setting (NMIP6Config *self,
+ NMSettingIPConfig *setting,
+ guint32 route_table,
+ guint32 route_metric)
{
NMIP6ConfigPrivate *priv;
guint naddresses, nroutes, nnameservers, nsearches;
@@ -709,14 +718,14 @@ nm_ip6_config_merge_setting (NMIP6Config *self, NMSettingIPConfig *setting, guin
nm_ip_route_get_next_hop_binary (s_route, &route.gateway);
if (nm_ip_route_get_metric (s_route) == -1)
- route.metric = default_route_metric;
+ route.metric = route_metric;
else
route.metric = nm_ip_route_get_metric (s_route);
route.rt_source = NM_IP_CONFIG_SOURCE_USER;
nm_utils_ip6_address_clear_host_address (&route.network, &route.network, route.plen);
- merge_route_attributes (s_route, &route);
+ merge_route_attributes (s_route, &route, route_table);
_add_route (self, NULL, &route, NULL);
}
diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h
index f8365dfc84..25868fb74b 100644
--- a/src/nm-ip6-config.h
+++ b/src/nm-ip6-config.h
@@ -109,13 +109,16 @@ NMIP6Config *nm_ip6_config_capture (struct _NMDedupMultiIndex *multi_idx, NMPlat
gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary);
void nm_ip6_config_add_device_routes (NMIP6Config *self,
- guint32 default_route_metric);
+ guint32 route_metric);
gboolean nm_ip6_config_commit (const NMIP6Config *self,
NMPlatform *platform,
NMIPRouteTableSyncMode route_table_sync,
GPtrArray **out_temporary_not_available);
-void nm_ip6_config_merge_setting (NMIP6Config *self, NMSettingIPConfig *setting, guint32 default_route_metric);
+void nm_ip6_config_merge_setting (NMIP6Config *self,
+ NMSettingIPConfig *setting,
+ guint32 route_table,
+ guint32 route_metric);
NMSetting *nm_ip6_config_create_setting (const NMIP6Config *self);
diff --git a/src/nm-types.h b/src/nm-types.h
index bd5e249baa..af99bdcfad 100644
--- a/src/nm-types.h
+++ b/src/nm-types.h
@@ -197,6 +197,23 @@ typedef enum {
NM_IP_CONFIG_MERGE_NO_DNS = (1LL << 1),
} NMIPConfigMergeFlags;
+
+/**
+ * NMIPRouteTableSyncMode:
+ * @NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN: only the main table is synced. For all
+ * other tables, NM won't delete any extra routes.
+ * @NM_IP_ROUTE_TABLE_SYNC_MODE_FULL: NM will sync all tables, except the
+ * local table (255).
+ * @NM_IP_ROUTE_TABLE_SYNC_MODE_ALL: NM will sync all tables, including the
+ * local table (255).
+ */
+typedef enum {
+ NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN = 1,
+ NM_IP_ROUTE_TABLE_SYNC_MODE_FULL = 2,
+ NM_IP_ROUTE_TABLE_SYNC_MODE_ALL = 3,
+} NMIPRouteTableSyncMode;
+
+
/* settings */
typedef struct _NMAgentManager NMAgentManager;
typedef struct _NMSecretAgent NMSecretAgent;
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index adf13cb614..9b0929757e 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -3602,14 +3602,10 @@ nm_platform_ip_route_get_prune_list (NMPlatform *self,
nm_assert (NM_IS_PLATFORM (self));
nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
- nm_assert (NM_IN_SET (route_table_sync, NM_IP_ROUTE_TABLE_SYNC_MODE_NONE,
- NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN,
+ nm_assert (NM_IN_SET (route_table_sync, NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN,
NM_IP_ROUTE_TABLE_SYNC_MODE_FULL,
NM_IP_ROUTE_TABLE_SYNC_MODE_ALL));
- if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_NONE)
- return NULL;
-
nmp_lookup_init_addrroute (&lookup,
addr_family == AF_INET
? NMP_OBJECT_TYPE_IP4_ROUTE
@@ -3626,7 +3622,7 @@ nm_platform_ip_route_get_prune_list (NMPlatform *self,
const NMPObject *obj = c_list_entry (iter, NMDedupMultiEntry, lst_entries)->obj;
if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_FULL) {
- if (nm_platform_route_table_uncoerce (NMP_OBJECT_CAST_IP_ROUTE (obj)->table_coerced, TRUE) == (RT_TABLE_LOCAL))
+ if (nm_platform_route_table_uncoerce (NMP_OBJECT_CAST_IP_ROUTE (obj)->table_coerced, TRUE) == RT_TABLE_LOCAL)
continue;
} else if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN) {
if (!nm_platform_route_table_is_main (NMP_OBJECT_CAST_IP_ROUTE (obj)->table_coerced))
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
index 96e3cb10cd..c5dff6a527 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c
@@ -1285,8 +1285,8 @@ make_ip4_setting (shvarFile *ifcfg,
NM_SETTING_IP_CONFIG_MAY_FAIL, !svGetValueBoolean (ifcfg, "IPV4_FAILURE_FATAL", FALSE),
NM_SETTING_IP_CONFIG_ROUTE_METRIC, svGetValueInt64 (ifcfg, "IPV4_ROUTE_METRIC", 10,
-1, G_MAXUINT32, -1),
- NM_SETTING_IP_CONFIG_ROUTE_TABLE_SYNC, (int) svGetValueInt64 (ifcfg, "IPV4_ROUTE_TABLE_SYNC", 10,
- G_MININT32, G_MAXINT32, NM_IP_ROUTE_TABLE_SYNC_MODE_DEFAULT),
+ NM_SETTING_IP_CONFIG_ROUTE_TABLE, (guint) svGetValueInt64 (ifcfg, "IPV4_ROUTE_TABLE", 10,
+ 0, G_MAXUINT32, 0),
NULL);
if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0)
@@ -1717,8 +1717,8 @@ make_ip6_setting (shvarFile *ifcfg,
NM_SETTING_IP_CONFIG_MAY_FAIL, !svGetValueBoolean (ifcfg, "IPV6_FAILURE_FATAL", FALSE),
NM_SETTING_IP_CONFIG_ROUTE_METRIC, svGetValueInt64 (ifcfg, "IPV6_ROUTE_METRIC", 10,
-1, G_MAXUINT32, -1),
- NM_SETTING_IP_CONFIG_ROUTE_TABLE_SYNC, (int) svGetValueInt64 (ifcfg, "IPV6_ROUTE_TABLE_SYNC", 10,
- G_MININT32, G_MAXINT32, NM_IP_ROUTE_TABLE_SYNC_MODE_DEFAULT),
+ NM_SETTING_IP_CONFIG_ROUTE_TABLE, (guint) svGetValueInt64 (ifcfg, "IPV6_ROUTE_TABLE", 10,
+ 0, G_MAXUINT32, 0),
NM_SETTING_IP6_CONFIG_IP6_PRIVACY, ip6_privacy_val,
NULL);
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
index 58b65ec03e..60db801ccd 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
@@ -2023,7 +2023,7 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
gint j;
guint i, num, n;
gint64 route_metric;
- NMIPRouteTableSyncMode route_table_sync;
+ NMIPRouteTableSyncMode route_table;
gint priority;
int timeout;
GString *searches;
@@ -2218,11 +2218,11 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
svSetValueStr (ifcfg, "IPV4_ROUTE_METRIC", tmp);
g_free (tmp);
- route_table_sync = nm_setting_ip_config_get_route_table_sync (s_ip4);
+ route_table = nm_setting_ip_config_get_route_table (s_ip4);
svSetValueInt64_cond (ifcfg,
- "IPV4_ROUTE_TABLE_SYNC",
- route_table_sync != NM_IP_ROUTE_TABLE_SYNC_MODE_DEFAULT,
- route_table_sync);
+ "IPV4_ROUTE_TABLE",
+ route_table != 0,
+ route_table);
/* Static routes - route-<name> file */
route_path = utils_get_route_path (svFileGetName (ifcfg));
@@ -2491,7 +2491,7 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
NMIPAddress *addr;
const char *dns;
gint64 route_metric;
- NMIPRouteTableSyncMode route_table_sync;
+ NMIPRouteTableSyncMode route_table;
GString *ip_str1, *ip_str2, *ip_ptr;
char *route6_path;
NMSettingIP6ConfigAddrGenMode addr_gen_mode;
@@ -2624,11 +2624,11 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
svSetValueStr (ifcfg, "IPV6_ROUTE_METRIC", tmp);
g_free (tmp);
- route_table_sync = nm_setting_ip_config_get_route_table_sync (s_ip6);
+ route_table = nm_setting_ip_config_get_route_table (s_ip6);
svSetValueInt64_cond (ifcfg,
- "IPV6_ROUTE_TABLE_SYNC",
- route_table_sync != NM_IP_ROUTE_TABLE_SYNC_MODE_DEFAULT,
- route_table_sync);
+ "IPV6_ROUTE_TABLE",
+ route_table != 0,
+ route_table);
/* IPv6 Privacy Extensions */
svUnsetValue (ifcfg, "IPV6_PRIVACY");
diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c
index 842bae9b1c..d19007c1e0 100644
--- a/src/vpn/nm-vpn-connection.c
+++ b/src/vpn/nm-vpn-connection.c
@@ -31,6 +31,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
+#include <linux/rtnetlink.h>
#include "nm-proxy-config.h"
#include "nm-ip4-config.h"
@@ -186,7 +187,7 @@ static void get_secrets (NMVpnConnection *self,
SecretsReq secrets_idx,
const char **hints);
-static NMIPRouteTableSyncMode get_route_table_sync (NMVpnConnection *self, int addr_family);
+static guint32 get_route_table (NMVpnConnection *self, int addr_family, gboolean fallback_main);
static void plugin_interactive_secrets_required (NMVpnConnection *self,
const char *message,
@@ -1152,7 +1153,9 @@ nm_vpn_connection_apply_config (NMVpnConnection *self)
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),
- get_route_table_sync (self, AF_INET)))
+ get_route_table (self, AF_INET, FALSE)
+ ? NM_IP_ROUTE_TABLE_SYNC_MODE_FULL
+ : NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN))
return FALSE;
nm_platform_ip4_dev_route_blacklist_set (nm_netns_get_platform (priv->netns),
priv->ip_ifindex,
@@ -1163,7 +1166,9 @@ nm_vpn_connection_apply_config (NMVpnConnection *self)
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),
- get_route_table_sync (self, AF_INET6),
+ get_route_table (self, AF_INET6, FALSE)
+ ? NM_IP_ROUTE_TABLE_SYNC_MODE_FULL
+ : NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN,
NULL))
return FALSE;
}
@@ -1435,12 +1440,14 @@ nm_vpn_connection_get_ip6_route_metric (NMVpnConnection *self)
return (route_metric >= 0) ? route_metric : NM_VPN_ROUTE_METRIC_DEFAULT;
}
-static NMIPRouteTableSyncMode
-get_route_table_sync (NMVpnConnection *self, int addr_family)
+static guint32
+get_route_table (NMVpnConnection *self,
+ int addr_family,
+ gboolean fallback_main)
{
NMConnection *connection;
NMSettingIPConfig *s_ip;
- NMIPRouteTableSyncMode route_table_sync = NM_IP_ROUTE_TABLE_SYNC_MODE_DEFAULT;
+ guint32 route_table = 0;
nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
@@ -1452,13 +1459,10 @@ get_route_table_sync (NMVpnConnection *self, int addr_family)
s_ip = nm_connection_get_setting_ip6_config (connection);
if (s_ip)
- route_table_sync = nm_setting_ip_config_get_route_table_sync (s_ip);
+ route_table = nm_setting_ip_config_get_route_table (s_ip);
}
- if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_DEFAULT)
- route_table_sync = NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN;
-
- return route_table_sync;
+ return route_table ?: (fallback_main ? RT_TABLE_MAIN : 0);
}
static void
@@ -1622,6 +1626,7 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict)
/* Merge in user overrides from the NMConnection's IPv4 setting */
nm_ip4_config_merge_setting (config,
nm_connection_get_setting_ip4_config (_get_applied_connection (self)),
+ get_route_table (self, AF_INET, TRUE),
route_metric);
if (!nm_ip4_config_get_never_default (config)) {
@@ -1802,6 +1807,7 @@ next:
/* Merge in user overrides from the NMConnection's IPv6 setting */
nm_ip6_config_merge_setting (config,
nm_connection_get_setting_ip6_config (_get_applied_connection (self)),
+ get_route_table (self, AF_INET6, TRUE),
route_metric);
if (!nm_ip6_config_get_never_default (config)) {