core: rework tracking of gateway/default-route in ip-config

Instead of having 3 properties @gateway, @never_default and @has_gateway
on NMIP4Config/NMIP6Config that determine the default-route, track the
default-route as a regular route.

The gateway setting is the configuration knob for the default-route.
Since an NMIP4Config/NMIP6Config instance only has one gateway property,
it cannot track more then one default-routes (see related bug rh#1445417).
Especially with policy routing, it might be interesting to configure a
default-route in multiple tables.

Also, later it might be interesting to allow adding default-routes as
regular static routes in a connection, so that the user can configure additional
route parameters for the default-route or add default-routes in multiple tables.

With this patch, default-routes now have a rt_source property according to their
origin.

Also, the previous commits of this branch broke handling of the
default-route :) . That should be working now again.
This commit is contained in:
Thomas Haller 2017-10-04 15:21:21 +02:00
parent 2bdfc092d4
commit 5c299454b4
34 changed files with 1096 additions and 893 deletions

View file

@ -474,6 +474,15 @@ act_stage3_ip4_config_start (NMDevice *device,
} }
priv->ppp_manager = nm_ppp_manager_create (ppp_iface, &err); priv->ppp_manager = nm_ppp_manager_create (ppp_iface, &err);
if (priv->ppp_manager) {
nm_ppp_manager_set_route_parameters (priv->ppp_manager,
nm_device_get_route_table (device, AF_INET, TRUE),
nm_device_get_route_metric (device, AF_INET),
nm_device_get_route_table (device, AF_INET6, TRUE),
nm_device_get_route_metric (device, AF_INET6));
}
if ( !priv->ppp_manager if ( !priv->ppp_manager
|| !nm_ppp_manager_start (priv->ppp_manager, req, || !nm_ppp_manager_start (priv->ppp_manager, req,
nm_setting_adsl_get_username (s_adsl), nm_setting_adsl_get_username (s_adsl),

View file

@ -999,6 +999,7 @@ ppp_ip4_config (NMPPPManager *ppp_manager,
static NMActStageReturn static NMActStageReturn
pppoe_stage3_ip4_config_start (NMDeviceEthernet *self, NMDeviceStateReason *out_failure_reason) pppoe_stage3_ip4_config_start (NMDeviceEthernet *self, NMDeviceStateReason *out_failure_reason)
{ {
NMDevice *device = NM_DEVICE (self);
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
NMSettingPppoe *s_pppoe; NMSettingPppoe *s_pppoe;
NMActRequest *req; NMActRequest *req;
@ -1010,9 +1011,17 @@ pppoe_stage3_ip4_config_start (NMDeviceEthernet *self, NMDeviceStateReason *out_
s_pppoe = (NMSettingPppoe *) nm_device_get_applied_setting ((NMDevice *) self, NM_TYPE_SETTING_PPPOE); s_pppoe = (NMSettingPppoe *) nm_device_get_applied_setting ((NMDevice *) self, NM_TYPE_SETTING_PPPOE);
g_return_val_if_fail (s_pppoe, NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (s_pppoe, NM_ACT_STAGE_RETURN_FAILURE);
priv->ppp_manager = nm_ppp_manager_create (nm_device_get_iface (NM_DEVICE (self)), priv->ppp_manager = nm_ppp_manager_create (nm_device_get_iface (device),
&err); &err);
if (priv->ppp_manager) {
nm_ppp_manager_set_route_parameters (priv->ppp_manager,
nm_device_get_route_table (device, AF_INET, TRUE),
nm_device_get_route_metric (device, AF_INET),
nm_device_get_route_table (device, AF_INET6, TRUE),
nm_device_get_route_metric (device, AF_INET6));
}
if ( !priv->ppp_manager if ( !priv->ppp_manager
|| !nm_ppp_manager_start (priv->ppp_manager, req, || !nm_ppp_manager_start (priv->ppp_manager, req,
nm_setting_pppoe_get_username (s_pppoe), nm_setting_pppoe_get_username (s_pppoe),

View file

@ -138,7 +138,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason)
NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE (self); NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE (self);
NMSettingPppoe *s_pppoe; NMSettingPppoe *s_pppoe;
NMActRequest *req; NMActRequest *req;
GError *err = NULL; GError *error = NULL;
req = nm_device_get_act_request (NM_DEVICE (self)); req = nm_device_get_act_request (NM_DEVICE (self));
g_return_val_if_fail (req, NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (req, NM_ACT_STAGE_RETURN_FAILURE);
@ -149,14 +149,22 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason)
g_clear_object (&priv->pending_ip4_config); g_clear_object (&priv->pending_ip4_config);
nm_clear_g_free (&priv->pending_ifname); nm_clear_g_free (&priv->pending_ifname);
priv->ppp_manager = nm_ppp_manager_create (nm_setting_pppoe_get_parent (s_pppoe), &err); priv->ppp_manager = nm_ppp_manager_create (nm_setting_pppoe_get_parent (s_pppoe), &error);
if (priv->ppp_manager) {
nm_ppp_manager_set_route_parameters (priv->ppp_manager,
nm_device_get_route_table (device, AF_INET, TRUE),
nm_device_get_route_metric (device, AF_INET),
nm_device_get_route_table (device, AF_INET6, TRUE),
nm_device_get_route_metric (device, AF_INET6));
}
if ( !priv->ppp_manager if ( !priv->ppp_manager
|| !nm_ppp_manager_start (priv->ppp_manager, req, || !nm_ppp_manager_start (priv->ppp_manager, req,
nm_setting_pppoe_get_username (s_pppoe), nm_setting_pppoe_get_username (s_pppoe),
30, 0, &err)) { 30, 0, &error)) {
_LOGW (LOGD_DEVICE | LOGD_PPP, "PPPoE failed to start: %s", err->message); _LOGW (LOGD_DEVICE | LOGD_PPP, "PPPoE failed to start: %s", error->message);
g_error_free (err); g_error_free (error);
g_clear_object (&priv->ppp_manager); g_clear_object (&priv->ppp_manager);

View file

@ -339,6 +339,9 @@ typedef struct _NMDevicePrivate {
bool v4_commit_first_time:1; bool v4_commit_first_time:1;
bool v6_commit_first_time:1; bool v6_commit_first_time:1;
bool default_route_metric_penalty_ip4_has:1;
bool default_route_metric_penalty_ip6_has:1;
NMDeviceSysIfaceState sys_iface_state:2; NMDeviceSysIfaceState sys_iface_state:2;
bool v4_route_table_initalized:1; bool v4_route_table_initalized:1;
@ -366,11 +369,6 @@ typedef struct _NMDevicePrivate {
NMIP4Config * wwan_ip4_config; /* WWAN configuration */ NMIP4Config * wwan_ip4_config; /* WWAN configuration */
GSList * vpn4_configs; /* VPNs which use this device */ GSList * vpn4_configs; /* VPNs which use this device */
const NMPObject *default_route4;
const NMPObject *default_route6;
const NMPObject *default_routegw4;
const NMPObject *default_routegw6;
bool v4_has_shadowed_routes; bool v4_has_shadowed_routes;
const char *ip4_rp_filter; const char *ip4_rp_filter;
@ -1665,24 +1663,35 @@ _get_route_metric_default (NMDevice *self)
return 11000; return 11000;
} }
static guint32 static gboolean
route_metric_with_penalty (NMDevice *self, guint32 metric) default_route_metric_penalty_detect (NMDevice *self)
{ {
#if WITH_CONCHECK #if WITH_CONCHECK
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
const guint32 PENALTY = 20000;
/* Beware: for IPv6, a metric of 0 effectively means 1024.
* Only pass a normalized IPv6 metric (nm_utils_ip6_route_metric_normalize). */
/* currently we don't differentiate between IPv4 and IPv6 when detecting
* connectivity. */
if ( priv->connectivity_state != NM_CONNECTIVITY_FULL if ( priv->connectivity_state != NM_CONNECTIVITY_FULL
&& nm_connectivity_check_enabled (nm_connectivity_get ())) { && nm_connectivity_check_enabled (nm_connectivity_get ())) {
if (metric >= G_MAXUINT32 - PENALTY) return TRUE;
return G_MAXUINT32;
return metric + PENALTY;
} }
#endif #endif
return metric;
return FALSE;
}
static guint32
default_route_metric_penalty_get (NMDevice *self, int addr_family)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
nm_assert_addr_family (addr_family);
if ( addr_family == AF_INET
? priv->default_route_metric_penalty_ip4_has
: priv->default_route_metric_penalty_ip6_has)
return 20000;
return 0;
} }
guint32 guint32
@ -1736,13 +1745,17 @@ nm_device_get_route_table (NMDevice *self,
int addr_family, int addr_family,
gboolean fallback_main) gboolean fallback_main)
{ {
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDevicePrivate *priv;
NMConnection *connection; NMConnection *connection;
NMSettingIPConfig *s_ip; NMSettingIPConfig *s_ip;
guint32 route_table = 0; guint32 route_table = 0;
nm_assert_addr_family (addr_family); nm_assert_addr_family (addr_family);
g_return_val_if_fail (NM_IS_DEVICE (self), RT_TABLE_MAIN);
priv = NM_DEVICE_GET_PRIVATE (self);
/* the route table setting affects how we sync routes. We shall /* the route table setting affects how we sync routes. We shall
* not change it while the device is active, hence, cache it. */ * not change it while the device is active, hence, cache it. */
if (addr_family == AF_INET) { if (addr_family == AF_INET) {
@ -1801,24 +1814,14 @@ nm_device_get_best_default_route (NMDevice *self,
{ {
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
/* Prefer the best default-route we have in ipx_config.
*
* Otherwise, use priv->default_routeX. Usually, we would
* expect that if ipx_config has no default route, then
* also priv->default_routeX is unset. This is just to cover
* a case I cannot imagine now. */
switch (addr_family) { switch (addr_family) {
case AF_INET: case AF_INET:
return (priv->ip4_config ? nm_ip4_config_best_default_route_get (priv->ip4_config) : NULL) return priv->ip4_config ? nm_ip4_config_best_default_route_get (priv->ip4_config) : NULL;
?: priv->default_route4;
case AF_INET6: case AF_INET6:
return (priv->ip6_config ? nm_ip6_config_best_default_route_get (priv->ip6_config) : NULL) return priv->ip6_config ? nm_ip6_config_best_default_route_get (priv->ip6_config) : NULL;
?: priv->default_route6;
case AF_UNSPEC: case AF_UNSPEC:
return (priv->ip4_config ? nm_ip4_config_best_default_route_get (priv->ip4_config) : NULL) return (priv->ip4_config ? nm_ip4_config_best_default_route_get (priv->ip4_config) : NULL)
?: priv->default_route4 ?: (priv->ip6_config ? nm_ip6_config_best_default_route_get (priv->ip6_config) : NULL);
?: (priv->ip6_config ? nm_ip6_config_best_default_route_get (priv->ip6_config) : NULL)
?: priv->default_route6;
default: default:
g_return_val_if_reached (NULL); g_return_val_if_reached (NULL);
} }
@ -5767,15 +5770,11 @@ ip4_config_merge_and_apply (NMDevice *self,
NMConnection *connection; NMConnection *connection;
gboolean success; gboolean success;
NMIP4Config *composite; NMIP4Config *composite;
const guint32 default_route_metric = nm_device_get_route_metric (self, AF_INET);
guint32 gateway;
gboolean connection_has_default_route, connection_is_never_default;
gboolean ignore_auto_routes = FALSE; gboolean ignore_auto_routes = FALSE;
gboolean ignore_auto_dns = FALSE; gboolean ignore_auto_dns = FALSE;
gboolean ignore_default_routes = FALSE;
GSList *iter; GSList *iter;
NMPlatformIP4Route default_route;
gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL; gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL;
gboolean add_default_route = TRUE;
/* Apply ignore-auto-routes and ignore-auto-dns settings */ /* Apply ignore-auto-routes and ignore-auto-dns settings */
connection = nm_device_get_applied_connection (self); connection = nm_device_get_applied_connection (self);
@ -5785,6 +5784,7 @@ ip4_config_merge_and_apply (NMDevice *self,
if (s_ip4) { if (s_ip4) {
ignore_auto_routes = nm_setting_ip_config_get_ignore_auto_routes (s_ip4); ignore_auto_routes = nm_setting_ip_config_get_ignore_auto_routes (s_ip4);
ignore_auto_dns = nm_setting_ip_config_get_ignore_auto_dns (s_ip4); ignore_auto_dns = nm_setting_ip_config_get_ignore_auto_dns (s_ip4);
ignore_default_routes = nm_setting_ip_config_get_never_default (s_ip4);
} }
} }
@ -5797,17 +5797,22 @@ ip4_config_merge_and_apply (NMDevice *self,
ensure_con_ip4_config (self); ensure_con_ip4_config (self);
} }
if (commit)
priv->default_route_metric_penalty_ip4_has = default_route_metric_penalty_detect (self);
if (priv->dev_ip4_config) { if (priv->dev_ip4_config) {
nm_ip4_config_merge (composite, priv->dev_ip4_config, nm_ip4_config_merge (composite, priv->dev_ip4_config,
(ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0)
| (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0)); | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0)
| (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0),
default_route_metric_penalty_get (self, AF_INET));
} }
for (iter = priv->vpn4_configs; iter; iter = iter->next) for (iter = priv->vpn4_configs; iter; iter = iter->next)
nm_ip4_config_merge (composite, iter->data, NM_IP_CONFIG_MERGE_DEFAULT); nm_ip4_config_merge (composite, iter->data, NM_IP_CONFIG_MERGE_DEFAULT, 0);
if (priv->ext_ip4_config) if (priv->ext_ip4_config)
nm_ip4_config_merge (composite, priv->ext_ip4_config, NM_IP_CONFIG_MERGE_DEFAULT); nm_ip4_config_merge (composite, priv->ext_ip4_config, NM_IP_CONFIG_MERGE_DEFAULT, 0);
/* Merge WWAN config *last* to ensure modem-given settings overwrite /* Merge WWAN config *last* to ensure modem-given settings overwrite
* any external stuff set by pppd or other scripts. * any external stuff set by pppd or other scripts.
@ -5815,87 +5820,23 @@ ip4_config_merge_and_apply (NMDevice *self,
if (priv->wwan_ip4_config) { if (priv->wwan_ip4_config) {
nm_ip4_config_merge (composite, priv->wwan_ip4_config, nm_ip4_config_merge (composite, priv->wwan_ip4_config,
(ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0)
| (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0)); | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0)
| (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0),
default_route_metric_penalty_get (self, AF_INET));
} }
/* Merge user overrides into the composite config. For assumed connections, /* Merge user overrides into the composite config. For assumed connections,
* con_ip4_config is empty. */ * con_ip4_config is empty. */
if (priv->con_ip4_config) if (priv->con_ip4_config) {
nm_ip4_config_merge (composite, priv->con_ip4_config, NM_IP_CONFIG_MERGE_DEFAULT); nm_ip4_config_merge (composite, priv->con_ip4_config, NM_IP_CONFIG_MERGE_DEFAULT,
default_route_metric_penalty_get (self, AF_INET));
/* Add the default route... */
if (!commit) {
/* during a non-commit event, we always pickup whatever is configured. */
goto END_ADD_DEFAULT_ROUTE;
}
/* for external connections, we always pickup whatever is configured. */
if (nm_device_sys_iface_state_is_external (self))
goto END_ADD_DEFAULT_ROUTE;
connection_has_default_route
= nm_utils_connection_has_default_route (connection, AF_INET, &connection_is_never_default);
if ( !priv->v4_commit_first_time
&& connection_is_never_default) {
/* If the connection is explicitly configured as never-default, we enforce the (absence of the)
* default-route only once. That allows the user to configure a connection as never-default,
* but he can add default routes externally (via a dispatcher script) and NM will not interfere. */
goto END_ADD_DEFAULT_ROUTE;
}
nm_clear_nmp_object (&priv->default_route4);
nm_clear_nmp_object (&priv->default_routegw4);
if (!connection_has_default_route)
goto END_ADD_DEFAULT_ROUTE;
if (!nm_ip4_config_get_num_addresses (composite)) {
/* without addresses we can have no default route. */
goto END_ADD_DEFAULT_ROUTE;
}
gateway = nm_ip4_config_get_gateway (composite);
if ( !nm_ip4_config_has_gateway (composite)
&& nm_device_get_device_type (self) != NM_DEVICE_TYPE_MODEM)
goto END_ADD_DEFAULT_ROUTE;
add_default_route = FALSE;
memset (&default_route, 0, sizeof (default_route));
default_route.rt_source = NM_IP_CONFIG_SOURCE_USER;
default_route.gateway = gateway;
default_route.table_coerced = nm_platform_route_table_coerce (nm_device_get_route_table (self, AF_INET, TRUE));
default_route.metric = route_metric_with_penalty (self, default_route_metric);
nm_clear_nmp_object (&priv->default_route4);
nm_ip4_config_add_route (composite, &default_route, &priv->default_route4);
if (!( gateway == 0
|| nm_ip4_config_destination_is_direct (composite, gateway, 32)
|| nm_ip4_config_get_direct_route_for_host (composite, gateway))) {
/* add a direct route to the gateway */
default_route.network = gateway;
default_route.plen = 32;
default_route.gateway = 0;
nm_clear_nmp_object (&priv->default_routegw4);
nm_ip4_config_add_route (composite, &default_route, &priv->default_routegw4);
}
END_ADD_DEFAULT_ROUTE:
if (add_default_route) {
if (priv->default_route4)
nm_ip4_config_add_route (composite, NMP_OBJECT_CAST_IP4_ROUTE (priv->default_route4), NULL);
if (priv->default_routegw4)
nm_ip4_config_add_route (composite, NMP_OBJECT_CAST_IP4_ROUTE (priv->default_routegw4), NULL);
} }
if (commit) { if (commit) {
nm_ip4_config_add_device_routes (composite, nm_ip4_config_add_dependent_routes (composite,
nm_device_get_route_table (self, AF_INET, TRUE), nm_device_get_route_table (self, AF_INET, TRUE),
default_route_metric, nm_device_get_route_metric (self, AF_INET),
&ip4_dev_route_blacklist); &ip4_dev_route_blacklist);
} }
if (commit) { if (commit) {
@ -6481,15 +6422,11 @@ ip6_config_merge_and_apply (NMDevice *self,
NMConnection *connection; NMConnection *connection;
gboolean success; gboolean success;
NMIP6Config *composite; NMIP6Config *composite;
const guint32 default_route_metric = nm_device_get_route_metric (self, AF_INET6);
const struct in6_addr *gateway;
gboolean connection_has_default_route, connection_is_never_default;
gboolean ignore_auto_routes = FALSE; gboolean ignore_auto_routes = FALSE;
gboolean ignore_auto_dns = FALSE; gboolean ignore_auto_dns = FALSE;
gboolean ignore_default_routes = FALSE;
const char *token = NULL; const char *token = NULL;
GSList *iter; GSList *iter;
NMPlatformIP6Route default_route;
gboolean add_default_route = TRUE;
/* Apply ignore-auto-routes and ignore-auto-dns settings */ /* Apply ignore-auto-routes and ignore-auto-dns settings */
connection = nm_device_get_applied_connection (self); connection = nm_device_get_applied_connection (self);
@ -6501,6 +6438,7 @@ ip6_config_merge_and_apply (NMDevice *self,
ignore_auto_routes = nm_setting_ip_config_get_ignore_auto_routes (s_ip6); ignore_auto_routes = nm_setting_ip_config_get_ignore_auto_routes (s_ip6);
ignore_auto_dns = nm_setting_ip_config_get_ignore_auto_dns (s_ip6); ignore_auto_dns = nm_setting_ip_config_get_ignore_auto_dns (s_ip6);
ignore_default_routes = nm_setting_ip_config_get_never_default (s_ip6);
if (nm_setting_ip6_config_get_addr_gen_mode (ip6) == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64) if (nm_setting_ip6_config_get_addr_gen_mode (ip6) == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64)
token = nm_setting_ip6_config_get_token (ip6); token = nm_setting_ip6_config_get_token (ip6);
@ -6520,23 +6458,30 @@ ip6_config_merge_and_apply (NMDevice *self,
ensure_con_ip6_config (self); ensure_con_ip6_config (self);
} }
if (commit)
priv->default_route_metric_penalty_ip6_has = default_route_metric_penalty_detect (self);
/* Merge all the IP configs into the composite config */ /* Merge all the IP configs into the composite config */
if (priv->ac_ip6_config) { if (priv->ac_ip6_config) {
nm_ip6_config_merge (composite, priv->ac_ip6_config, nm_ip6_config_merge (composite, priv->ac_ip6_config,
(ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0)
| (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0)); | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0)
| (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0),
default_route_metric_penalty_get (self, AF_INET6));
} }
if (priv->dhcp6.ip6_config) { if (priv->dhcp6.ip6_config) {
nm_ip6_config_merge (composite, priv->dhcp6.ip6_config, nm_ip6_config_merge (composite, priv->dhcp6.ip6_config,
(ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0)
| (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0)); | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0)
| (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0),
default_route_metric_penalty_get (self, AF_INET6));
} }
for (iter = priv->vpn6_configs; iter; iter = iter->next) for (iter = priv->vpn6_configs; iter; iter = iter->next)
nm_ip6_config_merge (composite, iter->data, NM_IP_CONFIG_MERGE_DEFAULT); nm_ip6_config_merge (composite, iter->data, NM_IP_CONFIG_MERGE_DEFAULT, 0);
if (priv->ext_ip6_config) if (priv->ext_ip6_config)
nm_ip6_config_merge (composite, priv->ext_ip6_config, NM_IP_CONFIG_MERGE_DEFAULT); nm_ip6_config_merge (composite, priv->ext_ip6_config, NM_IP_CONFIG_MERGE_DEFAULT, 0);
/* Merge WWAN config *last* to ensure modem-given settings overwrite /* Merge WWAN config *last* to ensure modem-given settings overwrite
* any external stuff set by pppd or other scripts. * any external stuff set by pppd or other scripts.
@ -6544,7 +6489,9 @@ ip6_config_merge_and_apply (NMDevice *self,
if (priv->wwan_ip6_config) { if (priv->wwan_ip6_config) {
nm_ip6_config_merge (composite, priv->wwan_ip6_config, nm_ip6_config_merge (composite, priv->wwan_ip6_config,
(ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0)
| (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0)); | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0)
| (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0),
default_route_metric_penalty_get (self, AF_INET6));
} }
if (priv->rt6_temporary_not_available) { if (priv->rt6_temporary_not_available) {
@ -6561,78 +6508,15 @@ ip6_config_merge_and_apply (NMDevice *self,
/* Merge user overrides into the composite config. For assumed connections, /* Merge user overrides into the composite config. For assumed connections,
* con_ip6_config is empty. */ * con_ip6_config is empty. */
if (priv->con_ip6_config) if (priv->con_ip6_config) {
nm_ip6_config_merge (composite, priv->con_ip6_config, NM_IP_CONFIG_MERGE_DEFAULT); nm_ip6_config_merge (composite, priv->con_ip6_config, NM_IP_CONFIG_MERGE_DEFAULT,
default_route_metric_penalty_get (self, AF_INET6));
/* Add the default route... */
if (!commit) {
/* during a non-commit event, we always pickup whatever is configured. */
goto END_ADD_DEFAULT_ROUTE;
}
/* for external connections, we always pickup whatever is configured. */
if (nm_device_sys_iface_state_is_external (self))
goto END_ADD_DEFAULT_ROUTE;
connection_has_default_route
= nm_utils_connection_has_default_route (connection, AF_INET6, &connection_is_never_default);
if ( !priv->v6_commit_first_time
&& connection_is_never_default) {
/* If the connection is explicitly configured as never-default, we enforce the (absence of the)
* default-route only once. That allows the user to configure a connection as never-default,
* but he can add default routes externally (via a dispatcher script) and NM will not interfere. */
goto END_ADD_DEFAULT_ROUTE;
}
nm_clear_nmp_object (&priv->default_route6);
nm_clear_nmp_object (&priv->default_routegw6);
if (!connection_has_default_route)
goto END_ADD_DEFAULT_ROUTE;
if (!nm_ip6_config_get_num_addresses (composite)) {
/* without addresses we can have no default route. */
goto END_ADD_DEFAULT_ROUTE;
}
gateway = nm_ip6_config_get_gateway (composite);
if (!gateway)
goto END_ADD_DEFAULT_ROUTE;
add_default_route = FALSE;
memset (&default_route, 0, sizeof (default_route));
default_route.rt_source = NM_IP_CONFIG_SOURCE_USER;
default_route.gateway = *gateway;
default_route.table_coerced = nm_platform_route_table_coerce (nm_device_get_route_table (self, AF_INET6, TRUE));
default_route.metric = route_metric_with_penalty (self, default_route_metric);
nm_clear_nmp_object (&priv->default_route6);
nm_ip6_config_add_route (composite, &default_route, &priv->default_route6);
if (!nm_ip6_config_get_direct_route_for_host (composite, gateway)) {
/* add a direct route to the gateway */
default_route.network = *gateway;
default_route.plen = 128;
default_route.gateway = in6addr_any;
nm_clear_nmp_object (&priv->default_routegw6);
nm_ip6_config_add_route (composite, &default_route, &priv->default_routegw6);
}
END_ADD_DEFAULT_ROUTE:
if (add_default_route) {
if (priv->default_route6)
nm_ip6_config_add_route (composite, NMP_OBJECT_CAST_IP6_ROUTE (priv->default_route6), NULL);
if (priv->default_routegw6)
nm_ip6_config_add_route (composite, NMP_OBJECT_CAST_IP6_ROUTE (priv->default_routegw6), NULL);
} }
if (commit) { if (commit) {
nm_ip6_config_add_device_routes (composite, nm_ip6_config_add_dependent_routes (composite,
nm_device_get_route_table (self, AF_INET6, TRUE), nm_device_get_route_table (self, AF_INET6, TRUE),
default_route_metric); nm_device_get_route_metric (self, AF_INET6));
} }
/* Allow setting MTU etc */ /* Allow setting MTU etc */
@ -7477,14 +7361,6 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
if (!priv->ac_ip6_config) if (!priv->ac_ip6_config)
priv->ac_ip6_config = _ip6_config_new (self); priv->ac_ip6_config = _ip6_config_new (self);
if (changed & NM_NDISC_CONFIG_GATEWAYS) {
/* Use the first gateway as ordered in neighbor discovery cache. */
if (rdata->gateways_n)
nm_ip6_config_set_gateway (priv->ac_ip6_config, &rdata->gateways[0].address);
else
nm_ip6_config_set_gateway (priv->ac_ip6_config, NULL);
}
if (changed & NM_NDISC_CONFIG_ADDRESSES) { if (changed & NM_NDISC_CONFIG_ADDRESSES) {
guint8 plen; guint8 plen;
guint32 ifa_flags; guint32 ifa_flags;
@ -7510,8 +7386,11 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
ifa_flags); ifa_flags);
} }
if (changed & NM_NDISC_CONFIG_ROUTES) { if (NM_FLAGS_ANY (changed, NM_NDISC_CONFIG_ROUTES
| NM_NDISC_CONFIG_GATEWAYS)) {
nm_ip6_config_reset_routes_ndisc (priv->ac_ip6_config, nm_ip6_config_reset_routes_ndisc (priv->ac_ip6_config,
rdata->gateways,
rdata->gateways_n,
rdata->routes, rdata->routes,
rdata->routes_n, rdata->routes_n,
nm_device_get_route_table (self, AF_INET6, TRUE), nm_device_get_route_table (self, AF_INET6, TRUE),
@ -9016,8 +8895,6 @@ _cleanup_ip4_pre (NMDevice *self, CleanupType cleanup_type)
_LOGD (LOGD_DEVICE, "clearing queued IP4 config change"); _LOGD (LOGD_DEVICE, "clearing queued IP4 config change");
priv->queued_ip4_config_pending = FALSE; priv->queued_ip4_config_pending = FALSE;
nm_clear_nmp_object (&priv->default_route4);
nm_clear_nmp_object (&priv->default_routegw4);
dhcp4_cleanup (self, cleanup_type, FALSE); dhcp4_cleanup (self, cleanup_type, FALSE);
arp_cleanup (self); arp_cleanup (self);
dnsmasq_cleanup (self); dnsmasq_cleanup (self);
@ -9035,8 +8912,6 @@ _cleanup_ip6_pre (NMDevice *self, CleanupType cleanup_type)
_LOGD (LOGD_DEVICE, "clearing queued IP6 config change"); _LOGD (LOGD_DEVICE, "clearing queued IP6 config change");
priv->queued_ip6_config_pending = FALSE; priv->queued_ip6_config_pending = FALSE;
nm_clear_nmp_object (&priv->default_route6);
nm_clear_nmp_object (&priv->default_routegw6);
g_clear_object (&priv->dad6_ip6_config); g_clear_object (&priv->dad6_ip6_config);
dhcp6_cleanup (self, cleanup_type, FALSE); dhcp6_cleanup (self, cleanup_type, FALSE);
linklocal6_cleanup (self); linklocal6_cleanup (self);
@ -10631,7 +10506,7 @@ nm_device_start_ip_check (NMDevice *self)
NMSettingConnection *s_con; NMSettingConnection *s_con;
guint timeout = 0; guint timeout = 0;
const char *ping_binary = NULL; const char *ping_binary = NULL;
char buf[INET6_ADDRSTRLEN] = { 0 }; char buf[NM_UTILS_INET_ADDRSTRLEN];
NMLogDomain log_domain = LOGD_IP4; NMLogDomain log_domain = LOGD_IP4;
/* Shouldn't be any active ping here, since IP_CHECK happens after the /* Shouldn't be any active ping here, since IP_CHECK happens after the
@ -10650,25 +10525,24 @@ nm_device_start_ip_check (NMDevice *self)
g_assert (s_con); g_assert (s_con);
timeout = nm_setting_connection_get_gateway_ping_timeout (s_con); timeout = nm_setting_connection_get_gateway_ping_timeout (s_con);
buf[0] = '\0';
if (timeout) { if (timeout) {
const NMPObject *gw;
if (priv->ip4_config && priv->ip4_state == IP_DONE) { if (priv->ip4_config && priv->ip4_state == IP_DONE) {
guint gw = 0; gw = nm_ip4_config_best_default_route_get (priv->ip4_config);
if (gw) {
ping_binary = nm_utils_find_helper ("ping", "/usr/bin/ping", NULL); nm_utils_inet4_ntop (NMP_OBJECT_CAST_IP4_ROUTE (gw)->gateway, buf);
log_domain = LOGD_IP4; ping_binary = nm_utils_find_helper ("ping", "/usr/bin/ping", NULL);
log_domain = LOGD_IP4;
gw = nm_ip4_config_get_gateway (priv->ip4_config); }
if (gw && !inet_ntop (AF_INET, &gw, buf, sizeof (buf)))
buf[0] = '\0';
} else if (priv->ip6_config && priv->ip6_state == IP_DONE) { } else if (priv->ip6_config && priv->ip6_state == IP_DONE) {
const struct in6_addr *gw = NULL; gw = nm_ip6_config_best_default_route_get (priv->ip6_config);
if (gw) {
ping_binary = nm_utils_find_helper ("ping6", "/usr/bin/ping6", NULL); nm_utils_inet6_ntop (&NMP_OBJECT_CAST_IP6_ROUTE (gw)->gateway, buf);
log_domain = LOGD_IP6; ping_binary = nm_utils_find_helper ("ping6", "/usr/bin/ping6", NULL);
log_domain = LOGD_IP6;
gw = nm_ip6_config_get_gateway (priv->ip6_config); }
if (gw && !inet_ntop (AF_INET6, gw, buf, sizeof (buf)))
buf[0] = '\0';
} }
} }
@ -10884,12 +10758,18 @@ find_ip4_lease_config (NMDevice *self,
for (liter = leases; liter && !found; liter = liter->next) { for (liter = leases; liter && !found; liter = liter->next) {
NMIP4Config *lease_config = liter->data; NMIP4Config *lease_config = liter->data;
const NMPlatformIP4Address *address = nm_ip4_config_get_first_address (lease_config); const NMPlatformIP4Address *address = nm_ip4_config_get_first_address (lease_config);
guint32 gateway = nm_ip4_config_get_gateway (lease_config); const NMPObject *gw1, *gw2;
g_assert (address); g_assert (address);
if (!nm_ip4_config_address_exists (ext_ip4_config, address)) if (!nm_ip4_config_address_exists (ext_ip4_config, address))
continue; continue;
if (gateway != nm_ip4_config_get_gateway (ext_ip4_config)) gw1 = nm_ip4_config_best_default_route_get (lease_config);
if (!gw1)
continue;
gw2 = nm_ip4_config_best_default_route_get (ext_ip4_config);
if (!gw2)
continue;
if (NMP_OBJECT_CAST_IP4_ROUTE (gw1)->gateway != NMP_OBJECT_CAST_IP4_ROUTE (gw2)->gateway)
continue; continue;
found = g_object_ref (lease_config); found = g_object_ref (lease_config);
} }
@ -10999,37 +10879,39 @@ update_ext_ip_config (NMDevice *self, int addr_family, gboolean initial, gboolea
* (addresses,routes) that is no longer present externally from the internal * (addresses,routes) that is no longer present externally from the internal
* config. This way, we don't re-add addresses that were manually removed * config. This way, we don't re-add addresses that were manually removed
* by the user. */ * by the user. */
if (priv->con_ip4_config) if (priv->con_ip4_config) {
nm_ip4_config_intersect (priv->con_ip4_config, priv->ext_ip4_config); nm_ip4_config_intersect (priv->con_ip4_config, priv->ext_ip4_config,
if (priv->dev_ip4_config) default_route_metric_penalty_get (self, AF_INET));
nm_ip4_config_intersect (priv->dev_ip4_config, priv->ext_ip4_config); }
if (priv->wwan_ip4_config) if (priv->dev_ip4_config) {
nm_ip4_config_intersect (priv->wwan_ip4_config, priv->ext_ip4_config); nm_ip4_config_intersect (priv->dev_ip4_config, priv->ext_ip4_config,
default_route_metric_penalty_get (self, AF_INET));
}
if (priv->wwan_ip4_config) {
nm_ip4_config_intersect (priv->wwan_ip4_config, priv->ext_ip4_config,
default_route_metric_penalty_get (self, AF_INET));
}
for (iter = priv->vpn4_configs; iter; iter = iter->next) for (iter = priv->vpn4_configs; iter; iter = iter->next)
nm_ip4_config_intersect (iter->data, priv->ext_ip4_config); nm_ip4_config_intersect (iter->data, priv->ext_ip4_config, 0);
if ( priv->default_route4
&& !nm_ip4_config_nmpobj_lookup (priv->ext_ip4_config, priv->default_route4))
nm_clear_nmp_object (&priv->default_route4);
if ( priv->default_routegw4
&& !nm_ip4_config_nmpobj_lookup (priv->ext_ip4_config, priv->default_routegw4))
nm_clear_nmp_object (&priv->default_routegw4);
} }
/* Remove parts from ext_ip4_config to only contain the information that /* Remove parts from ext_ip4_config to only contain the information that
* was configured externally -- we already have the same configuration from * was configured externally -- we already have the same configuration from
* internal origins. */ * internal origins. */
if (priv->con_ip4_config) if (priv->con_ip4_config) {
nm_ip4_config_subtract (priv->ext_ip4_config, priv->con_ip4_config); nm_ip4_config_subtract (priv->ext_ip4_config, priv->con_ip4_config,
if (priv->dev_ip4_config) default_route_metric_penalty_get (self, AF_INET));
nm_ip4_config_subtract (priv->ext_ip4_config, priv->dev_ip4_config); }
if (priv->wwan_ip4_config) if (priv->dev_ip4_config) {
nm_ip4_config_subtract (priv->ext_ip4_config, priv->wwan_ip4_config); nm_ip4_config_subtract (priv->ext_ip4_config, priv->dev_ip4_config,
default_route_metric_penalty_get (self, AF_INET));
}
if (priv->wwan_ip4_config) {
nm_ip4_config_subtract (priv->ext_ip4_config, priv->wwan_ip4_config,
default_route_metric_penalty_get (self, AF_INET));
}
for (iter = priv->vpn4_configs; iter; iter = iter->next) for (iter = priv->vpn4_configs; iter; iter = iter->next)
nm_ip4_config_subtract (priv->ext_ip4_config, iter->data); nm_ip4_config_subtract (priv->ext_ip4_config, iter->data, 0);
if (priv->default_route4)
nm_ip4_config_nmpobj_remove (priv->ext_ip4_config, priv->default_route4);
if (priv->default_routegw4)
nm_ip4_config_nmpobj_remove (priv->ext_ip4_config, priv->default_routegw4);
} }
} else { } else {
@ -11051,41 +10933,47 @@ update_ext_ip_config (NMDevice *self, int addr_family, gboolean initial, gboolea
* (addresses,routes) that is no longer present externally from the internal * (addresses,routes) that is no longer present externally from the internal
* config. This way, we don't re-add addresses that were manually removed * config. This way, we don't re-add addresses that were manually removed
* by the user. */ * by the user. */
if (priv->con_ip6_config) if (priv->con_ip6_config) {
nm_ip6_config_intersect (priv->con_ip6_config, priv->ext_ip6_config); nm_ip6_config_intersect (priv->con_ip6_config, priv->ext_ip6_config,
if (priv->ac_ip6_config) default_route_metric_penalty_get (self, AF_INET6));
nm_ip6_config_intersect (priv->ac_ip6_config, priv->ext_ip6_config); }
if (priv->dhcp6.ip6_config) if (priv->ac_ip6_config) {
nm_ip6_config_intersect (priv->dhcp6.ip6_config, priv->ext_ip6_config); nm_ip6_config_intersect (priv->ac_ip6_config, priv->ext_ip6_config,
if (priv->wwan_ip6_config) default_route_metric_penalty_get (self, AF_INET6));
nm_ip6_config_intersect (priv->wwan_ip6_config, priv->ext_ip6_config); }
if (priv->dhcp6.ip6_config) {
nm_ip6_config_intersect (priv->dhcp6.ip6_config, priv->ext_ip6_config,
default_route_metric_penalty_get (self, AF_INET6));
}
if (priv->wwan_ip6_config) {
nm_ip6_config_intersect (priv->wwan_ip6_config, priv->ext_ip6_config,
default_route_metric_penalty_get (self, AF_INET6));
}
for (iter = priv->vpn6_configs; iter; iter = iter->next) for (iter = priv->vpn6_configs; iter; iter = iter->next)
nm_ip6_config_intersect (iter->data, priv->ext_ip6_config); nm_ip6_config_intersect (iter->data, priv->ext_ip6_config, 0);
if ( priv->default_route6
&& !nm_ip6_config_nmpobj_lookup (priv->ext_ip6_config, priv->default_route6))
nm_clear_nmp_object (&priv->default_route6);
if ( priv->default_routegw6
&& !nm_ip6_config_nmpobj_lookup (priv->ext_ip6_config, priv->default_routegw6))
nm_clear_nmp_object (&priv->default_routegw6);
} }
/* Remove parts from ext_ip6_config to only contain the information that /* Remove parts from ext_ip6_config to only contain the information that
* was configured externally -- we already have the same configuration from * was configured externally -- we already have the same configuration from
* internal origins. */ * internal origins. */
if (priv->con_ip6_config) if (priv->con_ip6_config) {
nm_ip6_config_subtract (priv->ext_ip6_config, priv->con_ip6_config); nm_ip6_config_subtract (priv->ext_ip6_config, priv->con_ip6_config,
if (priv->ac_ip6_config) default_route_metric_penalty_get (self, AF_INET6));
nm_ip6_config_subtract (priv->ext_ip6_config, priv->ac_ip6_config); }
if (priv->dhcp6.ip6_config) if (priv->ac_ip6_config) {
nm_ip6_config_subtract (priv->ext_ip6_config, priv->dhcp6.ip6_config); nm_ip6_config_subtract (priv->ext_ip6_config, priv->ac_ip6_config,
if (priv->wwan_ip6_config) default_route_metric_penalty_get (self, AF_INET6));
nm_ip6_config_subtract (priv->ext_ip6_config, priv->wwan_ip6_config); }
if (priv->dhcp6.ip6_config) {
nm_ip6_config_subtract (priv->ext_ip6_config, priv->dhcp6.ip6_config,
default_route_metric_penalty_get (self, AF_INET6));
}
if (priv->wwan_ip6_config) {
nm_ip6_config_subtract (priv->ext_ip6_config, priv->wwan_ip6_config,
default_route_metric_penalty_get (self, AF_INET6));
}
for (iter = priv->vpn6_configs; iter; iter = iter->next) for (iter = priv->vpn6_configs; iter; iter = iter->next)
nm_ip6_config_subtract (priv->ext_ip6_config, iter->data); nm_ip6_config_subtract (priv->ext_ip6_config, iter->data, 0);
if (priv->default_route6)
nm_ip6_config_nmpobj_remove (priv->ext_ip6_config, priv->default_route6);
if (priv->default_routegw6)
nm_ip6_config_nmpobj_remove (priv->ext_ip6_config, priv->default_routegw6);
} }
} }
@ -12403,6 +12291,9 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type)
priv->v4_route_table_initalized = FALSE; priv->v4_route_table_initalized = FALSE;
priv->v6_route_table_initalized = FALSE; priv->v6_route_table_initalized = FALSE;
priv->default_route_metric_penalty_ip4_has = FALSE;
priv->default_route_metric_penalty_ip6_has = FALSE;
priv->linklocal6_dad_counter = 0; priv->linklocal6_dad_counter = 0;
/* Clean up IP configs; this does not actually deconfigure the /* Clean up IP configs; this does not actually deconfigure the
@ -12410,10 +12301,6 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type)
*/ */
nm_device_set_ip4_config (self, NULL, TRUE, NULL); nm_device_set_ip4_config (self, NULL, TRUE, NULL);
nm_device_set_ip6_config (self, NULL, TRUE); nm_device_set_ip6_config (self, NULL, TRUE);
nm_clear_nmp_object (&priv->default_route4);
nm_clear_nmp_object (&priv->default_route6);
nm_clear_nmp_object (&priv->default_routegw4);
nm_clear_nmp_object (&priv->default_routegw6);
g_clear_object (&priv->proxy_config); g_clear_object (&priv->proxy_config);
g_clear_object (&priv->con_ip4_config); g_clear_object (&priv->con_ip4_config);
g_clear_object (&priv->dev_ip4_config); g_clear_object (&priv->dev_ip4_config);

View file

@ -912,8 +912,24 @@ static_stage3_ip4_done (NMModemBroadband *self)
_LOGI (" address %s/%d", address_string, address.plen); _LOGI (" address %s/%d", address_string, address.plen);
if (gw) { if (gw) {
nm_ip4_config_set_gateway (config, gw); guint32 ip4_route_table, ip4_route_metric;
_LOGI (" gateway %s", gw_string);
nm_modem_get_route_parameters (NM_MODEM (self),
&ip4_route_table,
&ip4_route_metric,
NULL,
NULL);
{
const NMPlatformIP4Route r = {
.rt_source = NM_IP_CONFIG_SOURCE_WWAN,
.gateway = gw,
.table_coerced = nm_platform_route_table_coerce (ip4_route_table),
.metric = ip4_route_metric,
};
_LOGI (" gateway %s", gw_string);
nm_ip4_config_add_route (config, &r, NULL);
}
} }
/* DNS servers */ /* DNS servers */
@ -1006,7 +1022,9 @@ stage3_ip6_done (NMModemBroadband *self)
address_string = mm_bearer_ip_config_get_gateway (self->_priv.ipv6_config); address_string = mm_bearer_ip_config_get_gateway (self->_priv.ipv6_config);
if (address_string) { if (address_string) {
if (!inet_pton (AF_INET6, address_string, (void *) &(address.address))) { guint32 ip6_route_table, ip6_route_metric;
if (inet_pton (AF_INET6, address_string, &address.address) != 1) {
error = g_error_new (NM_DEVICE_ERROR, error = g_error_new (NM_DEVICE_ERROR,
NM_DEVICE_ERROR_INVALID_CONNECTION, NM_DEVICE_ERROR_INVALID_CONNECTION,
"(%s) retrieving IPv6 configuration failed: invalid gateway given '%s'", "(%s) retrieving IPv6 configuration failed: invalid gateway given '%s'",
@ -1014,8 +1032,23 @@ stage3_ip6_done (NMModemBroadband *self)
address_string); address_string);
goto out; goto out;
} }
_LOGI (" gateway %s", address_string);
nm_ip6_config_set_gateway (config, &address.address); nm_modem_get_route_parameters (NM_MODEM (self),
NULL,
NULL,
&ip6_route_table,
&ip6_route_metric);
{
const NMPlatformIP6Route r = {
.rt_source = NM_IP_CONFIG_SOURCE_WWAN,
.gateway = address.address,
.table_coerced = nm_platform_route_table_coerce (ip6_route_table),
.metric = ip6_route_metric,
};
_LOGI (" gateway %s", address_string);
nm_ip6_config_add_route (config, &r, NULL);
}
} else if (ip_method == NM_MODEM_IP_METHOD_STATIC) { } else if (ip_method == NM_MODEM_IP_METHOD_STATIC) {
/* Gateway required for the 'static' method */ /* Gateway required for the 'static' method */
error = g_error_new (NM_DEVICE_ERROR, error = g_error_new (NM_DEVICE_ERROR,

View file

@ -833,6 +833,7 @@ context_property_changed (GDBusProxy *proxy,
const gchar *s, *addr_s; const gchar *s, *addr_s;
const gchar **array, **iter; const gchar **array, **iter;
guint32 address_network, gateway_network; guint32 address_network, gateway_network;
guint32 ip4_route_table, ip4_route_metric;
guint prefix = 0; guint prefix = 0;
_LOGD ("PropertyChanged: %s", property); _LOGD ("PropertyChanged: %s", property);
@ -938,16 +939,30 @@ context_property_changed (GDBusProxy *proxy,
nm_ip4_config_add_address (priv->ip4_config, &addr); nm_ip4_config_add_address (priv->ip4_config, &addr);
if (g_variant_lookup (v_dict, "Gateway", "&s", &s)) { if ( g_variant_lookup (v_dict, "Gateway", "&s", &s)
if ( s && s) {
&& nm_utils_parse_inaddr_bin (AF_INET, s, &gateway_network)) {
_LOGI ("Gateway: %s", s); if (!nm_utils_parse_inaddr_bin (AF_INET, s, &gateway_network)) {
nm_ip4_config_set_gateway (priv->ip4_config, gateway_network);
} else {
_LOGW ("invalid 'Gateway': %s", s); _LOGW ("invalid 'Gateway': %s", s);
goto out; goto out;
} }
nm_ip4_config_set_gateway (priv->ip4_config, gateway_network);
nm_modem_get_route_parameters (NM_MODEM (self),
&ip4_route_table,
&ip4_route_metric,
NULL,
NULL);
{
const NMPlatformIP4Route r = {
.rt_source = NM_IP_CONFIG_SOURCE_WWAN,
.gateway = gateway_network,
.table_coerced = nm_platform_route_table_coerce (ip4_route_table),
.metric = ip4_route_metric,
};
_LOGI ("Gateway: %s", s);
nm_ip4_config_add_route (priv->ip4_config, &r, NULL);
}
} else { } else {
_LOGW ("Settings 'Gateway' missing"); _LOGW ("Settings 'Gateway' missing");
goto out; goto out;
@ -981,17 +996,23 @@ context_property_changed (GDBusProxy *proxy,
_LOGI ("MessageProxy: %s", s); _LOGI ("MessageProxy: %s", s);
if ( s if ( s
&& nm_utils_parse_inaddr_bin (AF_INET, s, &address_network)) { && nm_utils_parse_inaddr_bin (AF_INET, s, &address_network)) {
const NMPlatformIP4Route mms_route = { nm_modem_get_route_parameters (NM_MODEM (self),
.network = address_network, &ip4_route_table,
.plen = 32, &ip4_route_metric,
.gateway = gateway_network, NULL,
.metric = 1, NULL);
};
/* FIXME: does not handle ipv4.route-table setting and always adds the {
* route to RT_TABLE_MAIN table. */ const NMPlatformIP4Route mms_route = {
.network = address_network,
.plen = 32,
.gateway = gateway_network,
.table_coerced = nm_platform_route_table_coerce (ip4_route_table),
.metric = ip4_route_metric,
};
nm_ip4_config_add_route (priv->ip4_config, &mms_route, NULL); nm_ip4_config_add_route (priv->ip4_config, &mms_route, NULL);
}
} else { } else {
_LOGW ("invalid MessageProxy: %s", s); _LOGW ("invalid MessageProxy: %s", s);
} }

View file

@ -26,6 +26,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <string.h> #include <string.h>
#include <termios.h> #include <termios.h>
#include <linux/rtnetlink.h>
#include "nm-core-internal.h" #include "nm-core-internal.h"
#include "platform/nm-platform.h" #include "platform/nm-platform.h"
@ -97,6 +98,11 @@ typedef struct _NMModemPrivate {
guint32 mm_ip_timeout; guint32 mm_ip_timeout;
guint32 ip4_route_table;
guint32 ip4_route_metric;
guint32 ip6_route_table;
guint32 ip6_route_metric;
/* PPP stats */ /* PPP stats */
guint32 in_bytes; guint32 in_bytes;
guint32 out_bytes; guint32 out_bytes;
@ -610,6 +616,14 @@ ppp_stage3_ip_config_start (NMModem *self,
priv->ppp_manager = nm_ppp_manager_create (priv->data_port, &error); priv->ppp_manager = nm_ppp_manager_create (priv->data_port, &error);
if (priv->ppp_manager) {
nm_ppp_manager_set_route_parameters (priv->ppp_manager,
priv->ip4_route_table,
priv->ip4_route_metric,
priv->ip6_route_table,
priv->ip6_route_metric);
}
if ( !priv->ppp_manager if ( !priv->ppp_manager
|| !nm_ppp_manager_start (priv->ppp_manager, req, ppp_name, || !nm_ppp_manager_start (priv->ppp_manager, req, ppp_name,
ip_timeout, baud_override, &error)) { ip_timeout, baud_override, &error)) {
@ -706,6 +720,8 @@ nm_modem_ip4_pre_commit (NMModem *modem,
{ {
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (modem); NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (modem);
nm_modem_set_route_parameters_from_device (modem, device);
/* If the modem has an ethernet-type data interface (ie, not PPP and thus /* If the modem has an ethernet-type data interface (ie, not PPP and thus
* not point-to-point) and IP config has a /32 prefix, then we assume that * not point-to-point) and IP config has a /32 prefix, then we assume that
* ARP will be pointless and we turn it off. * ARP will be pointless and we turn it off.
@ -1399,6 +1415,76 @@ nm_modem_get_iid (NMModem *self, NMUtilsIPv6IfaceId *out_iid)
/*****************************************************************************/ /*****************************************************************************/
void
nm_modem_get_route_parameters (NMModem *self,
guint32 *out_ip4_route_table,
guint32 *out_ip4_route_metric,
guint32 *out_ip6_route_table,
guint32 *out_ip6_route_metric)
{
NMModemPrivate *priv;
g_return_if_fail (NM_IS_MODEM (self));
priv = NM_MODEM_GET_PRIVATE (self);
NM_SET_OUT (out_ip4_route_table, priv->ip4_route_table);
NM_SET_OUT (out_ip4_route_metric, priv->ip4_route_metric);
NM_SET_OUT (out_ip6_route_table, priv->ip6_route_table);
NM_SET_OUT (out_ip6_route_metric, priv->ip6_route_metric);
}
void
nm_modem_set_route_parameters (NMModem *self,
guint32 ip4_route_table,
guint32 ip4_route_metric,
guint32 ip6_route_table,
guint32 ip6_route_metric)
{
NMModemPrivate *priv;
g_return_if_fail (NM_IS_MODEM (self));
priv = NM_MODEM_GET_PRIVATE (self);
if ( priv->ip4_route_table != ip4_route_table
|| priv->ip4_route_metric != ip4_route_metric
|| priv->ip6_route_table != ip6_route_table
|| priv->ip6_route_metric != ip6_route_metric) {
priv->ip4_route_table = ip4_route_table;
priv->ip4_route_metric = ip4_route_metric;
priv->ip6_route_table = ip6_route_table;
priv->ip6_route_metric = ip6_route_metric;
_LOGT ("route-parameters: table-v4: %u, metric-v4: %u, table-v6: %u, metric-v6: %u",
priv->ip4_route_table,
priv->ip4_route_metric,
priv->ip6_route_table,
priv->ip6_route_metric);
}
if (priv->ppp_manager) {
nm_ppp_manager_set_route_parameters (priv->ppp_manager,
priv->ip4_route_table,
priv->ip4_route_metric,
priv->ip6_route_table,
priv->ip6_route_metric);
}
}
void
nm_modem_set_route_parameters_from_device (NMModem *self,
NMDevice *device)
{
g_return_if_fail (NM_IS_DEVICE (device));
nm_modem_set_route_parameters (self,
nm_device_get_route_table (device, AF_INET, TRUE),
nm_device_get_route_metric (device, AF_INET),
nm_device_get_route_table (device, AF_INET6, TRUE),
nm_device_get_route_metric (device, AF_INET6));
}
/*****************************************************************************/
void void
nm_modem_get_capabilities (NMModem *self, nm_modem_get_capabilities (NMModem *self,
NMDeviceModemCapabilities *modem_caps, NMDeviceModemCapabilities *modem_caps,
@ -1533,7 +1619,15 @@ set_property (GObject *object, guint prop_id,
static void static void
nm_modem_init (NMModem *self) nm_modem_init (NMModem *self)
{ {
NMModemPrivate *priv;
self->_priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_MODEM, NMModemPrivate); self->_priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_MODEM, NMModemPrivate);
priv = self->_priv;
priv->ip4_route_table = RT_TABLE_MAIN;
priv->ip4_route_metric = 700;
priv->ip6_route_table = RT_TABLE_MAIN;
priv->ip6_route_metric = 700;
} }
static void static void

View file

@ -187,6 +187,21 @@ gboolean nm_modem_complete_connection (NMModem *self,
const GSList *existing_connections, const GSList *existing_connections,
GError **error); GError **error);
void nm_modem_get_route_parameters (NMModem *self,
guint32 *out_ip4_route_table,
guint32 *out_ip4_route_metric,
guint32 *out_ip6_route_table,
guint32 *out_ip6_route_metric);
void nm_modem_set_route_parameters (NMModem *self,
guint32 ip4_route_table,
guint32 ip4_route_metric,
guint32 ip6_route_table,
guint32 ip6_route_metric);
void nm_modem_set_route_parameters_from_device (NMModem *modem,
NMDevice *device);
NMActStageReturn nm_modem_act_stage1_prepare (NMModem *modem, NMActStageReturn nm_modem_act_stage1_prepare (NMModem *modem,
NMActRequest *req, NMActRequest *req,
NMDeviceStateReason *out_failure_reason); NMDeviceStateReason *out_failure_reason);

View file

@ -689,6 +689,8 @@ lease_validity_span (const char *str_expire, GDateTime *now)
* @addr_family: whether to read IPv4 or IPv6 leases * @addr_family: whether to read IPv4 or IPv6 leases
* @iface: the interface name to match leases with * @iface: the interface name to match leases with
* @ifindex: interface index of @iface * @ifindex: interface index of @iface
* @route_table: the route table for the default route.
* @route_metric: the route metric for the default route.
* @contents: the contents of a dhclient leasefile * @contents: the contents of a dhclient leasefile
* @now: the current UTC date/time; pass %NULL to automatically use current * @now: the current UTC date/time; pass %NULL to automatically use current
* UTC time. Testcases may need a different value for 'now' * UTC time. Testcases may need a different value for 'now'
@ -704,6 +706,8 @@ nm_dhcp_dhclient_read_lease_ip_configs (NMDedupMultiIndex *multi_idx,
int addr_family, int addr_family,
const char *iface, const char *iface,
int ifindex, int ifindex,
guint32 route_table,
guint32 route_metric,
const char *contents, const char *contents,
GDateTime *now) GDateTime *now)
{ {
@ -814,7 +818,17 @@ nm_dhcp_dhclient_read_lease_ip_configs (NMDedupMultiIndex *multi_idx,
ip4 = nm_ip4_config_new (multi_idx, ifindex); ip4 = nm_ip4_config_new (multi_idx, ifindex);
nm_ip4_config_add_address (ip4, &address); nm_ip4_config_add_address (ip4, &address);
nm_ip4_config_set_gateway (ip4, gw);
{
const NMPlatformIP4Route r = {
.rt_source = NM_IP_CONFIG_SOURCE_DHCP,
.gateway = gw,
.table_coerced = nm_platform_route_table_coerce (route_table),
.metric = route_metric,
};
nm_ip4_config_add_route (ip4, &r, NULL);
}
value = g_hash_table_lookup (hash, "option domain-name-servers"); value = g_hash_table_lookup (hash, "option domain-name-servers");
if (value) { if (value) {

View file

@ -47,6 +47,8 @@ GSList *nm_dhcp_dhclient_read_lease_ip_configs (struct _NMDedupMultiIndex *multi
int addr_family, int addr_family,
const char *iface, const char *iface,
int ifindex, int ifindex,
guint32 route_table,
guint32 route_metric,
const char *contents, const char *contents,
GDateTime *now); GDateTime *now);

View file

@ -167,9 +167,8 @@ nm_dhcp_dhclient_get_lease_ip_configs (NMDedupMultiIndex *multi_idx,
guint32 route_table, guint32 route_table,
guint32 route_metric) guint32 route_metric)
{ {
char *contents = NULL; gs_free char *contents = NULL;
char *leasefile; gs_free char *leasefile = NULL;
GSList *leases = NULL;
leasefile = get_dhclient_leasefile (addr_family, iface, uuid, NULL); leasefile = get_dhclient_leasefile (addr_family, iface, uuid, NULL);
if (!leasefile) if (!leasefile)
@ -178,13 +177,11 @@ nm_dhcp_dhclient_get_lease_ip_configs (NMDedupMultiIndex *multi_idx,
if ( g_file_test (leasefile, G_FILE_TEST_EXISTS) if ( g_file_test (leasefile, G_FILE_TEST_EXISTS)
&& g_file_get_contents (leasefile, &contents, NULL, NULL) && g_file_get_contents (leasefile, &contents, NULL, NULL)
&& contents && contents
&& contents[0]) && contents[0]) {
leases = nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, addr_family, iface, ifindex, contents, NULL); return nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, addr_family, iface, ifindex,
route_table, route_metric, contents, NULL);
g_free (leasefile); }
g_free (contents); return NULL;
return leases;
} }
static gboolean static gboolean

View file

@ -243,6 +243,8 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx,
gsize data_len; gsize data_len;
gboolean metered = FALSE; gboolean metered = FALSE;
gboolean static_default_gateway = FALSE; gboolean static_default_gateway = FALSE;
gboolean gateway_has = FALSE;
in_addr_t gateway = 0;
g_return_val_if_fail (lease != NULL, NULL); g_return_val_if_fail (lease != NULL, NULL);
@ -369,7 +371,8 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx,
} else { } else {
if (!static_default_gateway) { if (!static_default_gateway) {
static_default_gateway = TRUE; static_default_gateway = TRUE;
nm_ip4_config_set_gateway (ip4_config, route.gateway); gateway_has = TRUE;
gateway = route.gateway;
s = nm_utils_inet4_ntop (route.gateway, NULL); s = nm_utils_inet4_ntop (route.gateway, NULL);
LOG_LEASE (LOGD_DHCP4, "gateway %s", s); LOG_LEASE (LOGD_DHCP4, "gateway %s", s);
@ -390,13 +393,25 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx,
if (!static_default_gateway) { if (!static_default_gateway) {
r = sd_dhcp_lease_get_router (lease, &tmp_addr); r = sd_dhcp_lease_get_router (lease, &tmp_addr);
if (r == 0) { if (r == 0) {
nm_ip4_config_set_gateway (ip4_config, tmp_addr.s_addr); gateway_has = TRUE;
gateway = tmp_addr.s_addr;
s = nm_utils_inet4_ntop (tmp_addr.s_addr, NULL); s = nm_utils_inet4_ntop (tmp_addr.s_addr, NULL);
LOG_LEASE (LOGD_DHCP4, "gateway %s", s); LOG_LEASE (LOGD_DHCP4, "gateway %s", s);
add_option (options, dhcp4_requests, SD_DHCP_OPTION_ROUTER, s); add_option (options, dhcp4_requests, SD_DHCP_OPTION_ROUTER, s);
} }
} }
if (gateway_has) {
const NMPlatformIP4Route rt = {
.rt_source = NM_IP_CONFIG_SOURCE_DHCP,
.gateway = gateway,
.table_coerced = nm_platform_route_table_coerce (route_table),
.metric = route_metric,
};
nm_ip4_config_add_route (ip4_config, &rt, NULL);
}
/* MTU */ /* MTU */
r = sd_dhcp_lease_get_mtu (lease, &mtu); r = sd_dhcp_lease_get_mtu (lease, &mtu);
if (r == 0 && mtu) { if (r == 0 && mtu) {

View file

@ -405,7 +405,8 @@ nm_dhcp_utils_ip4_config_from_options (NMDedupMultiIndex *multi_idx,
in_addr_t addr; in_addr_t addr;
NMPlatformIP4Address address; NMPlatformIP4Address address;
char *str = NULL; char *str = NULL;
guint32 gwaddr = 0; gboolean gateway_has = FALSE;
guint32 gateway = 0;
guint8 plen = 0; guint8 plen = 0;
g_return_val_if_fail (options != NULL, NULL); g_return_val_if_fail (options != NULL, NULL);
@ -434,12 +435,12 @@ nm_dhcp_utils_ip4_config_from_options (NMDedupMultiIndex *multi_idx,
/* Routes: if the server returns classless static routes, we MUST ignore /* Routes: if the server returns classless static routes, we MUST ignore
* the 'static_routes' option. * the 'static_routes' option.
*/ */
if (!ip4_process_classless_routes (iface, options, route_table, route_metric, ip4_config, &gwaddr)) if (!ip4_process_classless_routes (iface, options, route_table, route_metric, ip4_config, &gateway))
process_classful_routes (iface, options, route_table, route_metric, ip4_config); process_classful_routes (iface, options, route_table, route_metric, ip4_config);
if (gwaddr) { if (gateway) {
_LOG2I (LOGD_DHCP4, iface, " gateway %s", nm_utils_inet4_ntop (gwaddr, NULL)); _LOG2I (LOGD_DHCP4, iface, " gateway %s", nm_utils_inet4_ntop (gateway, NULL));
nm_ip4_config_set_gateway (ip4_config, gwaddr); gateway_has = TRUE;
} else { } else {
/* If the gateway wasn't provided as a classless static route with a /* If the gateway wasn't provided as a classless static route with a
* subnet length of 0, try to find it using the old-style 'routers' option. * subnet length of 0, try to find it using the old-style 'routers' option.
@ -451,9 +452,9 @@ nm_dhcp_utils_ip4_config_from_options (NMDedupMultiIndex *multi_idx,
for (s = routers; *s; s++) { for (s = routers; *s; s++) {
/* FIXME: how to handle multiple routers? */ /* FIXME: how to handle multiple routers? */
if (inet_pton (AF_INET, *s, &gwaddr) > 0) { if (inet_pton (AF_INET, *s, &gateway) > 0) {
nm_ip4_config_set_gateway (ip4_config, gwaddr);
_LOG2I (LOGD_DHCP4, iface, " gateway %s", *s); _LOG2I (LOGD_DHCP4, iface, " gateway %s", *s);
gateway_has = TRUE;
break; break;
} else } else
_LOG2W (LOGD_DHCP4, iface, "ignoring invalid gateway '%s'", *s); _LOG2W (LOGD_DHCP4, iface, "ignoring invalid gateway '%s'", *s);
@ -462,6 +463,17 @@ nm_dhcp_utils_ip4_config_from_options (NMDedupMultiIndex *multi_idx,
} }
} }
if (gateway_has) {
const NMPlatformIP4Route r = {
.rt_source = NM_IP_CONFIG_SOURCE_DHCP,
.gateway = gateway,
.table_coerced = nm_platform_route_table_coerce (route_table),
.metric = route_metric,
};
nm_ip4_config_add_route (ip4_config, &r, NULL);
}
str = g_hash_table_lookup (options, "dhcp_lease_time"); str = g_hash_table_lookup (options, "dhcp_lease_time");
if (str) { if (str) {
address.lifetime = address.preferred = strtoul (str, NULL, 10); address.lifetime = address.preferred = strtoul (str, NULL, 10);

View file

@ -23,6 +23,7 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <linux/rtnetlink.h>
#include "nm-utils/nm-dedup-multi.h" #include "nm-utils/nm-dedup-multi.h"
@ -38,6 +39,8 @@
#define DEBUG 1 #define DEBUG 1
static const int IFINDEX = 5; static const int IFINDEX = 5;
static const guint32 ROUTE_TABLE = RT_TABLE_MAIN;
static const guint32 ROUTE_METRIC = 100;
static void static void
test_config (const char *orig, test_config (const char *orig,
@ -912,7 +915,7 @@ test_read_lease_ip4_config_basic (void)
/* Date from before the least expiration */ /* Date from before the least expiration */
now = g_date_time_new_utc (2013, 11, 1, 19, 55, 32); now = g_date_time_new_utc (2013, 11, 1, 19, 55, 32);
leases = nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, AF_INET, "wlan0", IFINDEX, contents, now); leases = nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, AF_INET, "wlan0", IFINDEX, ROUTE_TABLE, ROUTE_METRIC, contents, now);
g_assert_cmpint (g_slist_length (leases), ==, 2); g_assert_cmpint (g_slist_length (leases), ==, 2);
/* IP4Config #1 */ /* IP4Config #1 */
@ -929,7 +932,7 @@ test_read_lease_ip4_config_basic (void)
/* Gateway */ /* Gateway */
expected_addr = nmtst_inet4_from_string ("192.168.1.1"); expected_addr = nmtst_inet4_from_string ("192.168.1.1");
g_assert_cmpint (nm_ip4_config_get_gateway (config), ==, expected_addr); g_assert_cmpint (nmtst_ip4_config_get_gateway (config), ==, expected_addr);
/* DNS */ /* DNS */
g_assert_cmpint (nm_ip4_config_get_num_nameservers (config), ==, 1); g_assert_cmpint (nm_ip4_config_get_num_nameservers (config), ==, 1);
@ -952,7 +955,7 @@ test_read_lease_ip4_config_basic (void)
/* Gateway */ /* Gateway */
expected_addr = nmtst_inet4_from_string ("10.77.52.254"); expected_addr = nmtst_inet4_from_string ("10.77.52.254");
g_assert_cmpint (nm_ip4_config_get_gateway (config), ==, expected_addr); g_assert_cmpint (nmtst_ip4_config_get_gateway (config), ==, expected_addr);
/* DNS */ /* DNS */
g_assert_cmpint (nm_ip4_config_get_num_nameservers (config), ==, 2); g_assert_cmpint (nm_ip4_config_get_num_nameservers (config), ==, 2);
@ -987,7 +990,7 @@ test_read_lease_ip4_config_expired (void)
/* Date from *after* the lease expiration */ /* Date from *after* the lease expiration */
now = g_date_time_new_utc (2013, 12, 1, 19, 55, 32); now = g_date_time_new_utc (2013, 12, 1, 19, 55, 32);
leases = nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, AF_INET, "wlan0", IFINDEX, contents, now); leases = nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, AF_INET, "wlan0", IFINDEX, ROUTE_TABLE, ROUTE_METRIC, contents, now);
g_assert (leases == NULL); g_assert (leases == NULL);
g_date_time_unref (now); g_date_time_unref (now);
@ -1010,7 +1013,7 @@ test_read_lease_ip4_config_expect_failure (gconstpointer user_data)
/* Date from before the least expiration */ /* Date from before the least expiration */
now = g_date_time_new_utc (2013, 11, 1, 1, 1, 1); now = g_date_time_new_utc (2013, 11, 1, 1, 1, 1);
leases = nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, AF_INET, "wlan0", IFINDEX, contents, now); leases = nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, AF_INET, "wlan0", IFINDEX, ROUTE_TABLE, ROUTE_METRIC, contents, now);
g_assert (leases == NULL); g_assert (leases == NULL);
g_date_time_unref (now); g_date_time_unref (now);

View file

@ -114,7 +114,7 @@ test_generic_options (void)
/* Gateway */ /* Gateway */
g_assert (inet_pton (AF_INET, expected_gw, &tmp) > 0); g_assert (inet_pton (AF_INET, expected_gw, &tmp) > 0);
g_assert (nm_ip4_config_get_gateway (ip4_config) == tmp); g_assert (nmtst_ip4_config_get_gateway (ip4_config) == tmp);
g_assert_cmpint (nm_ip4_config_get_num_wins (ip4_config), ==, 0); g_assert_cmpint (nm_ip4_config_get_num_wins (ip4_config), ==, 0);
@ -133,7 +133,7 @@ test_generic_options (void)
g_assert (nm_ip4_config_get_nameserver (ip4_config, 1) == tmp); g_assert (nm_ip4_config_get_nameserver (ip4_config, 1) == tmp);
/* Routes */ /* Routes */
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2); g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 3);
/* Route #1 */ /* Route #1 */
route = _nmtst_ip4_config_get_route (ip4_config, 0); route = _nmtst_ip4_config_get_route (ip4_config, 0);
@ -146,13 +146,17 @@ test_generic_options (void)
/* Route #2 */ /* Route #2 */
route = _nmtst_ip4_config_get_route (ip4_config, 1); route = _nmtst_ip4_config_get_route (ip4_config, 1);
g_assert (inet_pton (AF_INET, expected_route2_dest, &tmp) > 0); g_assert (route->network == nmtst_inet4_from_string (expected_route2_dest));
g_assert (route->network == tmp); g_assert (route->gateway == nmtst_inet4_from_string (expected_route2_gw));
g_assert (inet_pton (AF_INET, expected_route2_gw, &tmp) > 0);
g_assert (route->gateway == tmp);
g_assert_cmpint (route->plen, ==, 32); g_assert_cmpint (route->plen, ==, 32);
g_assert_cmpint (route->metric, ==, 0); g_assert_cmpint (route->metric, ==, 0);
route = _nmtst_ip4_config_get_route (ip4_config, 2);
g_assert (route->network == nmtst_inet4_from_string ("0.0.0.0"));
g_assert (route->gateway == nmtst_inet4_from_string ("192.168.1.1"));
g_assert_cmpint (route->plen, ==, 0);
g_assert_cmpint (route->metric, ==, 0);
g_hash_table_destroy (options); g_hash_table_destroy (options);
} }
@ -238,7 +242,7 @@ ip4_test_gateway (NMIP4Config *ip4_config, const char *expected_gw)
g_assert_cmpint (nm_ip4_config_get_num_addresses (ip4_config), ==, 1); g_assert_cmpint (nm_ip4_config_get_num_addresses (ip4_config), ==, 1);
g_assert (inet_pton (AF_INET, expected_gw, &tmp) > 0); g_assert (inet_pton (AF_INET, expected_gw, &tmp) > 0);
g_assert (nm_ip4_config_get_gateway (ip4_config) == tmp); g_assert (nmtst_ip4_config_get_gateway (ip4_config) == tmp);
} }
static void static void
@ -261,9 +265,10 @@ test_classless_static_routes_1 (void)
ip4_config = _ip4_config_from_options (1, "eth0", options, 0); ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
/* IP4 routes */ /* IP4 routes */
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2); g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 3);
ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24);
ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 8); ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 8);
ip4_test_route (ip4_config, 2, "0.0.0.0", "192.168.1.1", 0);
g_hash_table_destroy (options); g_hash_table_destroy (options);
} }
@ -288,9 +293,10 @@ test_classless_static_routes_2 (void)
ip4_config = _ip4_config_from_options (1, "eth0", options, 0); ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
/* IP4 routes */ /* IP4 routes */
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2); g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 3);
ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24);
ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 8); ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 8);
ip4_test_route (ip4_config, 2, "0.0.0.0", expected_route1_gw, 0);
g_hash_table_destroy (options); g_hash_table_destroy (options);
} }
@ -316,9 +322,10 @@ test_fedora_dhclient_classless_static_routes (void)
ip4_config = _ip4_config_from_options (1, "eth0", options, 0); ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
/* IP4 routes */ /* IP4 routes */
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2); g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 3);
ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 25); ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 25);
ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 7); ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 7);
ip4_test_route (ip4_config, 2, "0.0.0.0", expected_route1_gw, 0);
/* Gateway */ /* Gateway */
ip4_test_gateway (ip4_config, expected_gateway); ip4_test_gateway (ip4_config, expected_gateway);
@ -348,8 +355,9 @@ test_dhclient_invalid_classless_routes_1 (void)
g_test_assert_expected_messages (); g_test_assert_expected_messages ();
/* IP4 routes */ /* IP4 routes */
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 1); g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2);
ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24);
ip4_test_route (ip4_config, 1, "0.0.0.0", expected_route1_gw, 0);
g_hash_table_destroy (options); g_hash_table_destroy (options);
} }
@ -380,9 +388,10 @@ test_dhcpcd_invalid_classless_routes_1 (void)
/* Test falling back to old-style static routes if the classless static /* Test falling back to old-style static routes if the classless static
* routes are invalid. * routes are invalid.
*/ */
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2); g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 3);
ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 32); ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 32);
ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 32); ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 32);
ip4_test_route (ip4_config, 2, "0.0.0.0", "192.168.1.1", 0);
g_hash_table_destroy (options); g_hash_table_destroy (options);
} }
@ -412,9 +421,10 @@ test_dhclient_invalid_classless_routes_2 (void)
/* Test falling back to old-style static routes if the classless static /* Test falling back to old-style static routes if the classless static
* routes are invalid. * routes are invalid.
*/ */
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2); g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 3);
ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 32); ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 32);
ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 32); ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 32);
ip4_test_route (ip4_config, 2, "0.0.0.0", "192.168.1.1", 0);
g_hash_table_destroy (options); g_hash_table_destroy (options);
} }
@ -446,9 +456,10 @@ test_dhcpcd_invalid_classless_routes_2 (void)
*/ */
/* Routes */ /* Routes */
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2); g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 3);
ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 32); ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 32);
ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 32); ip4_test_route (ip4_config, 1, expected_route2_dest, expected_route2_gw, 32);
ip4_test_route (ip4_config, 2, "0.0.0.0", "192.168.1.1", 0);
g_hash_table_destroy (options); g_hash_table_destroy (options);
} }
@ -474,8 +485,9 @@ test_dhclient_invalid_classless_routes_3 (void)
g_test_assert_expected_messages (); g_test_assert_expected_messages ();
/* IP4 routes */ /* IP4 routes */
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 1); g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2);
ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24);
ip4_test_route (ip4_config, 1, "0.0.0.0", expected_route1_gw, 0);
g_hash_table_destroy (options); g_hash_table_destroy (options);
} }
@ -501,8 +513,9 @@ test_dhcpcd_invalid_classless_routes_3 (void)
g_test_assert_expected_messages (); g_test_assert_expected_messages ();
/* IP4 routes */ /* IP4 routes */
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 1); g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2);
ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24);
ip4_test_route (ip4_config, 1, "0.0.0.0", expected_route1_gw, 0);
g_hash_table_destroy (options); g_hash_table_destroy (options);
} }
@ -525,8 +538,9 @@ test_dhclient_gw_in_classless_routes (void)
ip4_config = _ip4_config_from_options (1, "eth0", options, 0); ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
/* IP4 routes */ /* IP4 routes */
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 1); g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2);
ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24);
ip4_test_route (ip4_config, 1, "0.0.0.0", "192.2.3.4", 0);
/* Gateway */ /* Gateway */
ip4_test_gateway (ip4_config, expected_gateway); ip4_test_gateway (ip4_config, expected_gateway);
@ -552,8 +566,9 @@ test_dhcpcd_gw_in_classless_routes (void)
ip4_config = _ip4_config_from_options (1, "eth0", options, 0); ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
/* IP4 routes */ /* IP4 routes */
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 1); g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2);
ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); ip4_test_route (ip4_config, 0, expected_route1_dest, expected_route1_gw, 24);
ip4_test_route (ip4_config, 1, "0.0.0.0", "192.2.3.4", 0);
/* Gateway */ /* Gateway */
ip4_test_gateway (ip4_config, expected_gateway); ip4_test_gateway (ip4_config, expected_gateway);

View file

@ -135,16 +135,6 @@ add_interface_configuration (NMDnsSystemdResolved *self,
ic->configs = g_list_append (ic->configs, data->config); ic->configs = g_list_append (ic->configs, data->config);
} }
static void
add_domain (GVariantBuilder *domains,
const char *domain,
gboolean never_default)
{
/* If this link is never the default (e.g. only used for resources on this
* network) add a routing domain. */
g_variant_builder_add (domains, "(sb)", domain, never_default);
}
static void static void
update_add_ip_config (NMDnsSystemdResolved *self, update_add_ip_config (NMDnsSystemdResolved *self,
GVariantBuilder *dns, GVariantBuilder *dns,
@ -154,7 +144,7 @@ update_add_ip_config (NMDnsSystemdResolved *self,
int addr_family; int addr_family;
gsize addr_size; gsize addr_size;
guint i, n; guint i, n;
gboolean never_default; gboolean route_only;
if (NM_IS_IP4_CONFIG (config)) if (NM_IS_IP4_CONFIG (config))
addr_family = AF_INET; addr_family = AF_INET;
@ -188,31 +178,33 @@ update_add_ip_config (NMDnsSystemdResolved *self,
g_variant_builder_close (dns); g_variant_builder_close (dns);
} }
never_default = addr_family == AF_INET /* If this link is never the default (e.g. only used for resources on this
? nm_ip4_config_get_never_default (config) * network) add a routing domain. */
: nm_ip6_config_get_never_default (config); route_only = addr_family == AF_INET
? !nm_ip4_config_best_default_route_get (config)
: !nm_ip6_config_best_default_route_get (config);
n = addr_family == AF_INET n = addr_family == AF_INET
? nm_ip4_config_get_num_searches (config) ? nm_ip4_config_get_num_searches (config)
: nm_ip6_config_get_num_searches (config); : nm_ip6_config_get_num_searches (config);
if (n > 0) { if (n > 0) {
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
add_domain (domains, g_variant_builder_add (domains, "(sb)",
addr_family == AF_INET addr_family == AF_INET
? nm_ip4_config_get_search (config, i) ? nm_ip4_config_get_search (config, i)
: nm_ip6_config_get_search (config, i), : nm_ip6_config_get_search (config, i),
never_default); route_only);
} }
} else { } else {
n = addr_family == AF_INET n = addr_family == AF_INET
? nm_ip4_config_get_num_domains (config) ? nm_ip4_config_get_num_domains (config)
: nm_ip6_config_get_num_domains (config); : nm_ip6_config_get_num_domains (config);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
add_domain (domains, g_variant_builder_add (domains, "(sb)",
addr_family == AF_INET addr_family == AF_INET
? nm_ip4_config_get_domain (config, i) ? nm_ip4_config_get_domain (config, i)
: nm_ip6_config_get_domain (config, i), : nm_ip6_config_get_domain (config, i),
never_default); route_only);
} }
} }
} }

View file

@ -221,7 +221,7 @@ create_dm_cmd_line (const char *iface,
nm_cmd_line_add_string (cmd, s->str); nm_cmd_line_add_string (cmd, s->str);
g_string_truncate (s, 0); g_string_truncate (s, 0);
if (!nm_ip4_config_get_never_default (ip4_config)) { if (nm_ip4_config_best_default_route_get (ip4_config)) {
g_string_append (s, "--dhcp-option=option:router,"); g_string_append (s, "--dhcp-option=option:router,");
g_string_append (s, localaddr); g_string_append (s, localaddr);
nm_cmd_line_add_string (cmd, s->str); nm_cmd_line_add_string (cmd, s->str);

View file

@ -62,12 +62,13 @@ typedef enum {
NM_NDISC_PREFERENCE_HIGH NM_NDISC_PREFERENCE_HIGH
} NMNDiscPreference; } NMNDiscPreference;
typedef struct { struct _NMNDiscGateway {
struct in6_addr address; struct in6_addr address;
guint32 timestamp; guint32 timestamp;
guint32 lifetime; guint32 lifetime;
NMNDiscPreference preference; NMNDiscPreference preference;
} NMNDiscGateway; };
typedef struct _NMNDiscGateway NMNDiscGateway;
struct _NMNDiscAddress { struct _NMNDiscAddress {
struct in6_addr address; struct in6_addr address;

View file

@ -169,6 +169,15 @@ nm_utils_ip_route_metric_normalize (int addr_family, guint32 metric)
return addr_family == AF_INET6 ? nm_utils_ip6_route_metric_normalize (metric) : metric; return addr_family == AF_INET6 ? nm_utils_ip6_route_metric_normalize (metric) : metric;
} }
static inline guint32
nm_utils_ip_route_metric_penalize (int addr_family, guint32 metric, guint32 penalty)
{
metric = nm_utils_ip_route_metric_normalize (addr_family, metric);
if (metric < G_MAXUINT32 - penalty)
return metric + penalty;
return G_MAXUINT32;
}
int nm_utils_modprobe (GError **error, gboolean suppress_error_loggin, const char *arg1, ...) G_GNUC_NULL_TERMINATED; int nm_utils_modprobe (GError **error, gboolean suppress_error_loggin, const char *arg1, ...) G_GNUC_NULL_TERMINATED;
guint64 nm_utils_get_start_time_for_pid (pid_t pid, char *out_state, pid_t *out_ppid); guint64 nm_utils_get_start_time_for_pid (pid_t pid, char *out_state, pid_t *out_ppid);

View file

@ -124,9 +124,14 @@ dump_ip4_to_props (NMIP4Config *ip4, GVariantBuilder *builder)
g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("aau")); g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("aau"));
first = TRUE; first = TRUE;
nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &addr) { nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &addr) {
const NMPObject *default_route;
array[0] = addr->address; array[0] = addr->address;
array[1] = addr->plen; array[1] = addr->plen;
array[2] = first ? nm_ip4_config_get_gateway (ip4) : 0; array[2] = ( first
&& (default_route = nm_ip4_config_best_default_route_get (ip4)))
? NMP_OBJECT_CAST_IP4_ROUTE (default_route)->gateway
: (guint32) 0;
g_variant_builder_add (&int_builder, "@au", g_variant_builder_add (&int_builder, "@au",
g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32, g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32,
array, 3, sizeof (guint32))); array, 3, sizeof (guint32)));
@ -197,12 +202,15 @@ dump_ip6_to_props (NMIP6Config *ip6, GVariantBuilder *builder)
first = TRUE; first = TRUE;
nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6, &addr) { nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6, &addr) {
const NMPObject *default_route;
ip = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, ip = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
&addr->address, &addr->address,
sizeof (struct in6_addr), 1); sizeof (struct in6_addr), 1);
gw = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, gw = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
first ( first
? (nm_ip6_config_get_gateway (ip6) ?: &in6addr_any) && (default_route = nm_ip6_config_best_default_route_get (ip6)))
? &NMP_OBJECT_CAST_IP6_ROUTE (default_route)->gateway
: &in6addr_any, : &in6addr_any,
sizeof (struct in6_addr), 1); sizeof (struct in6_addr), 1);
g_variant_builder_add (&int_builder, "(@ayu@ay)", ip, addr->plen, gw); g_variant_builder_add (&int_builder, "(@ayu@ay)", ip, addr->plen, gw);

View file

@ -122,13 +122,13 @@ dhcp4_state_changed (NMDhcpClient *client,
existing = nm_ip4_config_capture (nm_platform_get_multi_idx (NM_PLATFORM_GET), existing = nm_ip4_config_capture (nm_platform_get_multi_idx (NM_PLATFORM_GET),
NM_PLATFORM_GET, gl.ifindex, FALSE); NM_PLATFORM_GET, gl.ifindex, FALSE);
if (last_config) if (last_config)
nm_ip4_config_subtract (existing, last_config); nm_ip4_config_subtract (existing, last_config, 0);
nm_ip4_config_merge (existing, ip4_config, NM_IP_CONFIG_MERGE_DEFAULT); nm_ip4_config_merge (existing, ip4_config, NM_IP_CONFIG_MERGE_DEFAULT, 0);
nm_ip4_config_add_device_routes (existing, nm_ip4_config_add_dependent_routes (existing,
RT_TABLE_MAIN, RT_TABLE_MAIN,
global_opt.priority_v4, global_opt.priority_v4,
&ip4_dev_route_blacklist); &ip4_dev_route_blacklist);
if (!nm_ip4_config_commit (existing, if (!nm_ip4_config_commit (existing,
NM_PLATFORM_GET, NM_PLATFORM_GET,
NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN)) NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN))
@ -168,20 +168,12 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
existing = nm_ip6_config_capture (nm_platform_get_multi_idx (NM_PLATFORM_GET), existing = nm_ip6_config_capture (nm_platform_get_multi_idx (NM_PLATFORM_GET),
NM_PLATFORM_GET, gl.ifindex, FALSE, global_opt.tempaddr); NM_PLATFORM_GET, gl.ifindex, FALSE, global_opt.tempaddr);
if (ndisc_config) if (ndisc_config)
nm_ip6_config_subtract (existing, ndisc_config); nm_ip6_config_subtract (existing, ndisc_config, 0);
else { else {
ndisc_config = nm_ip6_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET), ndisc_config = nm_ip6_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET),
gl.ifindex); gl.ifindex);
} }
if (changed & NM_NDISC_CONFIG_GATEWAYS) {
/* Use the first gateway as ordered in neighbor discovery cache. */
if (rdata->gateways_n)
nm_ip6_config_set_gateway (ndisc_config, &rdata->gateways[0].address);
else
nm_ip6_config_set_gateway (ndisc_config, NULL);
}
if (changed & NM_NDISC_CONFIG_ADDRESSES) { if (changed & NM_NDISC_CONFIG_ADDRESSES) {
guint8 plen; guint8 plen;
guint32 ifa_flags; guint32 ifa_flags;
@ -207,8 +199,11 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
ifa_flags); ifa_flags);
} }
if (changed & NM_NDISC_CONFIG_ROUTES) { if (NM_FLAGS_ANY (changed, NM_NDISC_CONFIG_ROUTES
| NM_NDISC_CONFIG_GATEWAYS)) {
nm_ip6_config_reset_routes_ndisc (ndisc_config, nm_ip6_config_reset_routes_ndisc (ndisc_config,
rdata->gateways,
rdata->gateways_n,
rdata->routes, rdata->routes,
rdata->routes_n, rdata->routes_n,
RT_TABLE_MAIN, RT_TABLE_MAIN,
@ -229,10 +224,10 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (global_opt.ifname, "mtu")), val); nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (global_opt.ifname, "mtu")), val);
} }
nm_ip6_config_merge (existing, ndisc_config, NM_IP_CONFIG_MERGE_DEFAULT); nm_ip6_config_merge (existing, ndisc_config, NM_IP_CONFIG_MERGE_DEFAULT, 0);
nm_ip6_config_add_device_routes (existing, nm_ip6_config_add_dependent_routes (existing,
RT_TABLE_MAIN, RT_TABLE_MAIN,
global_opt.priority_v6); global_opt.priority_v6);
if (!nm_ip6_config_commit (existing, if (!nm_ip6_config_commit (existing,
NM_PLATFORM_GET, NM_PLATFORM_GET,
NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN, NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN,

View file

@ -287,10 +287,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMIP4Config,
); );
typedef struct { typedef struct {
bool never_default:1;
bool metered:1; bool metered:1;
bool has_gateway:1;
guint32 gateway;
guint32 mtu; guint32 mtu;
int ifindex; int ifindex;
NMIPConfigSource mtu_source; NMIPConfigSource mtu_source;
@ -489,6 +486,19 @@ _nm_ip4_config_best_default_route_find (const NMIP4Config *self)
return new_best_default_route; return new_best_default_route;
} }
in_addr_t
nmtst_ip4_config_get_gateway (NMIP4Config *config)
{
const NMPObject *rt;
g_assert (NM_IS_IP4_CONFIG (config));
rt = nm_ip4_config_best_default_route_get (config);
if (!rt)
return 0;
return NMP_OBJECT_CAST_IP4_ROUTE (rt)->gateway;
}
/*****************************************************************************/ /*****************************************************************************/
static void static void
@ -575,9 +585,6 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
{ {
NMIP4Config *self; NMIP4Config *self;
NMIP4ConfigPrivate *priv; NMIP4ConfigPrivate *priv;
guint32 lowest_metric;
guint32 old_gateway = 0;
gboolean old_has_gateway = FALSE;
const NMDedupMultiHeadEntry *head_entry; const NMDedupMultiHeadEntry *head_entry;
NMDedupMultiIter iter; NMDedupMultiIter iter;
const NMPObject *plobj = NULL; const NMPObject *plobj = NULL;
@ -614,6 +621,7 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
sort_captured_addresses, sort_captured_addresses,
NULL); NULL);
has_addresses = TRUE; has_addresses = TRUE;
_notify_addresses (self);
} }
head_entry = nm_platform_lookup_addrroute (platform, head_entry = nm_platform_lookup_addrroute (platform,
@ -621,31 +629,15 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
ifindex); ifindex);
/* Extract gateway from default route */ /* Extract gateway from default route */
old_gateway = priv->gateway; nmp_cache_iter_for_each (&iter, head_entry, &plobj)
old_has_gateway = priv->has_gateway;
lowest_metric = G_MAXUINT32;
priv->has_gateway = FALSE;
nmp_cache_iter_for_each (&iter, head_entry, &plobj) {
const NMPlatformIP4Route *route = NMP_OBJECT_CAST_IP4_ROUTE (plobj);
if ( !route->table_coerced
&& NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)
&& route->rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) {
if (route->metric < lowest_metric) {
priv->gateway = route->gateway;
lowest_metric = route->metric;
}
priv->has_gateway = TRUE;
}
_add_route (self, plobj, NULL, NULL); _add_route (self, plobj, NULL, NULL);
}
/* If the interface has the default route, and has IPv4 addresses, capture /* If the interface has the default route, and has IPv4 addresses, capture
* nameservers from /etc/resolv.conf. * nameservers from /etc/resolv.conf.
*/ */
if (has_addresses && priv->has_gateway && capture_resolv_conf) { if ( has_addresses
&& priv->best_default_route
&& capture_resolv_conf) {
gs_free char *rc_contents = NULL; gs_free char *rc_contents = NULL;
if (g_file_get_contents (_PATH_RESCONF, &rc_contents, NULL, NULL)) { if (g_file_get_contents (_PATH_RESCONF, &rc_contents, NULL, NULL)) {
@ -657,25 +649,19 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
} }
} }
/* actually, nobody should be connected to the signal, just to be sure, notify */
_notify_addresses (self);
_notify_routes (self);
if ( priv->gateway != old_gateway
|| priv->has_gateway != old_has_gateway)
_notify (self, PROP_GATEWAY);
return self; return self;
} }
void void
nm_ip4_config_add_device_routes (NMIP4Config *self, nm_ip4_config_add_dependent_routes (NMIP4Config *self,
guint32 route_table, guint32 route_table,
guint32 route_metric, guint32 route_metric,
GPtrArray **out_ip4_dev_route_blacklist) GPtrArray **out_ip4_dev_route_blacklist)
{ {
const NMIP4ConfigPrivate *priv; const NMIP4ConfigPrivate *priv;
GPtrArray *ip4_dev_route_blacklist = NULL; GPtrArray *ip4_dev_route_blacklist = NULL;
const NMPlatformIP4Address *addr; const NMPlatformIP4Address *my_addr;
const NMPlatformIP4Route *my_route;
int ifindex; int ifindex;
NMDedupMultiIter iter; NMDedupMultiIter iter;
@ -689,18 +675,18 @@ nm_ip4_config_add_device_routes (NMIP4Config *self,
/* For IPv6 slaac, we explicitly add the device-routes (onlink) to NMIP6Config. /* For IPv6 slaac, we explicitly add the device-routes (onlink) to NMIP6Config.
* As we don't do that for IPv4 (and manual IPv6 addresses), add them explicitly. */ * As we don't do that for IPv4 (and manual IPv6 addresses), add them explicitly. */
nm_ip_config_iter_ip4_address_for_each (&iter, self, &addr) { nm_ip_config_iter_ip4_address_for_each (&iter, self, &my_addr) {
nm_auto_nmpobj NMPObject *r = NULL; nm_auto_nmpobj NMPObject *r = NULL;
NMPlatformIP4Route *route; NMPlatformIP4Route *route;
in_addr_t network; in_addr_t network;
if (addr->plen == 0) if (my_addr->plen == 0)
continue; continue;
nm_assert (addr->plen <= 32); nm_assert (my_addr->plen <= 32);
/* The destination network depends on the peer-address. */ /* The destination network depends on the peer-address. */
network = nm_utils_ip4_address_clear_host_address (addr->peer_address, addr->plen); network = nm_utils_ip4_address_clear_host_address (my_addr->peer_address, my_addr->plen);
if (_ipv4_is_zeronet (network)) { if (_ipv4_is_zeronet (network)) {
/* Kernel doesn't add device-routes for destinations that /* Kernel doesn't add device-routes for destinations that
@ -714,8 +700,8 @@ nm_ip4_config_add_device_routes (NMIP4Config *self,
route->ifindex = ifindex; route->ifindex = ifindex;
route->rt_source = NM_IP_CONFIG_SOURCE_KERNEL; route->rt_source = NM_IP_CONFIG_SOURCE_KERNEL;
route->network = network; route->network = network;
route->plen = addr->plen; route->plen = my_addr->plen;
route->pref_src = addr->address; route->pref_src = my_addr->address;
route->table_coerced = nm_platform_route_table_coerce (route_table); route->table_coerced = nm_platform_route_table_coerce (route_table);
route->metric = route_metric; route->metric = route_metric;
route->scope_inv = nm_platform_route_scope_inv (NM_RT_SCOPE_LINK); route->scope_inv = nm_platform_route_scope_inv (NM_RT_SCOPE_LINK);
@ -755,6 +741,27 @@ nm_ip4_config_add_device_routes (NMIP4Config *self,
} }
} }
again:
nm_ip_config_iter_ip4_route_for_each (&iter, self, &my_route) {
NMPlatformIP4Route rt;
if ( !NM_PLATFORM_IP_ROUTE_IS_DEFAULT (my_route)
|| my_route->gateway == 0
|| NM_IS_IP_CONFIG_SOURCE_RTPROT (my_route->rt_source)
|| nm_ip4_config_get_direct_route_for_host (self,
my_route->gateway,
nm_platform_route_table_uncoerce (my_route->table_coerced, TRUE)))
continue;
rt = *my_route;
rt.network = my_route->gateway;
rt.plen = 32;
rt.gateway = 0;
_add_route (self, NULL, &rt, NULL);
/* adding the route might have invalidated the iteration. Start again. */
goto again;
}
NM_SET_OUT (out_ip4_dev_route_blacklist, ip4_dev_route_blacklist); NM_SET_OUT (out_ip4_dev_route_blacklist, ip4_dev_route_blacklist);
} }
@ -848,6 +855,8 @@ nm_ip4_config_merge_setting (NMIP4Config *self,
NMIP4ConfigPrivate *priv; NMIP4ConfigPrivate *priv;
guint naddresses, nroutes, nnameservers, nsearches; guint naddresses, nroutes, nnameservers, nsearches;
int i, priority; int i, priority;
const char *gateway_str;
guint32 gateway_bin;
if (!setting) if (!setting)
return; return;
@ -864,15 +873,18 @@ nm_ip4_config_merge_setting (NMIP4Config *self,
nsearches = nm_setting_ip_config_get_num_dns_searches (setting); nsearches = nm_setting_ip_config_get_num_dns_searches (setting);
/* Gateway */ /* Gateway */
if (nm_setting_ip_config_get_never_default (setting)) if ( !nm_setting_ip_config_get_never_default (setting)
nm_ip4_config_set_never_default (self, TRUE); && (gateway_str = nm_setting_ip_config_get_gateway (setting))
else if (nm_setting_ip_config_get_ignore_auto_routes (setting)) && inet_pton (AF_INET, gateway_str, &gateway_bin) == 1
nm_ip4_config_set_never_default (self, FALSE); && gateway_bin) {
if (nm_setting_ip_config_get_gateway (setting)) { const NMPlatformIP4Route r = {
guint32 gateway; .rt_source = NM_IP_CONFIG_SOURCE_USER,
.gateway = gateway_bin,
.table_coerced = nm_platform_route_table_coerce (route_table),
.metric = route_metric,
};
inet_pton (AF_INET, nm_setting_ip_config_get_gateway (setting), &gateway); _add_route (self, NULL, &r, NULL);
nm_ip4_config_set_gateway (self, gateway);
} }
/* Addresses */ /* Addresses */
@ -961,8 +973,8 @@ nm_ip4_config_merge_setting (NMIP4Config *self,
NMSetting * NMSetting *
nm_ip4_config_create_setting (const NMIP4Config *self) nm_ip4_config_create_setting (const NMIP4Config *self)
{ {
const NMIP4ConfigPrivate *priv;
NMSettingIPConfig *s_ip4; NMSettingIPConfig *s_ip4;
guint32 gateway;
guint nnameservers, nsearches, noptions; guint nnameservers, nsearches, noptions;
const char *method = NULL; const char *method = NULL;
int i; int i;
@ -979,7 +991,8 @@ nm_ip4_config_create_setting (const NMIP4Config *self)
return NM_SETTING (s_ip4); return NM_SETTING (s_ip4);
} }
gateway = nm_ip4_config_get_gateway (self); priv = NM_IP4_CONFIG_GET_PRIVATE (self);
nnameservers = nm_ip4_config_get_num_nameservers (self); nnameservers = nm_ip4_config_get_num_nameservers (self);
nsearches = nm_ip4_config_get_num_searches (self); nsearches = nm_ip4_config_get_num_searches (self);
noptions = nm_ip4_config_get_num_dns_options (self); noptions = nm_ip4_config_get_num_dns_options (self);
@ -1007,10 +1020,12 @@ nm_ip4_config_create_setting (const NMIP4Config *self)
} }
/* Gateway */ /* Gateway */
if ( nm_ip4_config_has_gateway (self) if ( priv->best_default_route
&& nm_setting_ip_config_get_num_addresses (s_ip4) > 0) { && nm_setting_ip_config_get_num_addresses (s_ip4) > 0) {
g_object_set (s_ip4, g_object_set (s_ip4,
NM_SETTING_IP_CONFIG_GATEWAY, nm_utils_inet4_ntop (gateway, NULL), NM_SETTING_IP_CONFIG_GATEWAY,
nm_utils_inet4_ntop (NMP_OBJECT_CAST_IP4_ROUTE (priv->best_default_route)->gateway,
NULL),
NULL); NULL);
} }
@ -1070,7 +1085,10 @@ nm_ip4_config_create_setting (const NMIP4Config *self)
/*****************************************************************************/ /*****************************************************************************/
void void
nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src, NMIPConfigMergeFlags merge_flags) nm_ip4_config_merge (NMIP4Config *dst,
const NMIP4Config *src,
NMIPConfigMergeFlags merge_flags,
guint32 default_route_metric_penalty)
{ {
NMIP4ConfigPrivate *dst_priv; NMIP4ConfigPrivate *dst_priv;
const NMIP4ConfigPrivate *src_priv; const NMIP4ConfigPrivate *src_priv;
@ -1096,14 +1114,24 @@ nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src, NMIPConfigMergeFl
nm_ip4_config_add_nameserver (dst, nm_ip4_config_get_nameserver (src, i)); nm_ip4_config_add_nameserver (dst, nm_ip4_config_get_nameserver (src, i));
} }
/* default gateway */
if (nm_ip4_config_has_gateway (src))
nm_ip4_config_set_gateway (dst, nm_ip4_config_get_gateway (src));
/* routes */ /* routes */
if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_ROUTES)) { if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_ROUTES)) {
nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, src, NULL) const NMPlatformIP4Route *r_src;
nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, src, &r_src) {
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r_src)) {
if (NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES))
continue;
if (default_route_metric_penalty) {
NMPlatformIP4Route r = *r_src;
r.metric = nm_utils_ip_route_metric_penalize (AF_INET, r.metric, default_route_metric_penalty);
_add_route (dst, NULL, &r, NULL);
continue;
}
}
_add_route (dst, ipconf_iter.current->obj, NULL, NULL); _add_route (dst, ipconf_iter.current->obj, NULL, NULL);
}
} }
/* domains */ /* domains */
@ -1255,11 +1283,17 @@ _wins_get_index (const NMIP4Config *self, guint32 wins_server)
* nm_ip4_config_subtract: * nm_ip4_config_subtract:
* @dst: config from which to remove everything in @src * @dst: config from which to remove everything in @src
* @src: config to remove from @dst * @src: config to remove from @dst
* @default_route_metric_penalty: pretend that on source we applied
* a route penalty on the default-route. It means, for default routes
* we don't remove routes that match exactly, but those with a lower
* metric (with the penalty removed).
* *
* Removes everything in @src from @dst. * Removes everything in @src from @dst.
*/ */
void void
nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src) nm_ip4_config_subtract (NMIP4Config *dst,
const NMIP4Config *src,
guint32 default_route_metric_penalty)
{ {
NMIP4ConfigPrivate *dst_priv; NMIP4ConfigPrivate *dst_priv;
guint i; guint i;
@ -1296,23 +1330,31 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src)
nm_ip4_config_del_nameserver (dst, idx); nm_ip4_config_del_nameserver (dst, idx);
} }
/* default gateway */
if ( (nm_ip4_config_has_gateway (src) == nm_ip4_config_has_gateway (dst))
&& (nm_ip4_config_get_gateway (src) == nm_ip4_config_get_gateway (dst)))
nm_ip4_config_unset_gateway (dst);
if (!nm_ip4_config_get_num_addresses (dst))
nm_ip4_config_unset_gateway (dst);
/* routes */ /* routes */
changed = FALSE; changed = FALSE;
changed_default_route = FALSE; changed_default_route = FALSE;
nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, src, &r) { nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, src, &r) {
const NMPObject *o_src = NMP_OBJECT_UP_CAST (r);
NMPObject o_lookup_copy;
const NMPObject *o_lookup;
nm_auto_nmpobj const NMPObject *obj_old = NULL; nm_auto_nmpobj const NMPObject *obj_old = NULL;
if ( NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r)
&& default_route_metric_penalty) {
NMPlatformIP4Route *rr;
/* the default route was penalized when merging it to the combined ip-config.
* When subtracting the routes, we must re-do that process when comparing
* the routes. */
o_lookup = nmp_object_stackinit_obj (&o_lookup_copy, o_src);
rr = NMP_OBJECT_CAST_IP4_ROUTE (&o_lookup_copy);
rr->metric = nm_utils_ip_route_metric_penalize (AF_INET, rr->metric, default_route_metric_penalty);
} else
o_lookup = o_src;
if (nm_dedup_multi_index_remove_obj (dst_priv->multi_idx, if (nm_dedup_multi_index_remove_obj (dst_priv->multi_idx,
&dst_priv->idx_ip4_routes, &dst_priv->idx_ip4_routes,
NMP_OBJECT_UP_CAST (r), o_lookup,
(gconstpointer *) &obj_old)) { (gconstpointer *) &obj_old)) {
if (dst_priv->best_default_route == obj_old) { if (dst_priv->best_default_route == obj_old) {
nm_clear_nmp_object (&dst_priv->best_default_route); nm_clear_nmp_object (&dst_priv->best_default_route);
@ -1324,6 +1366,7 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src)
if (changed_default_route) { if (changed_default_route) {
_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, _nm_ip_config_best_default_route_set (&dst_priv->best_default_route,
_nm_ip4_config_best_default_route_find (dst)); _nm_ip4_config_best_default_route_find (dst));
_notify (dst, PROP_GATEWAY);
} }
if (changed) if (changed)
_notify_routes (dst); _notify_routes (dst);
@ -1379,7 +1422,9 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src)
} }
void void
nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src) nm_ip4_config_intersect (NMIP4Config *dst,
const NMIP4Config *src,
guint32 default_route_metric_penalty)
{ {
NMIP4ConfigPrivate *dst_priv; NMIP4ConfigPrivate *dst_priv;
const NMIP4ConfigPrivate *src_priv; const NMIP4ConfigPrivate *src_priv;
@ -1415,23 +1460,31 @@ nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src)
/* ignore nameservers */ /* ignore nameservers */
/* default gateway */
if ( !nm_ip4_config_get_num_addresses (dst)
|| (nm_ip4_config_has_gateway (src) != nm_ip4_config_has_gateway (dst))
|| (nm_ip4_config_get_gateway (src) != nm_ip4_config_get_gateway (dst))) {
nm_ip4_config_unset_gateway (dst);
}
/* routes */ /* routes */
changed = FALSE; changed = FALSE;
new_best_default_route = NULL; new_best_default_route = NULL;
nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, dst, &r) { nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, dst, &r) {
const NMPObject *o = NMP_OBJECT_UP_CAST (r); const NMPObject *o_dst = NMP_OBJECT_UP_CAST (r);
const NMPObject *o_lookup;
NMPObject o_lookup_copy;
if ( NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r)
&& default_route_metric_penalty) {
NMPlatformIP4Route *rr;
/* the default route was penalized when merging it to the combined ip-config.
* When intersecting the routes, we must re-do that process when comparing
* the routes. */
o_lookup = nmp_object_stackinit_obj (&o_lookup_copy, o_dst);
rr = NMP_OBJECT_CAST_IP4_ROUTE (&o_lookup_copy);
rr->metric = nm_utils_ip_route_metric_penalize (AF_INET, rr->metric, default_route_metric_penalty);
} else
o_lookup = o_dst;
if (nm_dedup_multi_index_lookup_obj (src_priv->multi_idx, if (nm_dedup_multi_index_lookup_obj (src_priv->multi_idx,
&src_priv->idx_ip4_routes, &src_priv->idx_ip4_routes,
o)) { o_lookup)) {
new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, o); new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, o_dst);
continue; continue;
} }
@ -1440,8 +1493,10 @@ nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src)
nm_assert_not_reached (); nm_assert_not_reached ();
changed = TRUE; changed = TRUE;
} }
if (_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route)) if (_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route)) {
nm_assert (changed); nm_assert (changed);
_notify (dst, PROP_GATEWAY);
}
if (changed) if (changed)
_notify_routes (dst); _notify_routes (dst);
@ -1502,22 +1557,6 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev
has_minor_changes = TRUE; has_minor_changes = TRUE;
} }
/* never_default */
if (src_priv->never_default != dst_priv->never_default) {
dst_priv->never_default = src_priv->never_default;
has_minor_changes = TRUE;
}
/* default gateway */
if ( src_priv->gateway != dst_priv->gateway
|| src_priv->has_gateway != dst_priv->has_gateway) {
if (src_priv->has_gateway)
nm_ip4_config_set_gateway (dst, src_priv->gateway);
else
nm_ip4_config_unset_gateway (dst);
has_relevant_changes = TRUE;
}
/* addresses */ /* addresses */
head_entry_src = nm_ip4_config_lookup_addresses (src); head_entry_src = nm_ip4_config_lookup_addresses (src);
nm_dedup_multi_iter_init (&ipconf_iter_src, head_entry_src); nm_dedup_multi_iter_init (&ipconf_iter_src, head_entry_src);
@ -1615,7 +1654,8 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev
new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, obj_new); new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, obj_new);
} }
nm_dedup_multi_index_dirty_remove_idx (dst_priv->multi_idx, &dst_priv->idx_ip4_routes, FALSE); nm_dedup_multi_index_dirty_remove_idx (dst_priv->multi_idx, &dst_priv->idx_ip4_routes, FALSE);
_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route); if (_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route))
_notify (dst, PROP_GATEWAY);
_notify_routes (dst); _notify_routes (dst);
} }
@ -1794,12 +1834,6 @@ nm_ip4_config_dump (const NMIP4Config *self, const char *detail)
nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, self, &address) nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, self, &address)
g_message (" a: %s", nm_platform_ip4_address_to_string (address, NULL, 0)); g_message (" a: %s", nm_platform_ip4_address_to_string (address, NULL, 0));
/* default gateway */
if (nm_ip4_config_has_gateway (self)) {
tmp = nm_ip4_config_get_gateway (self);
g_message (" gw: %s", nm_utils_inet4_ntop (tmp, NULL));
}
/* nameservers */ /* nameservers */
for (i = 0; i < nm_ip4_config_get_num_nameservers (self); i++) { for (i = 0; i < nm_ip4_config_get_num_nameservers (self); i++) {
tmp = nm_ip4_config_get_nameserver (self, i); tmp = nm_ip4_config_get_nameserver (self, i);
@ -1840,102 +1874,9 @@ nm_ip4_config_dump (const NMIP4Config *self, const char *detail)
g_message (" wins: %s", nm_utils_inet4_ntop (tmp, NULL)); g_message (" wins: %s", nm_utils_inet4_ntop (tmp, NULL));
} }
g_message (" n-dflt: %d", nm_ip4_config_get_never_default (self));
g_message (" mtrd: %d", (int) nm_ip4_config_get_metered (self)); g_message (" mtrd: %d", (int) nm_ip4_config_get_metered (self));
} }
gboolean
nm_ip4_config_destination_is_direct (const NMIP4Config *self, guint32 network, guint8 plen)
{
const NMPlatformIP4Address *item;
in_addr_t peer_network;
NMDedupMultiIter iter;
nm_ip_config_iter_ip4_address_for_each (&iter, self, &item) {
if (item->plen > plen)
continue;
peer_network = nm_utils_ip4_address_clear_host_address (item->peer_address, item->plen);
if (_ipv4_is_zeronet (peer_network))
continue;
if (peer_network != nm_utils_ip4_address_clear_host_address (network, item->plen))
continue;
return TRUE;
}
return FALSE;
}
/*****************************************************************************/
void
nm_ip4_config_set_never_default (NMIP4Config *self, gboolean never_default)
{
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
priv->never_default = never_default;
}
gboolean
nm_ip4_config_get_never_default (const NMIP4Config *self)
{
const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
return priv->never_default;
}
void
nm_ip4_config_set_gateway (NMIP4Config *self, guint32 gateway)
{
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
if (priv->gateway != gateway || !priv->has_gateway) {
priv->gateway = gateway;
priv->has_gateway = TRUE;
_notify (self, PROP_GATEWAY);
}
}
void
nm_ip4_config_unset_gateway (NMIP4Config *self)
{
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
if (priv->has_gateway) {
priv->gateway = 0;
priv->has_gateway = FALSE;
_notify (self, PROP_GATEWAY);
}
}
/**
* nm_ip4_config_has_gateway:
* @self: the #NMIP4Config object
*
* NetworkManager's handling of default-routes is limited and usually a default-route
* cannot have gateway 0.0.0.0. For peer-to-peer routes, we still want to
* support that, so we need to differenciate between no-default-route and a
* on-link-default route. Hence nm_ip4_config_has_gateway().
*
* Returns: whether the object has a gateway explicitly set. */
gboolean
nm_ip4_config_has_gateway (const NMIP4Config *self)
{
const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
return priv->has_gateway;
}
guint32
nm_ip4_config_get_gateway (const NMIP4Config *self)
{
const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
return priv->gateway;
}
/*****************************************************************************/ /*****************************************************************************/
void void
@ -2077,7 +2018,8 @@ nm_ip4_config_reset_routes (NMIP4Config *self)
if (nm_dedup_multi_index_remove_idx (priv->multi_idx, if (nm_dedup_multi_index_remove_idx (priv->multi_idx,
&priv->idx_ip4_routes) > 0) { &priv->idx_ip4_routes) > 0) {
nm_clear_nmp_object (&priv->best_default_route); if (nm_clear_nmp_object (&priv->best_default_route))
_notify (self, PROP_GATEWAY);
_notify_routes (self); _notify_routes (self);
} }
} }
@ -2105,11 +2047,19 @@ _add_route (NMIP4Config *self,
FALSE, FALSE,
&obj_old, &obj_old,
&obj_new_2)) { &obj_new_2)) {
gboolean changed_default_route = FALSE;
if ( priv->best_default_route == obj_old if ( priv->best_default_route == obj_old
&& obj_old != obj_new_2) && obj_old != obj_new_2) {
changed_default_route = TRUE;
nm_clear_nmp_object (&priv->best_default_route); nm_clear_nmp_object (&priv->best_default_route);
_nm_ip_config_best_default_route_merge (&priv->best_default_route, obj_new_2); }
NM_SET_OUT (out_obj_new, nmp_object_ref (obj_new_2)); NM_SET_OUT (out_obj_new, nmp_object_ref (obj_new_2));
if (_nm_ip_config_best_default_route_merge (&priv->best_default_route, obj_new_2))
changed_default_route = TRUE;
if (changed_default_route)
_notify (self, PROP_GATEWAY);
_notify_routes (self); _notify_routes (self);
} else } else
NM_SET_OUT (out_obj_new, nmp_object_ref (obj_new_2)); NM_SET_OUT (out_obj_new, nmp_object_ref (obj_new_2));
@ -2178,7 +2128,9 @@ _nmtst_ip4_config_get_route (const NMIP4Config *self, guint i)
} }
const NMPlatformIP4Route * const NMPlatformIP4Route *
nm_ip4_config_get_direct_route_for_host (const NMIP4Config *self, guint32 host) nm_ip4_config_get_direct_route_for_host (const NMIP4Config *self,
in_addr_t host,
guint32 route_table)
{ {
const NMPlatformIP4Route *best_route = NULL; const NMPlatformIP4Route *best_route = NULL;
const NMPlatformIP4Route *item; const NMPlatformIP4Route *item;
@ -2193,6 +2145,9 @@ nm_ip4_config_get_direct_route_for_host (const NMIP4Config *self, guint32 host)
if (best_route && best_route->plen > item->plen) if (best_route && best_route->plen > item->plen)
continue; continue;
if (nm_platform_route_table_uncoerce (item->table_coerced, TRUE) != route_table)
continue;
if (nm_utils_ip4_address_clear_host_address (host, item->plen) != nm_utils_ip4_address_clear_host_address (item->network, item->plen)) if (nm_utils_ip4_address_clear_host_address (host, item->plen) != nm_utils_ip4_address_clear_host_address (item->network, item->plen))
continue; continue;
@ -2704,8 +2659,9 @@ nm_ip4_config_nmpobj_remove (NMIP4Config *self,
break; break;
case NMP_OBJECT_TYPE_IP4_ROUTE: case NMP_OBJECT_TYPE_IP4_ROUTE:
if (priv->best_default_route == obj_old) { if (priv->best_default_route == obj_old) {
_nm_ip_config_best_default_route_set (&priv->best_default_route, if (_nm_ip_config_best_default_route_set (&priv->best_default_route,
_nm_ip4_config_best_default_route_find (self)); _nm_ip4_config_best_default_route_find (self)))
_notify (self, PROP_GATEWAY);
} }
_notify_routes (self); _notify_routes (self);
break; break;
@ -2736,9 +2692,6 @@ nm_ip4_config_hash (const NMIP4Config *self, GChecksum *sum, gboolean dns_only)
g_return_if_fail (sum); g_return_if_fail (sum);
if (!dns_only) { if (!dns_only) {
hash_u32 (sum, nm_ip4_config_has_gateway (self));
hash_u32 (sum, nm_ip4_config_get_gateway (self));
nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, self, &address) { nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, self, &address) {
hash_u32 (sum, address->address); hash_u32 (sum, address->address);
hash_u32 (sum, address->plen); hash_u32 (sum, address->plen);
@ -2893,7 +2846,10 @@ get_property (GObject *object, guint prop_id,
const guint32 dbus_addr[3] = { const guint32 dbus_addr[3] = {
address->address, address->address,
address->plen, address->plen,
i == 0 ? priv->gateway : 0, ( i == 0
&& priv->best_default_route)
? NMP_OBJECT_CAST_IP4_ROUTE (priv->best_default_route)->gateway
: (guint32) 0,
}; };
g_variant_builder_add (&builder_legacy, "@au", g_variant_builder_add (&builder_legacy, "@au",
@ -2978,9 +2934,11 @@ out_routes_cached:
priv->routes_variant); priv->routes_variant);
break; break;
case PROP_GATEWAY: case PROP_GATEWAY:
if (priv->has_gateway) if (priv->best_default_route) {
g_value_set_string (value, nm_utils_inet4_ntop (priv->gateway, NULL)); g_value_set_string (value,
else nm_utils_inet4_ntop (NMP_OBJECT_CAST_IP4_ROUTE (priv->best_default_route)->gateway,
NULL));
} else
g_value_set_string (value, NULL); g_value_set_string (value, NULL);
break; break;
case PROP_NAMESERVERS: case PROP_NAMESERVERS:

View file

@ -80,12 +80,16 @@ nm_ip_config_best_default_route_is (const NMPObject *obj)
{ {
const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE (obj); const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE (obj);
/* return whether @obj is considered a default-route, that is, a route /* return whether @obj is considered a default-route.
* as added by NetworkManager. E.g. if the route is not in the main-table, *
* it's considered just like a regular route. */ * NMIP4Config/NMIP6Config tracks the (best) default-route explicitly, because
* at various places we act differently depending on whether there is a default-route
* configured.
*
* Note that this only considers the main routing table. */
return r return r
&& !r->table_coerced && NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r)
&& NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r); && nm_platform_route_table_is_main (r->table_coerced);
} }
const NMPObject *_nm_ip_config_best_default_route_find_better (const NMPObject *obj_cur, const NMPObject *obj_cmp); const NMPObject *_nm_ip_config_best_default_route_find_better (const NMPObject *obj_cur, const NMPObject *obj_cmp);
@ -151,10 +155,10 @@ 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); 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, void nm_ip4_config_add_dependent_routes (NMIP4Config *self,
guint32 route_table, guint32 route_table,
guint32 route_metric, guint32 route_metric,
GPtrArray **out_ip4_dev_route_blacklist); GPtrArray **out_ip4_dev_route_blacklist);
gboolean nm_ip4_config_commit (const NMIP4Config *self, gboolean nm_ip4_config_commit (const NMIP4Config *self,
NMPlatform *platform, NMPlatform *platform,
@ -167,24 +171,24 @@ void nm_ip4_config_merge_setting (NMIP4Config *self,
NMSetting *nm_ip4_config_create_setting (const NMIP4Config *self); NMSetting *nm_ip4_config_create_setting (const NMIP4Config *self);
void nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src, NMIPConfigMergeFlags merge_flags); void nm_ip4_config_merge (NMIP4Config *dst,
void nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src); const NMIP4Config *src,
void nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src); NMIPConfigMergeFlags merge_flags,
guint32 default_route_metric_penalty);
void nm_ip4_config_subtract (NMIP4Config *dst,
const NMIP4Config *src,
guint32 default_route_metric_penalty);
void nm_ip4_config_intersect (NMIP4Config *dst,
const NMIP4Config *src,
guint32 default_route_metric_penalty);
gboolean nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relevant_changes); gboolean nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relevant_changes);
gboolean nm_ip4_config_destination_is_direct (const NMIP4Config *self, guint32 dest, guint8 plen);
void nm_ip4_config_dump (const NMIP4Config *self, const char *detail); void nm_ip4_config_dump (const NMIP4Config *self, const char *detail);
void nm_ip4_config_set_never_default (NMIP4Config *self, gboolean never_default);
gboolean nm_ip4_config_get_never_default (const NMIP4Config *self);
void nm_ip4_config_set_gateway (NMIP4Config *self, guint32 gateway);
void nm_ip4_config_unset_gateway (NMIP4Config *self);
gboolean nm_ip4_config_has_gateway (const NMIP4Config *self);
guint32 nm_ip4_config_get_gateway (const NMIP4Config *self);
const NMPObject *nm_ip4_config_best_default_route_get (const NMIP4Config *self); const NMPObject *nm_ip4_config_best_default_route_get (const NMIP4Config *self);
const NMPObject *_nm_ip4_config_best_default_route_find (const NMIP4Config *self); const NMPObject *_nm_ip4_config_best_default_route_find (const NMIP4Config *self);
in_addr_t nmtst_ip4_config_get_gateway (NMIP4Config *config);
const NMDedupMultiHeadEntry *nm_ip4_config_lookup_addresses (const NMIP4Config *self); const NMDedupMultiHeadEntry *nm_ip4_config_lookup_addresses (const NMIP4Config *self);
void nm_ip4_config_reset_addresses (NMIP4Config *self); void nm_ip4_config_reset_addresses (NMIP4Config *self);
void nm_ip4_config_add_address (NMIP4Config *self, const NMPlatformIP4Address *address); void nm_ip4_config_add_address (NMIP4Config *self, const NMPlatformIP4Address *address);
@ -203,7 +207,9 @@ void _nmtst_ip4_config_del_route (NMIP4Config *self, guint i);
guint nm_ip4_config_get_num_routes (const NMIP4Config *self); guint nm_ip4_config_get_num_routes (const NMIP4Config *self);
const NMPlatformIP4Route *_nmtst_ip4_config_get_route (const NMIP4Config *self, guint i); const NMPlatformIP4Route *_nmtst_ip4_config_get_route (const NMIP4Config *self, guint i);
const NMPlatformIP4Route *nm_ip4_config_get_direct_route_for_host (const NMIP4Config *self, guint32 host); const NMPlatformIP4Route *nm_ip4_config_get_direct_route_for_host (const NMIP4Config *self,
in_addr_t host,
guint32 route_table);
void nm_ip4_config_reset_nameservers (NMIP4Config *self); void nm_ip4_config_reset_nameservers (NMIP4Config *self);
void nm_ip4_config_add_nameserver (NMIP4Config *self, guint32 nameserver); void nm_ip4_config_add_nameserver (NMIP4Config *self, guint32 nameserver);

View file

@ -58,11 +58,9 @@ _route_valid (const NMPlatformIP6Route *r)
/*****************************************************************************/ /*****************************************************************************/
typedef struct { typedef struct {
bool never_default:1;
int ifindex; int ifindex;
int dns_priority; int dns_priority;
NMSettingIP6ConfigPrivacy privacy; NMSettingIP6ConfigPrivacy privacy;
struct in6_addr gateway;
GArray *nameservers; GArray *nameservers;
GPtrArray *domains; GPtrArray *domains;
GPtrArray *searches; GPtrArray *searches;
@ -372,9 +370,6 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
{ {
NMIP6Config *self; NMIP6Config *self;
NMIP6ConfigPrivate *priv; NMIP6ConfigPrivate *priv;
guint32 lowest_metric = G_MAXUINT32;
struct in6_addr old_gateway = IN6ADDR_ANY_INIT;
gboolean has_gateway;
const NMDedupMultiHeadEntry *head_entry; const NMDedupMultiHeadEntry *head_entry;
NMDedupMultiIter iter; NMDedupMultiIter iter;
const NMPObject *plobj = NULL; const NMPObject *plobj = NULL;
@ -411,37 +406,22 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
nm_dedup_multi_head_entry_sort (head_entry, nm_dedup_multi_head_entry_sort (head_entry,
sort_captured_addresses, sort_captured_addresses,
GINT_TO_POINTER (use_temporary)); GINT_TO_POINTER (use_temporary));
_notify_addresses (self);
} }
head_entry = nm_platform_lookup_addrroute (platform, head_entry = nm_platform_lookup_addrroute (platform,
NMP_OBJECT_TYPE_IP6_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE,
ifindex); ifindex);
/* Extract gateway from default route */ nmp_cache_iter_for_each (&iter, head_entry, &plobj)
old_gateway = priv->gateway;
lowest_metric = G_MAXUINT32;
has_gateway = FALSE;
nmp_cache_iter_for_each (&iter, head_entry, &plobj) {
const NMPlatformIP6Route *route = NMP_OBJECT_CAST_IP6_ROUTE (plobj);
if ( !route->table_coerced
&& NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)
&& route->rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) {
if (route->metric < lowest_metric) {
priv->gateway = route->gateway;
lowest_metric = route->metric;
}
has_gateway = TRUE;
}
_add_route (self, plobj, NULL, NULL); _add_route (self, plobj, NULL, NULL);
}
/* If the interface has the default route, and has IPv6 addresses, capture /* If the interface has the default route, and has IPv6 addresses, capture
* nameservers from /etc/resolv.conf. * nameservers from /etc/resolv.conf.
*/ */
if (has_addresses && has_gateway && capture_resolv_conf) { if ( has_addresses
&& priv->best_default_route
&& capture_resolv_conf) {
gs_free char *rc_contents = NULL; gs_free char *rc_contents = NULL;
if (g_file_get_contents (_PATH_RESCONF, &rc_contents, NULL, NULL)) { if (g_file_get_contents (_PATH_RESCONF, &rc_contents, NULL, NULL)) {
@ -453,22 +433,17 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
} }
} }
/* actually, nobody should be connected to the signal, just to be sure, notify */
_notify_addresses (self);
_notify_routes (self);
if (!IN6_ARE_ADDR_EQUAL (&priv->gateway, &old_gateway))
_notify (self, PROP_GATEWAY);
return self; return self;
} }
void void
nm_ip6_config_add_device_routes (NMIP6Config *self, nm_ip6_config_add_dependent_routes (NMIP6Config *self,
guint32 route_table, guint32 route_table,
guint32 route_metric) guint32 route_metric)
{ {
const NMIP6ConfigPrivate *priv; const NMIP6ConfigPrivate *priv;
const NMPlatformIP6Address *addr; const NMPlatformIP6Address *my_addr;
const NMPlatformIP6Route *my_route;
int ifindex; int ifindex;
NMDedupMultiIter iter; NMDedupMultiIter iter;
@ -484,21 +459,21 @@ nm_ip6_config_add_device_routes (NMIP6Config *self,
* *
* For manually added IPv6 routes, add the device routes explicitly. */ * For manually added IPv6 routes, add the device routes explicitly. */
nm_ip_config_iter_ip6_address_for_each (&iter, self, &addr) { nm_ip_config_iter_ip6_address_for_each (&iter, self, &my_addr) {
NMPObject *r; NMPObject *r;
NMPlatformIP6Route *route; NMPlatformIP6Route *route;
gboolean has_peer; gboolean has_peer;
int routes_n, routes_i; int routes_n, routes_i;
if (NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_NOPREFIXROUTE)) if (NM_FLAGS_HAS (my_addr->n_ifa_flags, IFA_F_NOPREFIXROUTE))
continue; continue;
has_peer = !IN6_IS_ADDR_UNSPECIFIED (&addr->peer_address); has_peer = !IN6_IS_ADDR_UNSPECIFIED (&my_addr->peer_address);
/* If we have an IPv6 peer, we add two /128 routes /* If we have an IPv6 peer, we add two /128 routes
* (unless, both addresses are identical). */ * (unless, both addresses are identical). */
routes_n = ( has_peer routes_n = ( has_peer
&& !IN6_ARE_ADDR_EQUAL (&addr->address, &addr->peer_address)) && !IN6_ARE_ADDR_EQUAL (&my_addr->address, &my_addr->peer_address))
? 2 : 1; ? 2 : 1;
for (routes_i = 0; routes_i < routes_n; routes_i++) { for (routes_i = 0; routes_i < routes_n; routes_i++) {
@ -513,13 +488,13 @@ nm_ip6_config_add_device_routes (NMIP6Config *self,
if (has_peer) { if (has_peer) {
if (routes_i == 0) if (routes_i == 0)
route->network = addr->address; route->network = my_addr->address;
else else
route->network = addr->peer_address; route->network = my_addr->peer_address;
route->plen = 128; route->plen = 128;
} else { } else {
nm_utils_ip6_address_clear_host_address (&route->network, &addr->address, addr->plen); nm_utils_ip6_address_clear_host_address (&route->network, &my_addr->address, my_addr->plen);
route->plen = addr->plen; route->plen = my_addr->plen;
} }
nm_platform_ip_route_normalize (AF_INET6, (NMPlatformIPRoute *) route); nm_platform_ip_route_normalize (AF_INET6, (NMPlatformIPRoute *) route);
@ -533,6 +508,27 @@ nm_ip6_config_add_device_routes (NMIP6Config *self,
_add_route (self, r, NULL, NULL); _add_route (self, r, NULL, NULL);
} }
} }
again:
nm_ip_config_iter_ip6_route_for_each (&iter, self, &my_route) {
NMPlatformIP6Route rt;
if ( !NM_PLATFORM_IP_ROUTE_IS_DEFAULT (my_route)
|| IN6_IS_ADDR_UNSPECIFIED (&my_route->gateway)
|| NM_IS_IP_CONFIG_SOURCE_RTPROT (my_route->rt_source)
|| nm_ip6_config_get_direct_route_for_host (self,
&my_route->gateway,
nm_platform_route_table_uncoerce (my_route->table_coerced, TRUE)))
continue;
rt = *my_route;
rt.network = my_route->gateway;
rt.plen = 128;
rt.gateway = in6addr_any;
_add_route (self, NULL, &rt, NULL);
/* adding the route might have invalidated the iteration. Start again. */
goto again;
}
} }
gboolean gboolean
@ -644,6 +640,7 @@ nm_ip6_config_merge_setting (NMIP6Config *self,
NMIP6ConfigPrivate *priv; NMIP6ConfigPrivate *priv;
guint naddresses, nroutes, nnameservers, nsearches; guint naddresses, nroutes, nnameservers, nsearches;
const char *gateway_str; const char *gateway_str;
struct in6_addr gateway_bin;
int i, priority; int i, priority;
if (!setting) if (!setting)
@ -661,16 +658,18 @@ nm_ip6_config_merge_setting (NMIP6Config *self,
g_object_freeze_notify (G_OBJECT (self)); g_object_freeze_notify (G_OBJECT (self));
/* Gateway */ /* Gateway */
if (nm_setting_ip_config_get_never_default (setting)) if ( !nm_setting_ip_config_get_never_default (setting)
nm_ip6_config_set_never_default (self, TRUE); && (gateway_str = nm_setting_ip_config_get_gateway (setting))
else if (nm_setting_ip_config_get_ignore_auto_routes (setting)) && inet_pton (AF_INET6, gateway_str, &gateway_bin) == 1
nm_ip6_config_set_never_default (self, FALSE); && !IN6_IS_ADDR_UNSPECIFIED (&gateway_bin)) {
gateway_str = nm_setting_ip_config_get_gateway (setting); const NMPlatformIP6Route r = {
if (gateway_str) { .rt_source = NM_IP_CONFIG_SOURCE_USER,
struct in6_addr gateway; .gateway = gateway_bin,
.table_coerced = nm_platform_route_table_coerce (route_table),
.metric = route_metric,
};
inet_pton (AF_INET6, gateway_str, &gateway); _add_route (self, NULL, &r, NULL);
nm_ip6_config_set_gateway (self, &gateway);
} }
/* Addresses */ /* Addresses */
@ -753,8 +752,8 @@ nm_ip6_config_merge_setting (NMIP6Config *self,
NMSetting * NMSetting *
nm_ip6_config_create_setting (const NMIP6Config *self) nm_ip6_config_create_setting (const NMIP6Config *self)
{ {
const NMIP6ConfigPrivate *priv;
NMSettingIPConfig *s_ip6; NMSettingIPConfig *s_ip6;
const struct in6_addr *gateway;
guint nnameservers, nsearches, noptions; guint nnameservers, nsearches, noptions;
const char *method = NULL; const char *method = NULL;
int i; int i;
@ -771,7 +770,8 @@ nm_ip6_config_create_setting (const NMIP6Config *self)
return NM_SETTING (s_ip6); return NM_SETTING (s_ip6);
} }
gateway = nm_ip6_config_get_gateway (self); priv = NM_IP6_CONFIG_GET_PRIVATE (self);
nnameservers = nm_ip6_config_get_num_nameservers (self); nnameservers = nm_ip6_config_get_num_nameservers (self);
nsearches = nm_ip6_config_get_num_searches (self); nsearches = nm_ip6_config_get_num_searches (self);
noptions = nm_ip6_config_get_num_dns_options (self); noptions = nm_ip6_config_get_num_dns_options (self);
@ -803,10 +803,12 @@ nm_ip6_config_create_setting (const NMIP6Config *self)
} }
/* Gateway */ /* Gateway */
if ( gateway if ( priv->best_default_route
&& nm_setting_ip_config_get_num_addresses (s_ip6) > 0) { && nm_setting_ip_config_get_num_addresses (s_ip6) > 0) {
g_object_set (s_ip6, g_object_set (s_ip6,
NM_SETTING_IP_CONFIG_GATEWAY, nm_utils_inet6_ntop (gateway, NULL), NM_SETTING_IP_CONFIG_GATEWAY,
nm_utils_inet6_ntop (&NMP_OBJECT_CAST_IP6_ROUTE (priv->best_default_route)->gateway,
NULL),
NULL); NULL);
} }
@ -869,7 +871,10 @@ nm_ip6_config_create_setting (const NMIP6Config *self)
/*****************************************************************************/ /*****************************************************************************/
void void
nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFlags merge_flags) nm_ip6_config_merge (NMIP6Config *dst,
const NMIP6Config *src,
NMIPConfigMergeFlags merge_flags,
guint32 default_route_metric_penalty)
{ {
NMIP6ConfigPrivate *dst_priv; NMIP6ConfigPrivate *dst_priv;
const NMIP6ConfigPrivate *src_priv; const NMIP6ConfigPrivate *src_priv;
@ -895,14 +900,24 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl
nm_ip6_config_add_nameserver (dst, nm_ip6_config_get_nameserver (src, i)); nm_ip6_config_add_nameserver (dst, nm_ip6_config_get_nameserver (src, i));
} }
/* default gateway */
if (nm_ip6_config_get_gateway (src))
nm_ip6_config_set_gateway (dst, nm_ip6_config_get_gateway (src));
/* routes */ /* routes */
if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_ROUTES)) { if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_ROUTES)) {
nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, src, NULL) const NMPlatformIP6Route *r_src;
nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, src, &r_src) {
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r_src)) {
if (NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES))
continue;
if (default_route_metric_penalty) {
NMPlatformIP6Route r = *r_src;
r.metric = nm_utils_ip_route_metric_penalize (AF_INET6, r.metric, default_route_metric_penalty);
_add_route (dst, NULL, &r, NULL);
continue;
}
}
_add_route (dst, ipconf_iter.current->obj, NULL, NULL); _add_route (dst, ipconf_iter.current->obj, NULL, NULL);
}
} }
/* domains */ /* domains */
@ -930,25 +945,6 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl
g_object_thaw_notify (G_OBJECT (dst)); g_object_thaw_notify (G_OBJECT (dst));
} }
gboolean
nm_ip6_config_destination_is_direct (const NMIP6Config *self, const struct in6_addr *network, guint8 plen)
{
const NMPlatformIP6Address *item;
NMDedupMultiIter iter;
nm_assert (network);
nm_assert (plen <= 128);
nm_ip_config_iter_ip6_address_for_each (&iter, self, &item) {
if ( item->plen <= plen
&& !NM_FLAGS_HAS (item->n_ifa_flags, IFA_F_NOPREFIXROUTE)
&& nm_utils_ip6_address_same_prefix (&item->address, network, item->plen))
return TRUE;
}
return FALSE;
}
/*****************************************************************************/ /*****************************************************************************/
static int static int
@ -1017,11 +1013,17 @@ _dns_options_get_index (const NMIP6Config *self, const char *option)
* nm_ip6_config_subtract: * nm_ip6_config_subtract:
* @dst: config from which to remove everything in @src * @dst: config from which to remove everything in @src
* @src: config to remove from @dst * @src: config to remove from @dst
* * @default_route_metric_penalty: pretend that on source we applied
* a route penalty on the default-route. It means, for default routes
* we don't remove routes that match exactly, but those with a lower
* metric (with the penalty removed).
*
* Removes everything in @src from @dst. * Removes everything in @src from @dst.
*/ */
void void
nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src) nm_ip6_config_subtract (NMIP6Config *dst,
const NMIP6Config *src,
guint32 default_route_metric_penalty)
{ {
NMIP6ConfigPrivate *dst_priv; NMIP6ConfigPrivate *dst_priv;
guint i; guint i;
@ -1029,7 +1031,6 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
const NMPlatformIP6Address *a; const NMPlatformIP6Address *a;
const NMPlatformIP6Route *r; const NMPlatformIP6Route *r;
NMDedupMultiIter ipconf_iter; NMDedupMultiIter ipconf_iter;
const struct in6_addr *dst_tmp, *src_tmp;
gboolean changed; gboolean changed;
gboolean changed_default_route; gboolean changed_default_route;
@ -1059,24 +1060,31 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
nm_ip6_config_del_nameserver (dst, idx); nm_ip6_config_del_nameserver (dst, idx);
} }
/* default gateway */
src_tmp = nm_ip6_config_get_gateway (src);
dst_tmp = nm_ip6_config_get_gateway (dst);
if (src_tmp && dst_tmp && IN6_ARE_ADDR_EQUAL (src_tmp, dst_tmp))
nm_ip6_config_set_gateway (dst, NULL);
if (!nm_ip6_config_get_num_addresses (dst))
nm_ip6_config_set_gateway (dst, NULL);
/* routes */ /* routes */
changed = FALSE; changed = FALSE;
changed_default_route = FALSE; changed_default_route = FALSE;
nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, src, &r) { nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, src, &r) {
const NMPObject *o_src = NMP_OBJECT_UP_CAST (r);
NMPObject o_lookup_copy;
const NMPObject *o_lookup;
nm_auto_nmpobj const NMPObject *obj_old = NULL; nm_auto_nmpobj const NMPObject *obj_old = NULL;
if ( NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r)
&& default_route_metric_penalty) {
NMPlatformIP6Route *rr;
/* the default route was penalized when merging it to the combined ip-config.
* When subtracting the routes, we must re-do that process when comparing
* the routes. */
o_lookup = nmp_object_stackinit_obj (&o_lookup_copy, o_src);
rr = NMP_OBJECT_CAST_IP6_ROUTE (&o_lookup_copy);
rr->metric = nm_utils_ip_route_metric_penalize (AF_INET6, rr->metric, default_route_metric_penalty);
} else
o_lookup = o_src;
if (nm_dedup_multi_index_remove_obj (dst_priv->multi_idx, if (nm_dedup_multi_index_remove_obj (dst_priv->multi_idx,
&dst_priv->idx_ip6_routes, &dst_priv->idx_ip6_routes,
NMP_OBJECT_UP_CAST (r), o_lookup,
(gconstpointer *) &obj_old)) { (gconstpointer *) &obj_old)) {
if (dst_priv->best_default_route == obj_old) { if (dst_priv->best_default_route == obj_old) {
nm_clear_nmp_object (&dst_priv->best_default_route); nm_clear_nmp_object (&dst_priv->best_default_route);
@ -1088,6 +1096,7 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
if (changed_default_route) { if (changed_default_route) {
_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, _nm_ip_config_best_default_route_set (&dst_priv->best_default_route,
_nm_ip6_config_best_default_route_find (dst)); _nm_ip6_config_best_default_route_find (dst));
_notify (dst, PROP_GATEWAY);
} }
if (changed) if (changed)
_notify_routes (dst); _notify_routes (dst);
@ -1121,11 +1130,12 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
} }
void void
nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src) nm_ip6_config_intersect (NMIP6Config *dst,
const NMIP6Config *src,
guint32 default_route_metric_penalty)
{ {
NMIP6ConfigPrivate *dst_priv; NMIP6ConfigPrivate *dst_priv;
const NMIP6ConfigPrivate *src_priv; const NMIP6ConfigPrivate *src_priv;
const struct in6_addr *dst_tmp, *src_tmp;
NMDedupMultiIter ipconf_iter; NMDedupMultiIter ipconf_iter;
const NMPlatformIP6Address *a; const NMPlatformIP6Address *a;
const NMPlatformIP6Route *r; const NMPlatformIP6Route *r;
@ -1158,26 +1168,31 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src)
/* ignore nameservers */ /* ignore nameservers */
/* default gateway */
dst_tmp = nm_ip6_config_get_gateway (dst);
if (dst_tmp) {
src_tmp = nm_ip6_config_get_gateway (src);
if ( !nm_ip6_config_get_num_addresses (dst)
|| !src_tmp
|| !IN6_ARE_ADDR_EQUAL (src_tmp, dst_tmp))
nm_ip6_config_set_gateway (dst, NULL);
}
/* routes */ /* routes */
changed = FALSE; changed = FALSE;
new_best_default_route = NULL; new_best_default_route = NULL;
nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, dst, &r) { nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, dst, &r) {
const NMPObject *o = NMP_OBJECT_UP_CAST (r); const NMPObject *o_dst = NMP_OBJECT_UP_CAST (r);
const NMPObject *o_lookup;
NMPObject o_lookup_copy;
if ( NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r)
&& default_route_metric_penalty) {
NMPlatformIP6Route *rr;
/* the default route was penalized when merging it to the combined ip-config.
* When intersecting the routes, we must re-do that process when comparing
* the routes. */
o_lookup = nmp_object_stackinit_obj (&o_lookup_copy, o_dst);
rr = NMP_OBJECT_CAST_IP6_ROUTE (&o_lookup_copy);
rr->metric = nm_utils_ip_route_metric_penalize (AF_INET6, rr->metric, default_route_metric_penalty);
} else
o_lookup = o_dst;
if (nm_dedup_multi_index_lookup_obj (src_priv->multi_idx, if (nm_dedup_multi_index_lookup_obj (src_priv->multi_idx,
&src_priv->idx_ip6_routes, &src_priv->idx_ip6_routes,
o)) { o_lookup)) {
new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, o); new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, o_dst);
continue; continue;
} }
@ -1186,8 +1201,10 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src)
nm_assert_not_reached (); nm_assert_not_reached ();
changed = TRUE; changed = TRUE;
} }
if (_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route)) if (_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route)) {
nm_assert (changed); nm_assert (changed);
_notify (dst, PROP_GATEWAY);
}
if (changed) if (changed)
_notify_routes (dst); _notify_routes (dst);
@ -1247,18 +1264,6 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev
has_minor_changes = TRUE; has_minor_changes = TRUE;
} }
/* never_default */
if (src_priv->never_default != dst_priv->never_default) {
dst_priv->never_default = src_priv->never_default;
has_minor_changes = TRUE;
}
/* default gateway */
if (!IN6_ARE_ADDR_EQUAL (&src_priv->gateway, &dst_priv->gateway)) {
nm_ip6_config_set_gateway (dst, &src_priv->gateway);
has_relevant_changes = TRUE;
}
/* addresses */ /* addresses */
head_entry_src = nm_ip6_config_lookup_addresses (src); head_entry_src = nm_ip6_config_lookup_addresses (src);
nm_dedup_multi_iter_init (&ipconf_iter_src, head_entry_src); nm_dedup_multi_iter_init (&ipconf_iter_src, head_entry_src);
@ -1357,7 +1362,8 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev
new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, obj_new); new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, obj_new);
} }
nm_dedup_multi_index_dirty_remove_idx (dst_priv->multi_idx, &dst_priv->idx_ip6_routes, FALSE); nm_dedup_multi_index_dirty_remove_idx (dst_priv->multi_idx, &dst_priv->idx_ip6_routes, FALSE);
_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route); if (_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route))
_notify (dst, PROP_GATEWAY);
_notify_routes (dst); _notify_routes (dst);
} }
@ -1484,11 +1490,6 @@ nm_ip6_config_dump (const NMIP6Config *self, const char *detail)
nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, self, &address) nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, self, &address)
g_message (" a: %s", nm_platform_ip6_address_to_string (address, NULL, 0)); g_message (" a: %s", nm_platform_ip6_address_to_string (address, NULL, 0));
/* default gateway */
tmp = nm_ip6_config_get_gateway (self);
if (tmp)
g_message (" gw: %s", nm_utils_inet6_ntop (tmp, NULL));
/* nameservers */ /* nameservers */
for (i = 0; i < nm_ip6_config_get_num_nameservers (self); i++) { for (i = 0; i < nm_ip6_config_get_num_nameservers (self); i++) {
tmp = nm_ip6_config_get_nameserver (self, i); tmp = nm_ip6_config_get_nameserver (self, i);
@ -1512,51 +1513,6 @@ nm_ip6_config_dump (const NMIP6Config *self, const char *detail)
g_message (" dnsopt: %s", nm_ip6_config_get_dns_option (self, i)); g_message (" dnsopt: %s", nm_ip6_config_get_dns_option (self, i));
g_message (" dnspri: %d", nm_ip6_config_get_dns_priority (self)); g_message (" dnspri: %d", nm_ip6_config_get_dns_priority (self));
g_message (" n-dflt: %d", nm_ip6_config_get_never_default (self));
}
/*****************************************************************************/
void
nm_ip6_config_set_never_default (NMIP6Config *self, gboolean never_default)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
priv->never_default = never_default;
}
gboolean
nm_ip6_config_get_never_default (const NMIP6Config *self)
{
const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
return priv->never_default;
}
void
nm_ip6_config_set_gateway (NMIP6Config *self, const struct in6_addr *gateway)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
if (gateway) {
if (IN6_ARE_ADDR_EQUAL (&priv->gateway, gateway))
return;
priv->gateway = *gateway;
} else {
if (IN6_IS_ADDR_UNSPECIFIED (&priv->gateway))
return;
memset (&priv->gateway, 0, sizeof (priv->gateway));
}
_notify (self, PROP_GATEWAY);
}
const struct in6_addr *
nm_ip6_config_get_gateway (const NMIP6Config *self)
{
const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
return IN6_IS_ADDR_UNSPECIFIED (&priv->gateway) ? NULL : &priv->gateway;
} }
/*****************************************************************************/ /*****************************************************************************/
@ -1809,6 +1765,8 @@ _lookup_route (const NMIP6Config *self,
void void
nm_ip6_config_reset_routes_ndisc (NMIP6Config *self, nm_ip6_config_reset_routes_ndisc (NMIP6Config *self,
const NMNDiscGateway *gateways,
guint gateways_n,
const NMNDiscRoute *routes, const NMNDiscRoute *routes,
guint routes_n, guint routes_n,
guint32 route_table, guint32 route_table,
@ -1857,12 +1815,38 @@ nm_ip6_config_reset_routes_ndisc (NMIP6Config *self,
new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, obj_new); new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, obj_new);
} }
if (_nm_ip_config_best_default_route_set (&priv->best_default_route, new_best_default_route)) /* Use the first gateway as ordered in neighbor discovery cache. */
changed = TRUE; if (gateways_n) {
const NMPObject *obj_new;
const NMPlatformIP6Route r = {
.rt_source = NM_IP_CONFIG_SOURCE_NDISC,
.ifindex = priv->ifindex,
.gateway = gateways[0].address,
.table_coerced = nm_platform_route_table_coerce (route_table),
.metric = route_metric,
};
if (_nm_ip_config_add_obj (priv->multi_idx,
&priv->idx_ip6_routes_,
priv->ifindex,
NULL,
(const NMPlatformObject *) &r,
FALSE,
TRUE,
NULL,
&obj_new))
changed = TRUE;
new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, obj_new);
}
if (nm_dedup_multi_index_dirty_remove_idx (priv->multi_idx, &priv->idx_ip6_routes, FALSE) > 0) if (nm_dedup_multi_index_dirty_remove_idx (priv->multi_idx, &priv->idx_ip6_routes, FALSE) > 0)
changed = TRUE; changed = TRUE;
if (_nm_ip_config_best_default_route_set (&priv->best_default_route, new_best_default_route)) {
changed = TRUE;
_notify (self, PROP_GATEWAY);
}
if (changed) if (changed)
_notify_routes (self); _notify_routes (self);
} }
@ -1874,7 +1858,8 @@ nm_ip6_config_reset_routes (NMIP6Config *self)
if (nm_dedup_multi_index_remove_idx (priv->multi_idx, if (nm_dedup_multi_index_remove_idx (priv->multi_idx,
&priv->idx_ip6_routes) > 0) { &priv->idx_ip6_routes) > 0) {
nm_clear_nmp_object (&priv->best_default_route); if (nm_clear_nmp_object (&priv->best_default_route))
_notify (self, PROP_GATEWAY);
_notify_routes (self); _notify_routes (self);
} }
} }
@ -1902,11 +1887,19 @@ _add_route (NMIP6Config *self,
FALSE, FALSE,
&obj_old, &obj_old,
&obj_new_2)) { &obj_new_2)) {
gboolean changed_default_route = FALSE;
if ( priv->best_default_route == obj_old if ( priv->best_default_route == obj_old
&& obj_old != obj_new_2) && obj_old != obj_new_2) {
changed_default_route = TRUE;
nm_clear_nmp_object (&priv->best_default_route); nm_clear_nmp_object (&priv->best_default_route);
_nm_ip_config_best_default_route_merge (&priv->best_default_route, obj_new_2); }
NM_SET_OUT (out_obj_new, nmp_object_ref (obj_new_2)); NM_SET_OUT (out_obj_new, nmp_object_ref (obj_new_2));
if (_nm_ip_config_best_default_route_merge (&priv->best_default_route, obj_new_2))
changed_default_route = TRUE;
if (changed_default_route)
_notify (self, PROP_GATEWAY);
_notify_routes (self); _notify_routes (self);
} else } else
NM_SET_OUT (out_obj_new, nmp_object_ref (obj_new_2)); NM_SET_OUT (out_obj_new, nmp_object_ref (obj_new_2));
@ -1975,7 +1968,9 @@ _nmtst_ip6_config_get_route (const NMIP6Config *self, guint i)
} }
const NMPlatformIP6Route * const NMPlatformIP6Route *
nm_ip6_config_get_direct_route_for_host (const NMIP6Config *self, const struct in6_addr *host) nm_ip6_config_get_direct_route_for_host (const NMIP6Config *self,
const struct in6_addr *host,
guint32 route_table)
{ {
const NMPlatformIP6Route *best_route = NULL; const NMPlatformIP6Route *best_route = NULL;
const NMPlatformIP6Route *item; const NMPlatformIP6Route *item;
@ -1990,6 +1985,9 @@ nm_ip6_config_get_direct_route_for_host (const NMIP6Config *self, const struct i
if (best_route && best_route->plen > item->plen) if (best_route && best_route->plen > item->plen)
continue; continue;
if (nm_platform_route_table_uncoerce (item->table_coerced, TRUE) != route_table)
continue;
if (!nm_utils_ip6_address_same_prefix (host, &item->network, item->plen)) if (!nm_utils_ip6_address_same_prefix (host, &item->network, item->plen))
continue; continue;
@ -2357,8 +2355,9 @@ nm_ip6_config_nmpobj_remove (NMIP6Config *self,
break; break;
case NMP_OBJECT_TYPE_IP6_ROUTE: case NMP_OBJECT_TYPE_IP6_ROUTE:
if (priv->best_default_route == obj_old) { if (priv->best_default_route == obj_old) {
_nm_ip_config_best_default_route_set (&priv->best_default_route, if (_nm_ip_config_best_default_route_set (&priv->best_default_route,
_nm_ip6_config_best_default_route_find (self)); _nm_ip6_config_best_default_route_find (self)))
_notify (self, PROP_GATEWAY);
} }
_notify_routes (self); _notify_routes (self);
break; break;
@ -2398,8 +2397,6 @@ nm_ip6_config_hash (const NMIP6Config *self, GChecksum *sum, gboolean dns_only)
g_return_if_fail (sum); g_return_if_fail (sum);
if (dns_only == FALSE) { if (dns_only == FALSE) {
hash_in6addr (sum, nm_ip6_config_get_gateway (self));
nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, self, &address) { nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, self, &address) {
hash_in6addr (sum, &address->address); hash_in6addr (sum, &address->address);
hash_u32 (sum, address->plen); hash_u32 (sum, address->plen);
@ -2558,9 +2555,10 @@ get_property (GObject *object, guint prop_id,
&address->address, 16, 1), &address->address, 16, 1),
address->plen, address->plen,
g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
i == 0 ( i == 0
? (nm_ip6_config_get_gateway (self) ?: &in6addr_any) && priv->best_default_route)
: &in6addr_any, ? &NMP_OBJECT_CAST_IP6_ROUTE (priv->best_default_route)->gateway
: &in6addr_any,
16, 1)); 16, 1));
} }
} }
@ -2636,9 +2634,11 @@ out_routes_cached:
priv->routes_variant); priv->routes_variant);
break; break;
case PROP_GATEWAY: case PROP_GATEWAY:
if (!IN6_IS_ADDR_UNSPECIFIED (&priv->gateway)) if (priv->best_default_route) {
g_value_set_string (value, nm_utils_inet6_ntop (&priv->gateway, NULL)); g_value_set_string (value,
else nm_utils_inet6_ntop (&NMP_OBJECT_CAST_IP6_ROUTE (priv->best_default_route)->gateway,
NULL));
} else
g_value_set_string (value, NULL); g_value_set_string (value, NULL);
break; break;
case PROP_NAMESERVERS: case PROP_NAMESERVERS:

View file

@ -108,9 +108,9 @@ struct _NMDedupMultiIndex *nm_ip6_config_get_multi_idx (const NMIP6Config *self)
NMIP6Config *nm_ip6_config_capture (struct _NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex, NMIP6Config *nm_ip6_config_capture (struct _NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex,
gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary); gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary);
void nm_ip6_config_add_device_routes (NMIP6Config *self, void nm_ip6_config_add_dependent_routes (NMIP6Config *self,
guint32 route_table, guint32 route_table,
guint32 route_metric); guint32 route_metric);
gboolean nm_ip6_config_commit (const NMIP6Config *self, gboolean nm_ip6_config_commit (const NMIP6Config *self,
NMPlatform *platform, NMPlatform *platform,
@ -123,19 +123,19 @@ void nm_ip6_config_merge_setting (NMIP6Config *self,
NMSetting *nm_ip6_config_create_setting (const NMIP6Config *self); NMSetting *nm_ip6_config_create_setting (const NMIP6Config *self);
void nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFlags merge_flags); void nm_ip6_config_merge (NMIP6Config *dst,
void nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src); const NMIP6Config *src,
void nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src); NMIPConfigMergeFlags merge_flags,
guint32 default_route_metric_penalty);
void nm_ip6_config_subtract (NMIP6Config *dst,
const NMIP6Config *src,
guint32 default_route_metric_penalty);
void nm_ip6_config_intersect (NMIP6Config *dst,
const NMIP6Config *src,
guint32 default_route_metric_penalty);
gboolean nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relevant_changes); gboolean nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relevant_changes);
int nm_ip6_config_destination_is_direct (const NMIP6Config *self, const struct in6_addr *dest, guint8 plen);
void nm_ip6_config_dump (const NMIP6Config *self, const char *detail); void nm_ip6_config_dump (const NMIP6Config *self, const char *detail);
void nm_ip6_config_set_never_default (NMIP6Config *self, gboolean never_default);
gboolean nm_ip6_config_get_never_default (const NMIP6Config *self);
void nm_ip6_config_set_gateway (NMIP6Config *self, const struct in6_addr *);
const struct in6_addr *nm_ip6_config_get_gateway (const NMIP6Config *self);
const NMPObject *nm_ip6_config_best_default_route_get (const NMIP6Config *self); const NMPObject *nm_ip6_config_best_default_route_get (const NMIP6Config *self);
const NMPObject *_nm_ip6_config_best_default_route_find (const NMIP6Config *self); const NMPObject *_nm_ip6_config_best_default_route_find (const NMIP6Config *self);
@ -163,7 +163,9 @@ void _nmtst_ip6_config_del_route (NMIP6Config *self, guint i);
guint nm_ip6_config_get_num_routes (const NMIP6Config *self); guint nm_ip6_config_get_num_routes (const NMIP6Config *self);
const NMPlatformIP6Route *_nmtst_ip6_config_get_route (const NMIP6Config *self, guint i); const NMPlatformIP6Route *_nmtst_ip6_config_get_route (const NMIP6Config *self, guint i);
const NMPlatformIP6Route *nm_ip6_config_get_direct_route_for_host (const NMIP6Config *self, const struct in6_addr *host); const NMPlatformIP6Route *nm_ip6_config_get_direct_route_for_host (const NMIP6Config *self,
const struct in6_addr *host,
guint32 route_table);
const NMPlatformIP6Address *nm_ip6_config_get_subnet_for_host (const NMIP6Config *self, const struct in6_addr *host); const NMPlatformIP6Address *nm_ip6_config_get_subnet_for_host (const NMIP6Config *self, const struct in6_addr *host);
void nm_ip6_config_reset_nameservers (NMIP6Config *self); void nm_ip6_config_reset_nameservers (NMIP6Config *self);
@ -210,7 +212,10 @@ void nm_ip6_config_reset_addresses_ndisc (NMIP6Config *self,
guint8 plen, guint8 plen,
guint32 ifa_flags); guint32 ifa_flags);
struct _NMNDiscRoute; struct _NMNDiscRoute;
struct _NMNDiscGateway;
void nm_ip6_config_reset_routes_ndisc (NMIP6Config *self, void nm_ip6_config_reset_routes_ndisc (NMIP6Config *self,
const struct _NMNDiscGateway *gateways,
guint gateways_n,
const struct _NMNDiscRoute *routes, const struct _NMNDiscRoute *routes,
guint routes_n, guint routes_n,
guint32 route_table, guint32 route_table,

View file

@ -194,7 +194,8 @@ typedef enum {
typedef enum { typedef enum {
NM_IP_CONFIG_MERGE_DEFAULT = 0, NM_IP_CONFIG_MERGE_DEFAULT = 0,
NM_IP_CONFIG_MERGE_NO_ROUTES = (1LL << 0), NM_IP_CONFIG_MERGE_NO_ROUTES = (1LL << 0),
NM_IP_CONFIG_MERGE_NO_DNS = (1LL << 1), NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES = (1LL << 1),
NM_IP_CONFIG_MERGE_NO_DNS = (1LL << 2),
} NMIPConfigMergeFlags; } NMIPConfigMergeFlags;

View file

@ -98,6 +98,22 @@ nm_ppp_manager_create (const char *iface, GError **error)
return ret; return ret;
} }
void
nm_ppp_manager_set_route_parameters (NMPPPManager *self,
guint32 ip4_route_table,
guint32 ip4_route_metric,
guint32 ip6_route_table,
guint32 ip6_route_metric)
{
g_return_if_fail (ppp_ops);
ppp_ops->set_route_parameters (self,
ip4_route_table,
ip4_route_metric,
ip6_route_table,
ip6_route_metric);
}
gboolean gboolean
nm_ppp_manager_start (NMPPPManager *self, nm_ppp_manager_start (NMPPPManager *self,
NMActRequest *req, NMActRequest *req,

View file

@ -25,6 +25,13 @@
NMPPPManager * nm_ppp_manager_create (const char *iface, NMPPPManager * nm_ppp_manager_create (const char *iface,
GError **error); GError **error);
void nm_ppp_manager_set_route_parameters (NMPPPManager *ppp_manager,
guint32 ip4_route_table,
guint32 ip4_route_metric,
guint32 ip6_route_table,
guint32 ip6_route_metric);
gboolean nm_ppp_manager_start (NMPPPManager *self, gboolean nm_ppp_manager_start (NMPPPManager *self,
NMActRequest *req, NMActRequest *req,
const char *ppp_name, const char *ppp_name,

View file

@ -42,6 +42,7 @@
#endif #endif
#include <linux/if.h> #include <linux/if.h>
#include <linux/if_ppp.h> #include <linux/if_ppp.h>
#include <linux/rtnetlink.h>
#include "NetworkManagerUtils.h" #include "NetworkManagerUtils.h"
#include "platform/nm-platform.h" #include "platform/nm-platform.h"
@ -105,6 +106,11 @@ typedef struct {
char *ip_iface; char *ip_iface;
int monitor_fd; int monitor_fd;
guint monitor_id; guint monitor_id;
guint32 ip4_route_table;
guint32 ip4_route_metric;
guint32 ip6_route_table;
guint32 ip6_route_metric;
} NMPPPManagerPrivate; } NMPPPManagerPrivate;
struct _NMPPPManager { struct _NMPPPManager {
@ -132,6 +138,37 @@ static void _ppp_kill (NMPPPManager *manager);
/*****************************************************************************/ /*****************************************************************************/
static void
_ppp_manager_set_route_paramters (NMPPPManager *self,
guint32 ip4_route_table,
guint32 ip4_route_metric,
guint32 ip6_route_table,
guint32 ip6_route_metric)
{
NMPPPManagerPrivate *priv;
g_return_if_fail (NM_IS_PPP_MANAGER (self));
priv = NM_PPP_MANAGER_GET_PRIVATE (self);
if ( priv->ip4_route_table != ip4_route_table
|| priv->ip4_route_metric != ip4_route_metric
|| priv->ip6_route_table != ip6_route_table
|| priv->ip6_route_metric != ip6_route_metric) {
priv->ip4_route_table = ip4_route_table;
priv->ip4_route_metric = ip4_route_metric;
priv->ip6_route_table = ip6_route_table;
priv->ip6_route_metric = ip6_route_metric;
_LOGT ("route-parameters: table-v4: %u, metric-v4: %u, table-v6: %u, metric-v6: %u",
priv->ip4_route_table,
priv->ip4_route_metric,
priv->ip6_route_table,
priv->ip6_route_metric);
}
}
/*****************************************************************************/
static gboolean static gboolean
monitor_cb (gpointer user_data) monitor_cb (gpointer user_data)
{ {
@ -404,6 +441,7 @@ impl_ppp_manager_set_ip4_config (NMPPPManager *manager,
NMPlatformIP4Address address; NMPlatformIP4Address address;
guint32 u32, mtu; guint32 u32, mtu;
GVariantIter *iter; GVariantIter *iter;
int ifindex;
_LOGI ("(IPv4 Config Get) reply received."); _LOGI ("(IPv4 Config Get) reply received.");
@ -412,8 +450,11 @@ impl_ppp_manager_set_ip4_config (NMPPPManager *manager,
if (!set_ip_config_common (manager, config_dict, NM_PPP_IP4_CONFIG_INTERFACE, &mtu)) if (!set_ip_config_common (manager, config_dict, NM_PPP_IP4_CONFIG_INTERFACE, &mtu))
goto out; goto out;
config = nm_ip4_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET), ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface);
nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface)); if (ifindex <= 0)
goto out;
config = nm_ip4_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET), ifindex);
if (mtu) if (mtu)
nm_ip4_config_set_mtu (config, mtu, NM_IP_CONFIG_SOURCE_PPP); nm_ip4_config_set_mtu (config, mtu, NM_IP_CONFIG_SOURCE_PPP);
@ -425,7 +466,15 @@ impl_ppp_manager_set_ip4_config (NMPPPManager *manager,
address.address = u32; address.address = u32;
if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_GATEWAY, "u", &u32)) { if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_GATEWAY, "u", &u32)) {
nm_ip4_config_set_gateway (config, u32); const NMPlatformIP4Route r = {
.ifindex = ifindex,
.rt_source = NM_IP_CONFIG_SOURCE_PPP,
.gateway = u32,
.table_coerced = nm_platform_route_table_coerce (priv->ip4_route_table),
.metric = priv->ip4_route_metric,
};
nm_ip4_config_add_route (config, &r, NULL);
address.peer_address = u32; address.peer_address = u32;
} else } else
address.peer_address = address.address; address.peer_address = address.address;
@ -500,6 +549,7 @@ impl_ppp_manager_set_ip6_config (NMPPPManager *manager,
struct in6_addr a; struct in6_addr a;
NMUtilsIPv6IfaceId iid = NM_UTILS_IPV6_IFACE_ID_INIT; NMUtilsIPv6IfaceId iid = NM_UTILS_IPV6_IFACE_ID_INIT;
gboolean has_peer = FALSE; gboolean has_peer = FALSE;
int ifindex;
_LOGI ("(IPv6 Config Get) reply received."); _LOGI ("(IPv6 Config Get) reply received.");
@ -508,14 +558,25 @@ impl_ppp_manager_set_ip6_config (NMPPPManager *manager,
if (!set_ip_config_common (manager, config_dict, NM_PPP_IP6_CONFIG_INTERFACE, NULL)) if (!set_ip_config_common (manager, config_dict, NM_PPP_IP6_CONFIG_INTERFACE, NULL))
goto out; goto out;
config = nm_ip6_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET), ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface);
nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface)); if (ifindex <= 0)
goto out;
config = nm_ip6_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET), ifindex);
memset (&addr, 0, sizeof (addr)); memset (&addr, 0, sizeof (addr));
addr.plen = 64; addr.plen = 64;
if (iid_value_to_ll6_addr (config_dict, NM_PPP_IP6_CONFIG_PEER_IID, &a, NULL)) { if (iid_value_to_ll6_addr (config_dict, NM_PPP_IP6_CONFIG_PEER_IID, &a, NULL)) {
nm_ip6_config_set_gateway (config, &a); const NMPlatformIP6Route r = {
.ifindex = ifindex,
.rt_source = NM_IP_CONFIG_SOURCE_PPP,
.gateway = a,
.table_coerced = nm_platform_route_table_coerce (priv->ip6_route_table),
.metric = priv->ip6_route_metric,
};
nm_ip6_config_add_route (config, &r, NULL);
addr.peer_address = a; addr.peer_address = a;
has_peer = TRUE; has_peer = TRUE;
} }
@ -1167,7 +1228,7 @@ set_property (GObject *object, guint prop_id,
switch (prop_id) { switch (prop_id) {
case PROP_PARENT_IFACE: case PROP_PARENT_IFACE:
g_free (priv->parent_iface); /* construct-only */
priv->parent_iface = g_value_dup_string (value); priv->parent_iface = g_value_dup_string (value);
break; break;
default: default:
@ -1181,7 +1242,13 @@ set_property (GObject *object, guint prop_id,
static void static void
nm_ppp_manager_init (NMPPPManager *manager) nm_ppp_manager_init (NMPPPManager *manager)
{ {
NM_PPP_MANAGER_GET_PRIVATE (manager)->monitor_fd = -1; NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager);
priv->monitor_fd = -1;
priv->ip4_route_table = RT_TABLE_MAIN;
priv->ip4_route_metric = 460;
priv->ip6_route_table = RT_TABLE_MAIN;
priv->ip6_route_metric = 460;
} }
static NMPPPManager * static NMPPPManager *
@ -1291,9 +1358,10 @@ nm_ppp_manager_class_init (NMPPPManagerClass *manager_class)
} }
NMPPPOps ppp_ops = { NMPPPOps ppp_ops = {
.create = _ppp_manager_new, .create = _ppp_manager_new,
.start = _ppp_manager_start, .set_route_parameters = _ppp_manager_set_route_paramters,
.stop_async = _ppp_manager_stop_async, .start = _ppp_manager_start,
.stop_finish = _ppp_manager_stop_finish, .stop_async = _ppp_manager_stop_async,
.stop_sync = _ppp_manager_stop_sync, .stop_finish = _ppp_manager_stop_finish,
.stop_sync = _ppp_manager_stop_sync,
}; };

View file

@ -22,7 +22,7 @@
#ifndef __NM_PPP_MANAGER_H__ #ifndef __NM_PPP_MANAGER_H__
#define __NM_PPP_MANAGER_H__ #define __NM_PPP_MANAGER_H__
#define NM_PPP_MANAGER_PARENT_IFACE "parent-iface" #define NM_PPP_MANAGER_PARENT_IFACE "parent-iface"
#define NM_PPP_MANAGER_SIGNAL_STATE_CHANGED "state-changed" #define NM_PPP_MANAGER_SIGNAL_STATE_CHANGED "state-changed"
#define NM_PPP_MANAGER_SIGNAL_IP4_CONFIG "ip4-config" #define NM_PPP_MANAGER_SIGNAL_IP4_CONFIG "ip4-config"

View file

@ -24,6 +24,12 @@
typedef const struct { typedef const struct {
NMPPPManager *(*create) (const char *iface); NMPPPManager *(*create) (const char *iface);
void (*set_route_parameters) (NMPPPManager *manager,
guint32 route_table_v4,
guint32 route_metric_v4,
guint32 route_table_v6,
guint32 route_metric_v6);
gboolean (*start) (NMPPPManager *manager, gboolean (*start) (NMPPPManager *manager,
NMActRequest *req, NMActRequest *req,
const char *ppp_name, const char *ppp_name,

View file

@ -47,7 +47,16 @@ build_test_config (void)
route = *nmtst_platform_ip4_route ("172.16.0.0", 16, "192.168.1.1"); route = *nmtst_platform_ip4_route ("172.16.0.0", 16, "192.168.1.1");
nm_ip4_config_add_route (config, &route, NULL); nm_ip4_config_add_route (config, &route, NULL);
nm_ip4_config_set_gateway (config, nmtst_inet4_from_string ("192.168.1.1")); {
const NMPlatformIP4Route r = {
.rt_source = NM_IP_CONFIG_SOURCE_DHCP,
.gateway = nmtst_inet4_from_string ("192.168.1.1"),
.table_coerced = 0,
.metric = 100,
};
nm_ip4_config_add_route (config, &r, NULL);
}
nm_ip4_config_add_nameserver (config, nmtst_inet4_from_string ("4.2.2.1")); nm_ip4_config_add_nameserver (config, nmtst_inet4_from_string ("4.2.2.1"));
nm_ip4_config_add_nameserver (config, nmtst_inet4_from_string ("4.2.2.2")); nm_ip4_config_add_nameserver (config, nmtst_inet4_from_string ("4.2.2.2"));
@ -106,7 +115,7 @@ test_subtract (void)
nm_ip4_config_set_mtu (dst, expected_mtu, NM_IP_CONFIG_SOURCE_UNKNOWN); nm_ip4_config_set_mtu (dst, expected_mtu, NM_IP_CONFIG_SOURCE_UNKNOWN);
nm_ip4_config_subtract (dst, src); nm_ip4_config_subtract (dst, src, 0);
/* ensure what's left is what we expect */ /* ensure what's left is what we expect */
g_assert_cmpuint (nm_ip4_config_get_num_addresses (dst), ==, 1); g_assert_cmpuint (nm_ip4_config_get_num_addresses (dst), ==, 1);
@ -116,7 +125,8 @@ test_subtract (void)
g_assert_cmpuint (test_addr->peer_address, ==, test_addr->address); g_assert_cmpuint (test_addr->peer_address, ==, test_addr->address);
g_assert_cmpuint (test_addr->plen, ==, expected_addr_plen); g_assert_cmpuint (test_addr->plen, ==, expected_addr_plen);
g_assert_cmpuint (nm_ip4_config_get_gateway (dst), ==, 0); g_assert (!nm_ip4_config_best_default_route_get (dst));
g_assert_cmpuint (nmtst_ip4_config_get_gateway (dst), ==, 0);
g_assert_cmpuint (nm_ip4_config_get_num_routes (dst), ==, 1); g_assert_cmpuint (nm_ip4_config_get_num_routes (dst), ==, 1);
test_route = _nmtst_ip4_config_get_route (dst, 0); test_route = _nmtst_ip4_config_get_route (dst, 0);
@ -278,15 +288,15 @@ test_merge_subtract_mtu (void)
nm_ip4_config_set_mtu (cfg2, expected_mtu2, NM_IP_CONFIG_SOURCE_UNKNOWN); nm_ip4_config_set_mtu (cfg2, expected_mtu2, NM_IP_CONFIG_SOURCE_UNKNOWN);
nm_ip4_config_set_mtu (cfg3, expected_mtu3, NM_IP_CONFIG_SOURCE_UNKNOWN); nm_ip4_config_set_mtu (cfg3, expected_mtu3, NM_IP_CONFIG_SOURCE_UNKNOWN);
nm_ip4_config_merge (cfg1, cfg2, NM_IP_CONFIG_MERGE_DEFAULT); nm_ip4_config_merge (cfg1, cfg2, NM_IP_CONFIG_MERGE_DEFAULT, 0);
/* ensure MSS and MTU are in cfg1 */ /* ensure MSS and MTU are in cfg1 */
g_assert_cmpuint (nm_ip4_config_get_mtu (cfg1), ==, expected_mtu2); g_assert_cmpuint (nm_ip4_config_get_mtu (cfg1), ==, expected_mtu2);
nm_ip4_config_merge (cfg1, cfg3, NM_IP_CONFIG_MERGE_DEFAULT); nm_ip4_config_merge (cfg1, cfg3, NM_IP_CONFIG_MERGE_DEFAULT, 0);
/* ensure again the MSS and MTU in cfg1 got overridden */ /* ensure again the MSS and MTU in cfg1 got overridden */
g_assert_cmpuint (nm_ip4_config_get_mtu (cfg1), ==, expected_mtu3); g_assert_cmpuint (nm_ip4_config_get_mtu (cfg1), ==, expected_mtu3);
nm_ip4_config_subtract (cfg1, cfg3); nm_ip4_config_subtract (cfg1, cfg3, 0);
/* ensure MSS and MTU are zero in cfg1 */ /* ensure MSS and MTU are zero in cfg1 */
g_assert_cmpuint (nm_ip4_config_get_mtu (cfg1), ==, 0); g_assert_cmpuint (nm_ip4_config_get_mtu (cfg1), ==, 0);

View file

@ -40,7 +40,7 @@ build_test_config (void)
nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("abcd:1200::", 24, "abcd:1234:4321:cdde::2", NULL), NULL); nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("abcd:1200::", 24, "abcd:1234:4321:cdde::2", NULL), NULL);
nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("2001::", 16, "2001:abba::2234", NULL), NULL); nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("2001::", 16, "2001:abba::2234", NULL), NULL);
nm_ip6_config_set_gateway (config, nmtst_inet6_from_string ("3001:abba::3234")); nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("::", 0, "3001:abba::3234", NULL), NULL);
nm_ip6_config_add_nameserver (config, nmtst_inet6_from_string ("1:2:3:4::1")); nm_ip6_config_add_nameserver (config, nmtst_inet6_from_string ("1:2:3:4::1"));
nm_ip6_config_add_nameserver (config, nmtst_inet6_from_string ("1:2:3:4::2")); nm_ip6_config_add_nameserver (config, nmtst_inet6_from_string ("1:2:3:4::2"));
@ -84,7 +84,7 @@ test_subtract (void)
nm_ip6_config_add_domain (dst, expected_domain); nm_ip6_config_add_domain (dst, expected_domain);
nm_ip6_config_add_search (dst, expected_search); nm_ip6_config_add_search (dst, expected_search);
nm_ip6_config_subtract (dst, src); nm_ip6_config_subtract (dst, src, 0);
/* ensure what's left is what we expect */ /* ensure what's left is what we expect */
g_assert_cmpuint (nm_ip6_config_get_num_addresses (dst), ==, 1); g_assert_cmpuint (nm_ip6_config_get_num_addresses (dst), ==, 1);
@ -95,7 +95,7 @@ test_subtract (void)
g_assert (memcmp (&test_addr->peer_address, &in6addr_any, sizeof (tmp)) == 0); g_assert (memcmp (&test_addr->peer_address, &in6addr_any, sizeof (tmp)) == 0);
g_assert_cmpuint (test_addr->plen, ==, expected_addr_plen); g_assert_cmpuint (test_addr->plen, ==, expected_addr_plen);
g_assert (nm_ip6_config_get_gateway (dst) == NULL); g_assert (nm_ip6_config_best_default_route_get (dst) == NULL);
g_assert_cmpuint (nm_ip6_config_get_num_routes (dst), ==, 1); g_assert_cmpuint (nm_ip6_config_get_num_routes (dst), ==, 1);
test_route = _nmtst_ip6_config_get_route (dst, 0); test_route = _nmtst_ip6_config_get_route (dst, 0);

View file

@ -1018,9 +1018,6 @@ print_vpn_config (NMVpnConnection *self)
nm_utils_inet4_ntop (route->gateway, buf)); nm_utils_inet4_ntop (route->gateway, buf));
} }
_LOGI ("Data: Forbid Default Route: %s",
nm_ip4_config_get_never_default (priv->ip4_config) ? "yes" : "no");
num = nm_ip4_config_get_num_nameservers (priv->ip4_config); num = nm_ip4_config_get_num_nameservers (priv->ip4_config);
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
_LOGI ("Data: Internal DNS: %s", _LOGI ("Data: Internal DNS: %s",
@ -1055,9 +1052,6 @@ print_vpn_config (NMVpnConnection *self)
nm_utils_inet6_ntop (&route->gateway, buf)); nm_utils_inet6_ntop (&route->gateway, buf));
} }
_LOGI ("Data: Forbid Default Route: %s",
nm_ip6_config_get_never_default (priv->ip6_config) ? "yes" : "no");
num = nm_ip6_config_get_num_nameservers (priv->ip6_config); num = nm_ip6_config_get_num_nameservers (priv->ip6_config);
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
_LOGI ("Data: Internal DNS: %s", _LOGI ("Data: Internal DNS: %s",
@ -1098,19 +1092,13 @@ apply_parent_device_config (NMVpnConnection *self)
vpn4_parent_config = nm_ip4_config_new (nm_netns_get_multi_idx (priv->netns), vpn4_parent_config = nm_ip4_config_new (nm_netns_get_multi_idx (priv->netns),
ifindex); ifindex);
if (priv->ip_ifindex <= 0) if (priv->ip_ifindex <= 0)
nm_ip4_config_merge (vpn4_parent_config, priv->ip4_config, NM_IP_CONFIG_MERGE_NO_DNS); nm_ip4_config_merge (vpn4_parent_config, priv->ip4_config, NM_IP_CONFIG_MERGE_NO_DNS, 0);
} }
if (priv->ip6_config) { if (priv->ip6_config) {
vpn6_parent_config = nm_ip6_config_new (nm_netns_get_multi_idx (priv->netns), vpn6_parent_config = nm_ip6_config_new (nm_netns_get_multi_idx (priv->netns),
ifindex); ifindex);
if (priv->ip_ifindex <= 0) { if (priv->ip_ifindex <= 0)
nm_ip6_config_merge (vpn6_parent_config, priv->ip6_config, NM_IP_CONFIG_MERGE_NO_DNS); nm_ip6_config_merge (vpn6_parent_config, priv->ip6_config, NM_IP_CONFIG_MERGE_NO_DNS, 0);
/* Also clear the gateway. We don't configure the gateway as part of the
* vpn-config. Instead we tell NMDefaultRouteManager directly about the
* default route. */
nm_ip6_config_set_gateway (vpn6_parent_config, NULL);
}
} }
} }
@ -1479,6 +1467,7 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict)
gboolean b; gboolean b;
int ip_ifindex; int ip_ifindex;
guint32 mss = 0; guint32 mss = 0;
gboolean never_default = FALSE;
g_return_if_fail (dict && g_variant_is_of_type (dict, G_VARIANT_TYPE_VARDICT)); g_return_if_fail (dict && g_variant_is_of_type (dict, G_VARIANT_TYPE_VARDICT));
@ -1523,10 +1512,8 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict)
address.plen = 24; address.plen = 24;
/* Internal address of the VPN subnet's gateway */ /* Internal address of the VPN subnet's gateway */
if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_INT_GATEWAY, "u", &u32)) { if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_INT_GATEWAY, "u", &u32))
priv->ip4_internal_gw = u32; priv->ip4_internal_gw = u32;
nm_ip4_config_set_gateway (config, priv->ip4_internal_gw);
}
if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS, "u", &u32)) if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS, "u", &u32))
address.address = u32; address.address = u32;
@ -1625,7 +1612,7 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict)
} }
if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT, "b", &b)) if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT, "b", &b))
nm_ip4_config_set_never_default (config, b); never_default = b;
/* Merge in user overrides from the NMConnection's IPv4 setting */ /* Merge in user overrides from the NMConnection's IPv4 setting */
nm_ip4_config_merge_setting (config, nm_ip4_config_merge_setting (config,
@ -1633,11 +1620,11 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict)
route_table, route_table,
route_metric); route_metric);
if (!nm_ip4_config_get_never_default (config)) { if (!never_default) {
const NMPlatformIP4Route r = { const NMPlatformIP4Route r = {
.ifindex = ip_ifindex, .ifindex = ip_ifindex,
.rt_source = NM_IP_CONFIG_SOURCE_VPN, .rt_source = NM_IP_CONFIG_SOURCE_VPN,
.gateway = nm_ip4_config_get_gateway (config), .gateway = priv->ip4_internal_gw,
.table_coerced = nm_platform_route_table_coerce (route_table), .table_coerced = nm_platform_route_table_coerce (route_table),
.metric = route_metric, .metric = route_metric,
.mss = mss, .mss = mss,
@ -1648,10 +1635,10 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict)
g_clear_pointer (&priv->ip4_dev_route_blacklist, g_ptr_array_unref); g_clear_pointer (&priv->ip4_dev_route_blacklist, g_ptr_array_unref);
nm_ip4_config_add_device_routes (config, nm_ip4_config_add_dependent_routes (config,
route_table, route_table,
nm_vpn_connection_get_ip4_route_metric (self), nm_vpn_connection_get_ip4_route_metric (self),
&priv->ip4_dev_route_blacklist); &priv->ip4_dev_route_blacklist);
if (priv->ip4_config) { if (priv->ip4_config) {
nm_ip4_config_replace (priv->ip4_config, config, NULL); nm_ip4_config_replace (priv->ip4_config, config, NULL);
@ -1679,6 +1666,7 @@ nm_vpn_connection_ip6_config_get (NMVpnConnection *self, GVariant *dict)
gboolean b; gboolean b;
int ip_ifindex; int ip_ifindex;
guint32 mss = 0; guint32 mss = 0;
gboolean never_default = FALSE;
g_return_if_fail (dict && g_variant_is_of_type (dict, G_VARIANT_TYPE_VARDICT)); g_return_if_fail (dict && g_variant_is_of_type (dict, G_VARIANT_TYPE_VARDICT));
@ -1713,7 +1701,6 @@ nm_vpn_connection_ip6_config_get (NMVpnConnection *self, GVariant *dict)
g_clear_pointer (&priv->ip6_internal_gw, g_free); g_clear_pointer (&priv->ip6_internal_gw, g_free);
if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_INT_GATEWAY, "@ay", &v)) { if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_INT_GATEWAY, "@ay", &v)) {
priv->ip6_internal_gw = ip6_addr_dup_from_variant (v); priv->ip6_internal_gw = ip6_addr_dup_from_variant (v);
nm_ip6_config_set_gateway (config, priv->ip6_internal_gw);
g_variant_unref (v); g_variant_unref (v);
} }
@ -1812,7 +1799,7 @@ next:
} }
if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT, "b", &b)) if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT, "b", &b))
nm_ip6_config_set_never_default (config, b); never_default = b;
/* Merge in user overrides from the NMConnection's IPv6 setting */ /* Merge in user overrides from the NMConnection's IPv6 setting */
nm_ip6_config_merge_setting (config, nm_ip6_config_merge_setting (config,
@ -1820,11 +1807,11 @@ next:
route_table, route_table,
route_metric); route_metric);
if (!nm_ip6_config_get_never_default (config)) { if (!never_default) {
const NMPlatformIP6Route r = { const NMPlatformIP6Route r = {
.ifindex = ip_ifindex, .ifindex = ip_ifindex,
.rt_source = NM_IP_CONFIG_SOURCE_VPN, .rt_source = NM_IP_CONFIG_SOURCE_VPN,
.gateway = *(nm_ip6_config_get_gateway (config) ?: &in6addr_any), .gateway = *(priv->ip6_internal_gw ?: &in6addr_any),
.table_coerced = nm_platform_route_table_coerce (route_table), .table_coerced = nm_platform_route_table_coerce (route_table),
.metric = route_metric, .metric = route_metric,
.mss = mss, .mss = mss,
@ -1833,9 +1820,9 @@ next:
nm_ip6_config_add_route (config, &r, NULL); nm_ip6_config_add_route (config, &r, NULL);
} }
nm_ip6_config_add_device_routes (config, nm_ip6_config_add_dependent_routes (config,
route_table, route_table,
route_metric); route_metric);
if (priv->ip6_config) { if (priv->ip6_config) {
nm_ip6_config_replace (priv->ip6_config, config, NULL); nm_ip6_config_replace (priv->ip6_config, config, NULL);