Commit 9a3117f1 authored by Thomas Haller's avatar Thomas Haller
Browse files

core: track IPv4 device routes in NMIP4Config

For IPv6, we create device routes when processing the RA and add it to
NMIP6Config like any other route. For IPv4 we didn't do that. Instead
we created the list of device routes during nm_ip4_config_commit() and
passed it to nm_platform_ip_route_sync().
parent 4b4efac3
......@@ -496,8 +496,8 @@ static void nm_device_set_proxy_config (NMDevice *self, const char *pac_url);
static gboolean nm_device_set_ip4_config (NMDevice *self,
NMIP4Config *config,
guint32 default_route_metric,
gboolean commit);
gboolean commit,
GPtrArray *ip4_dev_route_blacklist);
static gboolean ip4_config_merge_and_apply (NMDevice *self,
NMIP4Config *config,
gboolean commit);
......@@ -3885,7 +3885,7 @@ nm_device_removed (NMDevice *self, gboolean unconfigure_ip_config)
if (!unconfigure_ip_config)
return;
nm_device_set_ip4_config (self, NULL, 0, FALSE);
nm_device_set_ip4_config (self, NULL, FALSE, NULL);
nm_device_set_ip6_config (self, NULL, FALSE);
}
......@@ -5578,6 +5578,7 @@ ip4_config_merge_and_apply (NMDevice *self,
gboolean ignore_auto_dns = FALSE;
GSList *iter;
NMPlatformIP4Route default_route;
gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL;
/* Merge all the configs into the composite config */
if (config) {
......@@ -5694,12 +5695,19 @@ ip4_config_merge_and_apply (NMDevice *self,
}
END_ADD_DEFAULT_ROUTE:
if (commit) {
nm_ip4_config_add_device_routes (composite,
default_route_metric,
&ip4_dev_route_blacklist);
}
if (commit) {
if (NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit)
NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit (self, composite);
}
success = nm_device_set_ip4_config (self, composite, default_route_metric, commit);
success = nm_device_set_ip4_config (self, composite, commit, ip4_dev_route_blacklist);
g_object_unref (composite);
if (commit)
......@@ -9739,8 +9747,8 @@ 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)
gboolean commit,
GPtrArray *ip4_dev_route_blacklist)
{
NMDevicePrivate *priv;
NMIP4Config *old_config = NULL;
......@@ -9766,8 +9774,10 @@ 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),
default_route_metric);
nm_device_get_platform (self));
nm_platform_ip4_dev_route_blacklist_set (nm_device_get_platform (self),
nm_ip4_config_get_ifindex (new_config),
ip4_dev_route_blacklist);
}
if (new_config) {
......@@ -11986,7 +11996,7 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type)
/* 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, 0, TRUE);
nm_device_set_ip4_config (self, NULL, TRUE, NULL);
nm_device_set_ip6_config (self, NULL, TRUE);
nm_clear_nmp_object (&priv->default_route4);
nm_clear_nmp_object (&priv->default_route6);
......
......@@ -107,6 +107,7 @@ dhcp4_state_changed (NMDhcpClient *client,
{
static NMIP4Config *last_config = NULL;
NMIP4Config *existing;
gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL;
g_return_if_fail (!ip4_config || NM_IS_IP4_CONFIG (ip4_config));
......@@ -123,11 +124,17 @@ dhcp4_state_changed (NMDhcpClient *client,
nm_ip4_config_subtract (existing, last_config);
nm_ip4_config_merge (existing, ip4_config, NM_IP_CONFIG_MERGE_DEFAULT);
nm_ip4_config_add_device_routes (existing,
global_opt.priority_v4,
&ip4_dev_route_blacklist);
if (!nm_ip4_config_commit (existing,
NM_PLATFORM_GET,
global_opt.priority_v4))
NM_PLATFORM_GET))
_LOGW (LOGD_DHCP4, "failed to apply DHCPv4 config");
nm_platform_ip4_dev_route_blacklist_set (NM_PLATFORM_GET,
gl.ifindex,
ip4_dev_route_blacklist);
if (last_config)
g_object_unref (last_config);
last_config = nm_ip4_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET),
......
......@@ -724,107 +724,113 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
return self;
}
gboolean
nm_ip4_config_commit (const NMIP4Config *self,
NMPlatform *platform,
guint32 default_route_metric)
void
nm_ip4_config_add_device_routes (NMIP4Config *self,
guint32 default_route_metric,
GPtrArray **out_ip4_dev_route_blacklist)
{
const NMIP4ConfigPrivate *priv;
gs_unref_ptrarray GPtrArray *addresses = NULL;
gs_unref_ptrarray GPtrArray *routes = NULL;
gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL;
GPtrArray *ip4_dev_route_blacklist = NULL;
const NMPlatformIP4Address *addr;
int ifindex;
guint i;
gboolean success = TRUE;
NMDedupMultiIter iter;
g_return_val_if_fail (NM_IS_IP4_CONFIG (self), FALSE);
g_return_if_fail (NM_IS_IP4_CONFIG (self));
priv = NM_IP4_CONFIG_GET_PRIVATE (self);
ifindex = nm_ip4_config_get_ifindex (self);
g_return_val_if_fail (ifindex > 0, FALSE);
g_return_if_fail (ifindex > 0);
addresses = nm_dedup_multi_objs_to_ptr_array_head (nm_ip4_config_lookup_addresses (self),
NULL, NULL);
/* For IPv6, we explicitly add the device-routes (onlink) to NMIP6Config.
* As we don't do that for IPv4, add it here shortly before syncing
* the routes. */
routes = nm_dedup_multi_objs_to_ptr_array_head (nm_ip4_config_lookup_routes (self),
NULL, NULL);
nm_ip_config_iter_ip4_address_for_each (&iter, self, &addr) {
nm_auto_nmpobj NMPObject *r = NULL;
NMPlatformIP4Route *route;
in_addr_t network;
if (addresses) {
/* For IPv6, we explicitly add the device-routes (onlink) to NMIP6Config.
* As we don't do that for IPv4, add it here shortly before syncing
* the routes. */
for (i = 0; i < addresses->len; i++) {
const NMPObject *o = addresses->pdata[i];
const NMPlatformIP4Address *addr;
nm_auto_nmpobj NMPObject *r = NULL;
NMPlatformIP4Route *route;
in_addr_t network;
if (!o)
continue;
addr = NMP_OBJECT_CAST_IP4_ADDRESS (o);
if (addr->plen == 0)
continue;
nm_assert (addr->plen <= 32);
/* The destination network depends on the peer-address. */
network = nm_utils_ip4_address_clear_host_address (addr->peer_address, addr->plen);
if (_ipv4_is_zeronet (network)) {
/* Kernel doesn't add device-routes for destinations that
* start with 0.x.y.z. Skip them. */
continue;
}
if (addr->plen == 0)
continue;
nm_assert (addr->plen <= 32);
/* The destination network depends on the peer-address. */
network = nm_utils_ip4_address_clear_host_address (addr->peer_address, addr->plen);
if (_ipv4_is_zeronet (network)) {
/* Kernel doesn't add device-routes for destinations that
* start with 0.x.y.z. Skip them. */
continue;
}
r = nmp_object_new (NMP_OBJECT_TYPE_IP4_ROUTE, NULL);
route = NMP_OBJECT_CAST_IP4_ROUTE (r);
route->ifindex = ifindex;
route->rt_source = NM_IP_CONFIG_SOURCE_KERNEL;
route->network = network;
route->plen = addr->plen;
route->pref_src = addr->address;
route->metric = default_route_metric;
route->scope_inv = nm_platform_route_scope_inv (NM_RT_SCOPE_LINK);
nm_platform_ip_route_normalize (AF_INET, (NMPlatformIPRoute *) route);
r = nmp_object_new (NMP_OBJECT_TYPE_IP4_ROUTE, NULL);
route = NMP_OBJECT_CAST_IP4_ROUTE (r);
if (_lookup_route (self,
r,
NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID)) {
/* we already track this route. Don't add it again. */
} else
_add_route (self, nmp_object_ref (r), NULL, NULL);
route->ifindex = ifindex;
route->rt_source = NM_IP_CONFIG_SOURCE_KERNEL;
route->network = network;
route->plen = addr->plen;
route->pref_src = addr->address;
route->metric = default_route_metric;
route->scope_inv = nm_platform_route_scope_inv (NM_RT_SCOPE_LINK);
if ( out_ip4_dev_route_blacklist
&& default_route_metric != NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE) {
nm_auto_nmpobj NMPObject *r_dev = NULL;
r_dev = nmp_object_clone (r, FALSE);
route = NMP_OBJECT_CAST_IP4_ROUTE (r_dev);
route->metric = NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE;
nm_platform_ip_route_normalize (AF_INET, (NMPlatformIPRoute *) route);
if (_lookup_route (self,
r,
r_dev,
NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID)) {
/* we already track this route. Don't add it again. */
/* we track such a route explicitly. Don't blacklist it. */
} else {
if (!routes)
routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref);
g_ptr_array_add (routes, (gpointer) nmp_object_ref (r));
if (!ip4_dev_route_blacklist)
ip4_dev_route_blacklist = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref);
g_ptr_array_add (ip4_dev_route_blacklist,
g_steal_pointer (&r_dev));
}
}
}
if (default_route_metric != NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE) {
nm_auto_nmpobj NMPObject *r_dev = NULL;
NM_SET_OUT (out_ip4_dev_route_blacklist, ip4_dev_route_blacklist);
}
r_dev = nmp_object_clone (r, FALSE);
route = NMP_OBJECT_CAST_IP4_ROUTE (r_dev);
route->metric = NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE;
gboolean
nm_ip4_config_commit (const NMIP4Config *self,
NMPlatform *platform)
{
gs_unref_ptrarray GPtrArray *addresses = NULL;
gs_unref_ptrarray GPtrArray *routes = NULL;
int ifindex;
gboolean success = TRUE;
nm_platform_ip_route_normalize (AF_INET, (NMPlatformIPRoute *) route);
g_return_val_if_fail (NM_IS_IP4_CONFIG (self), FALSE);
if (_lookup_route (self,
r_dev,
NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID)) {
/* we track such a route explicitly. Don't blacklist it. */
} else {
if (!ip4_dev_route_blacklist)
ip4_dev_route_blacklist = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref);
ifindex = nm_ip4_config_get_ifindex (self);
g_return_val_if_fail (ifindex > 0, FALSE);
g_ptr_array_add (ip4_dev_route_blacklist,
g_steal_pointer (&r_dev));
}
}
}
}
addresses = nm_dedup_multi_objs_to_ptr_array_head (nm_ip4_config_lookup_addresses (self),
NULL, NULL);
routes = nm_dedup_multi_objs_to_ptr_array_head (nm_ip4_config_lookup_routes (self),
NULL, NULL);
nm_platform_ip4_address_sync (platform, ifindex, addresses);
......@@ -836,10 +842,6 @@ nm_ip4_config_commit (const NMIP4Config *self,
NULL))
success = FALSE;
nm_platform_ip4_dev_route_blacklist_set (platform,
ifindex,
ip4_dev_route_blacklist);
return success;
}
......
......@@ -150,9 +150,14 @@ int nm_ip4_config_get_ifindex (const NMIP4Config *self);
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,
GPtrArray **out_ip4_dev_route_blacklist);
gboolean nm_ip4_config_commit (const NMIP4Config *self,
NMPlatform *platform,
guint32 default_route_metric);
NMPlatform *platform);
void nm_ip4_config_merge_setting (NMIP4Config *self, NMSettingIPConfig *setting, guint32 default_route_metric);
NMSetting *nm_ip4_config_create_setting (const NMIP4Config *self);
......
......@@ -121,6 +121,8 @@ typedef struct {
NMNetns *netns;
GPtrArray *ip4_dev_route_blacklist;
GDBusProxy *proxy;
GCancellable *cancellable;
GVariant *connect_hash;
......@@ -1147,9 +1149,11 @@ 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_vpn_connection_get_ip4_route_metric (self)))
nm_netns_get_platform (priv->netns)))
return FALSE;
nm_platform_ip4_dev_route_blacklist_set (nm_netns_get_platform (priv->netns),
priv->ip_ifindex,
priv->ip4_dev_route_blacklist);
}
if (priv->ip6_config) {
......@@ -1601,6 +1605,12 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict)
nm_ip4_config_add_route (config, &r, NULL);
}
g_clear_pointer (&priv->ip4_dev_route_blacklist, g_ptr_array_unref);
nm_ip4_config_add_device_routes (config,
nm_vpn_connection_get_ip4_route_metric (self),
&priv->ip4_dev_route_blacklist);
if (priv->ip4_config) {
nm_ip4_config_replace (priv->ip4_config, config, NULL);
g_object_unref (config);
......@@ -2704,6 +2714,8 @@ dispose (GObject *object)
g_clear_pointer (&priv->connect_hash, g_variant_unref);
g_clear_pointer (&priv->ip4_dev_route_blacklist, g_ptr_array_unref);
nm_clear_g_source (&priv->connect_timeout);
dispatcher_cleanup (self);
......
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