mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-05-05 18:08:05 +02:00
platform,core: merge branch 'th/platform-rt-prefsrc'
https://bugzilla.redhat.com/show_bug.cgi?id=2046293 https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1550
This commit is contained in:
commit
2dfeec9aea
21 changed files with 1472 additions and 628 deletions
|
|
@ -120,6 +120,7 @@ ForEachMacros: [
|
|||
'nm_manager_for_each_device',
|
||||
'nm_manager_for_each_device_safe',
|
||||
'nm_platform_iter_obj_for_each',
|
||||
'nm_prioq_for_each',
|
||||
'nmp_cache_iter_for_each',
|
||||
'nmp_cache_iter_for_each_link',
|
||||
'nmp_cache_iter_for_each_reverse',
|
||||
|
|
|
|||
|
|
@ -3522,7 +3522,7 @@ _dev_ip_state_check(NMDevice *self, int addr_family)
|
|||
&s_is_pending,
|
||||
&s_is_failed);
|
||||
|
||||
has_tna = priv->l3cfg && nm_l3cfg_has_temp_not_available_obj(priv->l3cfg, addr_family);
|
||||
has_tna = priv->l3cfg && nm_l3cfg_has_failedobj_pending(priv->l3cfg, addr_family);
|
||||
if (has_tna)
|
||||
s_is_pending = TRUE;
|
||||
|
||||
|
|
@ -3967,9 +3967,7 @@ after_merge_flags:
|
|||
}
|
||||
|
||||
static gboolean
|
||||
_dev_l3_register_l3cds_add_config(NMDevice *self,
|
||||
L3ConfigDataType l3cd_type,
|
||||
NML3CfgConfigFlags flags)
|
||||
_dev_l3_register_l3cds_add_config(NMDevice *self, L3ConfigDataType l3cd_type)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
|
||||
NML3ConfigMergeFlags merge_flags;
|
||||
|
|
@ -3992,7 +3990,7 @@ _dev_l3_register_l3cds_add_config(NMDevice *self,
|
|||
_prop_get_ipvx_dns_priority(self, AF_INET6),
|
||||
acd_defend_type,
|
||||
acd_timeout_msec,
|
||||
flags,
|
||||
NM_L3CFG_CONFIG_FLAGS_NONE,
|
||||
merge_flags);
|
||||
}
|
||||
|
||||
|
|
@ -4000,7 +3998,6 @@ static gboolean
|
|||
_dev_l3_register_l3cds_set_one_full(NMDevice *self,
|
||||
L3ConfigDataType l3cd_type,
|
||||
const NML3ConfigData *l3cd,
|
||||
NML3CfgConfigFlags flags,
|
||||
NMTernary commit_sync)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
|
||||
|
|
@ -4024,7 +4021,7 @@ _dev_l3_register_l3cds_set_one_full(NMDevice *self,
|
|||
|
||||
if (priv->l3cfg) {
|
||||
if (priv->l3cds[l3cd_type].d) {
|
||||
if (_dev_l3_register_l3cds_add_config(self, l3cd_type, flags))
|
||||
if (_dev_l3_register_l3cds_add_config(self, l3cd_type))
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -4048,11 +4045,7 @@ _dev_l3_register_l3cds_set_one(NMDevice *self,
|
|||
const NML3ConfigData *l3cd,
|
||||
NMTernary commit_sync)
|
||||
{
|
||||
return _dev_l3_register_l3cds_set_one_full(self,
|
||||
l3cd_type,
|
||||
l3cd,
|
||||
NM_L3CFG_CONFIG_FLAGS_NONE,
|
||||
commit_sync);
|
||||
return _dev_l3_register_l3cds_set_one_full(self, l3cd_type, l3cd, commit_sync);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -4107,7 +4100,7 @@ _dev_l3_register_l3cds(NMDevice *self,
|
|||
}
|
||||
if (is_external)
|
||||
continue;
|
||||
if (_dev_l3_register_l3cds_add_config(self, i, NM_L3CFG_CONFIG_FLAGS_NONE))
|
||||
if (_dev_l3_register_l3cds_add_config(self, i))
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -4261,6 +4254,7 @@ _dev_l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, N
|
|||
_dev_ipshared4_spawn_dnsmasq(self);
|
||||
nm_clear_l3cd(&priv->ipshared_data_4.v4.l3cd);
|
||||
}
|
||||
_dev_ip_state_check_async(self, AF_UNSPEC);
|
||||
_dev_ipmanual_check_ready(self);
|
||||
return;
|
||||
case NM_L3_CONFIG_NOTIFY_TYPE_IPV4LL_EVENT:
|
||||
|
|
@ -4270,10 +4264,6 @@ _dev_l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, N
|
|||
return;
|
||||
case NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE:
|
||||
return;
|
||||
case NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED:
|
||||
/* we commit again. This way we try to configure the routes.*/
|
||||
_dev_l3_cfg_commit(self, FALSE);
|
||||
return;
|
||||
case NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE:
|
||||
if (NM_FLAGS_ANY(notify_data->platform_change_on_idle.obj_type_flags,
|
||||
nmp_object_type_to_flags(NMP_OBJECT_TYPE_LINK)
|
||||
|
|
@ -4305,9 +4295,6 @@ _dev_l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, N
|
|||
* synchronously to update the current state and schedule a commit. */
|
||||
nm_ndisc_dad_failed(priv->ipac6_data.ndisc, conflicts, TRUE);
|
||||
} else if (ready) {
|
||||
if (nm_l3cfg_has_temp_not_available_obj(priv->l3cfg, AF_INET6))
|
||||
_dev_l3_cfg_commit(self, FALSE);
|
||||
|
||||
nm_clear_l3cd(&priv->ipac6_data.l3cd);
|
||||
_dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_READY);
|
||||
_dev_ip_state_check_async(self, AF_INET6);
|
||||
|
|
@ -10314,14 +10301,6 @@ _dev_ipmanual_check_ready(NMDevice *self)
|
|||
_dev_ipmanual_set_state(self, addr_family, NM_DEVICE_IP_STATE_FAILED);
|
||||
_dev_ip_state_check_async(self, AF_UNSPEC);
|
||||
} else if (ready) {
|
||||
if (priv->ipmanual_data.state_x[IS_IPv4] != NM_DEVICE_IP_STATE_READY
|
||||
&& nm_l3cfg_has_temp_not_available_obj(priv->l3cfg, addr_family)) {
|
||||
/* Addresses with pending ACD/DAD are a possible cause for the
|
||||
* presence of temporarily-not-available objects. Once all addresses
|
||||
* are ready, retry to commit those unavailable objects. */
|
||||
_dev_l3_cfg_commit(self, FALSE);
|
||||
}
|
||||
|
||||
_dev_ipmanual_set_state(self, addr_family, NM_DEVICE_IP_STATE_READY);
|
||||
_dev_ip_state_check_async(self, AF_UNSPEC);
|
||||
}
|
||||
|
|
@ -10487,7 +10466,6 @@ _dev_ipdhcpx_notify(NMDhcpClient *client, const NMDhcpClientNotifyData *notify_d
|
|||
_dev_l3_register_l3cds_set_one_full(self,
|
||||
L3_CONFIG_DATA_TYPE_DHCP_X(IS_IPv4),
|
||||
notify_data->lease_update.l3cd,
|
||||
NM_L3CFG_CONFIG_FLAGS_FORCE_ONCE,
|
||||
FALSE);
|
||||
|
||||
if (notify_data->lease_update.accepted) {
|
||||
|
|
@ -10708,7 +10686,6 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family)
|
|||
_dev_l3_register_l3cds_set_one_full(self,
|
||||
L3_CONFIG_DATA_TYPE_DHCP_X(IS_IPv4),
|
||||
previous_lease,
|
||||
NM_L3CFG_CONFIG_FLAGS_FORCE_ONCE,
|
||||
FALSE);
|
||||
}
|
||||
|
||||
|
|
@ -11641,11 +11618,7 @@ _dev_ipac6_ndisc_config_changed(NMNDisc *ndisc,
|
|||
|
||||
_dev_ipac6_grace_period_start(self, 0, TRUE);
|
||||
|
||||
_dev_l3_register_l3cds_set_one_full(self,
|
||||
L3_CONFIG_DATA_TYPE_AC_6,
|
||||
l3cd,
|
||||
NM_L3CFG_CONFIG_FLAGS_FORCE_ONCE,
|
||||
FALSE);
|
||||
_dev_l3_register_l3cds_set_one_full(self, L3_CONFIG_DATA_TYPE_AC_6, l3cd, FALSE);
|
||||
|
||||
nm_clear_l3cd(&priv->ipac6_data.l3cd);
|
||||
ready = nm_l3cfg_check_ready(priv->l3cfg,
|
||||
|
|
|
|||
|
|
@ -2604,7 +2604,6 @@ nm_l3_config_data_add_dependent_device_routes(NML3ConfigData *self,
|
|||
int addr_family,
|
||||
guint32 route_table,
|
||||
guint32 route_metric,
|
||||
gboolean force_commit,
|
||||
const NML3ConfigData *source)
|
||||
{
|
||||
const int IS_IPv4 = NM_IS_IPv4(addr_family);
|
||||
|
|
@ -2649,7 +2648,6 @@ nm_l3_config_data_add_dependent_device_routes(NML3ConfigData *self,
|
|||
self->ifindex,
|
||||
route_table,
|
||||
route_metric,
|
||||
force_commit,
|
||||
&r_stack.r4);
|
||||
if (r)
|
||||
nm_l3_config_data_add_route(self, addr_family, NULL, r);
|
||||
|
|
@ -2685,13 +2683,12 @@ nm_l3_config_data_add_dependent_device_routes(NML3ConfigData *self,
|
|||
}
|
||||
|
||||
rx.r6 = (NMPlatformIP6Route){
|
||||
.ifindex = self->ifindex,
|
||||
.rt_source = NM_IP_CONFIG_SOURCE_KERNEL,
|
||||
.table_coerced = nm_platform_route_table_coerce(route_table),
|
||||
.metric = route_metric,
|
||||
.network = *a6,
|
||||
.plen = plen,
|
||||
.r_force_commit = force_commit,
|
||||
.ifindex = self->ifindex,
|
||||
.rt_source = NM_IP_CONFIG_SOURCE_KERNEL,
|
||||
.table_coerced = nm_platform_route_table_coerce(route_table),
|
||||
.metric = route_metric,
|
||||
.network = *a6,
|
||||
.plen = plen,
|
||||
};
|
||||
|
||||
nm_platform_ip_route_normalize(addr_family, &rx.rx);
|
||||
|
|
@ -3197,7 +3194,6 @@ nm_l3_config_data_merge(NML3ConfigData *self,
|
|||
NMPlatformIPXAddress a;
|
||||
NML3ConfigMergeHookResult hook_result = {
|
||||
.ip4acd_not_ready = NM_OPTION_BOOL_DEFAULT,
|
||||
.force_commit = NM_OPTION_BOOL_DEFAULT,
|
||||
};
|
||||
|
||||
#define _ensure_a() \
|
||||
|
|
@ -3230,12 +3226,6 @@ nm_l3_config_data_merge(NML3ConfigData *self,
|
|||
a.a4.a_acd_not_ready = (!!hook_result.ip4acd_not_ready);
|
||||
}
|
||||
|
||||
if (hook_result.force_commit != NM_OPTION_BOOL_DEFAULT
|
||||
&& (!!hook_result.force_commit) != a_src->a_force_commit) {
|
||||
_ensure_a();
|
||||
a.ax.a_force_commit = (!!hook_result.force_commit);
|
||||
}
|
||||
|
||||
nm_l3_config_data_add_address_full(self,
|
||||
addr_family,
|
||||
a_src == &a.ax ? NULL : obj,
|
||||
|
|
@ -3255,7 +3245,6 @@ nm_l3_config_data_merge(NML3ConfigData *self,
|
|||
NMPlatformIPXRoute r;
|
||||
NML3ConfigMergeHookResult hook_result = {
|
||||
.ip4acd_not_ready = NM_OPTION_BOOL_DEFAULT,
|
||||
.force_commit = NM_OPTION_BOOL_DEFAULT,
|
||||
};
|
||||
|
||||
#define _ensure_r() \
|
||||
|
|
@ -3281,12 +3270,6 @@ nm_l3_config_data_merge(NML3ConfigData *self,
|
|||
r.rx.ifindex = self->ifindex;
|
||||
}
|
||||
|
||||
if (hook_result.force_commit != NM_OPTION_BOOL_DEFAULT
|
||||
&& (!!hook_result.force_commit) != r_src->r_force_commit) {
|
||||
_ensure_r();
|
||||
r.rx.r_force_commit = (!!hook_result.force_commit);
|
||||
}
|
||||
|
||||
if (!NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_CLONE)) {
|
||||
if (r_src->table_any) {
|
||||
_ensure_r();
|
||||
|
|
|
|||
|
|
@ -137,7 +137,6 @@ NML3ConfigData *nm_l3_config_data_new_from_platform(NMDedupMultiIndex *mu
|
|||
|
||||
typedef struct {
|
||||
NMOptionBool ip4acd_not_ready;
|
||||
NMOptionBool force_commit;
|
||||
} NML3ConfigMergeHookResult;
|
||||
|
||||
typedef gboolean (*NML3ConfigMergeHookAddObj)(const NML3ConfigData *l3cd,
|
||||
|
|
@ -164,7 +163,6 @@ void nm_l3_config_data_add_dependent_device_routes(NML3ConfigData *self,
|
|||
int addr_family,
|
||||
guint32 route_table,
|
||||
guint32 route_metric,
|
||||
gboolean force_commit,
|
||||
const NML3ConfigData *source);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -55,15 +55,11 @@ typedef enum _nm_packed {
|
|||
* "don't change" behavior. At least once. If the address/route
|
||||
* is still not (no longer) configured on the subsequent
|
||||
* commit, it's not getting added again.
|
||||
* @NM_L3CFG_CONFIG_FLAGS_FORCE_ONCE: if set, objects in the
|
||||
* NML3ConfigData are committed to platform even if they were
|
||||
* removed externally.
|
||||
*/
|
||||
typedef enum _nm_packed {
|
||||
NM_L3CFG_CONFIG_FLAGS_NONE = 0,
|
||||
NM_L3CFG_CONFIG_FLAGS_ONLY_FOR_ACD = (1LL << 0),
|
||||
NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE = (1LL << 1),
|
||||
NM_L3CFG_CONFIG_FLAGS_FORCE_ONCE = (1LL << 2),
|
||||
} NML3CfgConfigFlags;
|
||||
|
||||
typedef enum _nm_packed {
|
||||
|
|
@ -132,8 +128,6 @@ typedef enum {
|
|||
* and neither should you call into NML3Cfg again (reentrancy). */
|
||||
NM_L3_CONFIG_NOTIFY_TYPE_L3CD_CHANGED,
|
||||
|
||||
NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED,
|
||||
|
||||
NM_L3_CONFIG_NOTIFY_TYPE_ACD_EVENT,
|
||||
|
||||
/* emitted before the merged l3cd is committed to platform.
|
||||
|
|
@ -412,7 +406,7 @@ gboolean nm_l3cfg_check_ready(NML3Cfg *self,
|
|||
NML3CfgCheckReadyFlags flags,
|
||||
GArray **conflicts);
|
||||
|
||||
gboolean nm_l3cfg_has_temp_not_available_obj(NML3Cfg *self, int addr_family);
|
||||
gboolean nm_l3cfg_has_failedobj_pending(NML3Cfg *self, int addr_family);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,44 @@
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
gconstpointer tag;
|
||||
CList watcher_by_tag_lst_head;
|
||||
} WatcherByTag;
|
||||
|
||||
typedef struct {
|
||||
NMIPAddrTyped addr;
|
||||
CList watcher_ip_addr_lst_head;
|
||||
} WatcherDataIPAddr;
|
||||
|
||||
struct _NMNetnsWatcherHandle {
|
||||
NMNetnsWatcherType watcher_type;
|
||||
NMNetnsWatcherData watcher_data;
|
||||
gconstpointer tag;
|
||||
NMNetnsWatcherCallback callback;
|
||||
gpointer callback_user_data;
|
||||
|
||||
/* This is linked to "WatcherByTag.watcher_by_tag_lst_head" in
|
||||
* "priv->watcher_by_tag_idx". */
|
||||
CList watcher_tag_lst;
|
||||
|
||||
/* The registration data, which depends on the "watcher_type". */
|
||||
union {
|
||||
struct {
|
||||
CList watcher_ip_addr_lst;
|
||||
} ip_addr;
|
||||
} reg_data;
|
||||
|
||||
/* nm_netns_watcher_add() will mark the handle as non-dirty, while
|
||||
* nm_netns_watcher_remove_all() can delete only dirty handles (while
|
||||
* leaving non-dirty handles alive, but marking them as dirty).
|
||||
*
|
||||
* That allows a pattern where you just add the new handles that you want
|
||||
* now, and then call nm_netns_watcher_remove_all() to remove those that
|
||||
* should no longer be present. */
|
||||
bool watcher_dirty : 1;
|
||||
};
|
||||
|
||||
NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_PLATFORM, );
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -33,8 +71,20 @@ typedef struct {
|
|||
GHashTable *shared_ips;
|
||||
GHashTable *ecmp_track_by_obj;
|
||||
GHashTable *ecmp_track_by_ecmpid;
|
||||
CList l3cfg_signal_pending_lst_head;
|
||||
GSource *signal_pending_idle_source;
|
||||
|
||||
/* Indexes the watcher handles. */
|
||||
GHashTable *watcher_idx;
|
||||
|
||||
/* An index of WatcherByTag. It allows to lookup watcher handles by tag.
|
||||
* Handles without tag are not indexed. */
|
||||
GHashTable *watcher_by_tag_idx;
|
||||
|
||||
/* Index for WatcherDataIPAddr instances. Allows to lookup all subscribers
|
||||
* by IP address. */
|
||||
GHashTable *watcher_ip_data_idx;
|
||||
|
||||
CList l3cfg_signal_pending_lst_head;
|
||||
GSource *signal_pending_idle_source;
|
||||
} NMNetnsPrivate;
|
||||
|
||||
struct _NMNetns {
|
||||
|
|
@ -87,6 +137,24 @@ NM_DEFINE_SINGLETON_GETTER(NMNetns, nm_netns_get, NM_TYPE_NETNS);
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static WatcherDataIPAddr *
|
||||
_watcher_ip_data_lookup(NMNetns *self, int addr_family, gconstpointer addr);
|
||||
static void _watcher_handle_notify(NMNetns *self,
|
||||
NMNetnsWatcherHandle *handle,
|
||||
const NMNetnsWatcherEventData *event_data);
|
||||
static const char *
|
||||
_watcher_handle_to_string(const NMNetnsWatcherHandle *handle, char *buf, gsize buf_size);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static gboolean
|
||||
NM_NETNS_WATCHER_TYPE_VALID(NMNetnsWatcherType watcher_type)
|
||||
{
|
||||
return NM_IN_SET(watcher_type, NM_NETNS_WATCHER_TYPE_IP_ADDR);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
const NMPObject *representative_obj;
|
||||
const NMPObject *merged_obj;
|
||||
|
|
@ -437,7 +505,7 @@ _platform_signal_cb(NMPlatform *platform,
|
|||
|
||||
l3cfg = nm_netns_l3cfg_get(self, ifindex);
|
||||
if (!l3cfg)
|
||||
return;
|
||||
goto notify_watcher;
|
||||
|
||||
l3cfg->internal_netns.signal_pending_obj_type_flags |= nmp_object_type_to_flags(obj_type);
|
||||
|
||||
|
|
@ -450,6 +518,55 @@ _platform_signal_cb(NMPlatform *platform,
|
|||
}
|
||||
|
||||
_nm_l3cfg_notify_platform_change(l3cfg, change_type, NMP_OBJECT_UP_CAST(platform_object));
|
||||
|
||||
notify_watcher:
|
||||
switch (obj_type) {
|
||||
case NMP_OBJECT_TYPE_IP4_ADDRESS:
|
||||
case NMP_OBJECT_TYPE_IP6_ADDRESS:
|
||||
{
|
||||
NMNetnsWatcherHandle *handle;
|
||||
NMNetnsWatcherHandle *handle_safe;
|
||||
WatcherDataIPAddr *data;
|
||||
|
||||
data =
|
||||
_watcher_ip_data_lookup(self,
|
||||
obj_type == NMP_OBJECT_TYPE_IP4_ADDRESS ? AF_INET : AF_INET6,
|
||||
((const NMPlatformIPAddress *) platform_object)->address_ptr);
|
||||
|
||||
if (data) {
|
||||
const NMNetnsWatcherEventData event_data = {
|
||||
.ip_addr =
|
||||
{
|
||||
.change_type = change_type,
|
||||
.obj = NMP_OBJECT_UP_CAST(platform_object),
|
||||
},
|
||||
};
|
||||
char sbuf[500];
|
||||
|
||||
c_list_for_each_entry_safe (handle,
|
||||
handle_safe,
|
||||
&data->watcher_ip_addr_lst_head,
|
||||
reg_data.ip_addr.watcher_ip_addr_lst) {
|
||||
_LOGT("netns-watcher: %s %s",
|
||||
"notify",
|
||||
_watcher_handle_to_string(handle, sbuf, sizeof(sbuf)));
|
||||
|
||||
/* Note that we dispatch these events directly from the platform event
|
||||
* and while iterating over "data".
|
||||
*
|
||||
* From the callback, it's probably a bad idea to do anything in platform
|
||||
* that might change anything (emit new signals) or to nm_netns_watcher_remove*()
|
||||
* any other watcher.
|
||||
*
|
||||
* The callee needs to be careful. */
|
||||
_watcher_handle_notify(self, handle, &event_data);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -822,6 +939,460 @@ nm_netns_ip_route_ecmp_commit(NMNetns *self,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
_watcher_data_set(NMNetnsWatcherData *dst,
|
||||
NMNetnsWatcherType watcher_type,
|
||||
const NMNetnsWatcherData *src)
|
||||
{
|
||||
nm_assert(dst);
|
||||
nm_assert(src);
|
||||
|
||||
switch (watcher_type) {
|
||||
case NM_NETNS_WATCHER_TYPE_IP_ADDR:
|
||||
dst->ip_addr = src->ip_addr;
|
||||
return;
|
||||
}
|
||||
nm_assert_not_reached();
|
||||
}
|
||||
|
||||
static void
|
||||
_watcher_data_hash(NMHashState *h, NMNetnsWatcherType watcher_type, const NMNetnsWatcherData *data)
|
||||
{
|
||||
nm_assert(h);
|
||||
nm_assert(NM_NETNS_WATCHER_TYPE_VALID(watcher_type));
|
||||
nm_assert(data);
|
||||
|
||||
switch (watcher_type) {
|
||||
case NM_NETNS_WATCHER_TYPE_IP_ADDR:
|
||||
nm_ip_addr_typed_hash_update(h, &data->ip_addr.addr);
|
||||
return;
|
||||
}
|
||||
nm_assert_not_reached();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_watcher_data_equal(NMNetnsWatcherType watcher_type,
|
||||
const NMNetnsWatcherData *a,
|
||||
const NMNetnsWatcherData *b)
|
||||
{
|
||||
nm_assert(NM_NETNS_WATCHER_TYPE_VALID(watcher_type));
|
||||
nm_assert(a);
|
||||
nm_assert(b);
|
||||
|
||||
switch (watcher_type) {
|
||||
case NM_NETNS_WATCHER_TYPE_IP_ADDR:
|
||||
return nm_ip_addr_typed_equal(&a->ip_addr.addr, &b->ip_addr.addr);
|
||||
}
|
||||
return nm_assert_unreachable_val(FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
_watcher_by_tag_destroy(WatcherByTag *watcher_by_tag)
|
||||
{
|
||||
c_list_unlink_stale(&watcher_by_tag->watcher_by_tag_lst_head);
|
||||
nm_g_slice_free(watcher_by_tag);
|
||||
}
|
||||
|
||||
static void
|
||||
_watcher_handle_init(NMNetnsWatcherHandle *handle,
|
||||
NMNetnsWatcherType watcher_type,
|
||||
const NMNetnsWatcherData *watcher_data,
|
||||
gconstpointer tag)
|
||||
{
|
||||
nm_assert(handle);
|
||||
nm_assert(NM_NETNS_WATCHER_TYPE_VALID(watcher_type));
|
||||
|
||||
*handle = (NMNetnsWatcherHandle){
|
||||
.watcher_type = watcher_type,
|
||||
.tag = tag,
|
||||
.watcher_tag_lst = C_LIST_INIT(handle->watcher_tag_lst),
|
||||
};
|
||||
_watcher_data_set(&handle->watcher_data, watcher_type, watcher_data);
|
||||
}
|
||||
|
||||
static guint
|
||||
_watcher_handle_hash(gconstpointer data)
|
||||
{
|
||||
const NMNetnsWatcherHandle *watcher = data;
|
||||
NMHashState h;
|
||||
|
||||
nm_assert(watcher);
|
||||
nm_assert(watcher->tag);
|
||||
|
||||
nm_hash_init(&h, 2696278447u);
|
||||
nm_hash_update_vals(&h, watcher->tag, watcher->watcher_type);
|
||||
_watcher_data_hash(&h, watcher->watcher_type, &watcher->watcher_data);
|
||||
return nm_hash_complete(&h);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_watcher_handle_equal(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const NMNetnsWatcherHandle *ha = a;
|
||||
const NMNetnsWatcherHandle *hb = b;
|
||||
|
||||
nm_assert(ha);
|
||||
nm_assert(hb);
|
||||
nm_assert(ha->tag);
|
||||
nm_assert(hb->tag);
|
||||
|
||||
if (ha == hb)
|
||||
return TRUE;
|
||||
|
||||
return (ha->tag == hb->tag) && (ha->watcher_type == hb->watcher_type)
|
||||
&& _watcher_data_equal(ha->watcher_type, &ha->watcher_data, &hb->watcher_data);
|
||||
}
|
||||
|
||||
static const char *
|
||||
_watcher_handle_to_string(const NMNetnsWatcherHandle *handle, char *buf, gsize buf_size)
|
||||
{
|
||||
const char *buf0 = buf;
|
||||
char sbuf[NM_INET_ADDRSTRLEN];
|
||||
|
||||
nm_strbuf_append(&buf,
|
||||
&buf_size,
|
||||
"h:" NM_HASH_OBFUSCATE_PTR_FMT "[",
|
||||
NM_HASH_OBFUSCATE_PTR(handle));
|
||||
|
||||
if (handle->tag) {
|
||||
nm_strbuf_append(&buf,
|
||||
&buf_size,
|
||||
"tag:" NM_HASH_OBFUSCATE_PTR_FMT ",",
|
||||
NM_HASH_OBFUSCATE_PTR(handle->tag));
|
||||
}
|
||||
|
||||
switch (handle->watcher_type) {
|
||||
case NM_NETNS_WATCHER_TYPE_IP_ADDR:
|
||||
nm_strbuf_append_str(&buf, &buf_size, "ip-addr:");
|
||||
nm_strbuf_append_str(&buf,
|
||||
&buf_size,
|
||||
nm_inet_ntop(handle->watcher_data.ip_addr.addr.addr_family,
|
||||
&handle->watcher_data.ip_addr.addr.addr,
|
||||
sbuf));
|
||||
goto out;
|
||||
}
|
||||
nm_assert_not_reached();
|
||||
nm_strbuf_append_str(&buf, &buf_size, "unknown");
|
||||
|
||||
out:
|
||||
nm_strbuf_append_c(&buf, &buf_size, ']');
|
||||
return buf0;
|
||||
}
|
||||
|
||||
static void
|
||||
_watcher_handle_notify(NMNetns *self,
|
||||
NMNetnsWatcherHandle *handle,
|
||||
const NMNetnsWatcherEventData *event_data)
|
||||
{
|
||||
nm_assert(NM_IS_NETNS(self));
|
||||
nm_assert(handle);
|
||||
nm_assert(handle->callback);
|
||||
|
||||
handle->callback(self,
|
||||
handle->watcher_type,
|
||||
&handle->watcher_data,
|
||||
handle->tag,
|
||||
event_data,
|
||||
handle->callback_user_data);
|
||||
}
|
||||
|
||||
static WatcherDataIPAddr *
|
||||
_watcher_ip_data_lookup(NMNetns *self, int addr_family, gconstpointer addr)
|
||||
{
|
||||
WatcherDataIPAddr needle;
|
||||
|
||||
needle.addr.addr_family = addr_family;
|
||||
nm_ip_addr_set(addr_family, &needle.addr.addr, addr);
|
||||
return g_hash_table_lookup(NM_NETNS_GET_PRIVATE(self)->watcher_ip_data_idx, &needle);
|
||||
}
|
||||
|
||||
static WatcherDataIPAddr *
|
||||
_watcher_ip_data_lookup_addr(NMNetns *self, const NMIPAddrTyped *addr)
|
||||
{
|
||||
return _watcher_ip_data_lookup(self, addr->addr_family, &addr->addr);
|
||||
}
|
||||
|
||||
static guint
|
||||
_watcher_ip_data_hash(gconstpointer _data)
|
||||
{
|
||||
const WatcherDataIPAddr *data = _data;
|
||||
NMHashState h;
|
||||
|
||||
nm_assert(data);
|
||||
|
||||
nm_hash_init(&h, 3152126191u);
|
||||
nm_ip_addr_typed_hash_update(&h, &data->addr);
|
||||
return nm_hash_complete(&h);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_watcher_ip_data_equal(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const WatcherDataIPAddr *data_a = a;
|
||||
const WatcherDataIPAddr *data_b = b;
|
||||
|
||||
nm_assert(data_a);
|
||||
nm_assert(data_b);
|
||||
|
||||
return nm_ip_addr_typed_equal(&data_a->addr, &data_b->addr);
|
||||
}
|
||||
|
||||
static NMNetnsWatcherHandle *
|
||||
_watcher_lookup_handle(NMNetns *self,
|
||||
NMNetnsWatcherType watcher_type,
|
||||
const NMNetnsWatcherData *watcher_data,
|
||||
gconstpointer tag)
|
||||
{
|
||||
NMNetnsWatcherHandle handle_needle;
|
||||
|
||||
nm_assert(NM_IS_NETNS(self));
|
||||
nm_assert(tag);
|
||||
|
||||
_watcher_handle_init(&handle_needle, watcher_type, watcher_data, tag);
|
||||
return g_hash_table_lookup(NM_NETNS_GET_PRIVATE(self)->watcher_idx, &handle_needle);
|
||||
}
|
||||
|
||||
static void
|
||||
_watcher_register_handle(NMNetns *self, NMNetnsWatcherHandle *handle)
|
||||
{
|
||||
NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE(self);
|
||||
|
||||
switch (handle->watcher_type) {
|
||||
case NM_NETNS_WATCHER_TYPE_IP_ADDR:
|
||||
{
|
||||
WatcherDataIPAddr *data;
|
||||
|
||||
data = _watcher_ip_data_lookup_addr(self, &handle->watcher_data.ip_addr.addr);
|
||||
if (!data) {
|
||||
data = g_slice_new(WatcherDataIPAddr);
|
||||
*data = (WatcherDataIPAddr){
|
||||
.addr = handle->watcher_data.ip_addr.addr,
|
||||
.watcher_ip_addr_lst_head = C_LIST_INIT(data->watcher_ip_addr_lst_head),
|
||||
};
|
||||
if (!g_hash_table_add(priv->watcher_ip_data_idx, data))
|
||||
nm_assert_not_reached();
|
||||
}
|
||||
|
||||
c_list_link_tail(&data->watcher_ip_addr_lst_head,
|
||||
&handle->reg_data.ip_addr.watcher_ip_addr_lst);
|
||||
return;
|
||||
}
|
||||
}
|
||||
nm_assert_not_reached();
|
||||
}
|
||||
|
||||
static void
|
||||
_watcher_unregister_handle(NMNetns *self, NMNetnsWatcherHandle *handle)
|
||||
{
|
||||
NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE(self);
|
||||
|
||||
switch (handle->watcher_type) {
|
||||
case NM_NETNS_WATCHER_TYPE_IP_ADDR:
|
||||
{
|
||||
gboolean is_last;
|
||||
|
||||
nm_assert(({
|
||||
WatcherDataIPAddr *d;
|
||||
|
||||
d = _watcher_ip_data_lookup_addr(self, &handle->watcher_data.ip_addr.addr);
|
||||
d &&c_list_contains(&d->watcher_ip_addr_lst_head,
|
||||
&handle->reg_data.ip_addr.watcher_ip_addr_lst);
|
||||
}));
|
||||
|
||||
is_last = c_list_is_empty_or_single(&handle->reg_data.ip_addr.watcher_ip_addr_lst);
|
||||
|
||||
c_list_unlink(&handle->reg_data.ip_addr.watcher_ip_addr_lst);
|
||||
|
||||
if (is_last) {
|
||||
WatcherDataIPAddr *data;
|
||||
|
||||
data = _watcher_ip_data_lookup_addr(self, &handle->watcher_data.ip_addr.addr);
|
||||
nm_assert(data);
|
||||
nm_assert(c_list_is_empty(&data->watcher_ip_addr_lst_head));
|
||||
|
||||
if (!g_hash_table_remove(priv->watcher_ip_data_idx, data))
|
||||
nm_assert_not_reached();
|
||||
|
||||
nm_g_slice_free(data);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
nm_assert_not_reached();
|
||||
}
|
||||
|
||||
void
|
||||
nm_netns_watcher_add(NMNetns *self,
|
||||
NMNetnsWatcherType watcher_type,
|
||||
const NMNetnsWatcherData *watcher_data,
|
||||
gconstpointer tag,
|
||||
NMNetnsWatcherCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMNetnsPrivate *priv;
|
||||
NMNetnsWatcherHandle *handle;
|
||||
gboolean is_new = FALSE;
|
||||
char sbuf[500];
|
||||
|
||||
g_return_if_fail(NM_IS_NETNS(self));
|
||||
g_return_if_fail(NM_NETNS_WATCHER_TYPE_VALID(watcher_type));
|
||||
g_return_if_fail(callback);
|
||||
g_return_if_fail(tag);
|
||||
|
||||
priv = NM_NETNS_GET_PRIVATE(self);
|
||||
|
||||
handle = _watcher_lookup_handle(self, watcher_type, watcher_data, tag);
|
||||
|
||||
if (!handle) {
|
||||
WatcherByTag *watcher_by_tag;
|
||||
|
||||
if (G_UNLIKELY(g_hash_table_size(priv->watcher_idx) == 0))
|
||||
g_object_ref(self);
|
||||
|
||||
handle = g_slice_new(NMNetnsWatcherHandle);
|
||||
_watcher_handle_init(handle, watcher_type, watcher_data, tag);
|
||||
|
||||
if (!g_hash_table_add(priv->watcher_idx, handle))
|
||||
nm_assert_not_reached();
|
||||
|
||||
watcher_by_tag = g_hash_table_lookup(priv->watcher_by_tag_idx, &tag);
|
||||
|
||||
if (!watcher_by_tag) {
|
||||
watcher_by_tag = g_slice_new(WatcherByTag);
|
||||
*watcher_by_tag = (WatcherByTag){
|
||||
.tag = tag,
|
||||
.watcher_by_tag_lst_head = C_LIST_INIT(watcher_by_tag->watcher_by_tag_lst_head),
|
||||
};
|
||||
g_hash_table_add(priv->watcher_by_tag_idx, watcher_by_tag);
|
||||
}
|
||||
|
||||
c_list_link_tail(&watcher_by_tag->watcher_by_tag_lst_head, &handle->watcher_tag_lst);
|
||||
|
||||
is_new = TRUE;
|
||||
} else {
|
||||
/* Handles are deduplicated/shared. Hence it is error prone (and likely
|
||||
* a bug) to provide different callback/user_data. Such usage is
|
||||
* rejected here.
|
||||
*
|
||||
* This could be made to work, for example by now allowing handles to
|
||||
* be merged or simply requiring the caller to be careful to not get
|
||||
* this wrong. But that is currently not implemented nor needed.
|
||||
*/
|
||||
nm_assert(!tag
|
||||
|| (handle->callback == callback && handle->callback_user_data == user_data));
|
||||
}
|
||||
|
||||
if (_LOGT_ENABLED()
|
||||
&& (is_new || handle->callback != callback || handle->callback_user_data != user_data)) {
|
||||
_LOGT("netns-watcher: %s %s",
|
||||
is_new ? "register" : "update",
|
||||
_watcher_handle_to_string(handle, sbuf, sizeof(sbuf)));
|
||||
}
|
||||
|
||||
handle->callback = callback;
|
||||
handle->callback_user_data = user_data;
|
||||
handle->watcher_dirty = FALSE;
|
||||
|
||||
if (is_new)
|
||||
_watcher_register_handle(self, handle);
|
||||
|
||||
/* We cannot return a handle here, because handles are deduplicated via the priv->watchers_idx dictionary.
|
||||
* The usage pattern is to use nm_netns_watcher_remove_all(), and not remove them one by one.
|
||||
* As nm_netns_watcher_add() can return the same handle more than once, the user
|
||||
* wouldn't know when it's safe to call nm_netns_watcher_remove_handle().
|
||||
*
|
||||
* This could be extended by adding a ref-count to the handles. But that is not
|
||||
* used currently, so it's not possible to remove watcher by their handle. */
|
||||
}
|
||||
|
||||
static void
|
||||
nm_netns_watcher_remove_handle(NMNetns *self, NMNetnsWatcherHandle *handle)
|
||||
{
|
||||
NMNetnsPrivate *priv;
|
||||
char sbuf[500];
|
||||
|
||||
g_return_if_fail(NM_IS_NETNS(self));
|
||||
g_return_if_fail(handle);
|
||||
nm_assert(handle->tag);
|
||||
|
||||
priv = NM_NETNS_GET_PRIVATE(self);
|
||||
|
||||
nm_assert(g_hash_table_lookup(priv->watcher_idx, handle) == handle);
|
||||
|
||||
_LOGT("netns-watcher: %s %s",
|
||||
"unregister",
|
||||
_watcher_handle_to_string(handle, sbuf, sizeof(sbuf)));
|
||||
|
||||
_watcher_unregister_handle(self, handle);
|
||||
|
||||
if (!g_hash_table_remove(priv->watcher_idx, handle))
|
||||
nm_assert_not_reached();
|
||||
|
||||
if (c_list_is_empty_or_single(&handle->watcher_tag_lst)) {
|
||||
if (!g_hash_table_remove(priv->watcher_by_tag_idx, &handle->tag))
|
||||
nm_assert_not_reached();
|
||||
}
|
||||
|
||||
c_list_unlink_stale(&handle->watcher_tag_lst);
|
||||
nm_g_slice_free(handle);
|
||||
|
||||
if (G_UNLIKELY(g_hash_table_size(priv->watcher_idx) == 0))
|
||||
g_object_unref(self);
|
||||
}
|
||||
|
||||
void
|
||||
nm_netns_watcher_remove_all(NMNetns *self, gconstpointer tag, gboolean all)
|
||||
{
|
||||
NMNetnsPrivate *priv;
|
||||
WatcherByTag *watcher_by_tag;
|
||||
NMNetnsWatcherHandle *handle;
|
||||
NMNetnsWatcherHandle *handle_safe;
|
||||
|
||||
g_return_if_fail(NM_IS_NETNS(self));
|
||||
|
||||
/* remove-all only works with handles that have a tag associated.
|
||||
* Since NMNetns can have multiple users that are unknown to each
|
||||
* other, it makes no sense to have a remove-all function which
|
||||
* would remove all of them. */
|
||||
g_return_if_fail(tag);
|
||||
|
||||
priv = NM_NETNS_GET_PRIVATE(self);
|
||||
|
||||
watcher_by_tag = g_hash_table_lookup(priv->watcher_by_tag_idx, &tag);
|
||||
if (!watcher_by_tag)
|
||||
return;
|
||||
|
||||
c_list_for_each_entry_safe (handle,
|
||||
handle_safe,
|
||||
&watcher_by_tag->watcher_by_tag_lst_head,
|
||||
watcher_tag_lst) {
|
||||
gboolean is_last;
|
||||
|
||||
if (!all && !handle->watcher_dirty) {
|
||||
/* Survivors are marked as dirty. This enables a pattern where you
|
||||
* call nm_netns_watcher_add() on the elements you care about
|
||||
* (which clears the dirty flag), and then remove all dirty ones
|
||||
* with nm_netns_watcher_remove_all() (which marks the remaining
|
||||
* handles as dirty for the next time). */
|
||||
handle->watcher_dirty = TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
is_last = c_list_is_empty_or_single(&watcher_by_tag->watcher_by_tag_lst_head);
|
||||
nm_netns_watcher_remove_handle(self, handle);
|
||||
|
||||
if (is_last) {
|
||||
/* Removing the last handle destroys the "watcher_by_tag" and may even
|
||||
* destroy "self". We must not touch those pointers hereafter.
|
||||
*
|
||||
* If you ever *not* return here, make sure to handle that! */
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
|
|
@ -850,6 +1421,7 @@ nm_netns_init(NMNetns *self)
|
|||
NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE(self);
|
||||
|
||||
priv->_self_signal_user_data = self;
|
||||
|
||||
c_list_init(&priv->l3cfg_signal_pending_lst_head);
|
||||
|
||||
G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(EcmpTrackObj, obj) == 0);
|
||||
|
|
@ -859,6 +1431,14 @@ nm_netns_init(NMNetns *self)
|
|||
_ecmp_routes_by_ecmpid_equal,
|
||||
_ecmp_routes_by_ecmpid_free,
|
||||
NULL);
|
||||
|
||||
priv->watcher_idx = g_hash_table_new(_watcher_handle_hash, _watcher_handle_equal);
|
||||
G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(WatcherByTag, tag) == 0);
|
||||
priv->watcher_by_tag_idx = g_hash_table_new_full(nm_pdirect_hash,
|
||||
nm_pdirect_equal,
|
||||
(GDestroyNotify) _watcher_by_tag_destroy,
|
||||
NULL);
|
||||
priv->watcher_ip_data_idx = g_hash_table_new(_watcher_ip_data_hash, _watcher_ip_data_equal);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -937,10 +1517,17 @@ dispose(GObject *object)
|
|||
nm_assert(nm_g_hash_table_size(priv->l3cfgs) == 0);
|
||||
nm_assert(c_list_is_empty(&priv->l3cfg_signal_pending_lst_head));
|
||||
nm_assert(!priv->shared_ips);
|
||||
nm_assert(nm_g_hash_table_size(priv->watcher_idx) == 0);
|
||||
nm_assert(nm_g_hash_table_size(priv->watcher_by_tag_idx) == 0);
|
||||
nm_assert(nm_g_hash_table_size(priv->watcher_ip_data_idx) == 0);
|
||||
|
||||
nm_clear_pointer(&priv->ecmp_track_by_obj, g_hash_table_destroy);
|
||||
nm_clear_pointer(&priv->ecmp_track_by_ecmpid, g_hash_table_destroy);
|
||||
|
||||
nm_clear_pointer(&priv->watcher_idx, g_hash_table_destroy);
|
||||
nm_clear_pointer(&priv->watcher_by_tag_idx, g_hash_table_destroy);
|
||||
nm_clear_pointer(&priv->watcher_ip_data_idx, g_hash_table_destroy);
|
||||
|
||||
nm_clear_g_source_inst(&priv->signal_pending_idle_source);
|
||||
|
||||
if (priv->platform)
|
||||
|
|
|
|||
|
|
@ -59,4 +59,46 @@ void nm_netns_ip_route_ecmp_commit(NMNetns *self,
|
|||
GPtrArray **routes,
|
||||
gboolean is_reapply);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef enum {
|
||||
NM_NETNS_WATCHER_TYPE_IP_ADDR,
|
||||
} NMNetnsWatcherType;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
NMIPAddrTyped addr;
|
||||
} ip_addr;
|
||||
};
|
||||
} NMNetnsWatcherData;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
const NMPObject *obj;
|
||||
NMPlatformSignalChangeType change_type;
|
||||
} ip_addr;
|
||||
};
|
||||
} NMNetnsWatcherEventData;
|
||||
|
||||
typedef struct _NMNetnsWatcherHandle NMNetnsWatcherHandle;
|
||||
|
||||
typedef void (*NMNetnsWatcherCallback)(NMNetns *self,
|
||||
NMNetnsWatcherType watcher_type,
|
||||
const NMNetnsWatcherData *watcher_data,
|
||||
gconstpointer tag,
|
||||
const NMNetnsWatcherEventData *event_data,
|
||||
gpointer user_data);
|
||||
|
||||
void nm_netns_watcher_add(NMNetns *self,
|
||||
NMNetnsWatcherType watcher_type,
|
||||
const NMNetnsWatcherData *watcher_data,
|
||||
gconstpointer tag,
|
||||
NMNetnsWatcherCallback callback,
|
||||
gpointer user_data);
|
||||
|
||||
void
|
||||
nm_netns_watcher_remove_all(NMNetns *self, gconstpointer tag, gboolean all /* or only dirty */);
|
||||
|
||||
#endif /* __NM_NETNS_H__ */
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
#ifndef __NM_INET_UTILS_H__
|
||||
#define __NM_INET_UTILS_H__
|
||||
|
||||
#include "libnm-std-aux/unaligned-fundamental.h"
|
||||
|
||||
typedef union _NMIPAddr {
|
||||
guint8 addr_ptr[sizeof(struct in6_addr)];
|
||||
in_addr_t addr4;
|
||||
|
|
@ -15,6 +17,11 @@ typedef union _NMIPAddr {
|
|||
NMEtherAddr _ether_addr;
|
||||
} NMIPAddr;
|
||||
|
||||
typedef struct _NMIPAddrTyped {
|
||||
NMIPAddr addr;
|
||||
gint8 addr_family;
|
||||
} NMIPAddrTyped;
|
||||
|
||||
#define NM_IP_ADDR_INIT \
|
||||
{ \
|
||||
.addr_ptr = { 0 } \
|
||||
|
|
@ -85,14 +92,15 @@ nm_ip_addr_set(int addr_family, gpointer dst, gconstpointer src)
|
|||
static inline gboolean
|
||||
nm_ip_addr_is_null(int addr_family, gconstpointer addr)
|
||||
{
|
||||
NMIPAddr a;
|
||||
struct in6_addr a6;
|
||||
|
||||
nm_ip_addr_set(addr_family, &a, addr);
|
||||
nm_assert(addr);
|
||||
|
||||
if (NM_IS_IPv4(addr_family))
|
||||
return a.addr4 == 0;
|
||||
return unaligned_read_ne32(addr) == 0;
|
||||
|
||||
return IN6_IS_ADDR_UNSPECIFIED(&a.addr6);
|
||||
memcpy(&a6, addr, sizeof(struct in6_addr));
|
||||
return IN6_IS_ADDR_UNSPECIFIED(&a6);
|
||||
}
|
||||
|
||||
static inline NMIPAddr
|
||||
|
|
@ -138,6 +146,30 @@ nm_ip_addr_from_packed_array(int addr_family, gconstpointer ipaddr_arr, gsize id
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static inline int
|
||||
nm_ip_addr_typed_cmp(const NMIPAddrTyped *a, const NMIPAddrTyped *b)
|
||||
{
|
||||
NM_CMP_SELF(a, b);
|
||||
NM_CMP_FIELD(a, b, addr_family);
|
||||
NM_CMP_DIRECT_MEMCMP(&a->addr, &b->addr, nm_utils_addr_family_to_size(a->addr_family));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
nm_ip_addr_typed_equal(const NMIPAddrTyped *a, const NMIPAddrTyped *b)
|
||||
{
|
||||
return nm_ip_addr_typed_cmp(a, b) == 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
nm_ip_addr_typed_hash_update(NMHashState *h, const NMIPAddrTyped *addr)
|
||||
{
|
||||
nm_hash_update_vals(h, addr->addr_family);
|
||||
nm_hash_update_mem(h, &addr->addr, nm_utils_addr_family_to_size(addr->addr_family));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static inline guint32
|
||||
nm_ip4_addr_netmask_to_prefix(in_addr_t subnetmask)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,10 +21,36 @@
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
struct _NMPrioqItem {
|
||||
typedef struct _NMPrioqItem {
|
||||
void *data;
|
||||
unsigned *idx;
|
||||
};
|
||||
} PrioqItem;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define _nm_assert_q(q) \
|
||||
G_STMT_START \
|
||||
{ \
|
||||
const NMPrioq *const _q2 = (q); \
|
||||
\
|
||||
nm_assert(_q2); \
|
||||
nm_assert(_q2->_priv.n_items == 0 || _q2->_priv.items); \
|
||||
nm_assert(_q2->_priv.compare_func); \
|
||||
} \
|
||||
G_STMT_END
|
||||
|
||||
#define _nm_assert_item(q, item) \
|
||||
G_STMT_START \
|
||||
{ \
|
||||
const NMPrioq *const _q = (q); \
|
||||
const PrioqItem *const _item = (item); \
|
||||
\
|
||||
_nm_assert_q(_q); \
|
||||
\
|
||||
nm_assert(_item >= _q->_priv.items); \
|
||||
nm_assert(_item < &_q->_priv.items[_q->_priv.n_items]); \
|
||||
} \
|
||||
G_STMT_END
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -72,6 +98,15 @@ nm_prioq_destroy(NMPrioq *q)
|
|||
if (!q || !q->_priv.compare_func)
|
||||
return;
|
||||
|
||||
_nm_assert_q(q);
|
||||
|
||||
while (q->_priv.n_items > 0) {
|
||||
PrioqItem *i = &q->_priv.items[--q->_priv.n_items];
|
||||
|
||||
if (i->idx)
|
||||
*i->idx = NM_PRIOQ_IDX_NULL;
|
||||
}
|
||||
|
||||
free(q->_priv.items);
|
||||
q->_priv.compare_func = NULL;
|
||||
}
|
||||
|
|
@ -81,8 +116,7 @@ nm_prioq_destroy(NMPrioq *q)
|
|||
static int
|
||||
compare(NMPrioq *q, unsigned a, unsigned b)
|
||||
{
|
||||
nm_assert(q);
|
||||
nm_assert(q->_priv.compare_func);
|
||||
_nm_assert_q(q);
|
||||
nm_assert(a != b);
|
||||
nm_assert(a < q->_priv.n_items);
|
||||
nm_assert(b < q->_priv.n_items);
|
||||
|
|
@ -99,15 +133,13 @@ compare(NMPrioq *q, unsigned a, unsigned b)
|
|||
static void
|
||||
swap(NMPrioq *q, unsigned j, unsigned k)
|
||||
{
|
||||
nm_assert(q);
|
||||
_nm_assert_q(q);
|
||||
nm_assert(j < q->_priv.n_items);
|
||||
nm_assert(k < q->_priv.n_items);
|
||||
|
||||
nm_assert(!q->_priv.items[j].idx || *(q->_priv.items[j].idx) == j);
|
||||
nm_assert(!q->_priv.items[k].idx || *(q->_priv.items[k].idx) == k);
|
||||
|
||||
NM_SWAP(&q->_priv.items[j].data, &q->_priv.items[k].data);
|
||||
NM_SWAP(&q->_priv.items[j].idx, &q->_priv.items[k].idx);
|
||||
NM_SWAP(&q->_priv.items[j], &q->_priv.items[k]);
|
||||
|
||||
if (q->_priv.items[j].idx)
|
||||
*q->_priv.items[j].idx = j;
|
||||
|
|
@ -119,7 +151,7 @@ swap(NMPrioq *q, unsigned j, unsigned k)
|
|||
static unsigned
|
||||
shuffle_up(NMPrioq *q, unsigned idx)
|
||||
{
|
||||
nm_assert(q);
|
||||
_nm_assert_q(q);
|
||||
nm_assert(idx < q->_priv.n_items);
|
||||
|
||||
while (idx > 0) {
|
||||
|
|
@ -140,7 +172,7 @@ shuffle_up(NMPrioq *q, unsigned idx)
|
|||
static unsigned
|
||||
shuffle_down(NMPrioq *q, unsigned idx)
|
||||
{
|
||||
nm_assert(q);
|
||||
_nm_assert_q(q);
|
||||
|
||||
for (;;) {
|
||||
unsigned j;
|
||||
|
|
@ -184,19 +216,21 @@ nm_prioq_put(NMPrioq *q, void *data, unsigned *idx)
|
|||
{
|
||||
unsigned k;
|
||||
|
||||
nm_assert(q);
|
||||
_nm_assert_q(q);
|
||||
nm_assert(q->_priv.n_items < G_MAXUINT);
|
||||
|
||||
if (q->_priv.n_items >= q->_priv.n_allocated) {
|
||||
if (G_UNLIKELY(q->_priv.n_items >= q->_priv.n_allocated)) {
|
||||
q->_priv.n_allocated = NM_MAX((q->_priv.n_items + 1u) * 2u, 16u);
|
||||
q->_priv.items = g_renew(struct _NMPrioqItem, q->_priv.items, q->_priv.n_allocated);
|
||||
q->_priv.items = g_renew(PrioqItem, q->_priv.items, q->_priv.n_allocated);
|
||||
}
|
||||
|
||||
k = q->_priv.n_items++;
|
||||
|
||||
q->_priv.items[k] = (struct _NMPrioqItem){
|
||||
q->_priv.items[k] = (PrioqItem){
|
||||
.data = data,
|
||||
.idx = idx,
|
||||
};
|
||||
|
||||
if (idx)
|
||||
*idx = k;
|
||||
|
||||
|
|
@ -204,71 +238,88 @@ nm_prioq_put(NMPrioq *q, void *data, unsigned *idx)
|
|||
}
|
||||
|
||||
static void
|
||||
remove_item(NMPrioq *q, struct _NMPrioqItem *i)
|
||||
remove_item(NMPrioq *q, PrioqItem *i)
|
||||
{
|
||||
struct _NMPrioqItem *l;
|
||||
unsigned k;
|
||||
PrioqItem *l;
|
||||
unsigned k;
|
||||
|
||||
nm_assert(q);
|
||||
nm_assert(i);
|
||||
nm_assert(q->_priv.n_items > 0);
|
||||
nm_assert(i >= q->_priv.items);
|
||||
nm_assert(i < &q->_priv.items[q->_priv.n_items]);
|
||||
_nm_assert_item(q, i);
|
||||
|
||||
l = &q->_priv.items[q->_priv.n_items - 1u];
|
||||
if (i->idx)
|
||||
*i->idx = NM_PRIOQ_IDX_NULL;
|
||||
|
||||
q->_priv.n_items--;
|
||||
|
||||
l = &q->_priv.items[q->_priv.n_items];
|
||||
|
||||
if (i == l) {
|
||||
/* Last entry, let's just remove it */
|
||||
q->_priv.n_items--;
|
||||
/* Last entry, nothing to do. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Not last entry, let's replace the last entry with
|
||||
* this one, and reshuffle */
|
||||
/* Not last entry, let's replace this entry with the last one, and
|
||||
* reshuffle */
|
||||
|
||||
k = i - q->_priv.items;
|
||||
|
||||
*i = *l;
|
||||
|
||||
if (i->idx)
|
||||
*i->idx = k;
|
||||
q->_priv.n_items--;
|
||||
|
||||
k = shuffle_down(q, k);
|
||||
shuffle_up(q, k);
|
||||
}
|
||||
|
||||
_nm_pure static struct _NMPrioqItem *
|
||||
static PrioqItem *
|
||||
find_item(NMPrioq *q, void *data, unsigned *idx)
|
||||
{
|
||||
struct _NMPrioqItem *i;
|
||||
PrioqItem *i;
|
||||
|
||||
nm_assert(q);
|
||||
_nm_assert_q(q);
|
||||
|
||||
if (q->_priv.n_items <= 0)
|
||||
return NULL;
|
||||
|
||||
if (idx) {
|
||||
if (*idx == NM_PRIOQ_IDX_NULL || *idx >= q->_priv.n_items)
|
||||
return NULL;
|
||||
|
||||
i = &q->_priv.items[*idx];
|
||||
if (i->data == data)
|
||||
return i;
|
||||
} else {
|
||||
if (G_UNLIKELY(!idx)) {
|
||||
/* We allow using NMPrioq without "idx". In that case, it does a linear
|
||||
* search for the data. */
|
||||
for (i = q->_priv.items; i < &q->_priv.items[q->_priv.n_items]; i++) {
|
||||
if (i->data == data)
|
||||
return i;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
/* If the user however provides an "idx" pointer, then we assert that it is
|
||||
* consistent. That is, if data is not in the queue, then we require that
|
||||
* "*idx" is NM_PRIOQ_IDX_NULL, and otherwise we require that we really
|
||||
* find "data" at index "*idx".
|
||||
*
|
||||
* This means, when the user calls nm_prioq_{remove,update,reshuffle}()
|
||||
* with an "idx", then they must make sure that the index is consistent.
|
||||
* Usually this means they are required to initialize the index to
|
||||
* NM_PRIOQ_IDX_NULL while the data is not in the heap.
|
||||
*
|
||||
* This is done to assert more, and requires a stricter usage of the API
|
||||
* (in the hope to find misuses of the index). */
|
||||
|
||||
if (*idx >= q->_priv.n_items) {
|
||||
nm_assert(*idx == NM_PRIOQ_IDX_NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
i = &q->_priv.items[*idx];
|
||||
|
||||
if (i->data != data)
|
||||
return nm_assert_unreachable_val(NULL);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_prioq_remove(NMPrioq *q, void *data, unsigned *idx)
|
||||
{
|
||||
struct _NMPrioqItem *i;
|
||||
PrioqItem *i;
|
||||
|
||||
nm_assert(q);
|
||||
_nm_assert_q(q);
|
||||
|
||||
i = find_item(q, data, idx);
|
||||
if (!i)
|
||||
|
|
@ -278,28 +329,60 @@ nm_prioq_remove(NMPrioq *q, void *data, unsigned *idx)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
reshuffle_item(NMPrioq *q, PrioqItem *i)
|
||||
{
|
||||
unsigned k;
|
||||
|
||||
_nm_assert_item(q, i);
|
||||
|
||||
k = i - q->_priv.items;
|
||||
k = shuffle_down(q, k);
|
||||
shuffle_up(q, k);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_prioq_reshuffle(NMPrioq *q, void *data, unsigned *idx)
|
||||
{
|
||||
struct _NMPrioqItem *i;
|
||||
unsigned k;
|
||||
PrioqItem *i;
|
||||
|
||||
nm_assert(q);
|
||||
_nm_assert_q(q);
|
||||
|
||||
i = find_item(q, data, idx);
|
||||
if (!i)
|
||||
return FALSE;
|
||||
|
||||
k = i - q->_priv.items;
|
||||
k = shuffle_down(q, k);
|
||||
shuffle_up(q, k);
|
||||
reshuffle_item(q, i);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nm_prioq_update(NMPrioq *q, void *data, unsigned *idx, bool queued /* or else remove */)
|
||||
{
|
||||
PrioqItem *i;
|
||||
|
||||
_nm_assert_q(q);
|
||||
|
||||
i = find_item(q, data, idx);
|
||||
|
||||
if (!i) {
|
||||
if (queued)
|
||||
nm_prioq_put(q, data, idx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!queued) {
|
||||
remove_item(q, i);
|
||||
return;
|
||||
}
|
||||
|
||||
reshuffle_item(q, i);
|
||||
}
|
||||
|
||||
void *
|
||||
nm_prioq_peek_by_index(NMPrioq *q, unsigned idx)
|
||||
{
|
||||
nm_assert(q);
|
||||
_nm_assert_q(q);
|
||||
|
||||
if (idx >= q->_priv.n_items)
|
||||
return NULL;
|
||||
|
|
@ -312,7 +395,7 @@ nm_prioq_pop(NMPrioq *q)
|
|||
{
|
||||
void *data;
|
||||
|
||||
nm_assert(q);
|
||||
_nm_assert_q(q);
|
||||
|
||||
if (q->_priv.n_items <= 0)
|
||||
return NULL;
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ void nm_prioq_put(NMPrioq *q, void *data, unsigned *idx);
|
|||
gboolean nm_prioq_remove(NMPrioq *q, void *data, unsigned *idx);
|
||||
gboolean nm_prioq_reshuffle(NMPrioq *q, void *data, unsigned *idx);
|
||||
|
||||
void nm_prioq_update(NMPrioq *q, void *data, unsigned *idx, bool queued /* or else remove */);
|
||||
|
||||
void *nm_prioq_peek_by_index(NMPrioq *q, unsigned idx) _nm_pure;
|
||||
|
||||
static inline void *
|
||||
|
|
@ -53,7 +55,7 @@ nm_prioq_peek(NMPrioq *q)
|
|||
|
||||
void *nm_prioq_pop(NMPrioq *q);
|
||||
|
||||
#define NM_PRIOQ_FOREACH_ITEM(q, p) for (unsigned _i = 0; (p = nm_prioq_peek_by_index(q, _i)); _i++)
|
||||
#define nm_prioq_for_each(q, p) for (unsigned _i = 0; (p = nm_prioq_peek_by_index((q), _i)); _i++)
|
||||
|
||||
_nm_pure static inline unsigned
|
||||
nm_prioq_size(NMPrioq *q)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "c-list/src/c-list.h"
|
||||
#include "nm-errno.h"
|
||||
#include "nm-time-utils.h"
|
||||
#include "nm-str-buf.h"
|
||||
#include "nm-time-utils.h"
|
||||
|
||||
|
|
@ -4840,6 +4841,50 @@ nm_g_child_watch_source_new(GPid pid,
|
|||
return source;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_g_timeout_reschedule(GSource **src,
|
||||
gint64 *p_expiry_msec,
|
||||
gint64 expiry_msec,
|
||||
GSourceFunc func,
|
||||
gpointer user_data)
|
||||
{
|
||||
gint64 now_msec;
|
||||
gint64 timeout_msec;
|
||||
|
||||
/* (Re-)Schedules a timeout at "expiry_msec" (in
|
||||
* nm_utils_get_monotonic_timestamp_msec() scale).
|
||||
*
|
||||
* If a source is already scheduled in "*src" and "*p_expiry_msec" is
|
||||
* identical to "expiry_msec", then we assume the timer is already ticking,
|
||||
* and nothing is rescheduled.
|
||||
*
|
||||
* Otherwise, "*src" gets cancelled (if any), a new timer is scheduled
|
||||
* (assigned to "*src") and the new expiry is written to "*p_expiry_msec".
|
||||
*/
|
||||
|
||||
nm_assert(src);
|
||||
nm_assert(p_expiry_msec);
|
||||
|
||||
if (*src) {
|
||||
if (*p_expiry_msec == expiry_msec) {
|
||||
/* already scheduled with same expiry. */
|
||||
return FALSE;
|
||||
}
|
||||
nm_clear_g_source_inst(src);
|
||||
}
|
||||
|
||||
now_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||
|
||||
if (expiry_msec <= now_msec)
|
||||
timeout_msec = 0;
|
||||
else
|
||||
timeout_msec = NM_MIN(expiry_msec - now_msec, (gint64) G_MAXUINT);
|
||||
|
||||
*p_expiry_msec = expiry_msec;
|
||||
*src = nm_g_timeout_add_source(timeout_msec, func, user_data);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define _CTX_LOG(fmt, ...) \
|
||||
|
|
|
|||
|
|
@ -1543,6 +1543,12 @@ nm_g_timeout_add_source(guint timeout_msec, GSourceFunc func, gpointer user_data
|
|||
NULL);
|
||||
}
|
||||
|
||||
gboolean nm_g_timeout_reschedule(GSource **src,
|
||||
gint64 *p_expiry_msec,
|
||||
gint64 expiry_msec,
|
||||
GSourceFunc func,
|
||||
gpointer user_data);
|
||||
|
||||
static inline GSource *
|
||||
nm_g_timeout_add_seconds_source(guint timeout_sec, GSourceFunc func, gpointer user_data)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2348,7 +2348,7 @@ test_garray(void)
|
|||
static int
|
||||
_prioq_cmp(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
NM_CMP_DIRECT(GPOINTER_TO_UINT(a), GPOINTER_TO_UINT(b));
|
||||
NM_CMP_DIRECT(*((const guint32 *) a), *((const guint32 *) b));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2362,11 +2362,12 @@ static void
|
|||
test_nm_prioq(void)
|
||||
{
|
||||
nm_auto_prioq NMPrioq q = NM_PRIOQ_ZERO;
|
||||
gpointer data[200];
|
||||
gpointer data_pop[200];
|
||||
guint32 data[200];
|
||||
const guint32 *data_pop[200];
|
||||
guint data_idx[G_N_ELEMENTS(data)];
|
||||
guint i;
|
||||
guint n;
|
||||
guint m;
|
||||
gpointer p;
|
||||
|
||||
if (nmtst_get_rand_one_case_in(10))
|
||||
|
|
@ -2379,37 +2380,67 @@ test_nm_prioq(void)
|
|||
|
||||
g_assert(nm_prioq_size(&q) == 0);
|
||||
|
||||
if (nmtst_get_rand_one_case_in(10))
|
||||
if (nmtst_get_rand_one_case_in(100))
|
||||
return;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(data); i++) {
|
||||
data[i] = GUINT_TO_POINTER((nmtst_get_rand_uint32() % G_N_ELEMENTS(data)) + 1u);
|
||||
data[i] = nmtst_get_rand_uint32() % G_N_ELEMENTS(data);
|
||||
data_idx[i] = NM_PRIOQ_IDX_NULL;
|
||||
}
|
||||
|
||||
nm_prioq_put(&q, data[0], NULL);
|
||||
nm_prioq_put(&q, &data[0], NULL);
|
||||
g_assert(nm_prioq_size(&q) == 1);
|
||||
|
||||
p = nm_prioq_pop(&q);
|
||||
g_assert(p == data[0]);
|
||||
g_assert(p == &data[0]);
|
||||
g_assert(nm_prioq_size(&q) == 0);
|
||||
|
||||
g_assert(!nm_prioq_pop(&q));
|
||||
|
||||
n = nmtst_get_rand_uint32() % G_N_ELEMENTS(data);
|
||||
for (i = 0; i < n; i++)
|
||||
nm_prioq_put(&q, data[i], &data_idx[i]);
|
||||
nm_prioq_put(&q, &data[i], &data_idx[i]);
|
||||
|
||||
g_assert_cmpint(nm_prioq_size(&q), ==, n);
|
||||
m = n;
|
||||
for (i = 0; i < n; i++) {
|
||||
if (!nmtst_get_rand_bool())
|
||||
continue;
|
||||
|
||||
if (nmtst_get_rand_one_case_in(10))
|
||||
data[i] = nmtst_get_rand_uint32() % G_N_ELEMENTS(data);
|
||||
switch (nmtst_get_rand_uint32() % 4) {
|
||||
case 0:
|
||||
nm_prioq_reshuffle(&q, &data[i], &data_idx[i]);
|
||||
break;
|
||||
case 1:
|
||||
nm_prioq_remove(&q, &data[i], nmtst_get_rand_bool() ? &data_idx[i] : NULL);
|
||||
m--;
|
||||
break;
|
||||
case 2:
|
||||
nm_prioq_update(&q, &data[i], &data_idx[i], TRUE);
|
||||
break;
|
||||
case 3:
|
||||
nm_prioq_update(&q, &data[i], nmtst_get_rand_bool() ? &data_idx[i] : NULL, FALSE);
|
||||
m--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_assert_cmpint(nm_prioq_size(&q), ==, m);
|
||||
|
||||
if (nmtst_get_rand_one_case_in(50))
|
||||
return;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
for (i = 0; i < m; i++) {
|
||||
data_pop[i] = nm_prioq_pop(&q);
|
||||
g_assert(data_pop[i]);
|
||||
if (i > 0)
|
||||
g_assert_cmpint(*data_pop[i], >=, 0);
|
||||
g_assert_cmpint(*data_pop[i], <, G_N_ELEMENTS(data));
|
||||
g_assert(data_pop[i] >= &data[0]);
|
||||
g_assert(data_pop[i] < &data[n]);
|
||||
if (i > 0) {
|
||||
g_assert(_prioq_cmp(data_pop[i - 1], data_pop[i]) <= 0);
|
||||
g_assert_cmpint(*data_pop[i - 1], <=, *data_pop[i]);
|
||||
}
|
||||
}
|
||||
|
||||
g_assert(!nm_prioq_pop(&q));
|
||||
|
|
|
|||
|
|
@ -735,6 +735,7 @@ nm_lldp_neighbor_new(size_t raw_size)
|
|||
|
||||
n->raw_size = raw_size;
|
||||
n->ref_count = 1;
|
||||
n->prioq_idx = NM_PRIOQ_IDX_NULL;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8149,6 +8149,7 @@ do_add_addrroute(NMPlatform *platform,
|
|||
do_request_one_type_by_needle_object(platform, obj_id);
|
||||
}
|
||||
|
||||
NM_SET_OUT(out_extack_msg, g_steal_pointer(&extack_msg));
|
||||
return wait_for_nl_response_to_nmerr(seq_result);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4593,53 +4593,6 @@ nm_platform_ip_address_flush(NMPlatform *self, int addr_family, int ifindex)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static gboolean
|
||||
_route_is_temporary_not_available(NMPlatform *self,
|
||||
int err,
|
||||
const NMPObject *obj,
|
||||
const char **out_err_reason)
|
||||
{
|
||||
const NMPlatformIPXRoute *rx;
|
||||
const NMPlatformIP6Address *a;
|
||||
|
||||
nm_assert(NM_IS_PLATFORM(self));
|
||||
nm_assert(NMP_OBJECT_IS_VALID(obj));
|
||||
|
||||
if (err != -EINVAL)
|
||||
return FALSE;
|
||||
|
||||
rx = NMP_OBJECT_CAST_IPX_ROUTE(obj);
|
||||
|
||||
if (rx->rx.rt_source != NM_IP_CONFIG_SOURCE_USER) {
|
||||
/* we only allow this workaround for routes added manually by the user. */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (NMP_OBJECT_GET_TYPE(obj) == NMP_OBJECT_TYPE_IP4_ROUTE) {
|
||||
return FALSE;
|
||||
} else {
|
||||
const NMPlatformIP6Route *r = &rx->r6;
|
||||
|
||||
/* trying to add an IPv6 route with pref-src fails, if the address is
|
||||
* still tentative (rh#1452684). We need to hack around that.
|
||||
*
|
||||
* Detect it, by guessing whether that's the case. */
|
||||
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&r->pref_src))
|
||||
return FALSE;
|
||||
|
||||
a = nm_platform_ip6_address_get(self, r->ifindex, &r->pref_src);
|
||||
if (!a)
|
||||
return FALSE;
|
||||
if (!NM_FLAGS_HAS(a->n_ifa_flags, IFA_F_TENTATIVE)
|
||||
|| NM_FLAGS_HAS(a->n_ifa_flags, IFA_F_DADFAILED))
|
||||
return FALSE;
|
||||
|
||||
*out_err_reason = "tentative IPv6 src address not ready";
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static guint
|
||||
_ipv6_temporary_addr_prefixes_keep_hash(gconstpointer ptr)
|
||||
{
|
||||
|
|
@ -4968,8 +4921,8 @@ nm_platform_ip_route_get_prune_list(NMPlatform *self,
|
|||
* at the end of the operation. Note that if @routes contains
|
||||
* the same route, then it will not be deleted. @routes overrules
|
||||
* @routes_prune list.
|
||||
* @out_temporary_not_available: (allow-none) (out): routes that could
|
||||
* currently not be synced. The caller shall keep them and try later again.
|
||||
* @out_routes_failed: (allow-none) (out): routes that could
|
||||
* not be synced/added.
|
||||
*
|
||||
* Returns: %TRUE on success.
|
||||
*/
|
||||
|
|
@ -4979,7 +4932,7 @@ nm_platform_ip_route_sync(NMPlatform *self,
|
|||
int ifindex,
|
||||
GPtrArray *routes,
|
||||
GPtrArray *routes_prune,
|
||||
GPtrArray **out_temporary_not_available)
|
||||
GPtrArray **out_routes_failed)
|
||||
{
|
||||
const int IS_IPv4 = NM_IS_IPv4(addr_family);
|
||||
const NMPlatformVTableRoute *vt;
|
||||
|
|
@ -4999,9 +4952,7 @@ nm_platform_ip_route_sync(NMPlatform *self,
|
|||
|
||||
for (i_type = 0; routes && i_type < 2; i_type++) {
|
||||
for (i = 0; i < routes->len; i++) {
|
||||
gs_free char *extack_msg = NULL;
|
||||
gboolean gateway_route_added = FALSE;
|
||||
int r2;
|
||||
gs_free char *extack_msg = NULL;
|
||||
int r;
|
||||
|
||||
conf_o = routes->pdata[i];
|
||||
|
|
@ -5058,147 +5009,59 @@ nm_platform_ip_route_sync(NMPlatform *self,
|
|||
}
|
||||
}
|
||||
|
||||
sync_route_add:
|
||||
r = nm_platform_ip_route_add(self,
|
||||
NMP_NLM_FLAG_APPEND
|
||||
| NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE,
|
||||
conf_o,
|
||||
&extack_msg);
|
||||
if (r < 0) {
|
||||
const char *err_reason = NULL;
|
||||
|
||||
if (r == -EEXIST) {
|
||||
/* Don't fail for EEXIST. It's not clear that the existing route
|
||||
* is identical to the one that we were about to add. However,
|
||||
* above we should have deleted conflicting (non-identical) routes. */
|
||||
if (_LOGD_ENABLED()) {
|
||||
plat_entry =
|
||||
nm_platform_lookup_entry(self, NMP_CACHE_ID_TYPE_OBJECT_TYPE, conf_o);
|
||||
if (!plat_entry) {
|
||||
_LOG3D("route-sync: adding route %s failed with EEXIST, however we "
|
||||
"cannot find such a route",
|
||||
nmp_object_to_string(conf_o,
|
||||
NMP_OBJECT_TO_STRING_PUBLIC,
|
||||
sbuf1,
|
||||
sizeof(sbuf1)));
|
||||
} else if (vt->route_cmp(NMP_OBJECT_CAST_IPX_ROUTE(conf_o),
|
||||
NMP_OBJECT_CAST_IPX_ROUTE(plat_entry->obj),
|
||||
NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
|
||||
!= 0) {
|
||||
_LOG3D("route-sync: adding route %s failed due to existing "
|
||||
"(different!) route %s",
|
||||
nmp_object_to_string(conf_o,
|
||||
NMP_OBJECT_TO_STRING_PUBLIC,
|
||||
sbuf1,
|
||||
sizeof(sbuf1)),
|
||||
nmp_object_to_string(plat_entry->obj,
|
||||
NMP_OBJECT_TO_STRING_PUBLIC,
|
||||
sbuf2,
|
||||
sizeof(sbuf2)));
|
||||
}
|
||||
}
|
||||
} else if (NMP_OBJECT_CAST_IP_ROUTE(conf_o)->rt_source < NM_IP_CONFIG_SOURCE_USER) {
|
||||
_LOG3D("route-sync: ignore failure to add IPv%c route: %s: %s",
|
||||
vt->is_ip4 ? '4' : '6',
|
||||
nmp_object_to_string(conf_o,
|
||||
NMP_OBJECT_TO_STRING_PUBLIC,
|
||||
sbuf1,
|
||||
sizeof(sbuf1)),
|
||||
nm_strerror(r));
|
||||
} else if (out_temporary_not_available
|
||||
&& _route_is_temporary_not_available(self, r, conf_o, &err_reason)) {
|
||||
_LOG3D("route-sync: ignore temporary failure to add route (%s, %s): %s",
|
||||
nm_strerror(r),
|
||||
err_reason,
|
||||
nmp_object_to_string(conf_o,
|
||||
NMP_OBJECT_TO_STRING_PUBLIC,
|
||||
sbuf1,
|
||||
sizeof(sbuf1)));
|
||||
if (!*out_temporary_not_available)
|
||||
*out_temporary_not_available =
|
||||
g_ptr_array_new_full(0, (GDestroyNotify) nmp_object_unref);
|
||||
g_ptr_array_add(*out_temporary_not_available,
|
||||
(gpointer) nmp_object_ref(conf_o));
|
||||
} else if (!gateway_route_added
|
||||
&& ((r == -ENETUNREACH && vt->is_ip4
|
||||
&& !!NMP_OBJECT_CAST_IP4_ROUTE(conf_o)->gateway)
|
||||
|| (r == -EHOSTUNREACH && !vt->is_ip4
|
||||
&& !IN6_IS_ADDR_UNSPECIFIED(
|
||||
&NMP_OBJECT_CAST_IP6_ROUTE(conf_o)->gateway)))) {
|
||||
NMPObject oo;
|
||||
|
||||
if (vt->is_ip4) {
|
||||
const NMPlatformIP4Route *rt = NMP_OBJECT_CAST_IP4_ROUTE(conf_o);
|
||||
|
||||
nmp_object_stackinit(
|
||||
&oo,
|
||||
NMP_OBJECT_TYPE_IP4_ROUTE,
|
||||
&((NMPlatformIP4Route){
|
||||
.ifindex = rt->ifindex,
|
||||
.network = rt->gateway,
|
||||
.plen = 32,
|
||||
.metric = nm_platform_ip4_route_get_effective_metric(rt),
|
||||
.rt_source = rt->rt_source,
|
||||
.table_coerced = nm_platform_ip_route_get_effective_table(
|
||||
NM_PLATFORM_IP_ROUTE_CAST(rt)),
|
||||
}));
|
||||
} else {
|
||||
const NMPlatformIP6Route *rt = NMP_OBJECT_CAST_IP6_ROUTE(conf_o);
|
||||
|
||||
nmp_object_stackinit(
|
||||
&oo,
|
||||
NMP_OBJECT_TYPE_IP6_ROUTE,
|
||||
&((NMPlatformIP6Route){
|
||||
.ifindex = rt->ifindex,
|
||||
.network = rt->gateway,
|
||||
.plen = 128,
|
||||
.metric = nm_platform_ip6_route_get_effective_metric(rt),
|
||||
.rt_source = rt->rt_source,
|
||||
.table_coerced = nm_platform_ip_route_get_effective_table(
|
||||
NM_PLATFORM_IP_ROUTE_CAST(rt)),
|
||||
}));
|
||||
}
|
||||
|
||||
_LOG3D("route-sync: failure to add IPv%c route: %s: %s; try adding direct "
|
||||
"route to gateway %s",
|
||||
vt->is_ip4 ? '4' : '6',
|
||||
nmp_object_to_string(conf_o,
|
||||
NMP_OBJECT_TO_STRING_PUBLIC,
|
||||
sbuf1,
|
||||
sizeof(sbuf1)),
|
||||
nm_strerror(r),
|
||||
nmp_object_to_string(&oo,
|
||||
NMP_OBJECT_TO_STRING_PUBLIC,
|
||||
sbuf2,
|
||||
sizeof(sbuf2)));
|
||||
|
||||
r2 = nm_platform_ip_route_add(self,
|
||||
NMP_NLM_FLAG_APPEND
|
||||
| NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE,
|
||||
&oo,
|
||||
NULL);
|
||||
|
||||
if (r2 < 0) {
|
||||
_LOG3D("route-sync: failure to add gateway IPv%c route: %s: %s",
|
||||
vt->is_ip4 ? '4' : '6',
|
||||
if (r == 0) {
|
||||
/* success */
|
||||
} else if (r == -EEXIST) {
|
||||
/* Don't fail for EEXIST. It's not clear that the existing route
|
||||
* is identical to the one that we were about to add. However,
|
||||
* above we should have deleted conflicting (non-identical) routes. */
|
||||
if (_LOGD_ENABLED()) {
|
||||
plat_entry =
|
||||
nm_platform_lookup_entry(self, NMP_CACHE_ID_TYPE_OBJECT_TYPE, conf_o);
|
||||
if (!plat_entry) {
|
||||
_LOG3D("route-sync: adding route %s failed with EEXIST, however we "
|
||||
"cannot find such a route",
|
||||
nmp_object_to_string(conf_o,
|
||||
NMP_OBJECT_TO_STRING_PUBLIC,
|
||||
sbuf1,
|
||||
sizeof(sbuf1)));
|
||||
} else if (vt->route_cmp(NMP_OBJECT_CAST_IPX_ROUTE(conf_o),
|
||||
NMP_OBJECT_CAST_IPX_ROUTE(plat_entry->obj),
|
||||
NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
|
||||
!= 0) {
|
||||
_LOG3D("route-sync: adding route %s failed due to existing "
|
||||
"(different!) route %s",
|
||||
nmp_object_to_string(conf_o,
|
||||
NMP_OBJECT_TO_STRING_PUBLIC,
|
||||
sbuf1,
|
||||
sizeof(sbuf1)),
|
||||
nm_strerror(r2));
|
||||
nmp_object_to_string(plat_entry->obj,
|
||||
NMP_OBJECT_TO_STRING_PUBLIC,
|
||||
sbuf2,
|
||||
sizeof(sbuf2)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_LOG3D(
|
||||
"route-sync: failure to add IPv%c route: %s: %s%s%s%s",
|
||||
vt->is_ip4 ? '4' : '6',
|
||||
nmp_object_to_string(conf_o, NMP_OBJECT_TO_STRING_PUBLIC, sbuf1, sizeof(sbuf1)),
|
||||
nm_strerror(r),
|
||||
NM_PRINT_FMT_QUOTED(extack_msg, " (", extack_msg, ")", ""));
|
||||
|
||||
gateway_route_added = TRUE;
|
||||
goto sync_route_add;
|
||||
} else {
|
||||
_LOG3W("route-sync: failure to add IPv%c route: %s: %s",
|
||||
vt->is_ip4 ? '4' : '6',
|
||||
nmp_object_to_string(conf_o,
|
||||
NMP_OBJECT_TO_STRING_PUBLIC,
|
||||
sbuf1,
|
||||
sizeof(sbuf1)),
|
||||
nm_strerror(r));
|
||||
success = FALSE;
|
||||
success = FALSE;
|
||||
|
||||
if (out_routes_failed) {
|
||||
if (!*out_routes_failed) {
|
||||
*out_routes_failed =
|
||||
g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref);
|
||||
}
|
||||
g_ptr_array_add(*out_routes_failed, (gpointer) nmp_object_ref(conf_o));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5346,7 +5209,7 @@ _ip_route_add(NMPlatform *self, NMPNlmFlags flags, NMPObject *obj_stack, char **
|
|||
char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE];
|
||||
int ifindex;
|
||||
|
||||
_CHECK_SELF(self, klass, FALSE);
|
||||
_CHECK_SELF(self, klass, -NME_BUG);
|
||||
|
||||
/* The caller already ensures that this is a stack allocated copy, that
|
||||
* - stays alive for the duration of the call.
|
||||
|
|
@ -7037,7 +6900,6 @@ nm_platform_ip4_route_to_string_full(const NMPlatformIP4Route *route,
|
|||
"%s" /* rto_min */
|
||||
"%s" /* quickack */
|
||||
"%s" /* mtu */
|
||||
"%s" /* r_force_commit */
|
||||
"",
|
||||
nm_net_aux_rtnl_rtntype_n2a_maybe_buf(nm_platform_route_type_uncoerce(route->type_coerced),
|
||||
str_type),
|
||||
|
|
@ -7104,8 +6966,7 @@ nm_platform_ip4_route_to_string_full(const NMPlatformIP4Route *route,
|
|||
" mtu %s%" G_GUINT32_FORMAT,
|
||||
route->lock_mtu ? "lock " : "",
|
||||
route->mtu)
|
||||
: "",
|
||||
route->r_force_commit ? " force-commit" : "");
|
||||
: "");
|
||||
|
||||
if ((n_nexthops == 1 && route->ifindex > 0) || n_nexthops == 0) {
|
||||
/* A plain single hop route. Nothing extra to remark. */
|
||||
|
|
@ -7225,7 +7086,6 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz
|
|||
"%s" /* quickack */
|
||||
"%s" /* mtu */
|
||||
"%s" /* pref */
|
||||
"%s" /* r_force_commit */
|
||||
"",
|
||||
nm_net_aux_rtnl_rtntype_n2a_maybe_buf(nm_platform_route_type_uncoerce(route->type_coerced),
|
||||
str_type),
|
||||
|
|
@ -7292,8 +7152,7 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz
|
|||
str_pref,
|
||||
" pref %s",
|
||||
nm_icmpv6_router_pref_to_string(route->rt_pref, str_pref2, sizeof(str_pref2)))
|
||||
: "",
|
||||
route->r_force_commit ? " force-commit" : "");
|
||||
: "");
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
|
@ -8680,8 +8539,7 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
|
|||
obj->lock_initcwnd,
|
||||
obj->lock_initrwnd,
|
||||
obj->lock_mtu,
|
||||
obj->lock_mss,
|
||||
obj->r_force_commit));
|
||||
obj->lock_mss));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -8824,8 +8682,6 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
|
|||
NM_CMP_FIELD(a, b, initrwnd);
|
||||
NM_CMP_FIELD(a, b, mtu);
|
||||
NM_CMP_FIELD(a, b, rto_min);
|
||||
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL)
|
||||
NM_CMP_FIELD_UNSAFE(a, b, r_force_commit);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -8925,8 +8781,7 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj,
|
|||
obj->lock_initcwnd,
|
||||
obj->lock_initrwnd,
|
||||
obj->lock_mtu,
|
||||
obj->lock_mss,
|
||||
obj->r_force_commit),
|
||||
obj->lock_mss),
|
||||
obj->window,
|
||||
obj->cwnd,
|
||||
obj->initcwnd,
|
||||
|
|
@ -9016,8 +8871,6 @@ nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a,
|
|||
NM_CMP_DIRECT(_route_pref_normalize(a->rt_pref), _route_pref_normalize(b->rt_pref));
|
||||
else
|
||||
NM_CMP_FIELD(a, b, rt_pref);
|
||||
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL)
|
||||
NM_CMP_FIELD_UNSAFE(a, b, r_force_commit);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -9339,7 +9192,6 @@ nm_platform_ip4_address_generate_device_route(const NMPlatformIP4Address *addr,
|
|||
int ifindex,
|
||||
guint32 route_table,
|
||||
guint32 route_metric,
|
||||
gboolean force_commit,
|
||||
NMPlatformIP4Route *dst)
|
||||
{
|
||||
in_addr_t network_4;
|
||||
|
|
@ -9369,15 +9221,14 @@ nm_platform_ip4_address_generate_device_route(const NMPlatformIP4Address *addr,
|
|||
}
|
||||
|
||||
*dst = (NMPlatformIP4Route){
|
||||
.ifindex = ifindex,
|
||||
.rt_source = NM_IP_CONFIG_SOURCE_KERNEL,
|
||||
.network = network_4,
|
||||
.plen = addr->plen,
|
||||
.pref_src = addr->address,
|
||||
.table_coerced = nm_platform_route_table_coerce(route_table),
|
||||
.metric = route_metric,
|
||||
.scope_inv = nm_platform_route_scope_inv(NM_RT_SCOPE_LINK),
|
||||
.r_force_commit = force_commit,
|
||||
.ifindex = ifindex,
|
||||
.rt_source = NM_IP_CONFIG_SOURCE_KERNEL,
|
||||
.network = network_4,
|
||||
.plen = addr->plen,
|
||||
.pref_src = addr->address,
|
||||
.table_coerced = nm_platform_route_table_coerce(route_table),
|
||||
.metric = route_metric,
|
||||
.scope_inv = nm_platform_route_scope_inv(NM_RT_SCOPE_LINK),
|
||||
};
|
||||
|
||||
nm_platform_ip_route_normalize(AF_INET, (NMPlatformIPRoute *) dst);
|
||||
|
|
|
|||
|
|
@ -243,13 +243,6 @@ typedef enum {
|
|||
|
||||
guint _nm_platform_signal_id_get(NMPlatformSignalIdType signal_type);
|
||||
|
||||
typedef enum {
|
||||
NM_PLATFORM_SIGNAL_NONE,
|
||||
NM_PLATFORM_SIGNAL_ADDED,
|
||||
NM_PLATFORM_SIGNAL_CHANGED,
|
||||
NM_PLATFORM_SIGNAL_REMOVED,
|
||||
} NMPlatformSignalChangeType;
|
||||
|
||||
/* Default value for adding an IPv4 route. This is also what iproute2 does.
|
||||
* Note that contrary to IPv6, you can add routes with metric 0 and it is even
|
||||
* the default.
|
||||
|
|
@ -2306,6 +2299,19 @@ nm_platform_ip_route_get_gateway(int addr_family, const NMPlatformIPRoute *route
|
|||
return &((NMPlatformIP6Route *) route)->gateway;
|
||||
}
|
||||
|
||||
static inline gconstpointer
|
||||
nm_platform_ip_route_get_pref_src(int addr_family, const NMPlatformIPRoute *route)
|
||||
{
|
||||
nm_assert_addr_family(addr_family);
|
||||
|
||||
if (!route)
|
||||
return NULL;
|
||||
|
||||
if (NM_IS_IPv4(addr_family))
|
||||
return &((NMPlatformIP4Route *) route)->pref_src;
|
||||
return &((NMPlatformIP6Route *) route)->pref_src;
|
||||
}
|
||||
|
||||
int nm_platform_ip_route_add(NMPlatform *self,
|
||||
NMPNlmFlags flags,
|
||||
const NMPObject *route,
|
||||
|
|
@ -2326,7 +2332,7 @@ gboolean nm_platform_ip_route_sync(NMPlatform *self,
|
|||
int ifindex,
|
||||
GPtrArray *routes,
|
||||
GPtrArray *routes_prune,
|
||||
GPtrArray **out_temporary_not_available);
|
||||
GPtrArray **out_routes_failed);
|
||||
|
||||
gboolean nm_platform_ip_route_flush(NMPlatform *self, int addr_family, int ifindex);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,15 @@
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef enum {
|
||||
NM_PLATFORM_SIGNAL_NONE,
|
||||
NM_PLATFORM_SIGNAL_ADDED,
|
||||
NM_PLATFORM_SIGNAL_CHANGED,
|
||||
NM_PLATFORM_SIGNAL_REMOVED,
|
||||
} NMPlatformSignalChangeType;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef enum {
|
||||
NM_PLATFORM_LINK_DUPLEX_UNKNOWN,
|
||||
NM_PLATFORM_LINK_DUPLEX_HALF,
|
||||
|
|
|
|||
|
|
@ -1183,21 +1183,6 @@ nm_platform_lookup_object_by_addr_family(NMPlatform *platform,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static inline gboolean
|
||||
nmp_object_get_force_commit(const NMPObject *obj)
|
||||
{
|
||||
switch (NMP_OBJECT_GET_TYPE(obj)) {
|
||||
case NMP_OBJECT_TYPE_IP4_ADDRESS:
|
||||
case NMP_OBJECT_TYPE_IP6_ADDRESS:
|
||||
return NMP_OBJECT_CAST_IP_ADDRESS(obj)->a_force_commit;
|
||||
case NMP_OBJECT_TYPE_IP4_ROUTE:
|
||||
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
||||
return NMP_OBJECT_CAST_IP_ROUTE(obj)->r_force_commit;
|
||||
default:
|
||||
return nm_assert_unreachable_val(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
nmp_object_link_get_ifname(const NMPObject *obj)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -255,7 +255,6 @@ NMPlatformIP4Route *nm_platform_ip4_address_generate_device_route(const NMPlatfo
|
|||
int ifindex,
|
||||
guint32 route_table,
|
||||
guint32 route_metric,
|
||||
gboolean force_commit,
|
||||
NMPlatformIP4Route *dst);
|
||||
|
||||
typedef enum {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue