summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2020-09-07 16:11:59 +0200
committerThomas Haller <thaller@redhat.com>2020-09-07 16:11:59 +0200
commit19c8332f05f4c0680f496282e3396aef7d2a91f0 (patch)
tree2eff1c8073173b13555cd32b886c4ca44f792f13
parent97c1bed37e46906f5450f53333e903c679f47ffe (diff)
parent4038a8ff993f9fb30611d76a6937c6ff3e730966 (diff)
downloadNetworkManager-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.h2
-rw-r--r--src/devices/nm-device.c359
-rw-r--r--src/nm-dbus-object.c59
-rw-r--r--src/nm-dbus-object.h6
-rw-r--r--src/nm-l3-config-data.c236
-rw-r--r--src/nm-l3-config-data.h69
-rw-r--r--src/nm-l3cfg.c148
-rw-r--r--src/nm-l3cfg.h60
-rw-r--r--src/platform/nm-platform.h14
-rw-r--r--src/platform/nmp-object.h6
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