l3cfg: various fixes for l3cfg

This commit is contained in:
Thomas Haller 2020-09-19 12:20:45 +02:00
parent d627ec7075
commit 042112ea2d
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
5 changed files with 246 additions and 149 deletions

View file

@ -2967,12 +2967,7 @@ _dev_l3_platform_commit (NMDevice *self)
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);
success = nm_l3cfg_platform_commit (priv->l3cfg, NM_L3_CFG_COMMIT_TYPE_AUTO);
return success;
}
@ -2993,11 +2988,16 @@ _dev_l3_cfg_notify_cb (NML3Cfg *l3cfg,
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;
case NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED: {
const NML3ConfigNotifyPayloadAcdFailedSource *sources = payload->acd_completed.sources;
guint sources_len = payload->acd_completed.sources_len;
guint i;
if (payload->acd_completed.probe_result) {
/* FIXME(l3cfg) */
return;
}
for (i = 0; i < sources_len; i++) {
L3ConfigDataType l3cd_type = _dev_l3_config_data_tag_to_type (self, sources[i].tag);
@ -3011,7 +3011,7 @@ _dev_l3_cfg_notify_cb (NML3Cfg *l3cfg,
_dev_l3_cfg_acd_maybe_comlete (self);
return;
}
case NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED:
case NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT:
_dev_l3_cfg_acd_maybe_comlete (self);
return;
case NM_L3_CONFIG_NOTIFY_TYPE_NOTIFY_PLATFORM_CHANGE_ON_IDLE:

View file

@ -683,7 +683,7 @@ nm_l3_config_data_new (NMDedupMultiIndex *multi_idx,
};
_idx_type_init (&self->idx_addresses_4, NMP_OBJECT_TYPE_IP4_ADDRESS);
_idx_type_init (&self->idx_addresses_6, NMP_OBJECT_TYPE_IP4_ADDRESS);
_idx_type_init (&self->idx_addresses_6, NMP_OBJECT_TYPE_IP6_ADDRESS);
_idx_type_init (&self->idx_routes_4, NMP_OBJECT_TYPE_IP4_ROUTE);
_idx_type_init (&self->idx_routes_6, NMP_OBJECT_TYPE_IP6_ROUTE);
@ -1859,7 +1859,7 @@ _dedup_multi_index_cmp (const NML3ConfigData *a,
have_a = nm_platform_dedup_multi_iter_next_obj (&iter_a, &obj_a, obj_type);
if (!have_a) {
nm_assert (!nm_platform_dedup_multi_iter_next_obj (&iter_b, &obj_b, obj_type));
break;
return 0;
}
have_b = nm_platform_dedup_multi_iter_next_obj (&iter_b, &obj_b, obj_type);
@ -1867,8 +1867,6 @@ _dedup_multi_index_cmp (const NML3ConfigData *a,
NM_CMP_RETURN (nmp_object_cmp (obj_a, obj_b));
}
return 0;
}
int
@ -1882,10 +1880,10 @@ nm_l3_config_data_cmp (const NML3ConfigData *a, const NML3ConfigData *b)
NM_CMP_DIRECT (a->flags, b->flags);
_dedup_multi_index_cmp (a, b, NMP_OBJECT_TYPE_IP4_ADDRESS);
_dedup_multi_index_cmp (a, b, NMP_OBJECT_TYPE_IP6_ADDRESS);
_dedup_multi_index_cmp (a, b, NMP_OBJECT_TYPE_IP4_ROUTE);
_dedup_multi_index_cmp (a, b, NMP_OBJECT_TYPE_IP6_ROUTE);
NM_CMP_RETURN (_dedup_multi_index_cmp (a, b, NMP_OBJECT_TYPE_IP4_ADDRESS));
NM_CMP_RETURN (_dedup_multi_index_cmp (a, b, NMP_OBJECT_TYPE_IP6_ADDRESS));
NM_CMP_RETURN (_dedup_multi_index_cmp (a, b, NMP_OBJECT_TYPE_IP4_ROUTE));
NM_CMP_RETURN (_dedup_multi_index_cmp (a, b, NMP_OBJECT_TYPE_IP6_ROUTE));
for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) {
const int addr_family = IS_IPv4 ? AF_INET : AF_INET6;
@ -2705,17 +2703,20 @@ nm_l3_config_data_merge (NML3ConfigData *self,
if (self->ip6_privacy == NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN)
self->ip6_privacy = src->ip6_privacy;
if (!self->ndisc_hop_limit_set) {
if ( !self->ndisc_hop_limit_set
&& src->ndisc_hop_limit_set) {
self->ndisc_hop_limit_set = TRUE;
self->ndisc_hop_limit_val = src->ndisc_hop_limit_val;
}
if (!self->ndisc_reachable_time_msec_set) {
if ( !self->ndisc_reachable_time_msec_set
&& src->ndisc_reachable_time_msec_set) {
self->ndisc_reachable_time_msec_set = TRUE;
self->ndisc_reachable_time_msec_val = src->ndisc_reachable_time_msec_val;
}
if (!self->ndisc_retrans_timer_msec_set) {
if ( !self->ndisc_retrans_timer_msec_set
&& src->ndisc_retrans_timer_msec_set) {
self->ndisc_retrans_timer_msec_set = TRUE;
self->ndisc_retrans_timer_msec_val = src->ndisc_retrans_timer_msec_val;
}

View file

@ -29,7 +29,7 @@ ACD_ADDR_SKIP (in_addr_t addr)
return addr == 0u;
}
#define ACD_TRACK_FMT "["NM_HASH_OBFUSCATE_PTR_FMT","NM_HASH_OBFUSCATE_PTR_FMT","NM_HASH_OBFUSCATE_PTR_FMT"]"
#define ACD_TRACK_FMT "[l3cd="NM_HASH_OBFUSCATE_PTR_FMT",obj="NM_HASH_OBFUSCATE_PTR_FMT",tag="NM_HASH_OBFUSCATE_PTR_FMT"]"
#define ACD_TRACK_PTR2(l3cd, obj, tag) NM_HASH_OBFUSCATE_PTR (l3cd), NM_HASH_OBFUSCATE_PTR (obj), NM_HASH_OBFUSCATE_PTR (tag)
#define ACD_TRACK_PTR(acd_track) ACD_TRACK_PTR2 ((acd_track)->l3cd, (acd_track)->obj, (acd_track)->tag)
@ -74,6 +74,7 @@ typedef struct {
guint32 probing_timeout_msec;
CList acd_lst;
CList acd_notify_complete_lst;
CList acd_track_lst_head;
NML3Cfg *self;
@ -94,6 +95,8 @@ typedef struct {
bool probe_result:1;
bool announcing_failed_is_retrying:1;
bool initializing:1;
} AcdData;
struct _NML3CfgCommitTypeHandle {
@ -151,6 +154,8 @@ typedef struct _NML3CfgPrivate {
GHashTable *acd_lst_hash;
CList acd_lst_head;
CList acd_notify_complete_lst_head;
NAcd *nacd;
GSource *nacd_source;
@ -179,6 +184,8 @@ typedef struct _NML3CfgPrivate {
guint routes_temporary_not_available_id;
bool commit_type_update_sticky:1;
bool acd_is_pending:1;
bool acd_is_announcing:1;
@ -219,6 +226,8 @@ G_DEFINE_TYPE (NML3Cfg, nm_l3cfg, G_TYPE_OBJECT)
static void _property_emit_notify (NML3Cfg *self, NML3CfgPropertyEmitType emit_type);
static void _l3_acd_data_notify_acd_completed_all (NML3Cfg *self);
static gboolean _acd_has_valid_link (const NMPObject *obj,
const guint8 **out_addr_bin,
gboolean *out_acd_not_supported);
@ -249,21 +258,70 @@ NM_UTILS_ENUM2STR_DEFINE (_l3_cfg_commit_type_to_string, NML3CfgCommitType,
NM_UTILS_ENUM2STR (NM_L3_CFG_COMMIT_TYPE_REAPPLY, "reapply"),
);
static
NM_UTILS_ENUM2STR_DEFINE (_l3_config_notify_type_to_string, NML3ConfigNotifyType,
NM_UTILS_ENUM2STR (NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED, "acd-complete"),
NM_UTILS_ENUM2STR (NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE, "platform-change-on-idle"),
NM_UTILS_ENUM2STR (NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT, "post-commit"),
NM_UTILS_ENUM2STR (NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED, "routes-temporary-not-available-expired"),
NM_UTILS_ENUM2STR_IGNORE (_NM_L3_CONFIG_NOTIFY_TYPE_NUM),
);
/*****************************************************************************/
static void
_l3cfg_emit_signal_notify (NML3Cfg *self,
NML3ConfigNotifyType notify_type,
const NML3ConfigNotifyPayload *pay_load)
static const char *
_l3_config_notify_type_and_payload_to_string (NML3ConfigNotifyType notify_type,
const NML3ConfigNotifyPayload *payload,
char *sbuf,
gsize sbuf_size)
{
char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN];
char *s = sbuf;
gsize l = sbuf_size;
nm_assert (sbuf);
nm_assert (sbuf_size > 0);
_l3_config_notify_type_to_string (notify_type, s, l);
nm_utils_strbuf_seek_end (&s, &l);
switch (notify_type) {
case NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED:
nm_utils_strbuf_append (&s, &l, ", addr=%s, probe-result=%d",
_nm_utils_inet4_ntop (payload->acd_completed.addr, sbuf_addr),
(int) payload->acd_completed.probe_result);
break;
case NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE:
nm_utils_strbuf_append (&s, &l, ", obj-type-flags=0x%x",
payload->platform_change_on_idle.obj_type_flags);
break;
default:
break;
}
return sbuf;
}
void
_nm_l3cfg_emit_signal_notify (NML3Cfg *self,
NML3ConfigNotifyType notify_type,
const NML3ConfigNotifyPayload *payload)
{
char sbuf[100];
nm_assert (_NM_INT_NOT_NEGATIVE (notify_type));
nm_assert (notify_type < _NM_L3_CONFIG_NOTIFY_TYPE_NUM);
nm_assert ((!!payload) == NM_IN_SET (notify_type, NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED,
NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE));
_LOGT ("emit signal (%s)",
_l3_config_notify_type_and_payload_to_string (notify_type, payload, sbuf, sizeof (sbuf)));
g_signal_emit (self,
signals[SIGNAL_NOTIFY],
0,
(int) notify_type,
pay_load);
payload);
}
/*****************************************************************************/
@ -271,6 +329,7 @@ _l3cfg_emit_signal_notify (NML3Cfg *self,
static void
_l3_changed_configs_set_dirty (NML3Cfg *self)
{
_LOGT ("configuration changed");
self->priv.changed_configs = TRUE;
}
@ -378,49 +437,17 @@ _l3cfg_externally_removed_objs_counter (NML3Cfg *self,
}
static void
_l3cfg_externally_removed_objs_drop (NML3Cfg *self,
int addr_family)
_l3cfg_externally_removed_objs_drop (NML3Cfg *self)
{
const gboolean IS_IPv4 = NM_IS_IPv4 (addr_family);
GHashTableIter iter;
const NMPObject *obj;
nm_assert (NM_IS_L3CFG (self));
nm_assert (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET, AF_INET6));
if (addr_family == AF_UNSPEC) {
self->priv.p->externally_removed_objs_cnt_addresses_4 = 0;
self->priv.p->externally_removed_objs_cnt_addresses_6 = 0;
self->priv.p->externally_removed_objs_cnt_routes_4 = 0;
self->priv.p->externally_removed_objs_cnt_routes_6 = 0;
if (g_hash_table_size (self->priv.p->externally_removed_objs_hash) > 0)
_LOGD ("externally-removed: untrack all");
nm_clear_pointer (&self->priv.p->externally_removed_objs_hash, g_hash_table_unref);
return;
}
if ( self->priv.p->externally_removed_objs_cnt_addresses_x[IS_IPv4] == 0
&& self->priv.p->externally_removed_objs_cnt_routes_x[IS_IPv4] == 0)
return;
_LOGD ("externally-removed: untrack IPv%c",
nm_utils_addr_family_to_char (addr_family));
g_hash_table_iter_init (&iter, self->priv.p->externally_removed_objs_hash);
while (g_hash_table_iter_next (&iter, (gpointer *) &obj, NULL)) {
nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ADDRESS,
NMP_OBJECT_TYPE_IP6_ADDRESS,
NMP_OBJECT_TYPE_IP4_ROUTE,
NMP_OBJECT_TYPE_IP6_ROUTE));
if (NMP_OBJECT_GET_ADDR_FAMILY (obj) != addr_family)
g_hash_table_iter_remove (&iter);
}
self->priv.p->externally_removed_objs_cnt_addresses_x[IS_IPv4] = 0;
self->priv.p->externally_removed_objs_cnt_routes_x[IS_IPv4] = 0;
if ( self->priv.p->externally_removed_objs_cnt_addresses_x[!IS_IPv4] == 0
&& self->priv.p->externally_removed_objs_cnt_routes_x[!IS_IPv4] == 0)
nm_clear_pointer (&self->priv.p->externally_removed_objs_hash, g_hash_table_unref);
self->priv.p->externally_removed_objs_cnt_addresses_4 = 0;
self->priv.p->externally_removed_objs_cnt_addresses_6 = 0;
self->priv.p->externally_removed_objs_cnt_routes_4 = 0;
self->priv.p->externally_removed_objs_cnt_routes_6 = 0;
if (nm_g_hash_table_size (self->priv.p->externally_removed_objs_hash) > 0)
_LOGD ("externally-removed: untrack all");
nm_clear_pointer (&self->priv.p->externally_removed_objs_hash, g_hash_table_unref);
}
static void
@ -436,7 +463,7 @@ _l3cfg_externally_removed_objs_drop_unused (NML3Cfg *self)
return;
if (!self->priv.p->combined_l3cd_commited) {
_l3cfg_externally_removed_objs_drop (self, AF_UNSPEC);
_l3cfg_externally_removed_objs_drop (self);
return;
}
@ -482,8 +509,8 @@ _l3cfg_externally_removed_objs_track (NML3Cfg *self,
return;
}
if (!nm_l3_config_data_lookup_route_obj (self->priv.p->combined_l3cd_commited,
obj)) {
if (!nm_l3_config_data_lookup_obj (self->priv.p->combined_l3cd_commited,
obj)) {
/* we don't care about this object, so there is nothing to hide hide */
return;
}
@ -630,9 +657,11 @@ _nm_l3cfg_notify_platform_change_on_idle (NML3Cfg *self, guint32 obj_type_flags)
.obj_type_flags = obj_type_flags,
},
};
_l3cfg_emit_signal_notify (self,
NM_L3_CONFIG_NOTIFY_TYPE_NOTIFY_PLATFORM_CHANGE_ON_IDLE,
&payload);
_nm_l3cfg_emit_signal_notify (self,
NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE,
&payload);
_l3_acd_data_notify_acd_completed_all (self);
if (NM_FLAGS_ANY (obj_type_flags, nmp_object_type_to_flags (NMP_OBJECT_TYPE_IP4_ROUTE)))
_property_emit_notify (self, NM_L3CFG_PROPERTY_EMIT_TYPE_IP4_ROUTE);
@ -909,11 +938,8 @@ _l3_acd_platform_commit_acd_update (NML3Cfg *self)
*
* This makes the mechanism also suitable for internally triggering a commit when ACD completes. */
_LOGT ("acd: acd update now");
_l3_changed_configs_set_dirty (self);
nm_l3cfg_platform_commit (self,
NM_L3_CFG_COMMIT_TYPE_AUTO,
AF_INET,
NULL);
NM_L3_CFG_COMMIT_TYPE_AUTO);
}
static gboolean
@ -950,6 +976,7 @@ _l3_acd_nacd_event (int fd,
gpointer user_data)
{
NML3Cfg *self = user_data;
gboolean success = FALSE;
int r;
nm_assert (NM_IS_L3CFG (self));
@ -958,7 +985,7 @@ _l3_acd_nacd_event (int fd,
r = n_acd_dispatch (self->priv.p->nacd);
if (!NM_IN_SET (r, 0, N_ACD_E_PREEMPTED)) {
_LOGT ("acd: dispatch failed with error %d", r);
goto handle_failure;
goto out;
}
while (TRUE) {
@ -968,10 +995,12 @@ _l3_acd_nacd_event (int fd,
r = n_acd_pop_event (self->priv.p->nacd, &event);
if (r) {
_LOGT ("acd: pop-event failed with error %d", r);
goto handle_failure;
goto out;
}
if (!event) {
success = TRUE;
goto out;
}
if (!event)
return G_SOURCE_CONTINUE;
#define _acd_event_payload used
G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NAcdEvent, _acd_event_payload) == G_STRUCT_OFFSET (NAcdEvent, defended));
@ -1040,10 +1069,15 @@ _l3_acd_nacd_event (int fd,
nm_assert_not_reached ();
handle_failure:
/* Something is seriously wrong with our nacd instance. We handle that by resetting the
* ACD instance. */
_l3_acd_nacd_instance_reset (self, NM_TERNARY_TRUE, TRUE);
out:
if (!success) {
/* Something is seriously wrong with our nacd instance. We handle that by resetting the
* ACD instance. */
_l3_acd_nacd_instance_reset (self, NM_TERNARY_TRUE, TRUE);
}
_l3_acd_data_notify_acd_completed_all (self);
return G_SOURCE_CONTINUE;
}
@ -1054,6 +1088,7 @@ _l3_acd_nacd_instance_ensure_retry_cb (gpointer user_data)
nm_clear_g_source_inst (&self->priv.p->nacd_instance_ensure_retry);
_l3_changed_configs_set_dirty (self);
_l3_acd_platform_commit_acd_update (self);
return G_SOURCE_REMOVE;
@ -1294,12 +1329,14 @@ _l3_acd_data_add (NML3Cfg *self,
acd_data = g_slice_new (AcdData);
*acd_data = (AcdData) {
.self = self,
.addr = addr,
.acd_track_lst_head = C_LIST_INIT (acd_data->acd_track_lst_head),
.acd_state = ACD_STATE_INIT,
.probing_timestamp_msec = 0,
.probe_result = FALSE,
.self = self,
.addr = addr,
.acd_track_lst_head = C_LIST_INIT (acd_data->acd_track_lst_head),
.acd_notify_complete_lst = C_LIST_INIT (acd_data->acd_notify_complete_lst),
.acd_state = ACD_STATE_INIT,
.probing_timestamp_msec = 0,
.probe_result = FALSE,
.initializing = TRUE,
};
c_list_link_tail (&self->priv.p->acd_lst_head, &acd_data->acd_lst);
if (!g_hash_table_add (self->priv.p->acd_lst_hash, acd_data))
@ -1480,9 +1517,9 @@ _l3_acd_data_timeout_schedule_announce_restart (AcdData *acd_data,
}
static void
_l3_acd_data_notify_acd_failed (NML3Cfg *self,
AcdData *acd_data,
gboolean force_all)
_l3_acd_data_notify_acd_completed (NML3Cfg *self,
AcdData *acd_data,
gboolean force_all)
{
gs_free NML3ConfigNotifyPayloadAcdFailedSource *sources_free = NULL;
NML3ConfigNotifyPayloadAcdFailedSource *sources = NULL;
@ -1533,14 +1570,17 @@ _l3_acd_data_notify_acd_failed (NML3Cfg *self,
nm_assert (i == n);
payload = (NML3ConfigNotifyPayload) {
.acd_failed = {
.addr = acd_data->addr,
.sources_len = n,
.sources = sources,
.acd_completed = {
.addr = acd_data->addr,
.probe_result = acd_data->probe_result,
.sources_len = n,
.sources = sources,
},
};
_l3cfg_emit_signal_notify (self, NM_L3_CONFIG_NOTIFY_TYPE_ACD_FAILED, &payload);
_nm_l3cfg_emit_signal_notify (self,
NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED,
&payload);
for (i = 0; i < n; i++) {
nmp_object_unref (sources[i].obj);
@ -1548,6 +1588,30 @@ _l3_acd_data_notify_acd_failed (NML3Cfg *self,
}
}
static void
_l3_acd_data_notify_acd_completed_queue (NML3Cfg *self, AcdData *acd_data)
{
if (!c_list_is_empty (&acd_data->acd_notify_complete_lst)) {
nm_assert (c_list_contains (&self->priv.p->acd_notify_complete_lst_head, &acd_data->acd_notify_complete_lst));
return;
}
c_list_link_tail (&self->priv.p->acd_notify_complete_lst_head, &acd_data->acd_notify_complete_lst);
}
static void
_l3_acd_data_notify_acd_completed_all (NML3Cfg *self)
{
gs_unref_object NML3Cfg *self_keep_alive = NULL;
AcdData *acd_data;
while ((acd_data = c_list_first_entry (&self->priv.p->acd_notify_complete_lst_head, AcdData, acd_notify_complete_lst))) {
if (!self_keep_alive)
self_keep_alive = g_object_ref (self);
c_list_unlink (&acd_data->acd_notify_complete_lst);
_l3_acd_data_notify_acd_completed (self, acd_data, TRUE);
}
}
static void
_l3_acd_data_state_change (NML3Cfg *self,
AcdData *acd_data,
@ -1634,14 +1698,12 @@ _l3_acd_data_state_change (NML3Cfg *self,
* ACD_STATE_PROBE_DONE and configure the address right away. This avoids
* that we go through another hop.
*/
_LOGT_acd (acd_data,
"state: probe-done good (ACD disabled by configuration from the start)");
acd_data->acd_state = ACD_STATE_PROBE_DONE;
acd_data->probe_result = TRUE;
return;
log_reason = "ACD disabled by configuration from the start";
goto handle_probing_acd_good;
}
case ACD_STATE_CHANGE_MODE_POST_COMMIT:
acd_data->initializing = FALSE;
goto handle_post_commit;
case ACD_STATE_CHANGE_MODE_TIMEOUT: {
@ -1865,6 +1927,7 @@ _l3_acd_data_state_change (NML3Cfg *self,
return;
case ACD_STATE_CHANGE_MODE_INSTANCE_RESET:
nm_utils_get_monotonic_timestamp_msec_cached (&now_msec);
if (acd_data->acd_state <= ACD_STATE_PROBING) {
nm_assert (acd_data->acd_state == ACD_STATE_PROBING);
@ -1890,7 +1953,7 @@ _l3_acd_data_state_change (NML3Cfg *self,
acd_data->nacd_probe = n_acd_probe_free (acd_data->nacd_probe);
acd_data->acd_state = ACD_STATE_PROBE_DONE;
_l3_acd_data_timeout_schedule (acd_data, now_msec, now_msec, TRUE);
break;
return;
}
nm_assert_not_reached ();
@ -2045,7 +2108,7 @@ handle_probing_acd_good:
switch (acd_data->acd_state) {
case ACD_STATE_INIT:
_LOGT_acd (acd_data,
"state: probe-done good (%s, inializingbcwin)",
"state: probe-done good (%s, initializing)",
log_reason);
acd_data->acd_state = ACD_STATE_PROBE_DONE;
acd_data->probe_result = TRUE;
@ -2080,7 +2143,7 @@ handle_probe_done:
nm_assert (NM_IN_SET (acd_data->acd_state, ACD_STATE_PROBE_DONE,
ACD_STATE_ANNOUNCING));
if (state_change_mode == ACD_STATE_CHANGE_MODE_INIT)
if (acd_data->initializing)
return;
if (acd_data->acd_state >= ACD_STATE_ANNOUNCING) {
@ -2100,7 +2163,7 @@ handle_probe_done:
acd_data->probing_timestamp_msec = nm_utils_get_monotonic_timestamp_msec_cached (&now_msec);
_l3_acd_data_timeout_schedule_probing_full_restart (acd_data, now_msec);
}
_l3_acd_data_notify_acd_failed (self, acd_data, was_probing);
_l3_acd_data_notify_acd_completed_queue (self, acd_data);
return;
}
@ -2109,8 +2172,10 @@ handle_probe_done:
/* probing just completed. Schedule handling the change. */
_LOGT_acd (acd_data,
"state: acd probe succeed");
_l3_acd_data_notify_acd_completed_queue (self, acd_data);
if (!self->priv.p->acd_ready_on_idle_source) {
_l3_changed_configs_set_dirty (self);
if (state_change_mode != ACD_STATE_CHANGE_MODE_POST_COMMIT)
_l3_changed_configs_set_dirty (self);
self->priv.p->acd_ready_on_idle_source = nm_g_idle_source_new (G_PRIORITY_DEFAULT,
_l3_acd_ready_on_idle_cb,
self,
@ -2187,6 +2252,8 @@ _l3_acd_data_process_changes (NML3Cfg *self)
if ( !acd_is_pending
&& !acd_is_announcing)
_l3_acd_nacd_instance_reset (self, NM_TERNARY_DEFAULT, FALSE);
_l3_acd_data_notify_acd_completed_all (self);
}
/*****************************************************************************/
@ -2359,7 +2426,8 @@ nm_l3cfg_add_config (NML3Cfg *self,
tag,
replace_same_tag ? NULL : l3cd);
if (replace_same_tag) {
if ( replace_same_tag
&& idx >= 0) {
gssize idx2;
idx2 = idx;
@ -2663,7 +2731,7 @@ _routes_temporary_not_available_timeout (gpointer user_data)
if (any_expired) {
/* a route expired. We emit a signal, but we don't schedule it again. That will
* only happen if the user calls nm_l3cfg_platform_commit() again. */
_l3cfg_emit_signal_notify (self, NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED, NULL);
_nm_l3cfg_emit_signal_notify (self, NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED, NULL);
return G_SOURCE_REMOVE;
}
@ -2921,48 +2989,65 @@ _platform_commit (NML3Cfg *self,
gboolean
nm_l3cfg_platform_commit (NML3Cfg *self,
NML3CfgCommitType commit_type,
int addr_family,
gboolean *out_final_failure_for_temporary_not_available)
NML3CfgCommitType commit_type)
{
gboolean commit_type_detected = FALSE;
gboolean success = TRUE;
gboolean acd_was_pending;
char sbuf_ct[30];
g_return_val_if_fail (NM_IS_L3CFG (self), FALSE);
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_assert (NM_IN_SET (commit_type, NM_L3_CFG_COMMIT_TYPE_NONE,
NM_L3_CFG_COMMIT_TYPE_AUTO,
NM_L3_CFG_COMMIT_TYPE_ASSUME,
NM_L3_CFG_COMMIT_TYPE_UPDATE,
NM_L3_CFG_COMMIT_TYPE_ASSUME));
NM_L3_CFG_COMMIT_TYPE_REAPPLY));
NM_SET_OUT (out_final_failure_for_temporary_not_available, FALSE);
acd_was_pending = self->priv.p->acd_is_pending;
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)
switch (commit_type) {
case NM_L3_CFG_COMMIT_TYPE_AUTO:
/* if in "AUTO" mode we currently have commit-type "UPDATE", that
* causes also the following update to still be "UPDATE". Either
* the same commit */
commit_type_detected = TRUE;
commit_type = nm_l3cfg_commit_type_get (self);
if (commit_type == NM_L3_CFG_COMMIT_TYPE_UPDATE)
self->priv.p->commit_type_update_sticky = TRUE;
else if (self->priv.p->commit_type_update_sticky) {
self->priv.p->commit_type_update_sticky = FALSE;
commit_type = NM_L3_CFG_COMMIT_TYPE_UPDATE;
}
break;
case NM_L3_CFG_COMMIT_TYPE_ASSUME:
break;
case NM_L3_CFG_COMMIT_TYPE_REAPPLY:
case NM_L3_CFG_COMMIT_TYPE_UPDATE:
self->priv.p->commit_type_update_sticky = FALSE;
break;
case NM_L3_CFG_COMMIT_TYPE_NONE:
break;
}
_LOGT ("platform-commit %s%s",
_l3_cfg_commit_type_to_string (commit_type, sbuf_ct, sizeof (sbuf_ct)),
commit_type_detected ? " (auto)" : "");
if (commit_type == NM_L3_CFG_COMMIT_TYPE_NONE)
return TRUE;
nm_clear_g_source_inst (&self->priv.p->acd_ready_on_idle_source);
if (commit_type == NM_L3_CFG_COMMIT_TYPE_REAPPLY)
_l3cfg_externally_removed_objs_drop (self, addr_family);
_l3cfg_externally_removed_objs_drop (self);
if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET)) {
if (!_platform_commit (self, AF_INET, commit_type, out_final_failure_for_temporary_not_available))
success = FALSE;
}
if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET6)) {
if (!_platform_commit (self, AF_INET6, commit_type, out_final_failure_for_temporary_not_available))
success = FALSE;
}
/* FIXME(l3cfg): handle items currently not configurable in kernel. */
if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET))
_l3_acd_data_process_changes (self);
if (!_platform_commit (self, AF_INET, commit_type, NULL))
success = FALSE;
if (!_platform_commit (self, AF_INET6, commit_type, NULL))
success = FALSE;
if ( acd_was_pending
&& !self->priv.p->acd_is_pending)
_l3cfg_emit_signal_notify (self, NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED, NULL);
_l3_acd_data_process_changes (self);
_nm_l3cfg_emit_signal_notify (self, NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT, NULL);
return success;
}
@ -3009,8 +3094,7 @@ nm_l3cfg_commit_type_register (NML3Cfg *self,
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_L3_CFG_COMMIT_TYPE_UPDATE));
nm_assert ( !existing_handle
|| c_list_contains (&self->priv.p->commit_type_lst_head, &existing_handle->commit_type_lst));
@ -3037,6 +3121,7 @@ nm_l3cfg_commit_type_register (NML3Cfg *self,
if (handle->commit_type >= h->commit_type) {
c_list_link_before (&self->priv.p->commit_type_lst_head, &handle->commit_type_lst);
linked = TRUE;
break;
}
}
if (!linked)
@ -3175,6 +3260,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->acd_notify_complete_lst_head);
c_list_init (&self->priv.p->commit_type_lst_head);
}
@ -3223,6 +3309,7 @@ finalize (GObject *object)
_l3_acd_data_prune (self, TRUE);
nm_assert (c_list_is_empty (&self->priv.p->acd_lst_head));
nm_assert (c_list_is_empty (&self->priv.p->acd_notify_complete_lst_head));
nm_assert (nm_g_hash_table_size (self->priv.p->acd_lst_hash) == 0);
nm_clear_pointer (&self->priv.p->acd_lst_hash, g_hash_table_unref);

View file

@ -20,14 +20,17 @@
typedef enum {
NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED,
NM_L3_CONFIG_NOTIFY_TYPE_ACD_FAILED,
NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED,
/* emitted at the end of nm_l3cfg_platform_commit(). */
NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT,
/* NML3Cfg hooks to the NMPlatform signals for link, addresses and routes.
* It re-emits the signal on an idle handler. The purpose is for something
* like NMDevice which is already subscribed to these signals, it can get the
* notifications without also subscribing directly to the platform. */
NM_L3_CONFIG_NOTIFY_TYPE_NOTIFY_PLATFORM_CHANGE_ON_IDLE,
NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE,
_NM_L3_CONFIG_NOTIFY_TYPE_NUM,
} NML3ConfigNotifyType;
@ -43,8 +46,9 @@ typedef struct {
struct {
in_addr_t addr;
guint sources_len;
bool probe_result:1;
const NML3ConfigNotifyPayloadAcdFailedSource *sources;
} acd_failed;
} acd_completed;
struct {
guint32 obj_type_flags;
@ -140,6 +144,12 @@ gboolean nm_l3cfg_get_acd_is_pending (NML3Cfg *self);
/*****************************************************************************/
void _nm_l3cfg_emit_signal_notify (NML3Cfg *self,
NML3ConfigNotifyType notify_type,
const NML3ConfigNotifyPayload *pay_load);
/*****************************************************************************/
typedef enum {
NM_L3CFG_PROPERTY_EMIT_TYPE_ANY,
NM_L3CFG_PROPERTY_EMIT_TYPE_IP4_ROUTE,
@ -212,9 +222,7 @@ typedef enum _nm_packed {
} NML3CfgCommitType;
gboolean nm_l3cfg_platform_commit (NML3Cfg *self,
NML3CfgCommitType commit_type,
int addr_family,
gboolean *out_final_failure_for_temporary_not_available);
NML3CfgCommitType commit_type);
/*****************************************************************************/

View file

@ -192,6 +192,7 @@ _platform_signal_on_idle_cb (gpointer user_data)
c_list_splice (&work_list, &priv->l3cfg_signal_pending_lst_head);
while ((l3cfg_data = c_list_first_entry (&work_list, L3CfgData, signal_pending_lst))) {
nm_assert (NM_IS_L3CFG (l3cfg_data->l3cfg));
c_list_unlink (&l3cfg_data->signal_pending_lst);
_nm_l3cfg_notify_platform_change_on_idle (l3cfg_data->l3cfg,
nm_steal_int (&l3cfg_data->signal_pending_flag));