diff options
| author | Jeremy Bicha <jeremy.bicha@canonical.com> | 2022-02-08 12:07:45 -0500 |
|---|---|---|
| committer | Jeremy Bicha <jeremy.bicha@canonical.com> | 2022-02-08 12:07:45 -0500 |
| commit | 7d8baf4ac0480a542f000c1201df85427a22332c (patch) | |
| tree | 66284d67f52a1544900b7d7e2ba527be1bcbd02e /src/core/nm-l3cfg.c | |
| parent | 88c227d90a6b7b388c5c85d72802a0ca8f05ed5c (diff) | |
New upstream version 1.35.90
Diffstat (limited to 'src/core/nm-l3cfg.c')
| -rw-r--r-- | src/core/nm-l3cfg.c | 575 |
1 files changed, 391 insertions, 184 deletions
diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c index aa56c13f..aed4cf05 100644 --- a/src/core/nm-l3cfg.c +++ b/src/core/nm-l3cfg.c @@ -15,6 +15,7 @@ #include "nm-netns.h" #include "n-acd/src/n-acd.h" #include "nm-l3-ipv4ll.h" +#include "nm-ip-config.h" /*****************************************************************************/ @@ -203,6 +204,7 @@ typedef struct { guint32 acd_timeout_msec_confdata; NML3AcdDefendType acd_defend_type_confdata : 3; bool dirty_confdata : 1; + gboolean force_commit_once : 1; } L3ConfigData; /*****************************************************************************/ @@ -240,12 +242,20 @@ typedef struct _NML3CfgPrivate { CList acd_event_notify_lst_head; - NAcd * nacd; + NAcd *nacd; GSource *nacd_source; GSource *nacd_event_down_source; gint64 nacd_event_down_ratelimited_until_msec; + union { + struct { + NMIPConfig *ipconfig_6; + NMIPConfig *ipconfig_4; + }; + NMIPConfig *ipconfig_x[2]; + }; + /* This is for rate-limiting the creation of nacd instance. */ GSource *nacd_instance_ensure_retry; @@ -332,17 +342,17 @@ static void _l3_commit(NML3Cfg *self, NML3CfgCommitType commit_type, gboolean is static void _nm_l3cfg_emit_signal_notify_acd_event_all(NML3Cfg *self); static gboolean _acd_has_valid_link(const NMPObject *obj, - const guint8 ** out_addr_bin, - gboolean * out_acd_not_supported); + const guint8 **out_addr_bin, + gboolean *out_acd_not_supported); static void _l3_acd_nacd_instance_reset(NML3Cfg *self, NMTernary start_timer, gboolean acd_data_notify); -static void _l3_acd_data_state_change(NML3Cfg * self, - AcdData * acd_data, +static void _l3_acd_data_state_change(NML3Cfg *self, + AcdData *acd_data, AcdStateChangeMode mode, const NMEtherAddr *sender, - gint64 * p_now_msec); + gint64 *p_now_msec); static AcdData *_l3_acd_data_find(NML3Cfg *self, in_addr_t addr); @@ -402,6 +412,73 @@ static NM_UTILS_LOOKUP_DEFINE(_l3_acd_addr_state_to_string, /*****************************************************************************/ +NMIPConfig * +nm_l3cfg_ipconfig_get(NML3Cfg *self, int addr_family) +{ + g_return_val_if_fail(NM_IS_L3CFG(self), NULL); + nm_assert_addr_family(addr_family); + + return self->priv.p->ipconfig_x[NM_IS_IPv4(addr_family)]; +} + +static void +_ipconfig_toggle_notify(gpointer data, GObject *object, gboolean is_last_ref) +{ + NML3Cfg *self = NM_L3CFG(data); + NMIPConfig *ipconfig = NM_IP_CONFIG(object); + + if (!is_last_ref) { + /* This happens while we take another ref below. Ignore the signal. */ + nm_assert(!NM_IN_SET(ipconfig, self->priv.p->ipconfig_4, self->priv.p->ipconfig_6)); + return; + } + + if (ipconfig == self->priv.p->ipconfig_4) + self->priv.p->ipconfig_4 = NULL; + else { + nm_assert(ipconfig == self->priv.p->ipconfig_6); + self->priv.p->ipconfig_6 = NULL; + } + + /* We take a second reference to keep the instance alive, while also removing the + * toggle ref. This will notify the function again, but we will ignore that. */ + g_object_ref(ipconfig); + + g_object_remove_toggle_ref(G_OBJECT(ipconfig), _ipconfig_toggle_notify, self); + + /* pass on the reference, and unexport on idle. */ + nm_ip_config_take_and_unexport_on_idle(g_steal_pointer(&ipconfig)); +} + +NMIPConfig * +nm_l3cfg_ipconfig_acquire(NML3Cfg *self, int addr_family) +{ + NMIPConfig *ipconfig; + + g_return_val_if_fail(NM_IS_L3CFG(self), NULL); + nm_assert_addr_family(addr_family); + + ipconfig = self->priv.p->ipconfig_x[NM_IS_IPv4(addr_family)]; + + if (ipconfig) + return g_object_ref(ipconfig); + + ipconfig = nm_ip_config_new(addr_family, self); + + self->priv.p->ipconfig_x[NM_IS_IPv4(addr_family)] = ipconfig; + + /* The ipconfig keeps self alive. We use a toggle reference + * to avoid a cycle. But we anyway wouldn't want a strong reference, + * because the user releases the instance by unrefing it, and we + * notice that via the weak reference. */ + g_object_add_toggle_ref(G_OBJECT(ipconfig), _ipconfig_toggle_notify, self); + + /* We keep the toggle reference, and return the other reference to the caller. */ + return g_steal_pointer(&ipconfig); +} + +/*****************************************************************************/ + gboolean nm_l3cfg_is_vrf(const NML3Cfg *self) { @@ -415,13 +492,13 @@ nm_l3cfg_is_vrf(const NML3Cfg *self) static const char * _l3_config_notify_data_to_string(const NML3ConfigNotifyData *notify_data, - char * sbuf, + char *sbuf, gsize sbuf_size) { char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; char sbuf100[100]; char sbufobf[NM_HASH_OBFUSCATE_PTR_STR_BUF_SIZE]; - char * s = sbuf; + char *s = sbuf; gsize l = sbuf_size; in_addr_t addr4; @@ -509,7 +586,7 @@ _nm_l3cfg_emit_signal_notify_simple(NML3Cfg *self, NML3ConfigNotifyType notify_t } static void -_nm_l3cfg_emit_signal_notify_l3cd_changed(NML3Cfg * self, +_nm_l3cfg_emit_signal_notify_l3cd_changed(NML3Cfg *self, const NML3ConfigData *l3cd_old, const NML3ConfigData *l3cd_new, gboolean commited) @@ -538,7 +615,7 @@ _l3_changed_configs_set_dirty(NML3Cfg *self) /*****************************************************************************/ static void -_l3_acd_ipv4_addresses_on_link_update(NML3Cfg * self, +_l3_acd_ipv4_addresses_on_link_update(NML3Cfg *self, in_addr_t addr, gboolean add /* or else remove */) { @@ -596,7 +673,7 @@ static NAcdProbe * _nm_n_acd_data_probe_new(NML3Cfg *self, in_addr_t addr, guint32 timeout_msec, gpointer user_data) { nm_auto(n_acd_probe_config_freep) NAcdProbeConfig *probe_config = NULL; - NAcdProbe * probe; + NAcdProbe *probe; int r; nm_assert(self); @@ -628,7 +705,7 @@ _nm_n_acd_data_probe_new(NML3Cfg *self, in_addr_t addr, guint32 timeout_msec, gp G_STMT_START \ { \ if (NM_MORE_ASSERTS > 0) { \ - const NML3Cfg * _self = (self); \ + const NML3Cfg *_self = (self); \ const ObjStateData *_obj_state = (obj_state); \ \ nm_assert(_obj_state); \ @@ -866,7 +943,7 @@ _obj_states_update_all(NML3Cfg *self) for (i = 0; i < (int) G_N_ELEMENTS(obj_types); i++) { const NMPObjectType obj_type = obj_types[i]; NMDedupMultiIter o_iter; - const NMPObject * obj; + const NMPObject *obj; if (!self->priv.p->combined_l3cd_commited) continue; @@ -926,7 +1003,7 @@ _obj_states_update_all(NML3Cfg *self) } typedef struct { - NML3Cfg * self; + NML3Cfg *self; NML3CfgCommitType commit_type; } ObjStatesSyncFilterData; @@ -934,13 +1011,15 @@ static gboolean _obj_states_sync_filter(/* const NMDedupMultiObj * */ gconstpointer o, gpointer user_data) { char sbuf[sizeof(_nm_utils_to_string_buffer)]; - const NMPObject * obj = o; + const NMPObject *obj = o; const ObjStatesSyncFilterData *sync_filter_data = user_data; NMPObjectType obj_type; - ObjStateData * obj_state; + ObjStateData *obj_state; + NML3Cfg *self; nm_assert(sync_filter_data); nm_assert(NM_IS_L3CFG(sync_filter_data->self)); + self = sync_filter_data->self; obj_type = NMP_OBJECT_GET_TYPE(obj); @@ -955,15 +1034,12 @@ _obj_states_sync_filter(/* const NMDedupMultiObj * */ gconstpointer o, gpointer nm_assert(c_list_is_empty(&obj_state->os_zombie_lst)); if (!obj_state->os_nm_configured) { - NML3Cfg *self; - if (sync_filter_data->commit_type == NM_L3_CFG_COMMIT_TYPE_ASSUME && !_obj_state_data_get_assume_config_once(obj_state)) return FALSE; obj_state->os_nm_configured = TRUE; - self = sync_filter_data->self; _LOGD("obj-state: configure-first-time: %s", _obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf))); return TRUE; @@ -975,14 +1051,15 @@ _obj_states_sync_filter(/* const NMDedupMultiObj * */ gconstpointer o, gpointer return TRUE; } - if (!obj_state->os_plobj && sync_filter_data->commit_type != NM_L3_CFG_COMMIT_TYPE_REAPPLY) + if (!obj_state->os_plobj && sync_filter_data->commit_type != NM_L3_CFG_COMMIT_TYPE_REAPPLY + && !nmp_object_get_force_commit(obj)) return FALSE; return TRUE; } static void -_obj_state_zombie_lst_get_prune_lists(NML3Cfg * self, +_obj_state_zombie_lst_get_prune_lists(NML3Cfg *self, int addr_family, GPtrArray **out_addresses_prune, GPtrArray **out_routes_prune) @@ -991,8 +1068,8 @@ _obj_state_zombie_lst_get_prune_lists(NML3Cfg * self, const NMPObjectType obj_type_route = NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4); const NMPObjectType obj_type_address = NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4); char sbuf[sizeof(_nm_utils_to_string_buffer)]; - ObjStateData * obj_state; - ObjStateData * obj_state_safe; + ObjStateData *obj_state; + ObjStateData *obj_state_safe; nm_assert(NM_IS_L3CFG(self)); nm_assert(out_addresses_prune && !*out_addresses_prune); @@ -1003,7 +1080,7 @@ _obj_state_zombie_lst_get_prune_lists(NML3Cfg * self, &self->priv.p->obj_state_zombie_lst_head, os_zombie_lst) { NMPObjectType obj_type; - GPtrArray ** p_a; + GPtrArray **p_a; nm_assert_obj_state(self, obj_state); nm_assert(obj_state->os_zombie_count > 0); @@ -1073,16 +1150,16 @@ static void _load_link(NML3Cfg *self, gboolean initial) { nm_auto_nmpobj const NMPObject *obj_old = NULL; - const NMPObject * obj; - const char * ifname; - const char * ifname_old; + const NMPObject *obj; + const char *ifname; + const char *ifname_old; gboolean nacd_changed; gboolean nacd_new_valid; gboolean nacd_old_valid; - const guint8 * nacd_old_addr = NULL; - const guint8 * nacd_new_addr = NULL; + const guint8 *nacd_old_addr = NULL; + const guint8 *nacd_new_addr = NULL; gboolean nacd_link_now_up; - AcdData * acd_data; + AcdData *acd_data; if (initial) { obj = nm_platform_link_get_obj(self->priv.platform, self->priv.ifindex, TRUE); @@ -1172,9 +1249,9 @@ _nm_l3cfg_notify_platform_change_on_idle(NML3Cfg *self, guint32 obj_type_flags) } void -_nm_l3cfg_notify_platform_change(NML3Cfg * self, +_nm_l3cfg_notify_platform_change(NML3Cfg *self, NMPlatformSignalChangeType change_type, - const NMPObject * obj) + const NMPObject *obj) { NML3ConfigNotifyData notify_data; NMPObjectType obj_type; @@ -1247,9 +1324,9 @@ _acd_data_free(AcdData *acd_data) } static guint -_acd_data_collect_tracks_data(const AcdData * acd_data, +_acd_data_collect_tracks_data(const AcdData *acd_data, NMTernary dirty_selector, - guint32 * out_best_acd_timeout_msec, + guint32 *out_best_acd_timeout_msec, NML3AcdDefendType *out_best_acd_defend_type) { NML3AcdDefendType best_acd_defend_type = _NM_L3_ACD_DEFEND_TYPE_NONE; @@ -1257,6 +1334,15 @@ _acd_data_collect_tracks_data(const AcdData * acd_data, guint n = 0; guint i; + /* We do a simple search over all track-infos for the best, which determines + * our ACD state. That is, we prefer ACD disabled, and otherwise the + * shortest configured timeout. + * + * This linear search is probably fast enough, because we expect that each + * address/acd_data has few trackers. + * The alternative would be caching the best result, but that is more complicated, + * so not done. */ + for (i = 0; i < acd_data->info.n_track_infos; i++) { const NML3AcdAddrTrackInfo *acd_track = &acd_data->info.track_infos[i]; @@ -1280,9 +1366,9 @@ _acd_data_collect_tracks_data(const AcdData * acd_data, } static NML3AcdAddrTrackInfo * -_acd_data_find_track(const AcdData * acd_data, +_acd_data_find_track(const AcdData *acd_data, const NML3ConfigData *l3cd, - const NMPObject * obj, + const NMPObject *obj, gconstpointer tag) { guint i; @@ -1301,11 +1387,11 @@ _acd_data_find_track(const AcdData * acd_data, static gboolean _acd_has_valid_link(const NMPObject *obj, - const guint8 ** out_addr_bin, - gboolean * out_acd_not_supported) + const guint8 **out_addr_bin, + gboolean *out_acd_not_supported) { const NMPlatformLink *link; - const guint8 * addr_bin; + const guint8 *addr_bin; gsize addr_len; if (!obj) { @@ -1360,8 +1446,8 @@ _l3_acd_nacd_event(int fd, GIOCondition condition, gpointer user_data) while (TRUE) { NMEtherAddr sender_addr_data; const NMEtherAddr *sender_addr; - AcdData * acd_data; - NAcdEvent * event; + AcdData *acd_data; + NAcdEvent *event; if (!self->priv.p->nacd) { /* In the loop we emit signals, where *anything* might happen. @@ -1440,12 +1526,7 @@ _l3_acd_nacd_event(int fd, GIOCondition condition, gpointer user_data) "in %u msec)", timeout_msec); self->priv.p->nacd_event_down_source = - nm_g_timeout_source_new(timeout_msec, - G_PRIORITY_DEFAULT, - _l3_acd_nacd_event_down_timeout_cb, - self, - NULL); - g_source_attach(self->priv.p->nacd_event_down_source, NULL); + nm_g_timeout_add_source(timeout_msec, _l3_acd_nacd_event_down_timeout_cb, self); } break; default: @@ -1494,6 +1575,7 @@ _l3_acd_nacd_instance_reset(NML3Cfg *self, NMTernary start_timer, gboolean acd_d } nm_clear_g_source_inst(&self->priv.p->nacd_source); nm_clear_g_source_inst(&self->priv.p->nacd_instance_ensure_retry); + nm_clear_g_source_inst(&self->priv.p->nacd_event_down_source); if (c_list_is_empty(&self->priv.p->acd_lst_head)) start_timer = NM_TERNARY_DEFAULT; @@ -1505,12 +1587,9 @@ _l3_acd_nacd_instance_reset(NML3Cfg *self, NMTernary start_timer, gboolean acd_d break; case NM_TERNARY_TRUE: self->priv.p->nacd_instance_ensure_retry = - nm_g_timeout_source_new_seconds(ACD_ENSURE_RATELIMIT_MSEC / 1000u, - G_PRIORITY_DEFAULT, + nm_g_timeout_add_seconds_source(ACD_ENSURE_RATELIMIT_MSEC / 1000u, _l3_acd_nacd_instance_ensure_retry_cb, - self, - NULL); - g_source_attach(self->priv.p->nacd_instance_ensure_retry, NULL); + self); break; case NM_TERNARY_DEFAULT: break; @@ -1534,8 +1613,8 @@ static NAcd * _l3_acd_nacd_instance_ensure(NML3Cfg *self, gboolean *out_acd_not_supported) { nm_auto(n_acd_config_freep) NAcdConfig *config = NULL; - nm_auto(n_acd_unrefp) NAcd * nacd = NULL; - const guint8 * addr_bin; + nm_auto(n_acd_unrefp) NAcd *nacd = NULL; + const guint8 *addr_bin; gboolean acd_not_supported; gboolean valid; int fd; @@ -1599,11 +1678,11 @@ failed_create_acd: } static NAcdProbe * -_l3_acd_nacd_instance_create_probe(NML3Cfg * self, +_l3_acd_nacd_instance_create_probe(NML3Cfg *self, in_addr_t addr, guint32 timeout_msec, gpointer user_data, - gboolean * out_acd_not_supported, + gboolean *out_acd_not_supported, const char **out_failure_reason) { gboolean acd_not_supported; @@ -1699,17 +1778,17 @@ _l3_acd_data_defendconflict_warning_ratelimited(AcdData *acd_data, gint64 *p_now } static void -_l3_acd_data_add(NML3Cfg * self, +_l3_acd_data_add(NML3Cfg *self, const NML3ConfigData *l3cd, - const NMPObject * obj, + const NMPObject *obj, gconstpointer tag, NML3AcdDefendType acd_defend_type, guint32 acd_timeout_msec) { in_addr_t addr = NMP_OBJECT_CAST_IP4_ADDRESS(obj)->address; NML3AcdAddrTrackInfo *acd_track; - AcdData * acd_data; - const char * track_mode; + AcdData *acd_data; + const char *track_mode; char sbuf100[100]; if (ACD_ADDR_SKIP(addr)) @@ -1795,7 +1874,7 @@ _l3_acd_data_add(NML3Cfg * self, } static void -_l3_acd_data_add_all(NML3Cfg * self, +_l3_acd_data_add_all(NML3Cfg *self, const L3ConfigData *const *infos, guint infos_len, gboolean reapply) @@ -1817,7 +1896,7 @@ _l3_acd_data_add_all(NML3Cfg * self, for (i_info = 0; i_info < infos_len; i_info++) { const L3ConfigData *info = infos[i_info]; NMDedupMultiIter iter; - const NMPObject * obj; + const NMPObject *obj; nm_l3_config_data_iter_obj_for_each (&iter, info->l3cd, &obj, NMP_OBJECT_TYPE_IP4_ADDRESS) { _l3_acd_data_add(self, @@ -1859,14 +1938,24 @@ _l3_acd_data_timeout_cb(gpointer user_data) static void _l3_acd_data_timeout_schedule(AcdData *acd_data, gint64 timeout_msec) { + /* in _l3_acd_data_state_set_full() we clear the timer. At the same time, + * in _l3_acd_data_state_change(ACD_STATE_CHANGE_MODE_TIMEOUT) we only + * expect timeouts in certain states. + * + * That means, scheduling a timeout is only correct if we are in a certain + * state, which allows to handle timeouts. This assert checks for that to + * ensure we don't call a timeout in an unexpected state. */ + nm_assert(NM_IN_SET(acd_data->info.state, + NM_L3_ACD_ADDR_STATE_PROBING, + NM_L3_ACD_ADDR_STATE_USED, + NM_L3_ACD_ADDR_STATE_DEFENDING, + NM_L3_ACD_ADDR_STATE_CONFLICT)); + nm_clear_g_source_inst(&acd_data->acd_data_timeout_source); acd_data->acd_data_timeout_source = - nm_g_timeout_source_new(NM_CLAMP((gint64) 0, timeout_msec, (gint64) G_MAXUINT), - G_PRIORITY_DEFAULT, + nm_g_timeout_add_source(NM_CLAMP((gint64) 0, timeout_msec, (gint64) G_MAXUINT), _l3_acd_data_timeout_cb, - acd_data, - NULL); - g_source_attach(acd_data->acd_data_timeout_source, NULL); + acd_data); } static void @@ -1899,7 +1988,7 @@ _nm_l3cfg_emit_signal_notify_acd_event(NML3Cfg *self, AcdData *acd_data) { gs_free NML3AcdAddrTrackInfo *track_infos_clone = NULL; NML3ConfigNotifyData notify_data; - NML3AcdAddrInfo * info; + NML3AcdAddrInfo *info; guint i; nm_assert(acd_data); @@ -1908,7 +1997,7 @@ _nm_l3cfg_emit_signal_notify_acd_event(NML3Cfg *self, AcdData *acd_data) notify_data.notify_type = NM_L3_CONFIG_NOTIFY_TYPE_ACD_EVENT; notify_data.acd_event = (typeof(notify_data.acd_event)){ - .info = acd_data->info, + .info = acd_data->info, }; /* we need to clone the track-data, because the callee is allowed to add/remove @@ -1952,7 +2041,7 @@ static void _nm_l3cfg_emit_signal_notify_acd_event_all(NML3Cfg *self) { gs_unref_object NML3Cfg *self_keep_alive = NULL; - AcdData * acd_data; + AcdData *acd_data; while ((acd_data = c_list_first_entry(&self->priv.p->acd_event_notify_lst_head, AcdData, @@ -1964,11 +2053,11 @@ _nm_l3cfg_emit_signal_notify_acd_event_all(NML3Cfg *self) } } -_nm_printf(5, 6) static void _l3_acd_data_state_set_full(NML3Cfg * self, - AcdData * acd_data, +_nm_printf(5, 6) static void _l3_acd_data_state_set_full(NML3Cfg *self, + AcdData *acd_data, NML3AcdAddrState state, gboolean allow_commit, - const char * format, + const char *format, ...) { NML3AcdAddrState old_state; @@ -1993,17 +2082,19 @@ _nm_printf(5, 6) static void _l3_acd_data_state_set_full(NML3Cfg * self, else changed = FALSE; - if (format) { - gs_free char *msg = NULL; - va_list args; + if (_LOGT_ENABLED()) { + if (format) { + gs_free char *msg = NULL; + va_list args; - va_start(args, format); - msg = g_strdup_vprintf(format, args); - va_end(args); + va_start(args, format); + msg = g_strdup_vprintf(format, args); + va_end(args); - _LOGT_acd(acd_data, "set state to %s (%s)", _l3_acd_addr_state_to_string(state), msg); - } else - _LOGT_acd(acd_data, "set state to %s", _l3_acd_addr_state_to_string(state)); + _LOGT_acd(acd_data, "set state to %s (%s)", _l3_acd_addr_state_to_string(state), msg); + } else + _LOGT_acd(acd_data, "set state to %s", _l3_acd_addr_state_to_string(state)); + } if (changed && allow_commit) { /* The availability of an address just changed (and we are instructed to @@ -2014,8 +2105,8 @@ _nm_printf(5, 6) static void _l3_acd_data_state_set_full(NML3Cfg * self, } static void -_l3_acd_data_state_set(NML3Cfg * self, - AcdData * acd_data, +_l3_acd_data_state_set(NML3Cfg *self, + AcdData *acd_data, NML3AcdAddrState state, gboolean allow_commit) { @@ -2023,17 +2114,17 @@ _l3_acd_data_state_set(NML3Cfg * self, } static void -_l3_acd_data_state_change(NML3Cfg * self, - AcdData * acd_data, +_l3_acd_data_state_change(NML3Cfg *self, + AcdData *acd_data, AcdStateChangeMode state_change_mode, const NMEtherAddr *sender_addr, - gint64 * p_now_msec) + gint64 *p_now_msec) { guint32 acd_timeout_msec; NML3AcdDefendType acd_defend_type; gint64 now_msec; - const char * log_reason; + const char *log_reason; char sbuf256[256]; char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; @@ -2260,22 +2351,7 @@ handle_init: /* we are already probing. There is nothing to do for this timeout. */ return; } - - nm_utils_get_monotonic_timestamp_msec_cached(p_now_msec); - - if (acd_data->probing_timestamp_msec + ACD_WAIT_PROBING_EXTRA_TIME_MSEC - + ACD_WAIT_PROBING_EXTRA_TIME2_MSEC - >= (*p_now_msec)) { - /* hm. We failed to create a new probe too long. Something is really wrong - * internally, but let's ignore the issue and assume the address is good. What - * else would we do? Assume the address is USED? */ - _LOGT_acd(acd_data, - "probe-good (waiting for creating probe timed out. Assume good)"); - goto handle_start_defending; - } - - log_reason = "retry probing on timeout"; - goto handle_start_probing; + /* fall-through */ case NM_L3_ACD_ADDR_STATE_USED: case NM_L3_ACD_ADDR_STATE_CONFLICT: @@ -2295,7 +2371,10 @@ handle_init: acd_data->acd_defend_type_desired = acd_defend_type; if (acd_timeout_msec <= 0) { - log_reason = "acd disabled by configuration (restart after previous conflict)"; + if (acd_data->info.state == NM_L3_ACD_ADDR_STATE_PROBING) + log_reason = "acd disabled by configuration (timeout during probing)"; + else + log_reason = "acd disabled by configuration (restart after previous conflict)"; goto handle_probing_done; } @@ -2305,6 +2384,23 @@ handle_init: } nm_utils_get_monotonic_timestamp_msec_cached(p_now_msec); + + if (acd_data->info.state == NM_L3_ACD_ADDR_STATE_PROBING) { + if (acd_data->probing_timestamp_msec + ACD_WAIT_PROBING_EXTRA_TIME_MSEC + + ACD_WAIT_PROBING_EXTRA_TIME2_MSEC + >= (*p_now_msec)) { + /* hm. We failed to create a new probe too long. Something is really wrong + * internally, but let's ignore the issue and assume the address is good. What + * else would we do? Assume the address is USED? */ + _LOGT_acd(acd_data, + "probe-good (waiting for creating probe timed out. Assume good)"); + goto handle_start_defending; + } + + log_reason = "retry probing on timeout"; + goto handle_start_probing; + } + acd_data->probing_timestamp_msec = (*p_now_msec); acd_data->probing_timeout_msec = acd_timeout_msec; if (acd_data->info.state == NM_L3_ACD_ADDR_STATE_USED) @@ -2525,40 +2621,23 @@ handle_init: return; case ACD_STATE_CHANGE_MODE_INSTANCE_RESET: + nm_assert(NM_IN_SET(acd_data->info.state, + NM_L3_ACD_ADDR_STATE_PROBING, + NM_L3_ACD_ADDR_STATE_DEFENDING, + NM_L3_ACD_ADDR_STATE_READY, + NM_L3_ACD_ADDR_STATE_USED, + NM_L3_ACD_ADDR_STATE_CONFLICT, + NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED)); - switch (acd_data->info.state) { - case NM_L3_ACD_ADDR_STATE_INIT: - nm_assert_not_reached(); - return; - case NM_L3_ACD_ADDR_STATE_PROBING: - case NM_L3_ACD_ADDR_STATE_DEFENDING: - - if (!acd_data->nacd_probe) { - /* we failed starting to probe before and have a timer running to - * restart. We don't do anything now, but let the timer handle it. - * This also implements some rate limiting for us. */ - _LOGT_acd(acd_data, - "n-acd instance reset. Ignore event while restarting %s", - (acd_data->info.state == NM_L3_ACD_ADDR_STATE_PROBING) ? "probing" - : "defending"); - return; - } - - _LOGT_acd(acd_data, - "n-acd instance reset. Trigger a restart of the %s", - (acd_data->info.state == NM_L3_ACD_ADDR_STATE_PROBING) ? "probing" - : "defending"); - acd_data->nacd_probe = n_acd_probe_free(acd_data->nacd_probe); - _l3_acd_data_timeout_schedule(acd_data, 0); - return; - case NM_L3_ACD_ADDR_STATE_READY: - case NM_L3_ACD_ADDR_STATE_USED: - case NM_L3_ACD_ADDR_STATE_CONFLICT: - case NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED: - nm_assert(!acd_data->nacd_probe); - return; - } - nm_assert_not_reached(); + /* an instance-reset is a dramatic event. We start over with probing. */ + _LOGT_acd(acd_data, + "n-acd instance reset. Reset to probing while in state %s", + _l3_acd_addr_state_to_string(acd_data->info.state)); + acd_data->nacd_probe = n_acd_probe_free(acd_data->nacd_probe); + acd_data->last_defendconflict_timestamp_msec = 0; + acd_data->probing_timestamp_msec = nm_utils_get_monotonic_timestamp_msec_cached(p_now_msec); + _l3_acd_data_state_set(self, acd_data, NM_L3_ACD_ADDR_STATE_PROBING, FALSE); + _l3_acd_data_timeout_schedule(acd_data, 0); return; } @@ -2569,7 +2648,7 @@ handle_start_probing: if (TRUE) { const NML3AcdAddrState orig_state = acd_data->info.state; nm_auto(n_acd_probe_freep) NAcdProbe *probe = NULL; - const char * failure_reason; + const char *failure_reason; gboolean acd_not_supported; nm_assert(NM_IN_SET(acd_data->info.state, @@ -2646,10 +2725,10 @@ handle_probing_done: goto handle_start_defending; case NM_L3_ACD_ADDR_STATE_READY: case NM_L3_ACD_ADDR_STATE_DEFENDING: + case NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED: goto handle_start_defending; case NM_L3_ACD_ADDR_STATE_CONFLICT: return; - case NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED: nm_assert_not_reached(); return; } @@ -2689,7 +2768,7 @@ handle_start_defending: if (!acd_data->nacd_probe) { const char *failure_reason; - NAcdProbe * probe; + NAcdProbe *probe; if (acd_data->acd_data_timeout_source) { /* we already failed to create a probe. We are ratelimited to retry, but @@ -2786,11 +2865,11 @@ nm_l3cfg_get_acd_addr_info(NML3Cfg *self, in_addr_t addr) /*****************************************************************************/ gboolean -nm_l3cfg_check_ready(NML3Cfg * self, - const NML3ConfigData * l3cd, +nm_l3cfg_check_ready(NML3Cfg *self, + const NML3ConfigData *l3cd, int addr_family, NML3CfgCheckReadyFlags flags, - gboolean * acd_used) + gboolean *acd_used) { NMDedupMultiIter iter; const NMPObject *obj; @@ -2869,7 +2948,7 @@ static gboolean _l3_commit_on_idle_cb(gpointer user_data) { _nm_unused gs_unref_object NML3Cfg *self_keep_alive = NULL; - NML3Cfg * self = user_data; + NML3Cfg *self = user_data; NML3CfgCommitType commit_type; commit_type = self->priv.p->commit_on_idle_type; @@ -2948,7 +3027,7 @@ nm_l3cfg_commit_on_idle_is_scheduled(NML3Cfg *self) (&g_array_index((l3_config_datas), L3ConfigData, (idx))) static gssize -_l3_config_datas_find_next(GArray * l3_config_datas, +_l3_config_datas_find_next(GArray *l3_config_datas, guint start_idx, gconstpointer needle_tag, const NML3ConfigData *needle_l3cd) @@ -2978,9 +3057,9 @@ _l3_config_datas_get_sorted_cmp(gconstpointer p_a, gconstpointer p_b, gpointer u nm_assert(b); nm_assert(nm_l3_config_data_get_ifindex(a->l3cd) == nm_l3_config_data_get_ifindex(b->l3cd)); - /* we sort the entries with higher priority (more important, lower numerical value) + /* we sort the entries with higher priority (higher numerical value, more important) * first. */ - NM_CMP_FIELD(a, b, priority_confdata); + NM_CMP_FIELD(b, a, priority_confdata); /* if the priority is not unique, we sort them in the order they were added, * with the oldest first (lower numerical value). */ @@ -3028,8 +3107,16 @@ nm_l3cfg_mark_config_dirty(NML3Cfg *self, gconstpointer tag, gboolean dirty) } } +/* + * nm_l3cfg_add_config: + * @priority: all l3cd get merged/combined. This merging requires that some + * l3cd are more important than others. For example, coming from static IP + * configuration needs to take precedence over DHCP. The @priority determines + * the order in which l3cds get merged (and thus the outcome). Higher numbers + * mean more important!! + */ gboolean -nm_l3cfg_add_config(NML3Cfg * self, +nm_l3cfg_add_config(NML3Cfg *self, gconstpointer tag, gboolean replace_same_tag, const NML3ConfigData *l3cd, @@ -3123,7 +3210,8 @@ nm_l3cfg_add_config(NML3Cfg * self, .acd_timeout_msec_confdata = acd_timeout_msec, .priority_confdata = priority, .pseudo_timestamp_confdata = ++self->priv.p->pseudo_timestamp_counter, - .dirty_confdata = FALSE, + .force_commit_once = NM_FLAGS_HAS(config_flags, NM_L3CFG_CONFIG_FLAGS_FORCE_ONCE), + .dirty_confdata = FALSE, }; changed = TRUE; } else { @@ -3194,7 +3282,7 @@ nm_l3cfg_add_config(NML3Cfg * self, } static gboolean -_l3cfg_remove_config(NML3Cfg * self, +_l3cfg_remove_config(NML3Cfg *self, gconstpointer tag, gboolean only_dirty, const NML3ConfigData *l3cd) @@ -3264,21 +3352,22 @@ nm_l3cfg_remove_config_all_dirty(NML3Cfg *self, gconstpointer tag) /*****************************************************************************/ typedef struct { - NML3Cfg * self; + NML3Cfg *self; gconstpointer tag; bool assume_config_once; bool to_commit; + bool force_commit_once; } L3ConfigMergeHookAddObjData; static gboolean -_l3_hook_add_obj_cb(const NML3ConfigData * l3cd, - const NMPObject * obj, +_l3_hook_add_obj_cb(const NML3ConfigData *l3cd, + const NMPObject *obj, NML3ConfigMergeHookResult *hook_result, gpointer user_data) { const L3ConfigMergeHookAddObjData *hook_data = user_data; - NML3Cfg * self = hook_data->self; - AcdData * acd_data; + NML3Cfg *self = hook_data->self; + AcdData *acd_data; in_addr_t addr; gboolean acd_bad = FALSE; @@ -3286,8 +3375,10 @@ _l3_hook_add_obj_cb(const NML3ConfigData * l3cd, nm_assert(hook_result); nm_assert(hook_result->ip4acd_not_ready == NM_OPTION_BOOL_DEFAULT); nm_assert(hook_result->assume_config_once == NM_OPTION_BOOL_DEFAULT); + nm_assert(hook_result->force_commit == NM_OPTION_BOOL_DEFAULT); hook_result->assume_config_once = hook_data->assume_config_once; + hook_result->force_commit = hook_data->force_commit_once; switch (NMP_OBJECT_GET_TYPE(obj)) { case NMP_OBJECT_TYPE_IP4_ADDRESS: @@ -3327,7 +3418,8 @@ _l3_hook_add_obj_cb(const NML3ConfigData * l3cd, if (!NM_IN_SET(acd_data->info.state, NM_L3_ACD_ADDR_STATE_READY, - NM_L3_ACD_ADDR_STATE_DEFENDING)) { + NM_L3_ACD_ADDR_STATE_DEFENDING, + NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED)) { acd_bad = TRUE; goto out_ip4_address; } @@ -3347,21 +3439,21 @@ out_ip4_address: } static void -_l3cfg_update_combined_config(NML3Cfg * self, +_l3cfg_update_combined_config(NML3Cfg *self, gboolean to_commit, gboolean reapply, const NML3ConfigData **out_old /* transfer reference */, - gboolean * out_changed_combined_l3cd) + gboolean *out_changed_combined_l3cd) { - nm_auto_unref_l3cd const NML3ConfigData *l3cd_commited_old = NULL; - nm_auto_unref_l3cd const NML3ConfigData *l3cd_old = NULL; - nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; - gs_free const L3ConfigData **l3_config_datas_free = NULL; - const L3ConfigData ** l3_config_datas_arr; - guint l3_config_datas_len; - guint i; - gboolean merged_changed = FALSE; - gboolean commited_changed = FALSE; + nm_auto_unref_l3cd const NML3ConfigData *l3cd_commited_old = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd_old = NULL; + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + gs_free const L3ConfigData **l3_config_datas_free = NULL; + const L3ConfigData **l3_config_datas_arr; + guint l3_config_datas_len; + guint i; + gboolean merged_changed = FALSE; + gboolean commited_changed = FALSE; nm_assert(NM_IS_L3CFG(self)); nm_assert(!out_old || !*out_old); @@ -3388,6 +3480,20 @@ _l3cfg_update_combined_config(NML3Cfg * self, l3_config_datas_arr[i] = _l3_config_datas_at(self->priv.p->l3_config_datas, i); if (l3_config_datas_len > 1) { + /* We are about to merge the l3cds. The order in which we do that matters. + * + * Below, we iterate over the l3cds and merge them into a new one. nm_l3_config_data_merge() + * uses "NM_L3_CONFIG_ADD_FLAGS_EXCLUSIVE" flag, which means to keep the first entry. + * + * Consider for example addresses/routes, which have a set of ID attributes (based on + * which no duplicates can be accepted) and additional attributes. For example, trying + * to add the same address twice ("same" according to their ID), only one can be added. + * If they differ in their lifetimes, we need to make a choice. + * We could merge the attributes in a sensible way. Instead, NM_L3_CONFIG_ADD_FLAGS_EXCLUSIVE + * takes care to only take the first one. + * + * So we want to sort the more important entries *first*, and this is based on + * the priority_confdata. */ g_qsort_with_data(l3_config_datas_arr, l3_config_datas_len, sizeof(l3_config_datas_arr[0]), @@ -3417,12 +3523,21 @@ _l3cfg_update_combined_config(NML3Cfg * self, for (i = 0; i < l3_config_datas_len; i++) { const L3ConfigData *l3cd_data = l3_config_datas_arr[i]; + /* more important entries must be sorted *first*. */ + nm_assert( + i == 0 + || (l3_config_datas_arr[i - 1]->priority_confdata > l3cd_data->priority_confdata) + || (l3_config_datas_arr[i - 1]->priority_confdata == l3cd_data->priority_confdata + && l3_config_datas_arr[i - 1]->pseudo_timestamp_confdata + < l3cd_data->pseudo_timestamp_confdata)); + if (NM_FLAGS_HAS(l3cd_data->config_flags, NM_L3CFG_CONFIG_FLAGS_ONLY_FOR_ACD)) continue; hook_data.tag = l3cd_data->tag_confdata; hook_data.assume_config_once = NM_FLAGS_HAS(l3cd_data->config_flags, NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE); + hook_data.force_commit_once = l3cd_data->force_commit_once; nm_l3_config_data_merge(l3cd, l3cd_data->l3cd, @@ -3448,6 +3563,7 @@ _l3cfg_update_combined_config(NML3Cfg * self, IS_IPv4 ? AF_INET : AF_INET6, l3cd_data->default_route_table_x[IS_IPv4], l3cd_data->default_route_metric_x[IS_IPv4], + l3cd_data->force_commit_once, l3cd_data->l3cd); } } @@ -3524,7 +3640,7 @@ out: static gboolean _routes_temporary_not_available_timeout(gpointer user_data) { - NML3Cfg * self = NM_L3CFG(user_data); + NML3Cfg *self = NM_L3CFG(user_data); ObjStateData *obj_state; gint64 now_msec; gint64 expiry_msec; @@ -3563,12 +3679,12 @@ _routes_temporary_not_available_timeout(gpointer user_data) } static gboolean -_routes_temporary_not_available_update(NML3Cfg * self, +_routes_temporary_not_available_update(NML3Cfg *self, int addr_family, GPtrArray *routes_temporary_not_available_arr) { - ObjStateData * obj_state; - ObjStateData * obj_state_safe; + ObjStateData *obj_state; + ObjStateData *obj_state_safe; gint64 now_msec; gboolean prune_all = FALSE; gboolean success = TRUE; @@ -3699,7 +3815,7 @@ _l3_commit_ndisc_params(NML3Cfg *self, NML3CfgCommitType commit_type) guint32 reachable = 0; guint32 retrans = 0; int hop_limit = 0; - const char * ifname; + const char *ifname; if (commit_type < NM_L3_CFG_COMMIT_TYPE_UPDATE) { self->priv.p->ndisc_reachable_time_msec_set = FALSE; @@ -3757,7 +3873,7 @@ _l3_commit_ip6_privacy(NML3Cfg *self, NML3CfgCommitType commit_type) { NMSettingIP6ConfigPrivacy ip6_privacy; NMSettingIP6ConfigPrivacy ip6_privacy_set_before; - const char * ifname; + const char *ifname; if (commit_type < NM_L3_CFG_COMMIT_TYPE_UPDATE) ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; @@ -3861,14 +3977,76 @@ set: ip6_privacy_to_str(ip6_privacy)); } +static void +_l3_commit_ip6_token(NML3Cfg *self, NML3CfgCommitType commit_type) +{ + NMUtilsIPv6IfaceId token; + const NMPlatformLink *pllink; + int val; + + if (commit_type < NM_L3_CFG_COMMIT_TYPE_UPDATE || !self->priv.p->combined_l3cd_commited) + token.id = 0; + else + token = nm_l3_config_data_get_ip6_token(self->priv.p->combined_l3cd_commited); + + pllink = nm_l3cfg_get_pllink(self, TRUE); + if (!pllink || pllink->inet6_token.id == token.id) + return; + + if (_LOGT_ENABLED()) { + struct in6_addr addr = {}; + struct in6_addr addr_old = {}; + char addr_str[INET6_ADDRSTRLEN]; + char addr_str_old[INET6_ADDRSTRLEN]; + + nm_utils_ipv6_addr_set_interface_identifier(&addr, &token); + nm_utils_ipv6_addr_set_interface_identifier(&addr_old, &pllink->inet6_token); + + _LOGT("commit-ip6-token: set value %s (was %s)", + inet_ntop(AF_INET6, &addr, addr_str, INET6_ADDRSTRLEN), + inet_ntop(AF_INET6, &addr_old, addr_str_old, INET6_ADDRSTRLEN)); + } + + /* The kernel allows setting a token only when 'accept_ra' + * is 1: temporarily flip it if necessary; unfortunately + * this will also generate an additional Router Solicitation + * from kernel. */ + val = nm_platform_sysctl_ip_conf_get_int_checked(self->priv.platform, + AF_INET6, + pllink->name, + "accept_ra", + 10, + G_MININT32, + G_MAXINT32, + 1); + + if (val != 1) { + nm_platform_sysctl_ip_conf_set(self->priv.platform, + AF_INET6, + pllink->name, + "accept_ra", + "1"); + } + + nm_platform_link_set_ipv6_token(self->priv.platform, self->priv.ifindex, &token); + + if (val != 1) { + nm_platform_sysctl_ip_conf_set_int64(self->priv.platform, + AF_INET6, + pllink->name, + "accept_ra", + val); + } +} + static gboolean -_l3_commit_one(NML3Cfg * self, +_l3_commit_one(NML3Cfg *self, int addr_family, NML3CfgCommitType commit_type, gboolean changed_combined_l3cd, const NML3ConfigData *l3cd_old) { - const int IS_IPv4 = NM_IS_IPv4(addr_family); + const int IS_IPv4 = NM_IS_IPv4(addr_family); gs_unref_ptrarray GPtrArray *addresses = NULL; gs_unref_ptrarray GPtrArray *routes = NULL; gs_unref_ptrarray GPtrArray *addresses_prune = NULL; @@ -3892,7 +4070,7 @@ _l3_commit_one(NML3Cfg * self, _l3_cfg_commit_type_to_string(commit_type, sbuf_commit_type, sizeof(sbuf_commit_type))); if (self->priv.p->combined_l3cd_commited) { - const NMDedupMultiHeadEntry * head_entry; + const NMDedupMultiHeadEntry *head_entry; const ObjStatesSyncFilterData sync_filter_data = { .self = self, .commit_type = commit_type, @@ -3918,10 +4096,11 @@ _l3_commit_one(NML3Cfg * self, if (!IS_IPv4) { _l3_commit_ip6_privacy(self, commit_type); _l3_commit_ndisc_params(self, commit_type); + _l3_commit_ip6_token(self, commit_type); } if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_NONE) - route_table_sync = NM_IP_ROUTE_TABLE_SYNC_MODE_ALL; + route_table_sync = NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN; if (commit_type == NM_L3_CFG_COMMIT_TYPE_REAPPLY) { addresses_prune = nm_platform_ip_address_get_prune_list(self->priv.platform, @@ -3968,13 +4147,14 @@ _l3_commit_one(NML3Cfg * self, static void _l3_commit(NML3Cfg *self, NML3CfgCommitType commit_type, gboolean is_idle) { - _nm_unused gs_unref_object NML3Cfg *self_keep_alive = NULL; - nm_auto_unref_l3cd const NML3ConfigData *l3cd_old = NULL; + _nm_unused gs_unref_object NML3Cfg *self_keep_alive = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd_old = NULL; NML3CfgCommitType commit_type_auto; gboolean commit_type_from_auto = FALSE; gboolean is_sticky_update = FALSE; char sbuf_ct[30]; gboolean changed_combined_l3cd; + guint i; g_return_if_fail(NM_IS_L3CFG(self)); nm_assert(NM_IN_SET(commit_type, @@ -4038,6 +4218,15 @@ _l3_commit(NML3Cfg *self, NML3CfgCommitType commit_type, gboolean is_idle) _l3_acd_data_process_changes(self); + if (self->priv.p->l3_config_datas) { + for (i = 0; i < self->priv.p->l3_config_datas->len; i++) { + L3ConfigData *l3_config_data = _l3_config_datas_at(self->priv.p->l3_config_datas, i); + + if (l3_config_data->force_commit_once) + l3_config_data->force_commit_once = FALSE; + } + } + nm_assert(self->priv.p->commit_reentrant_count == 1); self->priv.p->commit_reentrant_count--; @@ -4083,10 +4272,10 @@ nm_l3cfg_commit_type_get(NML3Cfg *self) * is %NM_L3_CFG_COMMIT_TYPE_NONE. */ NML3CfgCommitTypeHandle * -nm_l3cfg_commit_type_register(NML3Cfg * self, +nm_l3cfg_commit_type_register(NML3Cfg *self, NML3CfgCommitType commit_type, NML3CfgCommitTypeHandle *existing_handle, - const char * source) + const char *source) { NML3CfgCommitTypeHandle *handle; NML3CfgCommitTypeHandle *h; @@ -4170,6 +4359,20 @@ nm_l3cfg_commit_type_unregister(NML3Cfg *self, NML3CfgCommitTypeHandle *handle) nm_g_slice_free(handle); } +void +nm_l3cfg_commit_type_reset_update(NML3Cfg *self) +{ + NML3CfgCommitTypeHandle *h; + + c_list_for_each_entry (h, &self->priv.p->commit_type_lst_head, commit_type_lst) { + if (h->commit_type >= NM_L3_CFG_COMMIT_TYPE_UPDATE) { + return; + } + } + + self->priv.p->commit_type_update_sticky = FALSE; +} + /*****************************************************************************/ const NML3ConfigData * @@ -4202,7 +4405,7 @@ gboolean nm_l3cfg_has_commited_ip6_addresses_pending_dad(NML3Cfg *self) { const NML3ConfigData *l3cd; - const NMPObject * plat_obj; + const NMPObject *plat_obj; NMPLookup plat_lookup; NMDedupMultiIter iter; @@ -4224,7 +4427,7 @@ nm_l3cfg_has_commited_ip6_addresses_pending_dad(NML3Cfg *self) nm_platform_iter_obj_for_each (&iter, self->priv.platform, &plat_lookup, &plat_obj) { const NMPlatformIP6Address *plat_addr = NMP_OBJECT_CAST_IP6_ADDRESS(plat_obj); - const NMDedupMultiEntry * l3cd_entry; + const NMDedupMultiEntry *l3cd_entry; if (!NM_FLAGS_HAS(plat_addr->n_ifa_flags, IFA_F_TENTATIVE) || NM_FLAGS_ANY(plat_addr->n_ifa_flags, IFA_F_DADFAILED | IFA_F_OPTIMISTIC)) @@ -4376,6 +4579,9 @@ finalize(GObject *object) { NML3Cfg *self = NM_L3CFG(object); + nm_assert(!self->priv.p->ipconfig_4); + nm_assert(!self->priv.p->ipconfig_6); + nm_assert(!self->priv.p->l3_config_datas); nm_assert(!self->priv.p->ipv4ll); @@ -4393,6 +4599,7 @@ finalize(GObject *object) nm_clear_pointer(&self->priv.p->nacd, n_acd_unref); nm_clear_g_source_inst(&self->priv.p->nacd_source); nm_clear_g_source_inst(&self->priv.p->nacd_instance_ensure_retry); + nm_clear_g_source_inst(&self->priv.p->nacd_event_down_source); nm_clear_g_source_inst(&self->priv.p->obj_state_temporary_not_available_timeout_source); |