diff --git a/src/core/nm-l3-config-data.c b/src/core/nm-l3-config-data.c index 2c28f4cc65..3ae17d5217 100644 --- a/src/core/nm-l3-config-data.c +++ b/src/core/nm-l3-config-data.c @@ -1104,6 +1104,14 @@ _l3_config_data_add_obj(NMDedupMultiIndex * multi_idx, obj_new_stackinit.ip_address.addr_source = obj_old->ip_address.addr_source; modified = TRUE; } + + /* OR assume_config_once flag */ + if (obj_new->ip_address.a_assume_config_once + && !obj_old->ip_address.a_assume_config_once) { + obj_new = nmp_object_stackinit_obj(&obj_new_stackinit, obj_new); + obj_new_stackinit.ip_address.a_assume_config_once = TRUE; + modified = TRUE; + } break; case NMP_OBJECT_TYPE_IP4_ROUTE: case NMP_OBJECT_TYPE_IP6_ROUTE: @@ -1113,6 +1121,14 @@ _l3_config_data_add_obj(NMDedupMultiIndex * multi_idx, obj_new_stackinit.ip_route.rt_source = obj_old->ip_route.rt_source; modified = TRUE; } + + /* OR assume_config_once flag */ + if (obj_new->ip_route.r_assume_config_once + && !obj_old->ip_route.r_assume_config_once) { + obj_new = nmp_object_stackinit_obj(&obj_new_stackinit, obj_new); + obj_new_stackinit.ip_route.r_assume_config_once = TRUE; + modified = TRUE; + } break; default: nm_assert_not_reached(); @@ -2736,7 +2752,8 @@ nm_l3_config_data_merge(NML3ConfigData * self, const NMPlatformIPAddress *a_src = NMP_OBJECT_CAST_IP_ADDRESS(obj); NMPlatformIPXAddress a; NML3ConfigMergeHookResult hook_result = { - .ip4acd_not_ready = NM_OPTION_BOOL_DEFAULT, + .ip4acd_not_ready = NM_OPTION_BOOL_DEFAULT, + .assume_config_once = NM_OPTION_BOOL_DEFAULT, }; #define _ensure_a() \ @@ -2766,6 +2783,12 @@ nm_l3_config_data_merge(NML3ConfigData * self, a.a4.a_acd_not_ready = (!!hook_result.ip4acd_not_ready); } + if (hook_result.assume_config_once != NM_OPTION_BOOL_DEFAULT + && (!!hook_result.assume_config_once) != a_src->a_assume_config_once) { + _ensure_a(); + a.ax.a_assume_config_once = (!!hook_result.assume_config_once); + } + nm_l3_config_data_add_address_full(self, addr_family, a_src == &a.ax ? NULL : obj, @@ -2784,7 +2807,8 @@ nm_l3_config_data_merge(NML3ConfigData * self, const NMPlatformIPRoute * r_src = NMP_OBJECT_CAST_IP_ROUTE(obj); NMPlatformIPXRoute r; NML3ConfigMergeHookResult hook_result = { - .ip4acd_not_ready = NM_OPTION_BOOL_DEFAULT, + .ip4acd_not_ready = NM_OPTION_BOOL_DEFAULT, + .assume_config_once = NM_OPTION_BOOL_DEFAULT, }; #define _ensure_r() \ @@ -2807,6 +2831,12 @@ nm_l3_config_data_merge(NML3ConfigData * self, nm_assert(hook_result.ip4acd_not_ready == NM_OPTION_BOOL_DEFAULT); + if (hook_result.assume_config_once != NM_OPTION_BOOL_DEFAULT + && (!!hook_result.assume_config_once) != r_src->r_assume_config_once) { + _ensure_r(); + r.rx.r_assume_config_once = (!!hook_result.assume_config_once); + } + if (!NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_CLONE)) { if (r_src->table_any) { _ensure_r(); diff --git a/src/core/nm-l3-config-data.h b/src/core/nm-l3-config-data.h index ac0278d3db..b2f36b3ed1 100644 --- a/src/core/nm-l3-config-data.h +++ b/src/core/nm-l3-config-data.h @@ -137,6 +137,7 @@ NML3ConfigData *nm_l3_config_data_new_from_platform(NMDedupMultiIndex * mu typedef struct { NMOptionBool ip4acd_not_ready; + NMOptionBool assume_config_once; } NML3ConfigMergeHookResult; typedef gboolean (*NML3ConfigMergeHookAddObj)(const NML3ConfigData * l3cd, diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c index c243c6a5bd..2e05200e38 100644 --- a/src/core/nm-l3cfg.c +++ b/src/core/nm-l3cfg.c @@ -2923,6 +2923,7 @@ nm_l3cfg_remove_config_all_dirty(NML3Cfg *self, gconstpointer tag) typedef struct { NML3Cfg * self; gconstpointer tag; + bool assume_config_once; } L3ConfigMergeHookAddObjData; static gboolean @@ -2940,6 +2941,9 @@ _l3_hook_add_obj_cb(const NML3ConfigData * l3cd, nm_assert(obj); 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); + + hook_result->assume_config_once = hook_data->assume_config_once; switch (NMP_OBJECT_GET_TYPE(obj)) { case NMP_OBJECT_TYPE_IP4_ADDRESS: @@ -3058,6 +3062,9 @@ _l3cfg_update_combined_config(NML3Cfg * self, 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); + nm_l3_config_data_merge(l3cd, l3cd_data->l3cd, l3cd_data->merge_flags, diff --git a/src/core/nm-l3cfg.h b/src/core/nm-l3cfg.h index 48ce86321a..9190e1f398 100644 --- a/src/core/nm-l3cfg.h +++ b/src/core/nm-l3cfg.h @@ -40,10 +40,23 @@ typedef enum _nm_packed { * nm_l3cfg_add_config() the same NML3Cfg again (with a different * tag), or by calling nm_l3cfg_add_config() again with this flag * cleared (and the same tag). + * @NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE: a commit with + * %NM_L3_CFG_COMMIT_TYPE_ASSUME, means to not remove/add + * addresses that are missing/already exist. The assume mode + * is for taking over a device gracefully after restart, so + * it aims to preserve whatever was configured (or not configured). + * With this flag enabled, the first commit in assume mode will still + * add the addresses/routes. This is necessary for example with IPv6LL. + * Also while assuming a device, we want to configure things + * (like an IPv6 address), so we need to bypass the common + * "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. */ typedef enum _nm_packed { - NM_L3CFG_CONFIG_FLAGS_NONE = 0, - NM_L3CFG_CONFIG_FLAGS_ONLY_FOR_ACD = (1LL << 0), + NM_L3CFG_CONFIG_FLAGS_NONE = 0, + NM_L3CFG_CONFIG_FLAGS_ONLY_FOR_ACD = (1LL << 0), + NM_L3CFG_CONFIG_FLAGS_ASSUME_CONFIG_ONCE = (1LL << 1), } NML3CfgConfigFlags; typedef enum _nm_packed {