Commit 5b0f895e authored by Thomas Haller's avatar Thomas Haller
Browse files

libnm,core: add TABLE attribute for routes settings

https://bugzilla.redhat.com/show_bug.cgi?id=1436531
parent c71f26bf
......@@ -1187,6 +1187,7 @@ nm_ip_route_set_attribute (NMIPRoute *route, const char *name, GVariant *value)
&(NMVariantAttributeSpec) { name, type, v4, v6, str_type }
static const NMVariantAttributeSpec * const ip_route_attribute_spec[] = {
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_TABLE, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_SRC, G_VARIANT_TYPE_STRING, TRUE, TRUE, 'a'),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_FROM, G_VARIANT_TYPE_STRING, FALSE, TRUE, 'p'),
ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_TOS, G_VARIANT_TYPE_BYTE, TRUE, FALSE, 0 ),
......
......@@ -131,6 +131,7 @@ gboolean nm_ip_route_attribute_validate (const char *name,
gboolean *known,
GError **error);
#define NM_IP_ROUTE_ATTRIBUTE_TABLE "table"
#define NM_IP_ROUTE_ATTRIBUTE_SRC "src"
#define NM_IP_ROUTE_ATTRIBUTE_FROM "from"
#define NM_IP_ROUTE_ATTRIBUTE_TOS "tos"
......
......@@ -1700,6 +1700,46 @@ out:
return nm_utils_ip_route_metric_normalize (addr_family, route_metric);
}
static NMIPRouteTableSyncMode
get_route_table_sync (NMDevice *self, int addr_family)
{
NMConnection *connection;
NMSettingIPConfig *s_ip;
NMIPRouteTableSyncMode route_table_sync = NM_IP_ROUTE_TABLE_SYNC_MODE_DEFAULT;
nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
connection = nm_device_get_applied_connection (self);
if (connection) {
if (addr_family == AF_INET)
s_ip = nm_connection_get_setting_ip4_config (connection);
else
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);
}
if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_DEFAULT) {
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);
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;
}
const NMPObject *
nm_device_get_best_default_route (NMDevice *self,
int addr_family)
......@@ -9902,7 +9942,8 @@ nm_device_set_ip4_config (NMDevice *self,
if (commit && new_config) {
_commit_mtu (self, new_config);
success = nm_ip4_config_commit (new_config,
nm_device_get_platform (self));
nm_device_get_platform (self),
get_route_table_sync (self, AF_INET));
nm_platform_ip4_dev_route_blacklist_set (nm_device_get_platform (self),
nm_ip4_config_get_ifindex (new_config),
ip4_dev_route_blacklist);
......@@ -10075,6 +10116,7 @@ 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),
&temporary_not_available);
if (!_rt6_temporary_not_available_set (self, temporary_not_available))
......
......@@ -31,6 +31,8 @@
#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
......
......@@ -128,7 +128,8 @@ dhcp4_state_changed (NMDhcpClient *client,
global_opt.priority_v4,
&ip4_dev_route_blacklist);
if (!nm_ip4_config_commit (existing,
NM_PLATFORM_GET))
NM_PLATFORM_GET,
NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN))
_LOGW (LOGD_DHCP4, "failed to apply DHCPv4 config");
nm_platform_ip4_dev_route_blacklist_set (NM_PLATFORM_GET,
......@@ -228,7 +229,10 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
nm_ip6_config_merge (existing, ndisc_config, NM_IP_CONFIG_MERGE_DEFAULT);
nm_ip6_config_add_device_routes (existing,
global_opt.priority_v6);
if (!nm_ip6_config_commit (existing, NM_PLATFORM_GET, NULL))
if (!nm_ip6_config_commit (existing,
NM_PLATFORM_GET,
NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN,
NULL))
_LOGW (LOGD_IP6, "failed to apply IPv6 config");
}
......
......@@ -705,8 +705,6 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
priv->has_gateway = TRUE;
}
if (route->table_coerced)
continue;
_add_route (self, plobj, NULL, NULL);
}
......@@ -821,7 +819,8 @@ nm_ip4_config_add_device_routes (NMIP4Config *self,
gboolean
nm_ip4_config_commit (const NMIP4Config *self,
NMPlatform *platform)
NMPlatform *platform,
NMIPRouteTableSyncMode route_table_sync)
{
gs_unref_ptrarray GPtrArray *addresses = NULL;
gs_unref_ptrarray GPtrArray *routes = NULL;
......@@ -842,7 +841,8 @@ nm_ip4_config_commit (const NMIP4Config *self,
routes_prune = nm_platform_ip_route_get_prune_list (platform,
AF_INET,
ifindex);
ifindex,
route_table_sync);
nm_platform_ip4_address_sync (platform, ifindex, addresses);
......@@ -868,6 +868,10 @@ 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);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TOS, tos, BYTE, byte);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, window, UINT32, uint32);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_CWND, cwnd, UINT32, uint32);
......@@ -3050,11 +3054,18 @@ out_addresses_cached:
"metric",
g_variant_new_uint32 (route->metric));
if (!nm_platform_route_table_is_main (route->table_coerced)) {
g_variant_builder_add (&route_builder, "{sv}",
"table",
g_variant_new_uint32 (nm_platform_route_table_uncoerce (route->table_coerced, TRUE)));
}
g_variant_builder_add (&builder_data, "a{sv}", &route_builder);
/* legacy versions of nm_ip4_route_set_prefix() in libnm-util assert that the
* plen is positive. Skip the default routes not to break older clients. */
if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) {
if ( nm_platform_route_table_is_main (route->table_coerced)
&& !NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) {
const guint32 dbus_route[4] = {
route->network,
route->plen,
......
......@@ -156,7 +156,8 @@ void nm_ip4_config_add_device_routes (NMIP4Config *self,
GPtrArray **out_ip4_dev_route_blacklist);
gboolean nm_ip4_config_commit (const NMIP4Config *self,
NMPlatform *platform);
NMPlatform *platform,
NMIPRouteTableSyncMode route_table_sync);
void nm_ip4_config_merge_setting (NMIP4Config *self, NMSettingIPConfig *setting, guint32 default_route_metric);
NMSetting *nm_ip4_config_create_setting (const NMIP4Config *self);
......
......@@ -502,8 +502,6 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
has_gateway = TRUE;
}
if (route->table_coerced)
continue;
_add_route (self, plobj, NULL, NULL);
}
......@@ -604,6 +602,7 @@ nm_ip6_config_add_device_routes (NMIP6Config *self,
gboolean
nm_ip6_config_commit (const NMIP6Config *self,
NMPlatform *platform,
NMIPRouteTableSyncMode route_table_sync,
GPtrArray **out_temporary_not_available)
{
gs_unref_ptrarray GPtrArray *addresses = NULL;
......@@ -625,7 +624,8 @@ nm_ip6_config_commit (const NMIP6Config *self,
routes_prune = nm_platform_ip_route_get_prune_list (platform,
AF_INET6,
ifindex);
ifindex,
route_table_sync);
nm_platform_ip6_address_sync (platform, ifindex, addresses, TRUE);
......@@ -651,6 +651,10 @@ 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);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, window, UINT32, uint32);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_CWND, cwnd, UINT32, uint32);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_INITCWND, initcwnd, UINT32, uint32);
......@@ -2714,11 +2718,18 @@ out_addresses_cached:
"metric",
g_variant_new_uint32 (route->metric));
if (!nm_platform_route_table_is_main (route->table_coerced)) {
g_variant_builder_add (&route_builder, "{sv}",
"table",
g_variant_new_uint32 (nm_platform_route_table_uncoerce (route->table_coerced, TRUE)));
}
g_variant_builder_add (&builder_data, "a{sv}", &route_builder);
/* legacy versions of nm_ip6_route_set_prefix() in libnm-util assert that the
* plen is positive. Skip the default routes not to break older clients. */
if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) {
if ( nm_platform_route_table_is_main (route->table_coerced)
&& !NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) {
g_variant_builder_add (&builder_legacy, "(@ayu@ayu)",
g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
&route->network, 16, 1),
......
......@@ -113,6 +113,7 @@ void nm_ip6_config_add_device_routes (NMIP6Config *self,
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);
NMSetting *nm_ip6_config_create_setting (const NMIP6Config *self);
......
......@@ -1988,6 +1988,7 @@ static NMPObject *
_new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
{
static struct nla_policy policy[RTA_MAX+1] = {
[RTA_TABLE] = { .type = NLA_U32 },
[RTA_IIF] = { .type = NLA_U32 },
[RTA_OIF] = { .type = NLA_U32 },
[RTA_PRIORITY] = { .type = NLA_U32 },
......@@ -2010,7 +2011,6 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
} nh;
guint32 mss;
guint32 window = 0, cwnd = 0, initcwnd = 0, initrwnd = 0, mtu = 0, lock = 0;
guint32 table;
if (!nlmsg_valid_hdr (nlh, sizeof (*rtm)))
return NULL;
......@@ -2030,10 +2030,6 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
if (err < 0)
goto errout;
table = tb[RTA_TABLE]
? nla_get_u32 (tb[RTA_TABLE])
: (guint32) rtm->rtm_table;
/*****************************************************************/
is_v4 = rtm->rtm_family == AF_INET;
......@@ -2149,7 +2145,10 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
obj = nmp_object_new (is_v4 ? NMP_OBJECT_TYPE_IP4_ROUTE : NMP_OBJECT_TYPE_IP6_ROUTE, NULL);
obj->ip_route.table_coerced = nm_platform_route_table_coerce (table);
obj->ip_route.table_coerced = nm_platform_route_table_coerce ( tb[RTA_TABLE]
? nla_get_u32 (tb[RTA_TABLE])
: (guint32) rtm->rtm_table);
obj->ip_route.ifindex = nh.ifindex;
if (_check_addr_or_errout (tb, RTA_DST, addr_len))
......
......@@ -3592,18 +3592,56 @@ _err_inval_due_to_ipv6_tentative_pref_src (NMPlatform *self, const NMPObject *ob
GPtrArray *
nm_platform_ip_route_get_prune_list (NMPlatform *self,
int addr_family,
int ifindex)
int ifindex,
NMIPRouteTableSyncMode route_table_sync)
{
NMPLookup lookup;
GPtrArray *routes_prune;
const NMDedupMultiHeadEntry *head_entry;
CList *iter;
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_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
: NMP_OBJECT_TYPE_IP6_ROUTE,
ifindex);
head_entry = nm_platform_lookup (self, &lookup);
if (!head_entry)
return NULL;
routes_prune = g_ptr_array_new_full (head_entry->len,
(GDestroyNotify) nm_dedup_multi_obj_unref);
c_list_for_each (iter, &head_entry->lst_entries_head) {
const NMPObject *obj = c_list_entry (iter, NMDedupMultiEntry, lst_entries)->obj;
return nm_platform_lookup_addrroute_clone (self,
addr_family == AF_INET
? NMP_OBJECT_TYPE_IP4_ROUTE
: NMP_OBJECT_TYPE_IP6_ROUTE,
ifindex,
nm_platform_lookup_predicate_routes_main,
NULL);
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))
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))
continue;
} else
nm_assert (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_ALL);
g_ptr_array_add (routes_prune, (gpointer) nmp_object_ref (obj));
}
if (routes_prune->len == 0) {
g_ptr_array_unref (routes_prune);
return NULL;
}
return routes_prune;
}
/**
......@@ -3800,21 +3838,19 @@ nm_platform_ip_route_flush (NMPlatform *self,
if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET)) {
gs_unref_ptrarray GPtrArray *routes_prune = NULL;
routes_prune = nm_platform_lookup_addrroute_clone (self,
NMP_OBJECT_TYPE_IP4_ROUTE,
ifindex,
NULL,
NULL);
routes_prune = nm_platform_ip_route_get_prune_list (self,
AF_INET,
ifindex,
NM_IP_ROUTE_TABLE_SYNC_MODE_ALL);
success &= nm_platform_ip_route_sync (self, AF_INET, ifindex, NULL, routes_prune, NULL);
}
if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET6)) {
gs_unref_ptrarray GPtrArray *routes_prune = NULL;
routes_prune = nm_platform_lookup_addrroute_clone (self,
NMP_OBJECT_TYPE_IP6_ROUTE,
ifindex,
NULL,
NULL);
routes_prune = nm_platform_ip_route_get_prune_list (self,
AF_INET6,
ifindex,
NM_IP_ROUTE_TABLE_SYNC_MODE_ALL);
success &= nm_platform_ip_route_sync (self, AF_INET6, ifindex, NULL, routes_prune, NULL);
}
return success;
......
......@@ -1219,7 +1219,8 @@ gboolean nm_platform_ip_route_delete (NMPlatform *self, const NMPObject *route);
GPtrArray *nm_platform_ip_route_get_prune_list (NMPlatform *self,
int addr_family,
int ifindex);
int ifindex,
NMIPRouteTableSyncMode route_table_sync);
gboolean nm_platform_ip_route_sync (NMPlatform *self,
int addr_family,
......
......@@ -468,6 +468,7 @@ typedef struct {
enum {
/* route attributes */
PARSE_LINE_ATTR_ROUTE_TABLE,
PARSE_LINE_ATTR_ROUTE_SRC,
PARSE_LINE_ATTR_ROUTE_FROM,
PARSE_LINE_ATTR_ROUTE_TOS,
......@@ -530,6 +531,8 @@ parse_route_line (const char *line,
char buf1[256];
char buf2[256];
ParseLineInfo infos[] = {
[PARSE_LINE_ATTR_ROUTE_TABLE] = { .key = NM_IP_ROUTE_ATTRIBUTE_TABLE,
.type = PARSE_LINE_TYPE_UINT32, },
[PARSE_LINE_ATTR_ROUTE_SRC] = { .key = NM_IP_ROUTE_ATTRIBUTE_SRC,
.type = PARSE_LINE_TYPE_ADDR, },
[PARSE_LINE_ATTR_ROUTE_FROM] = { .key = NM_IP_ROUTE_ATTRIBUTE_FROM,
......@@ -816,6 +819,11 @@ next:
info->key,
g_variant_new_byte (info->v.uint8));
break;
case PARSE_LINE_TYPE_UINT32:
nm_ip_route_set_attribute (route,
info->key,
g_variant_new_uint32 (info->v.uint32));
break;
case PARSE_LINE_TYPE_UINT32_WITH_LOCK:
if (info->v.uint32_with_lock.lock) {
nm_ip_route_set_attribute (route,
......
......@@ -1868,6 +1868,8 @@ get_route_attributes_string (NMIPRoute *route, int family)
}
} else if (nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_TOS)) {
g_string_append_printf (str, "%s 0x%02x", names[i], (unsigned) g_variant_get_byte (attr));
} else if (nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_TABLE)) {
g_string_append_printf (str, "%s %u", names[i], (unsigned) g_variant_get_uint32 (attr));
} else if ( nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_SRC)
|| nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_FROM)) {
char *arg = nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_SRC) ? "src" : "from";
......
......@@ -186,6 +186,8 @@ static void get_secrets (NMVpnConnection *self,
SecretsReq secrets_idx,
const char **hints);
static NMIPRouteTableSyncMode get_route_table_sync (NMVpnConnection *self, int addr_family);
static void plugin_interactive_secrets_required (NMVpnConnection *self,
const char *message,
const char **secrets);
......@@ -1149,7 +1151,8 @@ nm_vpn_connection_apply_config (NMVpnConnection *self)
if (priv->ip4_config) {
nm_assert (priv->ip_ifindex == nm_ip4_config_get_ifindex (priv->ip4_config));
if (!nm_ip4_config_commit (priv->ip4_config,
nm_netns_get_platform (priv->netns)))
nm_netns_get_platform (priv->netns),
get_route_table_sync (self, AF_INET)))
return FALSE;
nm_platform_ip4_dev_route_blacklist_set (nm_netns_get_platform (priv->netns),
priv->ip_ifindex,
......@@ -1160,6 +1163,7 @@ 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),
NULL))
return FALSE;
}
......@@ -1431,6 +1435,32 @@ 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)
{
NMConnection *connection;
NMSettingIPConfig *s_ip;
NMIPRouteTableSyncMode route_table_sync = NM_IP_ROUTE_TABLE_SYNC_MODE_DEFAULT;
nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
connection = _get_applied_connection (self);
if (connection) {
if (addr_family == AF_INET)
s_ip = nm_connection_get_setting_ip4_config (connection);
else
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);
}
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;
}
static void
nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict)
{
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment