diff options
author | Thomas Haller <thaller@redhat.com> | 2017-10-04 15:21:21 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-10-10 08:46:47 +0200 |
commit | 5c299454b49b165f645c25fd3e083c0bb747ad91 (patch) | |
tree | 259470cd32be8d0c78e4f4f88bad2ef83e8574a8 | |
parent | 2bdfc092d40daaf1af87a4cc2285caa63f35e9d3 (diff) | |
download | NetworkManager-5c299454b49b165f645c25fd3e083c0bb747ad91.tar.gz |
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.
34 files changed, 1098 insertions, 895 deletions
diff --git a/src/devices/adsl/nm-device-adsl.c b/src/devices/adsl/nm-device-adsl.c index fe622bdf8b..feeb243d02 100644 --- a/src/devices/adsl/nm-device-adsl.c +++ b/src/devices/adsl/nm-device-adsl.c @@ -474,6 +474,15 @@ act_stage3_ip4_config_start (NMDevice *device, } 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 || !nm_ppp_manager_start (priv->ppp_manager, req, nm_setting_adsl_get_username (s_adsl), diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index cc46a65837..ca30a1e8e7 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -999,6 +999,7 @@ ppp_ip4_config (NMPPPManager *ppp_manager, static NMActStageReturn pppoe_stage3_ip4_config_start (NMDeviceEthernet *self, NMDeviceStateReason *out_failure_reason) { + NMDevice *device = NM_DEVICE (self); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); NMSettingPppoe *s_pppoe; 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); 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); + 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 || !nm_ppp_manager_start (priv->ppp_manager, req, nm_setting_pppoe_get_username (s_pppoe), diff --git a/src/devices/nm-device-ppp.c b/src/devices/nm-device-ppp.c index 81db1dc0f7..09b25f50e2 100644 --- a/src/devices/nm-device-ppp.c +++ b/src/devices/nm-device-ppp.c @@ -138,7 +138,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE (self); NMSettingPppoe *s_pppoe; NMActRequest *req; - GError *err = NULL; + GError *error = NULL; req = nm_device_get_act_request (NM_DEVICE (self)); 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); 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 || !nm_ppp_manager_start (priv->ppp_manager, req, nm_setting_pppoe_get_username (s_pppoe), - 30, 0, &err)) { - _LOGW (LOGD_DEVICE | LOGD_PPP, "PPPoE failed to start: %s", err->message); - g_error_free (err); + 30, 0, &error)) { + _LOGW (LOGD_DEVICE | LOGD_PPP, "PPPoE failed to start: %s", error->message); + g_error_free (error); g_clear_object (&priv->ppp_manager); diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 8165c3fcf0..fd6f840a75 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -339,6 +339,9 @@ typedef struct _NMDevicePrivate { bool v4_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; bool v4_route_table_initalized:1; @@ -366,11 +369,6 @@ typedef struct _NMDevicePrivate { NMIP4Config * wwan_ip4_config; /* WWAN configuration */ 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; const char *ip4_rp_filter; @@ -1665,24 +1663,35 @@ _get_route_metric_default (NMDevice *self) return 11000; } -static guint32 -route_metric_with_penalty (NMDevice *self, guint32 metric) +static gboolean +default_route_metric_penalty_detect (NMDevice *self) { #if WITH_CONCHECK 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 - && nm_connectivity_check_enabled (nm_connectivity_get ())) { - if (metric >= G_MAXUINT32 - PENALTY) - return G_MAXUINT32; - return metric + PENALTY; + && nm_connectivity_check_enabled (nm_connectivity_get ())) { + return TRUE; } #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 @@ -1736,13 +1745,17 @@ nm_device_get_route_table (NMDevice *self, int addr_family, gboolean fallback_main) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv; NMConnection *connection; NMSettingIPConfig *s_ip; guint32 route_table = 0; 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 * not change it while the device is active, hence, cache it. */ if (addr_family == AF_INET) { @@ -1801,24 +1814,14 @@ nm_device_get_best_default_route (NMDevice *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) { case AF_INET: - return (priv->ip4_config ? nm_ip4_config_best_default_route_get (priv->ip4_config) : NULL) - ?: priv->default_route4; + return priv->ip4_config ? nm_ip4_config_best_default_route_get (priv->ip4_config) : NULL; case AF_INET6: - return (priv->ip6_config ? nm_ip6_config_best_default_route_get (priv->ip6_config) : NULL) - ?: priv->default_route6; + return priv->ip6_config ? nm_ip6_config_best_default_route_get (priv->ip6_config) : NULL; case AF_UNSPEC: 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->default_route6; + ?: (priv->ip6_config ? nm_ip6_config_best_default_route_get (priv->ip6_config) : NULL); default: g_return_val_if_reached (NULL); } @@ -5767,15 +5770,11 @@ ip4_config_merge_and_apply (NMDevice *self, NMConnection *connection; gboolean success; 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_dns = FALSE; + gboolean ignore_default_routes = FALSE; GSList *iter; - NMPlatformIP4Route default_route; gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL; - gboolean add_default_route = TRUE; /* Apply ignore-auto-routes and ignore-auto-dns settings */ connection = nm_device_get_applied_connection (self); @@ -5785,6 +5784,7 @@ ip4_config_merge_and_apply (NMDevice *self, if (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_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); } + if (commit) + priv->default_route_metric_penalty_ip4_has = default_route_metric_penalty_detect (self); + if (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_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) - 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) - 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 * 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) { nm_ip4_config_merge (composite, priv->wwan_ip4_config, (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, * con_ip4_config is empty. */ - if (priv->con_ip4_config) - nm_ip4_config_merge (composite, priv->con_ip4_config, NM_IP_CONFIG_MERGE_DEFAULT); - - /* 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 (priv->con_ip4_config) { + nm_ip4_config_merge (composite, priv->con_ip4_config, NM_IP_CONFIG_MERGE_DEFAULT, + default_route_metric_penalty_get (self, AF_INET)); } if (commit) { - nm_ip4_config_add_device_routes (composite, - nm_device_get_route_table (self, AF_INET, TRUE), - default_route_metric, - &ip4_dev_route_blacklist); + nm_ip4_config_add_dependent_routes (composite, + nm_device_get_route_table (self, AF_INET, TRUE), + nm_device_get_route_metric (self, AF_INET), + &ip4_dev_route_blacklist); } if (commit) { @@ -6481,15 +6422,11 @@ ip6_config_merge_and_apply (NMDevice *self, NMConnection *connection; gboolean success; 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_dns = FALSE; + gboolean ignore_default_routes = FALSE; const char *token = NULL; GSList *iter; - NMPlatformIP6Route default_route; - gboolean add_default_route = TRUE; /* Apply ignore-auto-routes and ignore-auto-dns settings */ 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_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) token = nm_setting_ip6_config_get_token (ip6); @@ -6520,23 +6458,30 @@ ip6_config_merge_and_apply (NMDevice *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 */ if (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_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) { nm_ip6_config_merge (composite, priv->dhcp6.ip6_config, (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) - 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) - 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 * 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) { nm_ip6_config_merge (composite, priv->wwan_ip6_config, (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) { @@ -6561,78 +6508,15 @@ ip6_config_merge_and_apply (NMDevice *self, /* Merge user overrides into the composite config. For assumed connections, * con_ip6_config is empty. */ - if (priv->con_ip6_config) - nm_ip6_config_merge (composite, priv->con_ip6_config, NM_IP_CONFIG_MERGE_DEFAULT); - - /* 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 (priv->con_ip6_config) { + nm_ip6_config_merge (composite, priv->con_ip6_config, NM_IP_CONFIG_MERGE_DEFAULT, + default_route_metric_penalty_get (self, AF_INET6)); } if (commit) { - nm_ip6_config_add_device_routes (composite, - nm_device_get_route_table (self, AF_INET6, TRUE), - default_route_metric); + nm_ip6_config_add_dependent_routes (composite, + nm_device_get_route_table (self, AF_INET6, TRUE), + nm_device_get_route_metric (self, AF_INET6)); } /* Allow setting MTU etc */ @@ -7477,14 +7361,6 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in if (!priv->ac_ip6_config) 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) { guint8 plen; guint32 ifa_flags; @@ -7510,8 +7386,11 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in 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, + rdata->gateways, + rdata->gateways_n, rdata->routes, rdata->routes_n, 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"); 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); arp_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"); 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); dhcp6_cleanup (self, cleanup_type, FALSE); linklocal6_cleanup (self); @@ -10631,7 +10506,7 @@ nm_device_start_ip_check (NMDevice *self) NMSettingConnection *s_con; guint timeout = 0; const char *ping_binary = NULL; - char buf[INET6_ADDRSTRLEN] = { 0 }; + char buf[NM_UTILS_INET_ADDRSTRLEN]; NMLogDomain log_domain = LOGD_IP4; /* 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); timeout = nm_setting_connection_get_gateway_ping_timeout (s_con); + buf[0] = '\0'; if (timeout) { - if (priv->ip4_config && priv->ip4_state == IP_DONE) { - guint gw = 0; + const NMPObject *gw; - 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'; + if (priv->ip4_config && priv->ip4_state == IP_DONE) { + gw = nm_ip4_config_best_default_route_get (priv->ip4_config); + if (gw) { + nm_utils_inet4_ntop (NMP_OBJECT_CAST_IP4_ROUTE (gw)->gateway, buf); + ping_binary = nm_utils_find_helper ("ping", "/usr/bin/ping", NULL); + log_domain = LOGD_IP4; + } } else if (priv->ip6_config && priv->ip6_state == IP_DONE) { - const struct in6_addr *gw = NULL; - - 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'; + gw = nm_ip6_config_best_default_route_get (priv->ip6_config); + if (gw) { + nm_utils_inet6_ntop (&NMP_OBJECT_CAST_IP6_ROUTE (gw)->gateway, buf); + ping_binary = nm_utils_find_helper ("ping6", "/usr/bin/ping6", NULL); + log_domain = LOGD_IP6; + } } } @@ -10884,12 +10758,18 @@ find_ip4_lease_config (NMDevice *self, for (liter = leases; liter && !found; liter = liter->next) { NMIP4Config *lease_config = liter->data; 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); if (!nm_ip4_config_address_exists (ext_ip4_config, address)) 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; 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 * config. This way, we don't re-add addresses that were manually removed * by the user. */ - if (priv->con_ip4_config) - nm_ip4_config_intersect (priv->con_ip4_config, priv->ext_ip4_config); - if (priv->dev_ip4_config) - nm_ip4_config_intersect (priv->dev_ip4_config, priv->ext_ip4_config); - if (priv->wwan_ip4_config) - nm_ip4_config_intersect (priv->wwan_ip4_config, priv->ext_ip4_config); + if (priv->con_ip4_config) { + nm_ip4_config_intersect (priv->con_ip4_config, priv->ext_ip4_config, + default_route_metric_penalty_get (self, AF_INET)); + } + if (priv->dev_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) - nm_ip4_config_intersect (iter->data, priv->ext_ip4_config); - 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); + nm_ip4_config_intersect (iter->data, priv->ext_ip4_config, 0); } /* Remove parts from ext_ip4_config to only contain the information that * was configured externally -- we already have the same configuration from * internal origins. */ - if (priv->con_ip4_config) - nm_ip4_config_subtract (priv->ext_ip4_config, priv->con_ip4_config); - if (priv->dev_ip4_config) - nm_ip4_config_subtract (priv->ext_ip4_config, priv->dev_ip4_config); - if (priv->wwan_ip4_config) - nm_ip4_config_subtract (priv->ext_ip4_config, priv->wwan_ip4_config); + if (priv->con_ip4_config) { + nm_ip4_config_subtract (priv->ext_ip4_config, priv->con_ip4_config, + default_route_metric_penalty_get (self, AF_INET)); + } + if (priv->dev_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) - nm_ip4_config_subtract (priv->ext_ip4_config, iter->data); - 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); + nm_ip4_config_subtract (priv->ext_ip4_config, iter->data, 0); } } 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 * config. This way, we don't re-add addresses that were manually removed * by the user. */ - if (priv->con_ip6_config) - nm_ip6_config_intersect (priv->con_ip6_config, priv->ext_ip6_config); - if (priv->ac_ip6_config) - nm_ip6_config_intersect (priv->ac_ip6_config, priv->ext_ip6_config); - if (priv->dhcp6.ip6_config) - nm_ip6_config_intersect (priv->dhcp6.ip6_config, priv->ext_ip6_config); - if (priv->wwan_ip6_config) - nm_ip6_config_intersect (priv->wwan_ip6_config, priv->ext_ip6_config); + if (priv->con_ip6_config) { + nm_ip6_config_intersect (priv->con_ip6_config, priv->ext_ip6_config, + default_route_metric_penalty_get (self, AF_INET6)); + } + if (priv->ac_ip6_config) { + nm_ip6_config_intersect (priv->ac_ip6_config, priv->ext_ip6_config, + default_route_metric_penalty_get (self, AF_INET6)); + } + 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) - nm_ip6_config_intersect (iter->data, priv->ext_ip6_config); - 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); + nm_ip6_config_intersect (iter->data, priv->ext_ip6_config, 0); } /* Remove parts from ext_ip6_config to only contain the information that * was configured externally -- we already have the same configuration from * internal origins. */ - if (priv->con_ip6_config) - nm_ip6_config_subtract (priv->ext_ip6_config, priv->con_ip6_config); - if (priv->ac_ip6_config) - nm_ip6_config_subtract (priv->ext_ip6_config, priv->ac_ip6_config); - if (priv->dhcp6.ip6_config) - nm_ip6_config_subtract (priv->ext_ip6_config, priv->dhcp6.ip6_config); - if (priv->wwan_ip6_config) - nm_ip6_config_subtract (priv->ext_ip6_config, priv->wwan_ip6_config); + if (priv->con_ip6_config) { + nm_ip6_config_subtract (priv->ext_ip6_config, priv->con_ip6_config, + default_route_metric_penalty_get (self, AF_INET6)); + } + if (priv->ac_ip6_config) { + nm_ip6_config_subtract (priv->ext_ip6_config, priv->ac_ip6_config, + default_route_metric_penalty_get (self, AF_INET6)); + } + 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) - nm_ip6_config_subtract (priv->ext_ip6_config, iter->data); - 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); + nm_ip6_config_subtract (priv->ext_ip6_config, iter->data, 0); } } @@ -12403,6 +12291,9 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) priv->v4_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; /* 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_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->con_ip4_config); g_clear_object (&priv->dev_ip4_config); diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c index fbd29b1e24..3a289f533c 100644 --- a/src/devices/wwan/nm-modem-broadband.c +++ b/src/devices/wwan/nm-modem-broadband.c @@ -912,8 +912,24 @@ static_stage3_ip4_done (NMModemBroadband *self) _LOGI (" address %s/%d", address_string, address.plen); if (gw) { - nm_ip4_config_set_gateway (config, gw); - _LOGI (" gateway %s", gw_string); + guint32 ip4_route_table, ip4_route_metric; + + 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 */ @@ -1006,7 +1022,9 @@ stage3_ip6_done (NMModemBroadband *self) address_string = mm_bearer_ip_config_get_gateway (self->_priv.ipv6_config); 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, NM_DEVICE_ERROR_INVALID_CONNECTION, "(%s) retrieving IPv6 configuration failed: invalid gateway given '%s'", @@ -1014,8 +1032,23 @@ stage3_ip6_done (NMModemBroadband *self) address_string); 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) { /* Gateway required for the 'static' method */ error = g_error_new (NM_DEVICE_ERROR, diff --git a/src/devices/wwan/nm-modem-ofono.c b/src/devices/wwan/nm-modem-ofono.c index a689550cf2..1fe6debcba 100644 --- a/src/devices/wwan/nm-modem-ofono.c +++ b/src/devices/wwan/nm-modem-ofono.c @@ -833,6 +833,7 @@ context_property_changed (GDBusProxy *proxy, const gchar *s, *addr_s; const gchar **array, **iter; guint32 address_network, gateway_network; + guint32 ip4_route_table, ip4_route_metric; guint prefix = 0; _LOGD ("PropertyChanged: %s", property); @@ -938,16 +939,30 @@ context_property_changed (GDBusProxy *proxy, nm_ip4_config_add_address (priv->ip4_config, &addr); - if (g_variant_lookup (v_dict, "Gateway", "&s", &s)) { - if ( s - && nm_utils_parse_inaddr_bin (AF_INET, s, &gateway_network)) { - _LOGI ("Gateway: %s", s); - nm_ip4_config_set_gateway (priv->ip4_config, gateway_network); - } else { + if ( g_variant_lookup (v_dict, "Gateway", "&s", &s) + && s) { + + if (!nm_utils_parse_inaddr_bin (AF_INET, s, &gateway_network)) { _LOGW ("invalid 'Gateway': %s", s); 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 { _LOGW ("Settings 'Gateway' missing"); goto out; @@ -981,17 +996,23 @@ context_property_changed (GDBusProxy *proxy, _LOGI ("MessageProxy: %s", s); if ( s && nm_utils_parse_inaddr_bin (AF_INET, s, &address_network)) { - const NMPlatformIP4Route mms_route = { - .network = address_network, - .plen = 32, - .gateway = gateway_network, - .metric = 1, - }; - - /* FIXME: does not handle ipv4.route-table setting and always adds the - * route to RT_TABLE_MAIN table. */ - - nm_ip4_config_add_route (priv->ip4_config, &mms_route, NULL); + nm_modem_get_route_parameters (NM_MODEM (self), + &ip4_route_table, + &ip4_route_metric, + NULL, + NULL); + + { + 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); + } } else { _LOGW ("invalid MessageProxy: %s", s); } diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c index c3f370475f..77495b62d8 100644 --- a/src/devices/wwan/nm-modem.c +++ b/src/devices/wwan/nm-modem.c @@ -26,6 +26,7 @@ #include <fcntl.h> #include <string.h> #include <termios.h> +#include <linux/rtnetlink.h> #include "nm-core-internal.h" #include "platform/nm-platform.h" @@ -97,6 +98,11 @@ typedef struct _NMModemPrivate { guint32 mm_ip_timeout; + guint32 ip4_route_table; + guint32 ip4_route_metric; + guint32 ip6_route_table; + guint32 ip6_route_metric; + /* PPP stats */ guint32 in_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); + 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 || !nm_ppp_manager_start (priv->ppp_manager, req, ppp_name, ip_timeout, baud_override, &error)) { @@ -706,6 +720,8 @@ nm_modem_ip4_pre_commit (NMModem *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 * not point-to-point) and IP config has a /32 prefix, then we assume that * ARP will be pointless and we turn it off. @@ -1400,6 +1416,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 nm_modem_get_capabilities (NMModem *self, NMDeviceModemCapabilities *modem_caps, NMDeviceModemCapabilities *current_caps) @@ -1533,7 +1619,15 @@ set_property (GObject *object, guint prop_id, static void nm_modem_init (NMModem *self) { + NMModemPrivate *priv; + 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 diff --git a/src/devices/wwan/nm-modem.h b/src/devices/wwan/nm-modem.h index c6efda951d..9546e4a12e 100644 --- a/src/devices/wwan/nm-modem.h +++ b/src/devices/wwan/nm-modem.h @@ -187,6 +187,21 @@ gboolean nm_modem_complete_connection (NMModem *self, const GSList *existing_connections, 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, NMActRequest *req, NMDeviceStateReason *out_failure_reason); diff --git a/src/dhcp/nm-dhcp-dhclient-utils.c b/src/dhcp/nm-dhcp-dhclient-utils.c index 6e32ae73b7..a82d78733b 100644 --- a/src/dhcp/nm-dhcp-dhclient-utils.c +++ b/src/dhcp/nm-dhcp-dhclient-utils.c @@ -689,6 +689,8 @@ lease_validity_span (const char *str_expire, GDateTime *now) * @addr_family: whether to read IPv4 or IPv6 leases * @iface: the interface name to match leases with * @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 * @now: the current UTC date/time; pass %NULL to automatically use current * 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, const char *iface, int ifindex, + guint32 route_table, + guint32 route_metric, const char *contents, GDateTime *now) { @@ -814,7 +818,17 @@ nm_dhcp_dhclient_read_lease_ip_configs (NMDedupMultiIndex *multi_idx, ip4 = nm_ip4_config_new (multi_idx, ifindex); 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"); if (value) { diff --git a/src/dhcp/nm-dhcp-dhclient-utils.h b/src/dhcp/nm-dhcp-dhclient-utils.h index a5dc9c2b62..94de196362 100644 --- a/src/dhcp/nm-dhcp-dhclient-utils.h +++ b/src/dhcp/nm-dhcp-dhclient-utils.h @@ -47,6 +47,8 @@ GSList *nm_dhcp_dhclient_read_lease_ip_configs (struct _NMDedupMultiIndex *multi int addr_family, const char *iface, int ifindex, + guint32 route_table, + guint32 route_metric, const char *contents, GDateTime *now); diff --git a/src/dhcp/nm-dhcp-dhclient.c b/src/dhcp/nm-dhcp-dhclient.c index 6259fb5b17..74d920a8da 100644 --- a/src/dhcp/nm-dhcp-dhclient.c +++ b/src/dhcp/nm-dhcp-dhclient.c @@ -167,9 +167,8 @@ nm_dhcp_dhclient_get_lease_ip_configs (NMDedupMultiIndex *multi_idx, guint32 route_table, guint32 route_metric) { - char *contents = NULL; - char *leasefile; - GSList *leases = NULL; + gs_free char *contents = NULL; + gs_free char *leasefile = NULL; leasefile = get_dhclient_leasefile (addr_family, iface, uuid, NULL); 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) && g_file_get_contents (leasefile, &contents, NULL, NULL) && contents - && contents[0]) - leases = nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, addr_family, iface, ifindex, contents, NULL); - - g_free (leasefile); - g_free (contents); - - return leases; + && contents[0]) { + return nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, addr_family, iface, ifindex, + route_table, route_metric, contents, NULL); + } + return NULL; } static gboolean diff --git a/src/dhcp/nm-dhcp-systemd.c b/src/dhcp/nm-dhcp-systemd.c index 5e0370db55..c8c90304c8 100644 --- a/src/dhcp/nm-dhcp-systemd.c +++ b/src/dhcp/nm-dhcp-systemd.c @@ -243,6 +243,8 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx, gsize data_len; gboolean metered = FALSE; gboolean static_default_gateway = FALSE; + gboolean gateway_has = FALSE; + in_addr_t gateway = 0; g_return_val_if_fail (lease != NULL, NULL); @@ -369,7 +371,8 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx, } else { if (!static_default_gateway) { 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); LOG_LEASE (LOGD_DHCP4, "gateway %s", s); @@ -390,13 +393,25 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx, if (!static_default_gateway) { r = sd_dhcp_lease_get_router (lease, &tmp_addr); 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); LOG_LEASE (LOGD_DHCP4, "gateway %s", 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 */ r = sd_dhcp_lease_get_mtu (lease, &mtu); if (r == 0 && mtu) { diff --git a/src/dhcp/nm-dhcp-utils.c b/src/dhcp/nm-dhcp-utils.c index 9e1e75a470..4b2d57b90f 100644 --- a/src/dhcp/nm-dhcp-utils.c +++ b/src/dhcp/nm-dhcp-utils.c @@ -405,7 +405,8 @@ nm_dhcp_utils_ip4_config_from_options (NMDedupMultiIndex *multi_idx, in_addr_t addr; NMPlatformIP4Address address; char *str = NULL; - guint32 gwaddr = 0; + gboolean gateway_has = FALSE; + guint32 gateway = 0; guint8 plen = 0; 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 * 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); - if (gwaddr) { - _LOG2I (LOGD_DHCP4, iface, " gateway %s", nm_utils_inet4_ntop (gwaddr, NULL)); - nm_ip4_config_set_gateway (ip4_config, gwaddr); + if (gateway) { + _LOG2I (LOGD_DHCP4, iface, " gateway %s", nm_utils_inet4_ntop (gateway, NULL)); + gateway_has = TRUE; } else { /* 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. @@ -451,9 +452,9 @@ nm_dhcp_utils_ip4_config_from_options (NMDedupMultiIndex *multi_idx, for (s = routers; *s; s++) { /* FIXME: how to handle multiple routers? */ - if (inet_pton (AF_INET, *s, &gwaddr) > 0) { - nm_ip4_config_set_gateway (ip4_config, gwaddr); + if (inet_pton (AF_INET, *s, &gateway) > 0) { _LOG2I (LOGD_DHCP4, iface, " gateway %s", *s); + gateway_has = TRUE; break; } else _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"); if (str) { address.lifetime = address.preferred = strtoul (str, NULL, 10); diff --git a/src/dhcp/tests/test-dhcp-dhclient.c b/src/dhcp/tests/test-dhcp-dhclient.c index a338c13394..f2e1f32157 100644 --- a/src/dhcp/tests/test-dhcp-dhclient.c +++ b/src/dhcp/tests/test-dhcp-dhclient.c @@ -23,6 +23,7 @@ #include <string.h> #include <unistd.h> #include <arpa/inet.h> +#include <linux/rtnetlink.h> #include "nm-utils/nm-dedup-multi.h" @@ -38,6 +39,8 @@ #define DEBUG 1 static const int IFINDEX = 5; +static const guint32 ROUTE_TABLE = RT_TABLE_MAIN; +static const guint32 ROUTE_METRIC = 100; static void test_config (const char *orig, @@ -912,7 +915,7 @@ test_read_lease_ip4_config_basic (void) /* Date from before the least expiration */ 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); /* IP4Config #1 */ @@ -929,7 +932,7 @@ test_read_lease_ip4_config_basic (void) /* Gateway */ 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 */ g_assert_cmpint (nm_ip4_config_get_num_nameservers (config), ==, 1); @@ -952,7 +955,7 @@ test_read_lease_ip4_config_basic (void) /* Gateway */ 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 */ 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 */ 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_date_time_unref (now); @@ -1010,7 +1013,7 @@ test_read_lease_ip4_config_expect_failure (gconstpointer user_data) /* Date from before the least expiration */ 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_date_time_unref (now); diff --git a/src/dhcp/tests/test-dhcp-utils.c b/src/dhcp/tests/test-dhcp-utils.c index 1ffadcd810..1419b2648d 100644 --- a/src/dhcp/tests/test-dhcp-utils.c +++ b/src/dhcp/tests/test-dhcp-utils.c @@ -114,7 +114,7 @@ test_generic_options (void) /* Gateway */ 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); @@ -133,7 +133,7 @@ test_generic_options (void) g_assert (nm_ip4_config_get_nameserver (ip4_config, 1) == tmp); /* 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 = _nmtst_ip4_config_get_route (ip4_config, 0); @@ -146,13 +146,17 @@ test_generic_options (void) /* Route #2 */ route = _nmtst_ip4_config_get_route (ip4_config, 1); - g_assert (inet_pton (AF_INET, expected_route2_dest, &tmp) > 0); - g_assert (route->network == tmp); - g_assert (inet_pton (AF_INET, expected_route2_gw, &tmp) > 0); - g_assert (route->gateway == tmp); + g_assert (route->network == nmtst_inet4_from_string (expected_route2_dest)); + g_assert (route->gateway == nmtst_inet4_from_string (expected_route2_gw)); g_assert_cmpint (route->plen, ==, 32); 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); } @@ -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 (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 @@ -261,9 +265,10 @@ test_classless_static_routes_1 (void) ip4_config = _ip4_config_from_options (1, "eth0", options, 0); /* 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, 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); } @@ -288,9 +293,10 @@ test_classless_static_routes_2 (void) ip4_config = _ip4_config_from_options (1, "eth0", options, 0); /* 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, 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); } @@ -316,9 +322,10 @@ test_fedora_dhclient_classless_static_routes (void) ip4_config = _ip4_config_from_options (1, "eth0", options, 0); /* 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, 1, expected_route2_dest, expected_route2_gw, 7); + ip4_test_route (ip4_config, 2, "0.0.0.0", expected_route1_gw, 0); /* Gateway */ ip4_test_gateway (ip4_config, expected_gateway); @@ -348,8 +355,9 @@ test_dhclient_invalid_classless_routes_1 (void) g_test_assert_expected_messages (); /* 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, 1, "0.0.0.0", expected_route1_gw, 0); 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 * 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, 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); } @@ -412,9 +421,10 @@ test_dhclient_invalid_classless_routes_2 (void) /* Test falling back to old-style static routes if the classless static * 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, 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); } @@ -446,9 +456,10 @@ test_dhcpcd_invalid_classless_routes_2 (void) */ /* 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, 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); } @@ -474,8 +485,9 @@ test_dhclient_invalid_classless_routes_3 (void) g_test_assert_expected_messages (); /* 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, 1, "0.0.0.0", expected_route1_gw, 0); g_hash_table_destroy (options); } @@ -501,8 +513,9 @@ test_dhcpcd_invalid_classless_routes_3 (void) g_test_assert_expected_messages (); /* 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, 1, "0.0.0.0", expected_route1_gw, 0); 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 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, 1, "0.0.0.0", "192.2.3.4", 0); /* 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 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, 1, "0.0.0.0", "192.2.3.4", 0); /* Gateway */ ip4_test_gateway (ip4_config, expected_gateway); diff --git a/src/dns/nm-dns-systemd-resolved.c b/src/dns/nm-dns-systemd-resolved.c index e7e71489fc..315f2c4d0d 100644 --- a/src/dns/nm-dns-systemd-resolved.c +++ b/src/dns/nm-dns-systemd-resolved.c @@ -136,16 +136,6 @@ add_interface_configuration (NMDnsSystemdResolved *self, } 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 update_add_ip_config (NMDnsSystemdResolved *self, GVariantBuilder *dns, GVariantBuilder *domains, @@ -154,7 +144,7 @@ update_add_ip_config (NMDnsSystemdResolved *self, int addr_family; gsize addr_size; guint i, n; - gboolean never_default; + gboolean route_only; if (NM_IS_IP4_CONFIG (config)) addr_family = AF_INET; @@ -188,31 +178,33 @@ update_add_ip_config (NMDnsSystemdResolved *self, g_variant_builder_close (dns); } - never_default = addr_family == AF_INET - ? nm_ip4_config_get_never_default (config) - : nm_ip6_config_get_never_default (config); + /* If this link is never the default (e.g. only used for resources on this + * network) add a routing domain. */ + 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 ? nm_ip4_config_get_num_searches (config) : nm_ip6_config_get_num_searches (config); if (n > 0) { for (i = 0; i < n; i++) { - add_domain (domains, - addr_family == AF_INET - ? nm_ip4_config_get_search (config, i) - : nm_ip6_config_get_search (config, i), - never_default); + g_variant_builder_add (domains, "(sb)", + addr_family == AF_INET + ? nm_ip4_config_get_search (config, i) + : nm_ip6_config_get_search (config, i), + route_only); } } else { n = addr_family == AF_INET ? nm_ip4_config_get_num_domains (config) : nm_ip6_config_get_num_domains (config); for (i = 0; i < n; i++) { - add_domain (domains, - addr_family == AF_INET - ? nm_ip4_config_get_domain (config, i) - : nm_ip6_config_get_domain (config, i), - never_default); + g_variant_builder_add (domains, "(sb)", + addr_family == AF_INET + ? nm_ip4_config_get_domain (config, i) + : nm_ip6_config_get_domain (config, i), + route_only); } } } diff --git a/src/dnsmasq/nm-dnsmasq-manager.c b/src/dnsmasq/nm-dnsmasq-manager.c index 3296cd0e73..4ac1e7c350 100644 --- a/src/dnsmasq/nm-dnsmasq-manager.c +++ b/src/dnsmasq/nm-dnsmasq-manager.c @@ -221,7 +221,7 @@ create_dm_cmd_line (const char *iface, nm_cmd_line_add_string (cmd, s->str); 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, localaddr); nm_cmd_line_add_string (cmd, s->str); diff --git a/src/ndisc/nm-ndisc.h b/src/ndisc/nm-ndisc.h index db19db0021..8b5f2bd5b1 100644 --- a/src/ndisc/nm-ndisc.h +++ b/src/ndisc/nm-ndisc.h @@ -62,12 +62,13 @@ typedef enum { NM_NDISC_PREFERENCE_HIGH } NMNDiscPreference; -typedef struct { +struct _NMNDiscGateway { struct in6_addr address; guint32 timestamp; guint32 lifetime; NMNDiscPreference preference; -} NMNDiscGateway; +}; +typedef struct _NMNDiscGateway NMNDiscGateway; struct _NMNDiscAddress { struct in6_addr address; diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index 21ff111a33..5fc5fe159b 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -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; } +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; guint64 nm_utils_get_start_time_for_pid (pid_t pid, char *out_state, pid_t *out_ppid); diff --git a/src/nm-dispatcher.c b/src/nm-dispatcher.c index b5b11812e0..237afdefe7 100644 --- a/src/nm-dispatcher.c +++ b/src/nm-dispatcher.c @@ -124,9 +124,14 @@ dump_ip4_to_props (NMIP4Config *ip4, GVariantBuilder *builder) g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("aau")); first = TRUE; nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &addr) { + const NMPObject *default_route; + array[0] = addr->address; 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_new_fixed_array (G_VARIANT_TYPE_UINT32, array, 3, sizeof (guint32))); @@ -197,12 +202,15 @@ dump_ip6_to_props (NMIP6Config *ip6, GVariantBuilder *builder) first = TRUE; 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, &addr->address, sizeof (struct in6_addr), 1); gw = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, - first - ? (nm_ip6_config_get_gateway (ip6) ?: &in6addr_any) + ( first + && (default_route = nm_ip6_config_best_default_route_get (ip6))) + ? &NMP_OBJECT_CAST_IP6_ROUTE (default_route)->gateway : &in6addr_any, sizeof (struct in6_addr), 1); g_variant_builder_add (&int_builder, "(@ayu@ay)", ip, addr->plen, gw); diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c index 4c21f40e12..4be92bfb44 100644 --- a/src/nm-iface-helper.c +++ b/src/nm-iface-helper.c @@ -122,13 +122,13 @@ dhcp4_state_changed (NMDhcpClient *client, existing = nm_ip4_config_capture (nm_platform_get_multi_idx (NM_PLATFORM_GET), NM_PLATFORM_GET, gl.ifindex, FALSE); 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_add_device_routes (existing, - RT_TABLE_MAIN, - global_opt.priority_v4, - &ip4_dev_route_blacklist); + nm_ip4_config_merge (existing, ip4_config, NM_IP_CONFIG_MERGE_DEFAULT, 0); + nm_ip4_config_add_dependent_routes (existing, + RT_TABLE_MAIN, + global_opt.priority_v4, + &ip4_dev_route_blacklist); if (!nm_ip4_config_commit (existing, NM_PLATFORM_GET, 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), NM_PLATFORM_GET, gl.ifindex, FALSE, global_opt.tempaddr); if (ndisc_config) - nm_ip6_config_subtract (existing, ndisc_config); + nm_ip6_config_subtract (existing, ndisc_config, 0); else { ndisc_config = nm_ip6_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET), 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) { guint8 plen; guint32 ifa_flags; @@ -207,8 +199,11 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in 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, + rdata->gateways, + rdata->gateways_n, rdata->routes, rdata->routes_n, 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_ip6_config_merge (existing, ndisc_config, NM_IP_CONFIG_MERGE_DEFAULT); - nm_ip6_config_add_device_routes (existing, - RT_TABLE_MAIN, - global_opt.priority_v6); + nm_ip6_config_merge (existing, ndisc_config, NM_IP_CONFIG_MERGE_DEFAULT, 0); + nm_ip6_config_add_dependent_routes (existing, + RT_TABLE_MAIN, + global_opt.priority_v6); if (!nm_ip6_config_commit (existing, NM_PLATFORM_GET, NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN, diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index b80ff8cc11..63eb3a71ff 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -287,10 +287,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMIP4Config, ); typedef struct { - bool never_default:1; bool metered:1; - bool has_gateway:1; - guint32 gateway; guint32 mtu; int ifindex; NMIPConfigSource mtu_source; @@ -489,6 +486,19 @@ _nm_ip4_config_best_default_route_find (const NMIP4Config *self) 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 @@ -575,9 +585,6 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i { NMIP4Config *self; NMIP4ConfigPrivate *priv; - guint32 lowest_metric; - guint32 old_gateway = 0; - gboolean old_has_gateway = FALSE; const NMDedupMultiHeadEntry *head_entry; NMDedupMultiIter iter; const NMPObject *plobj = NULL; @@ -614,6 +621,7 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i sort_captured_addresses, NULL); has_addresses = TRUE; + _notify_addresses (self); } head_entry = nm_platform_lookup_addrroute (platform, @@ -621,31 +629,15 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i ifindex); /* Extract gateway from default route */ - old_gateway = priv->gateway; - 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; - } - + nmp_cache_iter_for_each (&iter, head_entry, &plobj) _add_route (self, plobj, NULL, NULL); - } /* If the interface has the default route, and has IPv4 addresses, capture * 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; 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; } void -nm_ip4_config_add_device_routes (NMIP4Config *self, - guint32 route_table, - guint32 route_metric, - GPtrArray **out_ip4_dev_route_blacklist) +nm_ip4_config_add_dependent_routes (NMIP4Config *self, + guint32 route_table, + guint32 route_metric, + GPtrArray **out_ip4_dev_route_blacklist) { const NMIP4ConfigPrivate *priv; GPtrArray *ip4_dev_route_blacklist = NULL; - const NMPlatformIP4Address *addr; + const NMPlatformIP4Address *my_addr; + const NMPlatformIP4Route *my_route; int ifindex; 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. * 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; NMPlatformIP4Route *route; in_addr_t network; - if (addr->plen == 0) + if (my_addr->plen == 0) continue; - nm_assert (addr->plen <= 32); + nm_assert (my_addr->plen <= 32); /* 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)) { /* 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->rt_source = NM_IP_CONFIG_SOURCE_KERNEL; route->network = network; - route->plen = addr->plen; - route->pref_src = addr->address; + route->plen = my_addr->plen; + route->pref_src = my_addr->address; route->table_coerced = nm_platform_route_table_coerce (route_table); route->metric = route_metric; 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); } @@ -848,6 +855,8 @@ nm_ip4_config_merge_setting (NMIP4Config *self, NMIP4ConfigPrivate *priv; guint naddresses, nroutes, nnameservers, nsearches; int i, priority; + const char *gateway_str; + guint32 gateway_bin; if (!setting) return; @@ -864,15 +873,18 @@ nm_ip4_config_merge_setting (NMIP4Config *self, nsearches = nm_setting_ip_config_get_num_dns_searches (setting); /* Gateway */ - if (nm_setting_ip_config_get_never_default (setting)) - nm_ip4_config_set_never_default (self, TRUE); - else if (nm_setting_ip_config_get_ignore_auto_routes (setting)) - nm_ip4_config_set_never_default (self, FALSE); - if (nm_setting_ip_config_get_gateway (setting)) { - guint32 gateway; + if ( !nm_setting_ip_config_get_never_default (setting) + && (gateway_str = nm_setting_ip_config_get_gateway (setting)) + && inet_pton (AF_INET, gateway_str, &gateway_bin) == 1 + && gateway_bin) { + const NMPlatformIP4Route r = { + .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); - nm_ip4_config_set_gateway (self, gateway); + _add_route (self, NULL, &r, NULL); } /* Addresses */ @@ -961,8 +973,8 @@ nm_ip4_config_merge_setting (NMIP4Config *self, NMSetting * nm_ip4_config_create_setting (const NMIP4Config *self) { + const NMIP4ConfigPrivate *priv; NMSettingIPConfig *s_ip4; - guint32 gateway; guint nnameservers, nsearches, noptions; const char *method = NULL; int i; @@ -979,7 +991,8 @@ nm_ip4_config_create_setting (const NMIP4Config *self) 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); nsearches = nm_ip4_config_get_num_searches (self); noptions = nm_ip4_config_get_num_dns_options (self); @@ -1007,10 +1020,12 @@ nm_ip4_config_create_setting (const NMIP4Config *self) } /* Gateway */ - if ( nm_ip4_config_has_gateway (self) + if ( priv->best_default_route && nm_setting_ip_config_get_num_addresses (s_ip4) > 0) { 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); } @@ -1070,7 +1085,10 @@ nm_ip4_config_create_setting (const NMIP4Config *self) /*****************************************************************************/ 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; 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)); } - /* default gateway */ - if (nm_ip4_config_has_gateway (src)) - nm_ip4_config_set_gateway (dst, nm_ip4_config_get_gateway (src)); - /* 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); + } } /* domains */ @@ -1255,11 +1283,17 @@ _wins_get_index (const NMIP4Config *self, guint32 wins_server) * nm_ip4_config_subtract: * @dst: config from which to remove everything in @src * @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. */ 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; guint i; @@ -1296,23 +1330,31 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src) 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 */ changed = FALSE; changed_default_route = FALSE; 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; + 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, &dst_priv->idx_ip4_routes, - NMP_OBJECT_UP_CAST (r), + o_lookup, (gconstpointer *) &obj_old)) { if (dst_priv->best_default_route == obj_old) { 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) { _nm_ip_config_best_default_route_set (&dst_priv->best_default_route, _nm_ip4_config_best_default_route_find (dst)); + _notify (dst, PROP_GATEWAY); } if (changed) _notify_routes (dst); @@ -1379,7 +1422,9 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src) } 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; const NMIP4ConfigPrivate *src_priv; @@ -1415,23 +1460,31 @@ nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src) /* 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 */ changed = FALSE; new_best_default_route = NULL; 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, &src_priv->idx_ip4_routes, - o)) { - new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, o); + o_lookup)) { + new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, o_dst); continue; } @@ -1440,8 +1493,10 @@ nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src) nm_assert_not_reached (); 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); + _notify (dst, PROP_GATEWAY); + } if (changed) _notify_routes (dst); @@ -1502,22 +1557,6 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev 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 */ head_entry_src = nm_ip4_config_lookup_addresses (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); } 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); } @@ -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) 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 */ for (i = 0; i < nm_ip4_config_get_num_nameservers (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 (" n-dflt: %d", nm_ip4_config_get_never_default (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 @@ -2077,7 +2018,8 @@ nm_ip4_config_reset_routes (NMIP4Config *self) if (nm_dedup_multi_index_remove_idx (priv->multi_idx, &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); } } @@ -2105,11 +2047,19 @@ _add_route (NMIP4Config *self, FALSE, &obj_old, &obj_new_2)) { + gboolean changed_default_route = FALSE; + 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_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)); + 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); } else 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 * -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 *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) 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)) continue; @@ -2704,8 +2659,9 @@ nm_ip4_config_nmpobj_remove (NMIP4Config *self, break; case NMP_OBJECT_TYPE_IP4_ROUTE: if (priv->best_default_route == obj_old) { - _nm_ip_config_best_default_route_set (&priv->best_default_route, - _nm_ip4_config_best_default_route_find (self)); + if (_nm_ip_config_best_default_route_set (&priv->best_default_route, + _nm_ip4_config_best_default_route_find (self))) + _notify (self, PROP_GATEWAY); } _notify_routes (self); break; @@ -2736,9 +2692,6 @@ nm_ip4_config_hash (const NMIP4Config *self, GChecksum *sum, gboolean dns_only) g_return_if_fail (sum); 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) { hash_u32 (sum, address->address); hash_u32 (sum, address->plen); @@ -2893,7 +2846,10 @@ get_property (GObject *object, guint prop_id, const guint32 dbus_addr[3] = { address->address, 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", @@ -2978,9 +2934,11 @@ out_routes_cached: priv->routes_variant); break; case PROP_GATEWAY: - if (priv->has_gateway) - g_value_set_string (value, nm_utils_inet4_ntop (priv->gateway, NULL)); - else + if (priv->best_default_route) { + g_value_set_string (value, + nm_utils_inet4_ntop (NMP_OBJECT_CAST_IP4_ROUTE (priv->best_default_route)->gateway, + NULL)); + } else g_value_set_string (value, NULL); break; case PROP_NAMESERVERS: diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index 775869cd20..978471df29 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -80,12 +80,16 @@ nm_ip_config_best_default_route_is (const NMPObject *obj) { const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE (obj); - /* return whether @obj is considered a default-route, that is, a route - * as added by NetworkManager. E.g. if the route is not in the main-table, - * it's considered just like a regular route. */ + /* return whether @obj is considered a default-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 - && !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); @@ -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); -void nm_ip4_config_add_device_routes (NMIP4Config *self, - guint32 route_table, - guint32 route_metric, - GPtrArray **out_ip4_dev_route_blacklist); +void nm_ip4_config_add_dependent_routes (NMIP4Config *self, + guint32 route_table, + guint32 route_metric, + GPtrArray **out_ip4_dev_route_blacklist); gboolean nm_ip4_config_commit (const NMIP4Config *self, NMPlatform *platform, @@ -167,24 +171,24 @@ void nm_ip4_config_merge_setting (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_subtract (NMIP4Config *dst, const NMIP4Config *src); -void nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src); +void nm_ip4_config_merge (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_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_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_find (const NMIP4Config *self); +in_addr_t nmtst_ip4_config_get_gateway (NMIP4Config *config); + const NMDedupMultiHeadEntry *nm_ip4_config_lookup_addresses (const NMIP4Config *self); void nm_ip4_config_reset_addresses (NMIP4Config *self); 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); 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_add_nameserver (NMIP4Config *self, guint32 nameserver); diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 75c1515acb..81b443c67e 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -58,11 +58,9 @@ _route_valid (const NMPlatformIP6Route *r) /*****************************************************************************/ typedef struct { - bool never_default:1; int ifindex; int dns_priority; NMSettingIP6ConfigPrivacy privacy; - struct in6_addr gateway; GArray *nameservers; GPtrArray *domains; GPtrArray *searches; @@ -372,9 +370,6 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i { NMIP6Config *self; NMIP6ConfigPrivate *priv; - guint32 lowest_metric = G_MAXUINT32; - struct in6_addr old_gateway = IN6ADDR_ANY_INIT; - gboolean has_gateway; const NMDedupMultiHeadEntry *head_entry; NMDedupMultiIter iter; 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, sort_captured_addresses, GINT_TO_POINTER (use_temporary)); + _notify_addresses (self); } head_entry = nm_platform_lookup_addrroute (platform, NMP_OBJECT_TYPE_IP6_ROUTE, ifindex); - /* Extract gateway from default route */ - 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; - } - + nmp_cache_iter_for_each (&iter, head_entry, &plobj) _add_route (self, plobj, NULL, NULL); - } /* If the interface has the default route, and has IPv6 addresses, capture * 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; 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; } void -nm_ip6_config_add_device_routes (NMIP6Config *self, - guint32 route_table, - guint32 route_metric) +nm_ip6_config_add_dependent_routes (NMIP6Config *self, + guint32 route_table, + guint32 route_metric) { const NMIP6ConfigPrivate *priv; - const NMPlatformIP6Address *addr; + const NMPlatformIP6Address *my_addr; + const NMPlatformIP6Route *my_route; int ifindex; NMDedupMultiIter iter; @@ -484,21 +459,21 @@ nm_ip6_config_add_device_routes (NMIP6Config *self, * * 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; NMPlatformIP6Route *route; gboolean has_peer; 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; - 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 * (unless, both addresses are identical). */ 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; 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 (routes_i == 0) - route->network = addr->address; + route->network = my_addr->address; else - route->network = addr->peer_address; + route->network = my_addr->peer_address; route->plen = 128; } else { - nm_utils_ip6_address_clear_host_address (&route->network, &addr->address, addr->plen); - route->plen = addr->plen; + nm_utils_ip6_address_clear_host_address (&route->network, &my_addr->address, my_addr->plen); + route->plen = my_addr->plen; } 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); } } + +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 @@ -644,6 +640,7 @@ nm_ip6_config_merge_setting (NMIP6Config *self, NMIP6ConfigPrivate *priv; guint naddresses, nroutes, nnameservers, nsearches; const char *gateway_str; + struct in6_addr gateway_bin; int i, priority; if (!setting) @@ -661,16 +658,18 @@ nm_ip6_config_merge_setting (NMIP6Config *self, g_object_freeze_notify (G_OBJECT (self)); /* Gateway */ - if (nm_setting_ip_config_get_never_default (setting)) - nm_ip6_config_set_never_default (self, TRUE); - else if (nm_setting_ip_config_get_ignore_auto_routes (setting)) - nm_ip6_config_set_never_default (self, FALSE); - gateway_str = nm_setting_ip_config_get_gateway (setting); - if (gateway_str) { - struct in6_addr gateway; + if ( !nm_setting_ip_config_get_never_default (setting) + && (gateway_str = nm_setting_ip_config_get_gateway (setting)) + && inet_pton (AF_INET6, gateway_str, &gateway_bin) == 1 + && !IN6_IS_ADDR_UNSPECIFIED (&gateway_bin)) { + const NMPlatformIP6Route r = { + .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_INET6, gateway_str, &gateway); - nm_ip6_config_set_gateway (self, &gateway); + _add_route (self, NULL, &r, NULL); } /* Addresses */ @@ -753,8 +752,8 @@ nm_ip6_config_merge_setting (NMIP6Config *self, NMSetting * nm_ip6_config_create_setting (const NMIP6Config *self) { + const NMIP6ConfigPrivate *priv; NMSettingIPConfig *s_ip6; - const struct in6_addr *gateway; guint nnameservers, nsearches, noptions; const char *method = NULL; int i; @@ -771,7 +770,8 @@ nm_ip6_config_create_setting (const NMIP6Config *self) 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); nsearches = nm_ip6_config_get_num_searches (self); noptions = nm_ip6_config_get_num_dns_options (self); @@ -803,10 +803,12 @@ nm_ip6_config_create_setting (const NMIP6Config *self) } /* Gateway */ - if ( gateway + if ( priv->best_default_route && nm_setting_ip_config_get_num_addresses (s_ip6) > 0) { 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); } @@ -869,7 +871,10 @@ nm_ip6_config_create_setting (const NMIP6Config *self) /*****************************************************************************/ 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; 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)); } - /* default gateway */ - if (nm_ip6_config_get_gateway (src)) - nm_ip6_config_set_gateway (dst, nm_ip6_config_get_gateway (src)); - /* 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); + } } /* domains */ @@ -930,25 +945,6 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl 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 @@ -1017,11 +1013,17 @@ _dns_options_get_index (const NMIP6Config *self, const char *option) * nm_ip6_config_subtract: * @dst: config from which to remove everything in @src * @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. */ 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; guint i; @@ -1029,7 +1031,6 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src) const NMPlatformIP6Address *a; const NMPlatformIP6Route *r; NMDedupMultiIter ipconf_iter; - const struct in6_addr *dst_tmp, *src_tmp; gboolean changed; gboolean changed_default_route; @@ -1059,24 +1060,31 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src) 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 */ changed = FALSE; changed_default_route = FALSE; 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; + 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, &dst_priv->idx_ip6_routes, - NMP_OBJECT_UP_CAST (r), + o_lookup, (gconstpointer *) &obj_old)) { if (dst_priv->best_default_route == obj_old) { 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) { _nm_ip_config_best_default_route_set (&dst_priv->best_default_route, _nm_ip6_config_best_default_route_find (dst)); + _notify (dst, PROP_GATEWAY); } if (changed) _notify_routes (dst); @@ -1121,11 +1130,12 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src) } 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; const NMIP6ConfigPrivate *src_priv; - const struct in6_addr *dst_tmp, *src_tmp; NMDedupMultiIter ipconf_iter; const NMPlatformIP6Address *a; const NMPlatformIP6Route *r; @@ -1158,26 +1168,31 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src) /* 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 */ changed = FALSE; new_best_default_route = NULL; 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, &src_priv->idx_ip6_routes, - o)) { - new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, o); + o_lookup)) { + new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, o_dst); continue; } @@ -1186,8 +1201,10 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src) nm_assert_not_reached (); 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); + _notify (dst, PROP_GATEWAY); + } if (changed) _notify_routes (dst); @@ -1247,18 +1264,6 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev 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 */ head_entry_src = nm_ip6_config_lookup_addresses (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); } 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); } @@ -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) 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 */ for (i = 0; i < nm_ip6_config_get_num_nameservers (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 (" 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 nm_ip6_config_reset_routes_ndisc (NMIP6Config *self, + const NMNDiscGateway *gateways, + guint gateways_n, const NMNDiscRoute *routes, guint routes_n, 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); } - if (_nm_ip_config_best_default_route_set (&priv->best_default_route, new_best_default_route)) - changed = TRUE; + /* Use the first gateway as ordered in neighbor discovery cache. */ + 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) 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) _notify_routes (self); } @@ -1874,7 +1858,8 @@ nm_ip6_config_reset_routes (NMIP6Config *self) if (nm_dedup_multi_index_remove_idx (priv->multi_idx, &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); } } @@ -1902,11 +1887,19 @@ _add_route (NMIP6Config *self, FALSE, &obj_old, &obj_new_2)) { + gboolean changed_default_route = FALSE; + 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_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)); + 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); } else 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 * -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 *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) 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)) continue; @@ -2357,8 +2355,9 @@ nm_ip6_config_nmpobj_remove (NMIP6Config *self, break; case NMP_OBJECT_TYPE_IP6_ROUTE: if (priv->best_default_route == obj_old) { - _nm_ip_config_best_default_route_set (&priv->best_default_route, - _nm_ip6_config_best_default_route_find (self)); + if (_nm_ip_config_best_default_route_set (&priv->best_default_route, + _nm_ip6_config_best_default_route_find (self))) + _notify (self, PROP_GATEWAY); } _notify_routes (self); break; @@ -2398,8 +2397,6 @@ nm_ip6_config_hash (const NMIP6Config *self, GChecksum *sum, gboolean dns_only) g_return_if_fail (sum); 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) { hash_in6addr (sum, &address->address); hash_u32 (sum, address->plen); @@ -2558,9 +2555,10 @@ get_property (GObject *object, guint prop_id, &address->address, 16, 1), address->plen, g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, - i == 0 - ? (nm_ip6_config_get_gateway (self) ?: &in6addr_any) - : &in6addr_any, + ( i == 0 + && priv->best_default_route) + ? &NMP_OBJECT_CAST_IP6_ROUTE (priv->best_default_route)->gateway + : &in6addr_any, 16, 1)); } } @@ -2636,9 +2634,11 @@ out_routes_cached: priv->routes_variant); break; case PROP_GATEWAY: - if (!IN6_IS_ADDR_UNSPECIFIED (&priv->gateway)) - g_value_set_string (value, nm_utils_inet6_ntop (&priv->gateway, NULL)); - else + if (priv->best_default_route) { + g_value_set_string (value, + nm_utils_inet6_ntop (&NMP_OBJECT_CAST_IP6_ROUTE (priv->best_default_route)->gateway, + NULL)); + } else g_value_set_string (value, NULL); break; case PROP_NAMESERVERS: diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index 0440bc52d3..c55ee31ea9 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -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, gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary); -void nm_ip6_config_add_device_routes (NMIP6Config *self, - guint32 route_table, - guint32 route_metric); +void nm_ip6_config_add_dependent_routes (NMIP6Config *self, + guint32 route_table, + guint32 route_metric); gboolean nm_ip6_config_commit (const NMIP6Config *self, NMPlatform *platform, @@ -123,19 +123,19 @@ void nm_ip6_config_merge_setting (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_subtract (NMIP6Config *dst, const NMIP6Config *src); -void nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src); +void nm_ip6_config_merge (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); -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_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_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); 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); void nm_ip6_config_reset_nameservers (NMIP6Config *self); @@ -210,7 +212,10 @@ void nm_ip6_config_reset_addresses_ndisc (NMIP6Config *self, guint8 plen, guint32 ifa_flags); struct _NMNDiscRoute; +struct _NMNDiscGateway; void nm_ip6_config_reset_routes_ndisc (NMIP6Config *self, + const struct _NMNDiscGateway *gateways, + guint gateways_n, const struct _NMNDiscRoute *routes, guint routes_n, guint32 route_table, diff --git a/src/nm-types.h b/src/nm-types.h index af99bdcfad..e01c48b0a5 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -194,7 +194,8 @@ typedef enum { typedef enum { NM_IP_CONFIG_MERGE_DEFAULT = 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; diff --git a/src/ppp/nm-ppp-manager-call.c b/src/ppp/nm-ppp-manager-call.c index d67c0a99ce..ad3307a9d5 100644 --- a/src/ppp/nm-ppp-manager-call.c +++ b/src/ppp/nm-ppp-manager-call.c @@ -98,6 +98,22 @@ nm_ppp_manager_create (const char *iface, GError **error) 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 nm_ppp_manager_start (NMPPPManager *self, NMActRequest *req, diff --git a/src/ppp/nm-ppp-manager-call.h b/src/ppp/nm-ppp-manager-call.h index f21005f0fd..2258ae08f7 100644 --- a/src/ppp/nm-ppp-manager-call.h +++ b/src/ppp/nm-ppp-manager-call.h @@ -25,6 +25,13 @@ NMPPPManager * nm_ppp_manager_create (const char *iface, 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, NMActRequest *req, const char *ppp_name, diff --git a/src/ppp/nm-ppp-manager.c b/src/ppp/nm-ppp-manager.c index 06703366f3..75299d1a66 100644 --- a/src/ppp/nm-ppp-manager.c +++ b/src/ppp/nm-ppp-manager.c @@ -42,6 +42,7 @@ #endif #include <linux/if.h> #include <linux/if_ppp.h> +#include <linux/rtnetlink.h> #include "NetworkManagerUtils.h" #include "platform/nm-platform.h" @@ -105,6 +106,11 @@ typedef struct { char *ip_iface; int monitor_fd; guint monitor_id; + + guint32 ip4_route_table; + guint32 ip4_route_metric; + guint32 ip6_route_table; + guint32 ip6_route_metric; } NMPPPManagerPrivate; 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 monitor_cb (gpointer user_data) { @@ -404,6 +441,7 @@ impl_ppp_manager_set_ip4_config (NMPPPManager *manager, NMPlatformIP4Address address; guint32 u32, mtu; GVariantIter *iter; + int ifindex; _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)) goto out; - config = nm_ip4_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET), - nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface)); + ifindex = 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) 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; 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; } else address.peer_address = address.address; @@ -500,6 +549,7 @@ impl_ppp_manager_set_ip6_config (NMPPPManager *manager, struct in6_addr a; NMUtilsIPv6IfaceId iid = NM_UTILS_IPV6_IFACE_ID_INIT; gboolean has_peer = FALSE; + int ifindex; _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)) goto out; - config = nm_ip6_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET), - nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface)); + ifindex = 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)); addr.plen = 64; 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; has_peer = TRUE; } @@ -1167,7 +1228,7 @@ set_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_PARENT_IFACE: - g_free (priv->parent_iface); + /* construct-only */ priv->parent_iface = g_value_dup_string (value); break; default: @@ -1181,7 +1242,13 @@ set_property (GObject *object, guint prop_id, static void 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 * @@ -1291,9 +1358,10 @@ nm_ppp_manager_class_init (NMPPPManagerClass *manager_class) } NMPPPOps ppp_ops = { - .create = _ppp_manager_new, - .start = _ppp_manager_start, - .stop_async = _ppp_manager_stop_async, - .stop_finish = _ppp_manager_stop_finish, - .stop_sync = _ppp_manager_stop_sync, + .create = _ppp_manager_new, + .set_route_parameters = _ppp_manager_set_route_paramters, + .start = _ppp_manager_start, + .stop_async = _ppp_manager_stop_async, + .stop_finish = _ppp_manager_stop_finish, + .stop_sync = _ppp_manager_stop_sync, }; diff --git a/src/ppp/nm-ppp-manager.h b/src/ppp/nm-ppp-manager.h index b1a7bb609a..35fb1b6091 100644 --- a/src/ppp/nm-ppp-manager.h +++ b/src/ppp/nm-ppp-manager.h @@ -22,7 +22,7 @@ #ifndef __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_IP4_CONFIG "ip4-config" diff --git a/src/ppp/nm-ppp-plugin-api.h b/src/ppp/nm-ppp-plugin-api.h index 0a38fe0551..bb53690c63 100644 --- a/src/ppp/nm-ppp-plugin-api.h +++ b/src/ppp/nm-ppp-plugin-api.h @@ -24,6 +24,12 @@ typedef const struct { 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, NMActRequest *req, const char *ppp_name, diff --git a/src/tests/test-ip4-config.c b/src/tests/test-ip4-config.c index c2a1c006c5..649b443f2a 100644 --- a/src/tests/test-ip4-config.c +++ b/src/tests/test-ip4-config.c @@ -47,7 +47,16 @@ build_test_config (void) 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_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.2")); @@ -106,7 +115,7 @@ test_subtract (void) 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 */ 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->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); 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 (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 */ 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 */ 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 */ g_assert_cmpuint (nm_ip4_config_get_mtu (cfg1), ==, 0); diff --git a/src/tests/test-ip6-config.c b/src/tests/test-ip6-config.c index 05d2084ee5..bcbeee3e10 100644 --- a/src/tests/test-ip6-config.c +++ b/src/tests/test-ip6-config.c @@ -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 ("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::2")); @@ -84,7 +84,7 @@ test_subtract (void) nm_ip6_config_add_domain (dst, expected_domain); 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 */ 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_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); test_route = _nmtst_ip6_config_get_route (dst, 0); diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c index e9a2bd919f..4b474c50d9 100644 --- a/src/vpn/nm-vpn-connection.c +++ b/src/vpn/nm-vpn-connection.c @@ -1018,9 +1018,6 @@ print_vpn_config (NMVpnConnection *self) 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); for (i = 0; i < num; i++) { _LOGI ("Data: Internal DNS: %s", @@ -1055,9 +1052,6 @@ print_vpn_config (NMVpnConnection *self) 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); for (i = 0; i < num; i++) { _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), ifindex); 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) { vpn6_parent_config = nm_ip6_config_new (nm_netns_get_multi_idx (priv->netns), ifindex); - if (priv->ip_ifindex <= 0) { - nm_ip6_config_merge (vpn6_parent_config, priv->ip6_config, NM_IP_CONFIG_MERGE_NO_DNS); - - /* 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); - } + if (priv->ip_ifindex <= 0) + nm_ip6_config_merge (vpn6_parent_config, priv->ip6_config, NM_IP_CONFIG_MERGE_NO_DNS, 0); } } @@ -1479,6 +1467,7 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict) gboolean b; int ip_ifindex; guint32 mss = 0; + gboolean never_default = FALSE; 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; /* 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; - nm_ip4_config_set_gateway (config, priv->ip4_internal_gw); - } if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS, "u", &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)) - nm_ip4_config_set_never_default (config, b); + never_default = b; /* Merge in user overrides from the NMConnection's IPv4 setting */ nm_ip4_config_merge_setting (config, @@ -1633,11 +1620,11 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict) route_table, route_metric); - if (!nm_ip4_config_get_never_default (config)) { + if (!never_default) { const NMPlatformIP4Route r = { .ifindex = ip_ifindex, .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), .metric = route_metric, .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); - nm_ip4_config_add_device_routes (config, - route_table, - nm_vpn_connection_get_ip4_route_metric (self), - &priv->ip4_dev_route_blacklist); + nm_ip4_config_add_dependent_routes (config, + route_table, + nm_vpn_connection_get_ip4_route_metric (self), + &priv->ip4_dev_route_blacklist); if (priv->ip4_config) { nm_ip4_config_replace (priv->ip4_config, config, NULL); @@ -1679,6 +1666,7 @@ nm_vpn_connection_ip6_config_get (NMVpnConnection *self, GVariant *dict) gboolean b; int ip_ifindex; guint32 mss = 0; + gboolean never_default = FALSE; 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); if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_INT_GATEWAY, "@ay", &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); } @@ -1812,7 +1799,7 @@ next: } 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 */ nm_ip6_config_merge_setting (config, @@ -1820,11 +1807,11 @@ next: route_table, route_metric); - if (!nm_ip6_config_get_never_default (config)) { + if (!never_default) { const NMPlatformIP6Route r = { .ifindex = ip_ifindex, .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), .metric = route_metric, .mss = mss, @@ -1833,9 +1820,9 @@ next: nm_ip6_config_add_route (config, &r, NULL); } - nm_ip6_config_add_device_routes (config, - route_table, - route_metric); + nm_ip6_config_add_dependent_routes (config, + route_table, + route_metric); if (priv->ip6_config) { nm_ip6_config_replace (priv->ip6_config, config, NULL); |