diff options
author | Thomas Haller <thaller@redhat.com> | 2020-09-07 16:11:59 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2020-09-07 16:11:59 +0200 |
commit | 19c8332f05f4c0680f496282e3396aef7d2a91f0 (patch) | |
tree | 2eff1c8073173b13555cd32b886c4ca44f792f13 | |
parent | 97c1bed37e46906f5450f53333e903c679f47ffe (diff) | |
parent | 4038a8ff993f9fb30611d76a6937c6ff3e730966 (diff) | |
download | NetworkManager-19c8332f05f4c0680f496282e3396aef7d2a91f0.tar.gz |
l3cfg: merge branch 'th/l3cfg-7'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/618
-rw-r--r-- | src/devices/nm-device-private.h | 2 | ||||
-rw-r--r-- | src/devices/nm-device.c | 359 | ||||
-rw-r--r-- | src/nm-dbus-object.c | 59 | ||||
-rw-r--r-- | src/nm-dbus-object.h | 6 | ||||
-rw-r--r-- | src/nm-l3-config-data.c | 236 | ||||
-rw-r--r-- | src/nm-l3-config-data.h | 69 | ||||
-rw-r--r-- | src/nm-l3cfg.c | 148 | ||||
-rw-r--r-- | src/nm-l3cfg.h | 60 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 14 | ||||
-rw-r--r-- | src/platform/nmp-object.h | 6 |
10 files changed, 822 insertions, 137 deletions
diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h index cd72f3d712..1cda2e1950 100644 --- a/src/devices/nm-device-private.h +++ b/src/devices/nm-device-private.h @@ -160,6 +160,8 @@ NMIP6Config *nm_device_ip6_config_new (NMDevice *self); NMIPConfig *nm_device_ip_config_new (NMDevice *self, int addr_family); +NML3ConfigData *nm_device_create_l3_config_data (NMDevice *self); + /*****************************************************************************/ gint64 nm_device_get_configured_mtu_from_connection_default (NMDevice *self, diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 0f47a2c3ba..53a3085bea 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -28,6 +28,8 @@ #include "nm-libnm-core-intern/nm-ethtool-utils.h" #include "nm-libnm-core-intern/nm-common-macros.h" #include "nm-device-private.h" +#include "nm-l3cfg.h" +#include "nm-l3-config-data.h" #include "NetworkManagerUtils.h" #include "nm-manager.h" #include "platform/nm-platform.h" @@ -134,6 +136,21 @@ typedef struct { typedef void (*AcdCallback) (NMDevice *, NMIP4Config **, gboolean); +typedef enum { + /* The various NML3ConfigData types that we track explicitly. Note that + * their relative order matters: higher numbers in this enum means more + * important (and during merge overwrites other settings). */ + L3_CONFIG_DATA_TYPE_LL_4, + L3_CONFIG_DATA_TYPE_AC_6, + L3_CONFIG_DATA_TYPE_DHCP_4, + L3_CONFIG_DATA_TYPE_DHCP_6, + L3_CONFIG_DATA_TYPE_DEV_4, + L3_CONFIG_DATA_TYPE_DEV_6, + L3_CONFIG_DATA_TYPE_SETTING, + _L3_CONFIG_DATA_TYPE_NUM, + _L3_CONFIG_DATA_TYPE_NONE, +} L3ConfigDataType; + typedef struct { AcdCallback callback; NMDevice *device; @@ -286,23 +303,29 @@ typedef struct _NMDevicePrivate { char * path; union { - NML3Cfg *const l3cfg; - NML3Cfg *l3cfg_; + const char *const iface; + char * iface_; }; - union { - NML3Cfg *const ip_l3cfg; - NML3Cfg *ip_l3cfg_; + const char *const ip_iface; + char * ip_iface_; }; union { - const char *const iface; - char * iface_; + NML3Cfg *const l3cfg; + NML3Cfg *l3cfg_; }; + union { const int ifindex; int ifindex_; }; + union { + const int ip_ifindex; + int ip_ifindex_; + }; + + const NML3ConfigData *l3cds[_L3_CONFIG_DATA_TYPE_NUM]; int parent_ifindex; @@ -320,14 +343,6 @@ typedef struct _NMDevicePrivate { bool update_ip_config_completed_v4:1; bool update_ip_config_completed_v6:1; - union { - const char *const ip_iface; - char * ip_iface_; - }; - union { - const int ip_ifindex; - int ip_ifindex_; - }; NMDeviceType type; char * type_desc; NMLinkType link_type; @@ -419,6 +434,14 @@ typedef struct _NMDevicePrivate { * in the future. This is used to extend the grace period in this particular case. */ gint64 carrier_wait_until_ms; + union { + struct { + NML3ConfigMergeFlags l3config_merge_flags_6; + NML3ConfigMergeFlags l3config_merge_flags_4; + }; + NML3ConfigMergeFlags l3config_merge_flags_x[2]; + }; + bool carrier:1; bool ignore_carrier:1; @@ -435,6 +458,8 @@ typedef struct _NMDevicePrivate { bool v4_route_table_initialized:1; bool v6_route_table_initialized:1; + bool l3config_merge_flags_has:1; + bool v4_route_table_all_sync_before:1; bool v6_route_table_all_sync_before:1; @@ -678,6 +703,10 @@ static void nm_device_slave_notify_release (NMDevice *self, NMDeviceStateReason static void addrconf6_start_with_link_ready (NMDevice *self); static gboolean linklocal6_start (NMDevice *self); +static guint32 default_route_metric_penalty_get (NMDevice *self, int addr_family); + +static guint get_ipv4_dad_timeout (NMDevice *self); + static void _carrier_wait_check_queued_act_request (NMDevice *self); static gint64 _get_carrier_wait_ms (NMDevice *self); @@ -1233,6 +1262,21 @@ nm_device_ip_config_new (NMDevice *self, int addr_family) : (gpointer) nm_device_ip6_config_new (self); } +NML3ConfigData * +nm_device_create_l3_config_data (NMDevice *self) +{ + int ifindex; + + nm_assert (NM_IS_DEVICE (self)); + + ifindex = nm_device_get_ip_ifindex (self); + if (ifindex <= 0) + g_return_val_if_reached (NULL); + + return nm_l3_config_data_new (nm_device_get_multi_index (self), + ifindex); +} + static void applied_config_clear (AppliedConfig *config) { @@ -1755,6 +1799,246 @@ _set_ip_state (NMDevice *self, int addr_family, NMDeviceIPState new_state) /*****************************************************************************/ +static L3ConfigDataType +_dev_l3_config_data_tag_to_type (NMDevice *self, + gconstpointer tag) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + int d; + + if ( tag < ((gpointer) &priv->l3cds[0]) + || tag >= ((gpointer) &priv->l3cds[G_N_ELEMENTS (priv->l3cds)])) + return _L3_CONFIG_DATA_TYPE_NONE; + + d = ((const NML3ConfigData **) tag) - (&priv->l3cds[0]); + + nm_assert (d >= 0); + nm_assert (d < _L3_CONFIG_DATA_TYPE_NUM); + nm_assert (tag == &priv->l3cds[d]); + return d; +} + +static NML3ConfigMergeFlags +_dev_l3_get_merge_flags (NMDevice *self, + L3ConfigDataType type) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NML3ConfigMergeFlags flags; + NMConnection *connection; + NMSettingIPConfig *s_ip; + + if (G_UNLIKELY (!priv->l3config_merge_flags_has)) { + int IS_IPv4; + + connection = nm_device_get_applied_connection (self); + + for (IS_IPv4 = 0; IS_IPv4 < 2; IS_IPv4++) { + flags = NM_L3_CONFIG_MERGE_FLAGS_NONE; + + if ( connection + && (s_ip = nm_connection_get_setting_ip_config (connection, IS_IPv4 ? AF_INET : AF_INET6))) { + + if (nm_setting_ip_config_get_ignore_auto_routes (s_ip)) + flags |= NM_L3_CONFIG_MERGE_FLAGS_NO_ROUTES; + + if (nm_setting_ip_config_get_ignore_auto_dns (s_ip)) + flags |= NM_L3_CONFIG_MERGE_FLAGS_NO_DNS; + + if ( nm_setting_ip_config_get_never_default (s_ip) + || nm_setting_ip_config_get_gateway (s_ip)) { + /* if the connection has an explicit gateway, we also ignore + * the default routes from other sources. */ + flags |= NM_L3_CONFIG_MERGE_FLAGS_NO_DEFAULT_ROUTES; + } + } + + priv->l3config_merge_flags_x[IS_IPv4] = flags; + } + priv->l3config_merge_flags_has = TRUE; + } + + switch (type) { + + case L3_CONFIG_DATA_TYPE_SETTING: + case L3_CONFIG_DATA_TYPE_LL_4: + return NM_L3_CONFIG_MERGE_FLAGS_NONE; + + case L3_CONFIG_DATA_TYPE_DHCP_4: + case L3_CONFIG_DATA_TYPE_DEV_4: + return priv->l3config_merge_flags_4; + + case L3_CONFIG_DATA_TYPE_AC_6: + case L3_CONFIG_DATA_TYPE_DHCP_6: + case L3_CONFIG_DATA_TYPE_DEV_6: + return priv->l3config_merge_flags_6; + + case _L3_CONFIG_DATA_TYPE_NUM: + case _L3_CONFIG_DATA_TYPE_NONE: + break; + } + return nm_assert_unreachable_val (NM_L3_CONFIG_MERGE_FLAGS_NONE); +} + +_nm_unused /* FIXME(l3cfg) */ +static gboolean +_dev_l3_register_l3cds_set_one (NMDevice *self, + L3ConfigDataType l3cd_type, + const NML3ConfigData *l3cd) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + nm_auto_unref_l3cd const NML3ConfigData *l3cd_old_free = NULL; + const NML3ConfigData *l3cd_old; + gboolean changed = FALSE; + + l3cd_old = priv->l3cds[l3cd_type]; + if (l3cd != priv->l3cds[l3cd_type]) { + l3cd_old_free = g_steal_pointer (&priv->l3cds[l3cd_type]); + if (l3cd) + priv->l3cds[l3cd_type] = nm_l3_config_data_ref_and_seal (l3cd); + } + + if (priv->l3cfg) { + if (nm_l3cfg_add_config (priv->l3cfg, + &priv->l3cds[l3cd_type], + FALSE, + priv->l3cds[l3cd_type], + l3cd_type, + default_route_metric_penalty_get (self, AF_INET), + default_route_metric_penalty_get (self, AF_INET6), + get_ipv4_dad_timeout (self), + _dev_l3_get_merge_flags (self, l3cd_type))) + changed = TRUE; + + if ( l3cd_old + && l3cd_old != l3cd) { + if (nm_l3cfg_remove_config (priv->l3cfg, &priv->l3cds[l3cd_type], l3cd_old)) + changed = TRUE; + } + } + + return changed; +} + +static gboolean +_dev_l3_register_l3cds (NMDevice *self, + NML3Cfg *l3cfg, + gboolean do_add /* else remove */) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + guint32 default_route_penalty_4 = 0; + guint32 default_route_penalty_6 = 0; + guint32 acd_timeout_msec = 0; + gboolean is_external; + gboolean changed; + int i; + + if (!l3cfg) + return FALSE; + + is_external = nm_device_sys_iface_state_is_external (self); + if (!is_external) { + default_route_penalty_4 = default_route_metric_penalty_get (self, AF_INET); + default_route_penalty_6 = default_route_metric_penalty_get (self, AF_INET6); + acd_timeout_msec = get_ipv4_dad_timeout (self); + } + + changed = FALSE; + for (i = 0; i < G_N_ELEMENTS (priv->l3cds); i++) { + if (!priv->l3cds[i]) + continue; + if (!do_add) { + if (nm_l3cfg_remove_config (l3cfg, &priv->l3cds[i], priv->l3cds[i])) + changed = TRUE; + continue; + } + if (is_external) + continue; + if (nm_l3cfg_add_config (l3cfg, + &priv->l3cds[i], + FALSE, + priv->l3cds[i], + i, + default_route_penalty_4, + default_route_penalty_6, + acd_timeout_msec, + _dev_l3_get_merge_flags (self, i))) + changed = TRUE; + } + + return changed; +} + +_nm_unused /* FIXME(l3cfg) */ +static gboolean +_dev_l3_platform_commit (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + gboolean success; + + if (!priv->l3cfg) + return FALSE; + + if (nm_device_sys_iface_state_is_external (self)) + return TRUE; + + success = nm_l3cfg_platform_commit (priv->l3cfg, + nm_device_sys_iface_state_is_external_or_assume (self) + ? NM_L3_CFG_COMMIT_TYPE_ASSUME + : NM_L3_CFG_COMMIT_TYPE_UPDATE, + AF_UNSPEC, + NULL); + return success; +} + +static void +_dev_l3_cfg_acd_maybe_comlete (NMDevice *self) +{ + /* FIXME(l3cfg) */ +} + +static void +_dev_l3_cfg_notify_cb (NML3Cfg *l3cfg, + int notify_type_i, + const NML3ConfigNotifyPayload *payload, + NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + nm_assert (l3cfg == priv->l3cfg); + + switch ((NML3ConfigNotifyType) notify_type_i) { + case NM_L3_CONFIG_NOTIFY_TYPE_ACD_FAILED: { + const NML3ConfigNotifyPayloadAcdFailedSource *sources = payload->acd_failed.sources; + guint sources_len = payload->acd_failed.sources_len; + guint i; + + for (i = 0; i < sources_len; i++) { + L3ConfigDataType l3cd_type = _dev_l3_config_data_tag_to_type (self, sources[i].tag); + + if (NM_IN_SET (l3cd_type, L3_CONFIG_DATA_TYPE_DHCP_4)) { + nm_dhcp_client_decline (priv->dhcp_data_4.client, "Address conflict detected", NULL); + nm_device_ip_method_failed (self, AF_INET, + NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE); + return; + } + } + _dev_l3_cfg_acd_maybe_comlete (self); + return; + } + case NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED: + _dev_l3_cfg_acd_maybe_comlete (self); + return; + case NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED: + /* FIXME(l3cfg) */ + return; + case _NM_L3_CONFIG_NOTIFY_TYPE_NUM: + break; + } + nm_assert_not_reached (); +} + +/*****************************************************************************/ + const char * nm_device_get_udi (NMDevice *self) { @@ -1776,7 +2060,8 @@ _set_ifindex (NMDevice *self, int ifindex, gboolean is_ip_ifindex) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); gs_unref_object NML3Cfg *l3cfg_old = NULL; - NML3Cfg **p_l3cfg; + gboolean l3_changed; + int ip_ifindex_new; int *p_ifindex; if (ifindex < 0) @@ -1791,24 +2076,47 @@ _set_ifindex (NMDevice *self, int ifindex, gboolean is_ip_ifindex) *p_ifindex = ifindex; - p_l3cfg = is_ip_ifindex - ? &priv->ip_l3cfg_ - : &priv->l3cfg_; + ip_ifindex_new = nm_device_get_ip_ifindex (self); - l3cfg_old = g_steal_pointer (p_l3cfg); - if (ifindex > 0) - *p_l3cfg = nm_netns_access_l3cfg (priv->netns, ifindex); + if (priv->l3cfg) { + if ( ip_ifindex_new <= 0 + || ip_ifindex_new != nm_l3cfg_get_ifindex (priv->l3cfg)) { + g_signal_handlers_disconnect_by_func (priv->l3cfg, + G_CALLBACK (_dev_l3_cfg_notify_cb), + self); + l3cfg_old = g_steal_pointer (&priv->l3cfg_); + } + } + if ( !priv->l3cfg + && ip_ifindex_new > 0) { + priv->l3cfg_ = nm_netns_access_l3cfg (priv->netns, ip_ifindex_new); + + g_signal_connect (priv->l3cfg, + NM_L3CFG_SIGNAL_NOTIFY, + G_CALLBACK (_dev_l3_cfg_notify_cb), + self); + } _LOGD (LOGD_DEVICE, "ifindex: set %sifindex %d%s%s%s%s%s%s", is_ip_ifindex ? "ip-" : "", ifindex, - NM_PRINT_FMT_QUOTED (l3cfg_old, " (old-l3cfg: ", nm_hash_obfuscated_ptr_str_a (l3cfg_old), ")", ""), - NM_PRINT_FMT_QUOTED (*p_l3cfg, " (l3cfg: ", nm_hash_obfuscated_ptr_str_a (*p_l3cfg), ")", "")); + NM_PRINT_FMT_QUOTED (l3cfg_old && l3cfg_old != priv->l3cfg, " (old-l3cfg: ", nm_hash_obfuscated_ptr_str_a (l3cfg_old), ")", ""), + NM_PRINT_FMT_QUOTED (priv->l3cfg && l3cfg_old != priv->l3cfg, " (l3cfg: ", nm_hash_obfuscated_ptr_str_a (priv->l3cfg), ")", "")); if (!is_ip_ifindex) _notify (self, PROP_IFINDEX); + l3_changed = FALSE; + if (_dev_l3_register_l3cds (self, priv->l3cfg, TRUE)) + l3_changed = TRUE; + if (_dev_l3_register_l3cds (self, l3cfg_old, FALSE)) + l3_changed = TRUE; + + if (l3_changed) { + /* FIXME(l3cfg) */ + } + return TRUE; } @@ -7089,6 +7397,7 @@ activate_stage1_device_prepare (NMDevice *self) priv->v4_route_table_initialized = FALSE; priv->v6_route_table_initialized = FALSE; + priv->l3config_merge_flags_has = FALSE; _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_NONE); _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_NONE); @@ -12569,6 +12878,7 @@ check_and_reapply_connection (NMDevice *self, priv->v4_route_table_initialized = FALSE; priv->v6_route_table_initialized = FALSE; + priv->l3config_merge_flags_has = FALSE; /************************************************************************** * Reapply changes @@ -15653,6 +15963,7 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) priv->v4_route_table_initialized = FALSE; priv->v6_route_table_initialized = FALSE; + priv->l3config_merge_flags_has = FALSE; priv->v4_route_table_all_sync_before = FALSE; priv->v6_route_table_all_sync_before = FALSE; diff --git a/src/nm-dbus-object.c b/src/nm-dbus-object.c index db793b9da3..6320073ebe 100644 --- a/src/nm-dbus-object.c +++ b/src/nm-dbus-object.c @@ -84,26 +84,27 @@ _create_export_path (NMDBusObjectClass *klass) * Returns: the path @self was exported under */ const char * -nm_dbus_object_export (NMDBusObject *self) +nm_dbus_object_export (gpointer /* (NMDBusObject *) */ self) { + NMDBusObject *self1 = self; static guint64 id_counter = 0; - g_return_val_if_fail (NM_IS_DBUS_OBJECT (self), NULL); + g_return_val_if_fail (NM_IS_DBUS_OBJECT (self1), NULL); - g_return_val_if_fail (!self->internal.path, self->internal.path); + g_return_val_if_fail (!self1->internal.path, self1->internal.path); - nm_assert (!self->internal.is_unexporting); + nm_assert (!self1->internal.is_unexporting); - self->internal.path = _create_export_path (NM_DBUS_OBJECT_GET_CLASS (self)); + self1->internal.path = _create_export_path (NM_DBUS_OBJECT_GET_CLASS (self1)); - self->internal.export_version_id = ++id_counter; + self1->internal.export_version_id = ++id_counter; - _LOGT ("export: \"%s\"", self->internal.path); + _LOGT ("export: \"%s\"", self1->internal.path); - _nm_dbus_manager_obj_export (self); + _nm_dbus_manager_obj_export (self1); - _emit_exported_changed (self); - return self->internal.path; + _emit_exported_changed (self1); + return self1->internal.path; } /** @@ -114,13 +115,15 @@ nm_dbus_object_export (NMDBusObject *self) * auto-exported on future connections). */ void -nm_dbus_object_unexport (NMDBusObject *self) +nm_dbus_object_unexport (gpointer /* (NMDBusObject *) */ self) { - g_return_if_fail (NM_IS_DBUS_OBJECT (self)); + NMDBusObject *self1 = self; - g_return_if_fail (self->internal.path); + g_return_if_fail (NM_IS_DBUS_OBJECT (self1)); - _LOGT ("unexport: \"%s\"", self->internal.path); + g_return_if_fail (self1->internal.path); + + _LOGT ("unexport: \"%s\"", self1->internal.path); /* note that we emit the signal *before* actually unexporting the object. * The reason is, that listeners want to use this signal to know that @@ -133,16 +136,16 @@ nm_dbus_object_unexport (NMDBusObject *self) * The inconvenient part is, that at this point nm_dbus_object_get_path() * still returns the path. So, the callee needs to handle that. Possibly * by using "nm_dbus_object_get_path_still_exported()". */ - self->internal.is_unexporting = TRUE; + self1->internal.is_unexporting = TRUE; - _emit_exported_changed (self); + _emit_exported_changed (self1); - _nm_dbus_manager_obj_unexport (self); + _nm_dbus_manager_obj_unexport (self1); - nm_clear_g_free (&self->internal.path); - self->internal.export_version_id = 0; + nm_clear_g_free (&self1->internal.path); + self1->internal.export_version_id = 0; - self->internal.is_unexporting = FALSE; + self1->internal.is_unexporting = FALSE; } static gboolean @@ -155,21 +158,27 @@ _unexport_on_idle_cb (gpointer user_data) } void -nm_dbus_object_unexport_on_idle (NMDBusObject *self_take) +nm_dbus_object_unexport_on_idle (gpointer /* (NMDBusObject *) */ self_take) { - g_return_if_fail (NM_IS_DBUS_OBJECT (self_take)); + NMDBusObject *self = g_steal_pointer (&self_take); + + if (!self) + return; + + g_return_if_fail (NM_IS_DBUS_OBJECT (self)); - g_return_if_fail (self_take->internal.path); + g_return_if_fail (self->internal.path); /* There is no mechanism to cancel or abort the unexport. It will always * gonna happen. * * However, we register it to block shutdown, so that we ensure that it will happen. */ - nm_shutdown_wait_obj_register_object (self_take, "unexport-dbus-obj-on-idle"); + nm_shutdown_wait_obj_register_object (self, "unexport-dbus-obj-on-idle"); + /* pass on ownership. */ g_idle_add (_unexport_on_idle_cb, - g_steal_pointer (&self_take)); + g_steal_pointer (&self)); } /*****************************************************************************/ diff --git a/src/nm-dbus-object.h b/src/nm-dbus-object.h index ab09465f6c..014f043df2 100644 --- a/src/nm-dbus-object.h +++ b/src/nm-dbus-object.h @@ -163,10 +163,10 @@ nm_dbus_object_get_path_still_exported (NMDBusObject *self) : self->internal.path; } -const char *nm_dbus_object_export (NMDBusObject *self); -void nm_dbus_object_unexport (NMDBusObject *self); +const char *nm_dbus_object_export (gpointer /* (NMDBusObject *) */ self); +void nm_dbus_object_unexport (gpointer /* (NMDBusObject *) */ self); -void nm_dbus_object_unexport_on_idle (NMDBusObject *self_take); +void nm_dbus_object_unexport_on_idle (gpointer /* (NMDBusObject *) */ self_take); void _nm_dbus_object_clear_and_unexport (NMDBusObject **location); #define nm_dbus_object_clear_and_unexport(location) _nm_dbus_object_clear_and_unexport ((NMDBusObject **) (location)) diff --git a/src/nm-l3-config-data.c b/src/nm-l3-config-data.c index 7d1cb3a1a8..d547b5bd60 100644 --- a/src/nm-l3-config-data.c +++ b/src/nm-l3-config-data.c @@ -116,6 +116,11 @@ struct _NML3ConfigData { NMTernary metered:3; bool is_sealed:1; + + bool has_routes_with_type_local_4_set:1; + bool has_routes_with_type_local_6_set:1; + bool has_routes_with_type_local_4_val:1; + bool has_routes_with_type_local_6_val:1; }; /*****************************************************************************/ @@ -614,6 +619,50 @@ nmtst_l3_config_data_get_obj_at (const NML3ConfigData *self, /*****************************************************************************/ +gboolean +nm_l3_config_data_has_routes_with_type_local (const NML3ConfigData *self, int addr_family) +{ + const gboolean IS_IPv4 = NM_IS_IPv4 (addr_family); + NML3ConfigData *self_mutable; + NMDedupMultiIter iter; + const NMPObject *obj; + gboolean val; + + nm_assert (_NM_IS_L3_CONFIG_DATA (self, TRUE)); + nm_assert_addr_family (addr_family); + + if (IS_IPv4) { + if (G_LIKELY (self->has_routes_with_type_local_4_set)) + return self->has_routes_with_type_local_4_val; + } else { + if (G_LIKELY (self->has_routes_with_type_local_6_set)) + return self->has_routes_with_type_local_6_val; + } + + val = FALSE; + nm_l3_config_data_iter_obj_for_each (&iter, self, &obj, NMP_OBJECT_TYPE_IP_ROUTE (IS_IPv4)) { + if (NMP_OBJECT_CAST_IP_ROUTE (obj)->type_coerced == nm_platform_route_type_coerce (RTN_LOCAL)) { + val = TRUE; + break; + } + } + + /* the value gets accumulated and cached. Doing that is also permissible to a + * const/sealed instance. Hence, we cast the const-ness away. */ + self_mutable = (NML3ConfigData *) self; + if (IS_IPv4) { + self_mutable->has_routes_with_type_local_4_set = TRUE; + self_mutable->has_routes_with_type_local_4_val = val; + } else { + self_mutable->has_routes_with_type_local_6_set = TRUE; + self_mutable->has_routes_with_type_local_6_val = val; + } + + return val; +} + +/*****************************************************************************/ + NMDedupMultiIndex * nm_l3_config_data_get_multi_idx (const NML3ConfigData *self) { @@ -655,6 +704,26 @@ nm_l3_config_data_set_flags_full (NML3ConfigData *self, /*****************************************************************************/ +const NMPObject * +nm_l3_config_data_get_first_obj (const NML3ConfigData *self, + NMPObjectType obj_type, + gboolean (*predicate) (const NMPObject *obj)) +{ + NMDedupMultiIter iter; + const NMPObject *obj; + + nm_assert (_NM_IS_L3_CONFIG_DATA (self, TRUE)); + + nm_l3_config_data_iter_obj_for_each (&iter, self, &obj, obj_type) { + if ( !predicate + || predicate (obj)) + return obj; + } + return NULL; +} + +/*****************************************************************************/ + static gboolean _l3_config_data_add_obj (NMDedupMultiIndex *multi_idx, DedupMultiIdxType *idx_type, @@ -900,6 +969,10 @@ nm_l3_config_data_add_route_full (NML3ConfigData *self, || ( NMP_OBJECT_GET_ADDR_FAMILY (obj_new) == addr_family && _route_valid (addr_family, NMP_OBJECT_CAST_IP_ROUTE (obj_new)))); + if (IS_IPv4) + self->has_routes_with_type_local_4_set = FALSE; + else + self->has_routes_with_type_local_6_set = FALSE; if (_l3_config_data_add_obj (self->multi_idx, addr_family == AF_INET ? &self->idx_routes_4 @@ -997,6 +1070,19 @@ nm_l3_config_data_add_nameserver (NML3ConfigData *self, nameserver); } +gboolean +nm_l3_config_data_clear_nameserver (NML3ConfigData *self, + int addr_family) +{ + gs_unref_array GArray *old = NULL; + + nm_assert (_NM_IS_L3_CONFIG_DATA (self, FALSE)); + nm_assert_addr_family (addr_family); + + old = g_steal_pointer (&self->nameservers_x[NM_IS_IPv4 (addr_family)]); + return (nm_g_array_len (old) > 0); +} + const in_addr_t * nm_l3_config_data_get_wins (const NML3ConfigData *self, guint *out_len) @@ -1037,6 +1123,18 @@ nm_l3_config_data_set_nis_domain (NML3ConfigData *self, return nm_utils_strdup_reset (&self->nis_domain, nis_domain); } +const char *const* +nm_l3_config_data_get_domains (const NML3ConfigData *self, + int addr_family, + guint *out_len) +{ + nm_assert (_NM_IS_L3_CONFIG_DATA (self, FALSE)); + nm_assert_addr_family (addr_family); + nm_assert (out_len); + + return nm_strv_ptrarray_get_unsafe (self->domains_x[NM_IS_IPv4 (addr_family)], out_len); +} + gboolean nm_l3_config_data_add_domain (NML3ConfigData *self, int addr_family, @@ -1368,16 +1466,101 @@ _data_get_direct_route_for_host (const NML3ConfigData *self, /*****************************************************************************/ +/* Kernel likes to add device routes for all addresses. Normally, we want to suppress that + * with IFA_F_NOPREFIXROUTE. But we also want to support kernels that don't support that + * flag. So, we collect here all those routes that kernel might add but we don't want. + * If the route shows up within a certain timeout of us configuring the address, we assume + * that it was (undesirably) added by kernel and we remove it. + * + * The most common reason is that for each IPv4 address we want to add a corresponding device + * route with the right ipv4.route-metric. The route that kernel adds has metric 0, so it is + * undesired. + * + * FIXME(l3cfg): implement handling blacklisted routes. + * + * For IPv6, IFA_F_NOPREFIXROUTE is supported for a longer time and we don't do such a hack. + */ +GPtrArray * +nm_l3_config_data_get_blacklisted_ip4_routes (const NML3ConfigData *self, + gboolean is_vrf) +{ + gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL; + const NMPObject *my_addr_obj; + NMDedupMultiIter iter; + + nm_assert (_NM_IS_L3_CONFIG_DATA (self, FALSE)); + + /* For IPv6 slaac, we explicitly add the device-routes (onlink). + * As we don't do that for IPv4 and manual IPv6 addresses. Add them here + * as dependent routes. */ + + nm_l3_config_data_iter_obj_for_each (&iter, self, &my_addr_obj, NMP_OBJECT_TYPE_IP4_ADDRESS) { + const NMPlatformIP4Address *const my_addr = NMP_OBJECT_CAST_IP4_ADDRESS (my_addr_obj); + in_addr_t network_4; + NMPlatformIPXRoute rx; + + if (my_addr->external) + continue; + + nm_assert (my_addr->plen <= 32); + if (my_addr->plen == 0) + continue; + + network_4 = nm_utils_ip4_address_clear_host_address (my_addr->peer_address, + my_addr->plen); + + if (nm_utils_ip4_address_is_zeronet (network_4)) { + /* Kernel doesn't add device-routes for destinations that + * start with 0.x.y.z. Skip them. */ + continue; + } + + if ( my_addr->plen == 32 + && my_addr->address == my_addr->peer_address) { + /* Kernel doesn't add device-routes for /32 addresses unless + * they have a peer. */ + continue; + } + + rx.r4 = (NMPlatformIP4Route) { + .ifindex = self->ifindex, + .rt_source = NM_IP_CONFIG_SOURCE_KERNEL, + .network = network_4, + .plen = my_addr->plen, + .pref_src = my_addr->address, + .table_coerced = nm_platform_route_table_coerce (RT_TABLE_MAIN), + .metric = NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE, + .scope_inv = nm_platform_route_scope_inv (NM_RT_SCOPE_LINK), + }; + nm_platform_ip_route_normalize (AF_INET, &rx.rx); + + if (nm_l3_config_data_lookup_route (self, + AF_INET, + &rx.rx)) { + /* we track such a route explicitly. Don't blacklist it. */ + continue; + } + + if (!ip4_dev_route_blacklist) + ip4_dev_route_blacklist = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref); + + g_ptr_array_add (ip4_dev_route_blacklist, + nmp_object_new (NMP_OBJECT_TYPE_IP4_ROUTE, &rx)); + } + + return g_steal_pointer (&ip4_dev_route_blacklist); +} + +/*****************************************************************************/ + void nm_l3_config_data_add_dependent_routes (NML3ConfigData *self, int addr_family, guint32 route_table, guint32 route_metric, - gboolean is_vrf, - GPtrArray **out_ip4_dev_route_blacklist) + gboolean is_vrf) { const gboolean IS_IPv4 = NM_IS_IPv4 (addr_family); - gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL; gs_unref_ptrarray GPtrArray *extra_onlink_routes = NULL; const NMPObject *my_addr_obj; const NMPObject *my_route_obj; @@ -1478,28 +1661,6 @@ nm_l3_config_data_add_dependent_routes (NML3ConfigData *self, }; nm_platform_ip_route_normalize (addr_family, &rx.rx); nm_l3_config_data_add_route (self, addr_family, NULL, &rx.rx); - - if ( IS_IPv4 - && out_ip4_dev_route_blacklist - && ( route_table != RT_TABLE_MAIN - || route_metric != NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE)) { - - rx.r4.table_coerced = nm_platform_route_table_coerce (RT_TABLE_MAIN); - rx.r4.metric = NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE; - nm_platform_ip_route_normalize (addr_family, &rx.rx); - - if (nm_l3_config_data_lookup_route (self, - addr_family, - &rx.rx)) { - /* we track such a route explicitly. Don't blacklist it. */ - } else { - if (!ip4_dev_route_blacklist) - ip4_dev_route_blacklist = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref); - - g_ptr_array_add (ip4_dev_route_blacklist, - nmp_object_new (NMP_OBJECT_TYPE_IP4_ROUTE, &rx)); - } - } } else { const gboolean has_peer = !IN6_IS_ADDR_UNSPECIFIED (&my_addr->a6.peer_address); int routes_i; @@ -1590,8 +1751,6 @@ nm_l3_config_data_add_dependent_routes (NML3ConfigData *self, NULL); } } - - NM_SET_OUT (out_ip4_dev_route_blacklist, g_steal_pointer (&ip4_dev_route_blacklist)); } /*****************************************************************************/ @@ -1839,6 +1998,10 @@ _init_from_platform (NML3ConfigData *self, : NMP_OBJECT_TYPE_IP6_ADDRESS, self->ifindex); if (head_entry) { + if (IS_IPv4) + self->has_routes_with_type_local_4_set = FALSE; + else + self->has_routes_with_type_local_6_set = FALSE; nmp_cache_iter_for_each (&iter, head_entry, &plobj) { if (!_l3_config_data_add_obj (self->multi_idx, &self->idx_addresses_x[IS_IPv4], @@ -1922,25 +2085,6 @@ nm_l3_config_data_merge (NML3ConfigData *self, && !hook_add_addr (src, obj, hook_user_data)) continue; - if ( NM_FLAGS_HAS (merge_flags, NM_L3_CONFIG_MERGE_FLAGS_EXTERNAL) - && !NMP_OBJECT_CAST_IP_ADDRESS (obj)->external) { - NMPlatformIPXAddress a; - - if (IS_IPv4) - a.a4 = *NMP_OBJECT_CAST_IP4_ADDRESS (obj); - else - a.a6 = *NMP_OBJECT_CAST_IP6_ADDRESS (obj); - a.ax.ifindex = self->ifindex; - a.ax.external = TRUE; - nm_l3_config_data_add_address_full (self, - addr_family, - NULL, - &a.ax, - NM_L3_CONFIG_ADD_FLAGS_EXCLUSIVE, - NULL); - continue; - } - nm_l3_config_data_add_address_full (self, addr_family, obj, diff --git a/src/nm-l3-config-data.h b/src/nm-l3-config-data.h index d6e275724e..429325626c 100644 --- a/src/nm-l3-config-data.h +++ b/src/nm-l3-config-data.h @@ -51,18 +51,18 @@ typedef enum { * Note that if the respective NML3ConfigData has NM_L3_CONFIG_DAT_FLAGS_IGNORE_MERGE_NO_DEFAULT_ROUTES * set, this flag gets ignored during merge. * @NM_L3_CONFIG_MERGE_FLAGS_NO_DNS: don't merge DNS information - * @NM_L3_CONFIG_MERGE_FLAGS_EXTERNAL: mark new addresses as external */ -typedef enum { +typedef enum _nm_packed { NM_L3_CONFIG_MERGE_FLAGS_NONE = 0, NM_L3_CONFIG_MERGE_FLAGS_NO_ROUTES = (1LL << 0), NM_L3_CONFIG_MERGE_FLAGS_NO_DEFAULT_ROUTES = (1LL << 1), NM_L3_CONFIG_MERGE_FLAGS_NO_DNS = (1LL << 2), - NM_L3_CONFIG_MERGE_FLAGS_EXTERNAL = (1LL << 3), } NML3ConfigMergeFlags; /*****************************************************************************/ +static inline gboolean NM_IS_L3_CONFIG_DATA (const NML3ConfigData *self); + NML3ConfigData *nm_l3_config_data_new (NMDedupMultiIndex *multi_idx, int ifindex); const NML3ConfigData *nm_l3_config_data_ref (const NML3ConfigData *self); @@ -70,12 +70,49 @@ const NML3ConfigData *nm_l3_config_data_ref_and_seal (const NML3ConfigData *self const NML3ConfigData *nm_l3_config_data_seal (const NML3ConfigData *self); void nm_l3_config_data_unref (const NML3ConfigData *self); +#define nm_clear_l3cd(ptr) nm_clear_pointer ((ptr), nm_l3_config_data_unref) + NM_AUTO_DEFINE_FCN0 (const NML3ConfigData *, _nm_auto_unref_l3cd, nm_l3_config_data_unref); #define nm_auto_unref_l3cd nm_auto (_nm_auto_unref_l3cd) NM_AUTO_DEFINE_FCN0 (NML3ConfigData *, _nm_auto_unref_l3cd_init, nm_l3_config_data_unref); #define nm_auto_unref_l3cd_init nm_auto (_nm_auto_unref_l3cd_init) +static inline gboolean +nm_l3_config_data_reset (const NML3ConfigData **dst, const NML3ConfigData *src) +{ + nm_auto_unref_l3cd const NML3ConfigData *old = NULL; + + nm_assert (dst); + nm_assert (!*dst || NM_IS_L3_CONFIG_DATA (*dst)); + nm_assert (!src || NM_IS_L3_CONFIG_DATA (src)); + + if (*dst == src) + return FALSE; + old = *dst; + *dst = src ? nm_l3_config_data_ref_and_seal (src) : NULL; + return TRUE; +} + +static inline gboolean +nm_l3_config_data_reset_take (const NML3ConfigData **dst, const NML3ConfigData *src) +{ + nm_auto_unref_l3cd const NML3ConfigData *old = NULL; + + nm_assert (dst); + nm_assert (!*dst || NM_IS_L3_CONFIG_DATA (*dst)); + nm_assert (!src || NM_IS_L3_CONFIG_DATA (src)); + + if (*dst == src) { + if (src) + nm_l3_config_data_unref (src); + return FALSE; + } + old = *dst; + *dst = src ? nm_l3_config_data_seal (src) : NULL; + return TRUE; +} + gboolean nm_l3_config_data_is_sealed (const NML3ConfigData *self); NML3ConfigData *nm_l3_config_data_new_clone (const NML3ConfigData *src, @@ -105,23 +142,23 @@ void nm_l3_config_data_merge (NML3ConfigData *self, NML3ConfigMergeHookAddObj hook_add_addr, gpointer hook_user_data); +GPtrArray *nm_l3_config_data_get_blacklisted_ip4_routes (const NML3ConfigData *self, + gboolean is_vrf); + void nm_l3_config_data_add_dependent_routes (NML3ConfigData *self, int addr_family, guint32 route_table, guint32 route_metric, - gboolean is_vrf, - GPtrArray **out_ip4_dev_route_blacklist); + gboolean is_vrf); /*****************************************************************************/ int nm_l3_config_data_get_ifindex (const NML3ConfigData *self); -NMDedupMultiIndex *nm_l3_config_data_get_multi_idx (const NML3ConfigData *self); - static inline gboolean NM_IS_L3_CONFIG_DATA (const NML3ConfigData *self) { - /* NML3ConfigData is not an NMObject, so we cannot ask which type it has. + /* NML3ConfigData is not an NMObject/GObject, so we cannot ask which type it has. * This check here is really only useful for assertions, and there it is * enough to check whether the pointer is not NULL. * @@ -131,6 +168,8 @@ NM_IS_L3_CONFIG_DATA (const NML3ConfigData *self) return !!self; } +NMDedupMultiIndex *nm_l3_config_data_get_multi_idx (const NML3ConfigData *self); + /*****************************************************************************/ int nm_l3_config_data_cmp (const NML3ConfigData *a, const NML3ConfigData *b); @@ -232,6 +271,9 @@ nm_l3_config_data_get_num_routes (const NML3ConfigData *self, int addr_family) : NMP_OBJECT_TYPE_IP6_ROUTE); } +gboolean nm_l3_config_data_has_routes_with_type_local (const NML3ConfigData *self, + int addr_family); + const NMPObject *nmtst_l3_config_data_get_obj_at (const NML3ConfigData *self, NMPObjectType obj_type, guint i); @@ -299,6 +341,10 @@ nm_l3_config_data_unset_flags (NML3ConfigData *self, gboolean nm_l3_config_data_set_source (NML3ConfigData *self, NMIPConfigSource source); +const NMPObject *nm_l3_config_data_get_first_obj (const NML3ConfigData *self, + NMPObjectType obj_type, + gboolean (*predicate) (const NMPObject *obj)); + gboolean nm_l3_config_data_add_address_full (NML3ConfigData *self, int addr_family, const NMPObject *obj_new, @@ -407,9 +453,16 @@ gboolean nm_l3_config_data_add_nameserver (NML3ConfigData *self, int addr_family, gconstpointer /* (const NMIPAddr *) */ nameserver); +gboolean nm_l3_config_data_clear_nameserver (NML3ConfigData *self, + int addr_family); + gboolean nm_l3_config_data_add_nis_server (NML3ConfigData *self, in_addr_t nis_server); +const char *const*nm_l3_config_data_get_domains (const NML3ConfigData *self, + int addr_family, + guint *out_len); + gboolean nm_l3_config_data_set_nis_domain (NML3ConfigData *self, const char *nis_domain); diff --git a/src/nm-l3cfg.c b/src/nm-l3cfg.c index 01a7f00e51..2086cd00e7 100644 --- a/src/nm-l3cfg.c +++ b/src/nm-l3cfg.c @@ -95,6 +95,11 @@ typedef struct { bool announcing_failed_is_retrying:1; } AcdData; +struct _NML3CfgCommitTypeHandle { + CList commit_type_lst; + NML3CfgCommitType commit_type; +}; + typedef struct { const NML3ConfigData *l3cd; NML3ConfigMergeFlags merge_flags; @@ -131,6 +136,8 @@ typedef struct _NML3CfgPrivate { GArray *l3_config_datas; const NML3ConfigData *combined_l3cd; + CList commit_type_lst_head; + GHashTable *routes_temporary_not_available_hash; GHashTable *externally_removed_objs_hash; @@ -231,6 +238,8 @@ static AcdData *_l3_acd_data_find (NML3Cfg *self, static NM_UTILS_ENUM2STR_DEFINE (_l3_cfg_commit_type_to_string, NML3CfgCommitType, + NM_UTILS_ENUM2STR (NM_L3_CFG_COMMIT_TYPE_AUTO, "auto"), + NM_UTILS_ENUM2STR (NM_L3_CFG_COMMIT_TYPE_NONE, "none"), NM_UTILS_ENUM2STR (NM_L3_CFG_COMMIT_TYPE_ASSUME, "assume"), NM_UTILS_ENUM2STR (NM_L3_CFG_COMMIT_TYPE_UPDATE, "update"), NM_UTILS_ENUM2STR (NM_L3_CFG_COMMIT_TYPE_REAPPLY, "reapply"), @@ -878,7 +887,7 @@ _l3_acd_platform_commit_acd_update (NML3Cfg *self) _LOGT ("acd: acd update now"); self->priv.changed_configs = TRUE; nm_l3cfg_platform_commit (self, - NM_L3_CFG_COMMIT_TYPE_UPDATE, + NM_L3_CFG_COMMIT_TYPE_AUTO, AF_INET, NULL); } @@ -2297,7 +2306,7 @@ nm_l3cfg_mark_config_dirty (NML3Cfg *self, } } -void +gboolean nm_l3cfg_add_config (NML3Cfg *self, gconstpointer tag, gboolean replace_same_tag, @@ -2391,15 +2400,18 @@ nm_l3cfg_add_config (NML3Cfg *self, if (changed) self->priv.changed_configs = TRUE; + + return changed; } -static void +static gboolean _l3cfg_remove_config (NML3Cfg *self, gconstpointer tag, gboolean only_dirty, const NML3ConfigData *l3cd) { GArray *l3_config_datas; + gboolean changed; gssize idx; nm_assert (NM_IS_L3CFG (self)); @@ -2407,16 +2419,17 @@ _l3cfg_remove_config (NML3Cfg *self, l3_config_datas = self->priv.p->l3_config_datas; if (!l3_config_datas) - return; + return FALSE; idx = 0; + changed = FALSE; while (TRUE) { idx = _l3_config_datas_find_next (l3_config_datas, idx, tag, l3cd); if (idx < 0) - return; + return changed; if ( only_dirty && !_l3_config_datas_at (l3_config_datas, idx)->dirty) { @@ -2426,27 +2439,30 @@ _l3cfg_remove_config (NML3Cfg *self, self->priv.changed_configs = TRUE; _l3_config_datas_remove_index_fast (l3_config_datas, idx); - if (!l3cd) - return; + if (l3cd) { + /* only one was requested to be removed. We are done. */ + return TRUE; + } + changed = TRUE; } } -void +gboolean nm_l3cfg_remove_config (NML3Cfg *self, gconstpointer tag, const NML3ConfigData *ifcfg) { nm_assert (ifcfg); - _l3cfg_remove_config (self, tag, FALSE, ifcfg); + return _l3cfg_remove_config (self, tag, FALSE, ifcfg); } -void +gboolean nm_l3cfg_remove_config_all (NML3Cfg *self, gconstpointer tag, gboolean only_dirty) { - _l3cfg_remove_config (self, tag, only_dirty, NULL); + return _l3cfg_remove_config (self, tag, only_dirty, NULL); } /*****************************************************************************/ @@ -2749,7 +2765,8 @@ _platform_commit (NML3Cfg *self, gboolean success = TRUE; nm_assert (NM_IS_L3CFG (self)); - nm_assert (NM_IN_SET (commit_type, NM_L3_CFG_COMMIT_TYPE_REAPPLY, + nm_assert (NM_IN_SET (commit_type, NM_L3_CFG_COMMIT_TYPE_NONE, + NM_L3_CFG_COMMIT_TYPE_REAPPLY, NM_L3_CFG_COMMIT_TYPE_UPDATE, NM_L3_CFG_COMMIT_TYPE_ASSUME)); nm_assert_addr_family (addr_family); @@ -2866,7 +2883,9 @@ nm_l3cfg_platform_commit (NML3Cfg *self, gboolean acd_was_pending; g_return_val_if_fail (NM_IS_L3CFG (self), FALSE); - nm_assert (NM_IN_SET (commit_type, NM_L3_CFG_COMMIT_TYPE_REAPPLY, + nm_assert (NM_IN_SET (commit_type, NM_L3_CFG_COMMIT_TYPE_AUTO, + NM_L3_CFG_COMMIT_TYPE_NONE, + NM_L3_CFG_COMMIT_TYPE_REAPPLY, NM_L3_CFG_COMMIT_TYPE_UPDATE, NM_L3_CFG_COMMIT_TYPE_ASSUME)); @@ -2877,6 +2896,9 @@ nm_l3cfg_platform_commit (NML3Cfg *self, if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET)) nm_clear_g_source_inst (&self->priv.p->acd_ready_on_idle_source); + if (commit_type == NM_L3_CFG_COMMIT_TYPE_AUTO) + commit_type = nm_l3cfg_commit_type_get (self); + if (commit_type == NM_L3_CFG_COMMIT_TYPE_REAPPLY) _l3cfg_externally_removed_objs_drop (self, addr_family); @@ -2901,6 +2923,101 @@ nm_l3cfg_platform_commit (NML3Cfg *self, /*****************************************************************************/ +NML3CfgCommitType +nm_l3cfg_commit_type_get (NML3Cfg *self) +{ + NML3CfgCommitTypeHandle *handle; + + nm_assert (NM_IS_L3CFG (self)); + + handle = c_list_first_entry (&self->priv.p->commit_type_lst_head, NML3CfgCommitTypeHandle, commit_type_lst); + return handle + ? handle->commit_type + : NM_L3_CFG_COMMIT_TYPE_NONE; +} + +/** + * nm_l3cfg_commit_type_register: + * @self: the #NML3Cfg + * @commit_type: the commit type to register + * @existing_handle: instead of being a new registration, update an existing handle. + * This may be %NULL, which is like having no previous registration. + * + * NML3Cfg needs to know whether it is in charge of an interface (and how "much"). + * By default, it is not in charge, but various users can register themself with + * a certain @commit_type. The "higher" commit type is the used one when calling + * nm_l3cfg_platform_commit() with %NM_L3_CFG_COMMIT_TYPE_AUTO. + * + * Returns: a handle tracking the registration, or %NULL of @commit_type + * is %NM_L3_CFG_COMMIT_TYPE_NONE. + */ +NML3CfgCommitTypeHandle * +nm_l3cfg_commit_type_register (NML3Cfg *self, + NML3CfgCommitType commit_type, + NML3CfgCommitTypeHandle *existing_handle) +{ + NML3CfgCommitTypeHandle *handle; + NML3CfgCommitTypeHandle *h; + gboolean linked; + + nm_assert (NM_IS_L3CFG (self)); + nm_assert (NM_IN_SET (commit_type, NM_L3_CFG_COMMIT_TYPE_NONE, + NM_L3_CFG_COMMIT_TYPE_ASSUME, + NM_L3_CFG_COMMIT_TYPE_UPDATE, + NM_L3_CFG_COMMIT_TYPE_REAPPLY)); + nm_assert ( !existing_handle + || c_list_contains (&self->priv.p->commit_type_lst_head, &existing_handle->commit_type_lst)); + + if (existing_handle) { + if (commit_type == NM_L3_CFG_COMMIT_TYPE_NONE) { + nm_l3cfg_commit_type_unregister (self, existing_handle); + return NULL; + } + if (existing_handle->commit_type == commit_type) + return existing_handle; + c_list_unlink_stale (&existing_handle->commit_type_lst); + handle = existing_handle; + } else { + if (commit_type == NM_L3_CFG_COMMIT_TYPE_NONE) + return NULL; + handle = g_slice_new (NML3CfgCommitTypeHandle); + handle->commit_type = commit_type; + if (c_list_is_empty (&self->priv.p->commit_type_lst_head)) + g_object_ref (self); + } + + linked = FALSE; + c_list_for_each_entry (h, &self->priv.p->commit_type_lst_head, commit_type_lst) { + if (handle->commit_type >= h->commit_type) { + c_list_link_before (&self->priv.p->commit_type_lst_head, &handle->commit_type_lst); + linked = TRUE; + } + } + if (!linked) + c_list_link_tail (&self->priv.p->commit_type_lst_head, &handle->commit_type_lst); + + return handle; +} + +void +nm_l3cfg_commit_type_unregister (NML3Cfg *self, + NML3CfgCommitTypeHandle *handle) +{ + nm_assert (NM_IS_L3CFG (self)); + + if (!handle) + return; + + nm_assert (c_list_contains (&self->priv.p->commit_type_lst_head, &handle->commit_type_lst)); + + c_list_unlink_stale (&handle->commit_type_lst); + if (c_list_is_empty (&self->priv.p->commit_type_lst_head)) + g_object_unref (self); + nm_g_slice_free (handle); +} + +/*****************************************************************************/ + static void set_property (GObject *object, guint prop_id, @@ -2934,6 +3051,7 @@ nm_l3cfg_init (NML3Cfg *self) self->priv.p = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_L3CFG, NML3CfgPrivate); c_list_init (&self->priv.p->acd_lst_head); + c_list_init (&self->priv.p->commit_type_lst_head); } static void @@ -2972,6 +3090,8 @@ finalize (GObject *object) { NML3Cfg *self = NM_L3CFG (object); + nm_assert (c_list_is_empty (&self->priv.p->commit_type_lst_head)); + nm_clear_g_source_inst (&self->priv.p->acd_ready_on_idle_source); nm_assert (nm_g_array_len (self->priv.p->property_emit_list) == 0u); @@ -2994,7 +3114,7 @@ finalize (GObject *object) g_clear_object (&self->priv.netns); g_clear_object (&self->priv.platform); - nm_clear_pointer (&self->priv.p->combined_l3cd, nm_l3_config_data_unref); + nm_clear_l3cd (&self->priv.p->combined_l3cd); nm_clear_pointer (&self->priv.pllink, nmp_object_unref); diff --git a/src/nm-l3cfg.h b/src/nm-l3cfg.h index 335b59e614..4a3bab1111 100644 --- a/src/nm-l3cfg.h +++ b/src/nm-l3cfg.h @@ -128,27 +128,38 @@ void nm_l3cfg_mark_config_dirty (NML3Cfg *self, gconstpointer tag, gboolean dirty); -void nm_l3cfg_add_config (NML3Cfg *self, - gconstpointer tag, - gboolean replace_same_tag, - const NML3ConfigData *l3cd, - int priority, - guint32 default_route_penalty_4, - guint32 default_route_penalty_6, - guint32 acd_timeout_msec, - NML3ConfigMergeFlags merge_flags); - -void nm_l3cfg_remove_config (NML3Cfg *self, - gconstpointer tag, - const NML3ConfigData *ifcfg); - -void nm_l3cfg_remove_config_all (NML3Cfg *self, +gboolean nm_l3cfg_add_config (NML3Cfg *self, + gconstpointer tag, + gboolean replace_same_tag, + const NML3ConfigData *l3cd, + int priority, + guint32 default_route_penalty_4, + guint32 default_route_penalty_6, + guint32 acd_timeout_msec, + NML3ConfigMergeFlags merge_flags); + +gboolean nm_l3cfg_remove_config (NML3Cfg *self, gconstpointer tag, - gboolean only_dirty); + const NML3ConfigData *ifcfg); + +gboolean nm_l3cfg_remove_config_all (NML3Cfg *self, + gconstpointer tag, + gboolean only_dirty); /*****************************************************************************/ -typedef enum { +/* The numeric values of the enum matters: higher number mean more "important". + * E.g. "assume" tries to preserve the most settings, while "reapply" forces + * all configuration to match. */ +typedef enum _nm_packed { + + /* the NML3Cfg instance tracks with nm_l3cfg_commit_setup_register() the requested commit type. + * Use _NM_L3_CFG_COMMIT_TYPE_AUTO to automatically choose the level as requested. */ + NM_L3_CFG_COMMIT_TYPE_AUTO, + + /* Don't touch the interface. */ + NM_L3_CFG_COMMIT_TYPE_NONE, + /* ASSUME means to keep any pre-existing extra routes/addresses, while * also not adding routes/addresses that are not present yet. This is to * gracefully take over after restart, where the existing IP configuration @@ -172,4 +183,19 @@ gboolean nm_l3cfg_platform_commit (NML3Cfg *self, int addr_family, gboolean *out_final_failure_for_temporary_not_available); +/*****************************************************************************/ + +NML3CfgCommitType nm_l3cfg_commit_type_get (NML3Cfg *self); + +typedef struct _NML3CfgCommitTypeHandle NML3CfgCommitTypeHandle; + +NML3CfgCommitTypeHandle *nm_l3cfg_commit_type_register (NML3Cfg *self, + NML3CfgCommitType commit_type, + NML3CfgCommitTypeHandle *existing_handle); + +void nm_l3cfg_commit_type_unregister (NML3Cfg *self, + NML3CfgCommitTypeHandle *handle); + +/*****************************************************************************/ + #endif /* __NM_L3CFG_H__ */ diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index cece00dfe9..53bfcaf486 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -309,6 +309,8 @@ typedef enum { \ guint8 plen; \ \ + /* FIXME(l3cfg): the external marker won't be necessary anymore, because we only + * merge addresses we care about, and ignore (don't remove) external addresses. */ \ bool external:1; \ \ bool use_ip4_broadcast_address:1; \ @@ -1919,6 +1921,18 @@ gboolean nm_platform_ip_address_flush (NMPlatform *self, int addr_family, int ifindex); +static inline gconstpointer +nm_platform_ip_address_get_peer_address (int addr_family, + const NMPlatformIPAddress *addr) +{ + nm_assert_addr_family (addr_family); + nm_assert (addr); + + if (NM_IS_IPv4 (addr_family)) + return &((NMPlatformIP4Address *) addr)->peer_address; + return &((NMPlatformIP6Address *) addr)->peer_address; +} + void nm_platform_ip_route_normalize (int addr_family, NMPlatformIPRoute *route); diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index bbe2193225..4d9ec2a638 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -1066,6 +1066,12 @@ nmp_object_ip_route_is_best_defaut_route (const NMPObject *obj) && r->type_coerced == nm_platform_route_type_coerce (1 /* RTN_UNICAST */); } +static inline gboolean +nmp_object_ip6_address_is_not_link_local (const NMPObject *obj) +{ + return !IN6_IS_ADDR_LINKLOCAL (&NMP_OBJECT_CAST_IP6_ADDRESS (obj)->address); +} + /*****************************************************************************/ static inline gboolean |