diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2023-09-09 13:53:25 +0200 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2023-10-05 09:04:32 +0200 |
commit | ed565f91469987e1b6eaf0e0263fe2b02853ed7b (patch) | |
tree | 3e8cc44074bf5a4b7a751ba2c1090fb36ffb358e | |
parent | 7548ff57d3750bfe73294e59421fc7b22b26a866 (diff) |
l3cfg: fix pruning of ACD data
If a commit is invoked without any change to the l3cd or to the ACD
data, in _l3cfg_update_combined_config() we skip calling
_l3_acd_data_add_all(), which should clear the dirty flag from ACDs.
Therefore, in case of such no-op commits the ACDs still marked as
dirty - but valid - are removed via:
_l3_commit()
_l3_acd_data_process_changes()
_l3_acd_data_prune()
_l3_acd_data_prune_one()
Invoking a l3cfg commit without any actual changes is allowed, see the
explanation in commit e773559d9d92 ('device: schedule an idle commit
when setting device's sys-iface-state').
The bug is visible by running test 'bond_addreses_restart_persistence'
with IPv4 ACD/DAD is enabled by default: after restart IPv6 completes
immediately, the devices becomes ACTIVATED, the sys-iface-state
transitions from ASSUME to MANAGED, a commit is done, and it
incorrectly prunes the ACD data. The result is that the IPv4 address
is never added again.
Fix this by doing the pruning only when we update the dirty flags.
-rw-r--r-- | src/core/nm-l3cfg.c | 9 |
1 files changed, 8 insertions, 1 deletions
diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c index 2d0c372b72..42f18a6982 100644 --- a/src/core/nm-l3cfg.c +++ b/src/core/nm-l3cfg.c @@ -334,6 +334,7 @@ typedef struct _NML3CfgPrivate { bool nacd_acd_not_supported : 1; bool acd_ipv4_addresses_on_link_has : 1; + bool acd_data_pruning_needed : 1; bool changed_configs_configs : 1; bool changed_configs_acd_state : 1; @@ -3059,7 +3060,10 @@ _l3_acd_data_process_changes(NML3Cfg *self) AcdData *acd_data; gint64 now_msec = 0; - _l3_acd_data_prune(self, FALSE); + if (self->priv.p->acd_data_pruning_needed) + _l3_acd_data_prune(self, FALSE); + + self->priv.p->acd_data_pruning_needed = FALSE; c_list_for_each_entry (acd_data, &self->priv.p->acd_lst_head, acd_lst) { _l3_acd_data_state_change(self, @@ -3789,6 +3793,8 @@ _l3cfg_update_combined_config(NML3Cfg *self, NM_SET_OUT(out_changed_combined_l3cd, FALSE); + self->priv.p->acd_data_pruning_needed = FALSE; + if (!self->priv.p->changed_configs_configs) { if (!self->priv.p->changed_configs_acd_state) goto out; @@ -3836,6 +3842,7 @@ _l3cfg_update_combined_config(NML3Cfg *self, self->priv.p->changed_configs_acd_state = TRUE; } else { _l3_acd_data_add_all(self, l3_config_datas_arr, l3_config_datas_len, reapply); + self->priv.p->acd_data_pruning_needed = TRUE; self->priv.p->changed_configs_acd_state = FALSE; } |