l3cfg: merge branch 'th/l3cfg-7'

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/618
This commit is contained in:
Thomas Haller 2020-09-07 16:11:59 +02:00
commit 19c8332f05
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
10 changed files with 823 additions and 138 deletions

View file

@ -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,

View file

@ -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;
@ -285,24 +302,30 @@ typedef struct _NMDevicePrivate {
char * udi;
char * path;
union {
const char *const iface;
char * iface_;
};
union {
const char *const ip_iface;
char * ip_iface_;
};
union {
NML3Cfg *const l3cfg;
NML3Cfg *l3cfg_;
};
union {
NML3Cfg *const ip_l3cfg;
NML3Cfg *ip_l3cfg_;
};
union {
const char *const iface;
char * iface_;
};
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;

View file

@ -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);
g_return_if_fail (self_take->internal.path);
if (!self)
return;
g_return_if_fail (NM_IS_DBUS_OBJECT (self));
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));
}
/*****************************************************************************/

View file

@ -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))

View file

@ -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,

View file

@ -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);

View file

@ -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);

View file

@ -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);
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);
void nm_l3cfg_remove_config (NML3Cfg *self,
gconstpointer tag,
const NML3ConfigData *ifcfg);
void nm_l3cfg_remove_config_all (NML3Cfg *self,
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__ */

View file

@ -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);

View file

@ -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