mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-10-15 20:45:32 +00:00
l3cfg: merge branch 'th/l3cfg-7'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/618
This commit is contained in:
commit
19c8332f05
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
148
src/nm-l3cfg.c
148
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);
|
||||
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue