From 3522d8ee92ac9d11c7425c679f2e245801cba1aa Mon Sep 17 00:00:00 2001 From: eabdullin Date: Mon, 15 Jan 2024 11:45:45 +0300 Subject: [PATCH] Sync with stable --- .../1001-cloud-setup-IMDSv2-rh2151987.patch | 1490 ++++++++++++++++ ...-support-to-no-aaaa-option-rh2144521.patch | 104 ++ ...03-suppport-bond-port-prio-rh1920398.patch | 1531 +++++++++++++++++ ...to-teamd-in-update_connect-rh2182029.patch | 52 + ...e-the-address-when-removed-rh2209353.patch | 140 ++ ...read-infiniband-from-ifcfg-rh2209164.patch | 1299 ++++++++++++++ ...ock-autoconnect-on-reapply-rh2207690.patch | 47 + ...ix-terminating-in-reconfig-rh2221903.patch | 190 ++ SPECS/NetworkManager.spec | 35 +- 9 files changed, 4887 insertions(+), 1 deletion(-) create mode 100644 SOURCES/1001-cloud-setup-IMDSv2-rh2151987.patch create mode 100644 SOURCES/1002-dns-add-support-to-no-aaaa-option-rh2144521.patch create mode 100644 SOURCES/1003-suppport-bond-port-prio-rh1920398.patch create mode 100644 SOURCES/1004-team-don-t-try-to-connect-to-teamd-in-update_connect-rh2182029.patch create mode 100644 SOURCES/1005-ipv6ll-don-t-regenerate-the-address-when-removed-rh2209353.patch create mode 100644 SOURCES/1006-fix-read-infiniband-from-ifcfg-rh2209164.patch create mode 100644 SOURCES/1007-unblock-autoconnect-on-reapply-rh2207690.patch create mode 100644 SOURCES/1008-cloud-setup-fix-terminating-in-reconfig-rh2221903.patch diff --git a/SOURCES/1001-cloud-setup-IMDSv2-rh2151987.patch b/SOURCES/1001-cloud-setup-IMDSv2-rh2151987.patch new file mode 100644 index 0000000..eefa70a --- /dev/null +++ b/SOURCES/1001-cloud-setup-IMDSv2-rh2151987.patch @@ -0,0 +1,1490 @@ +From 89a6ce575d52bbaa1b928275c39517a071449da7 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Mon, 27 Feb 2023 09:14:10 +0100 +Subject: [PATCH 1/7] cloud-setup: use nm_strv_dup_packed() in + nm_http_client_poll_get() + +No need to do a deep clone. The strv array is not ever modified and we +pack it together in one memory allocation. + +(cherry picked from commit 599fe234ea4864396eb70530513b2646aa97f576) +(cherry picked from commit 3787eacac9c1fc9ff9b423f9d9cea9907e209ebb) +(cherry picked from commit 89a6ce575d52bbaa1b928275c39517a071449da7) +--- + src/nm-cloud-setup/nm-http-client.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/src/nm-cloud-setup/nm-http-client.c b/src/nm-cloud-setup/nm-http-client.c +index a0964e2165..98ede1e403 100644 +--- a/src/nm-cloud-setup/nm-http-client.c ++++ b/src/nm-cloud-setup/nm-http-client.c +@@ -419,7 +419,7 @@ _poll_get_data_free(gpointer data) + g_free(poll_get_data->uri); + + nm_clear_pointer(&poll_get_data->response_data, g_bytes_unref); +- g_strfreev((char **) poll_get_data->http_headers); ++ g_free((gpointer) poll_get_data->http_headers); + + nm_g_slice_free(poll_get_data); + } +@@ -552,9 +552,14 @@ nm_http_client_poll_get(NMHttpClient *self, + .check_fcn = check_fcn, + .check_user_data = check_user_data, + .response_code = -1, +- .http_headers = NM_CAST_STRV_CC(g_strdupv((char **) http_headers)), ++ .http_headers = NULL, + }; + ++ if (http_headers) { ++ poll_get_data->http_headers = ++ nm_strv_dup_packed(http_headers, -1) ?: g_new(const char *, 1); ++ } ++ + nmcs_wait_for_objects_register(poll_get_data->task); + + g_task_set_task_data(poll_get_data->task, poll_get_data, _poll_get_data_free); +-- +2.39.2 + + +From 36d417af60a2a09863e00cae869899883265ee8c Mon Sep 17 00:00:00 2001 +From: Lubomir Rintel +Date: Mon, 27 Feb 2023 00:09:13 +0100 +Subject: [PATCH 2/7] cloud_setup: unexport nm_http_client_get() + +It's not used anywhere. + +(cherry picked from commit ce225b2c06089adc402277f2b80afacb9da8cc5f) +(cherry picked from commit 23b9514080c0c578ec5a8e023081837240f41896) +(cherry picked from commit 36d417af60a2a09863e00cae869899883265ee8c) +--- + src/nm-cloud-setup/nm-http-client.c | 4 ++-- + src/nm-cloud-setup/nm-http-client.h | 15 --------------- + 2 files changed, 2 insertions(+), 17 deletions(-) + +diff --git a/src/nm-cloud-setup/nm-http-client.c b/src/nm-cloud-setup/nm-http-client.c +index 98ede1e403..e6cc20fa75 100644 +--- a/src/nm-cloud-setup/nm-http-client.c ++++ b/src/nm-cloud-setup/nm-http-client.c +@@ -256,7 +256,7 @@ _get_cancelled_cb(GObject *object, gpointer user_data) + _ehandle_complete(edata, error); + } + +-void ++static void + nm_http_client_get(NMHttpClient *self, + const char *url, + int timeout_msec, +@@ -366,7 +366,7 @@ nm_http_client_get(NMHttpClient *self, + * + * Returns: %TRUE on success or %FALSE with an error code. + */ +-gboolean ++static gboolean + nm_http_client_get_finish(NMHttpClient *self, + GAsyncResult *result, + long *out_response_code, +diff --git a/src/nm-cloud-setup/nm-http-client.h b/src/nm-cloud-setup/nm-http-client.h +index 0a7052ae25..6cc08ba97c 100644 +--- a/src/nm-cloud-setup/nm-http-client.h ++++ b/src/nm-cloud-setup/nm-http-client.h +@@ -27,21 +27,6 @@ GMainContext *nm_http_client_get_main_context(NMHttpClient *self); + + /*****************************************************************************/ + +-void nm_http_client_get(NMHttpClient *self, +- const char *uri, +- int timeout_msec, +- gssize max_data, +- const char *const *http_headers, +- GCancellable *cancellable, +- GAsyncReadyCallback callback, +- gpointer user_data); +- +-gboolean nm_http_client_get_finish(NMHttpClient *self, +- GAsyncResult *result, +- long *out_response_code, +- GBytes **out_response_data, +- GError **error); +- + typedef gboolean (*NMHttpClientPollGetCheckFcn)(long response_code, + GBytes *response_data, + gpointer check_user_data, +-- +2.39.2 + + +From 20cd11ee4974bb1690d523d5700492ad9c618688 Mon Sep 17 00:00:00 2001 +From: Lubomir Rintel +Date: Mon, 27 Feb 2023 00:09:40 +0100 +Subject: [PATCH 3/7] cloud-setup: rename get/Get identifiers to req and Req + +We're going to extend those to issue methods other than GET. +Also, "request" would've been too long, "req" looks nicer. + +(cherry picked from commit 85ce088616aae3d61c9bc51eb395d1f59ed9a503) +(cherry picked from commit 6e8cfbae32e22ba75693146039b53b516a4147e1) +(cherry picked from commit 20cd11ee4974bb1690d523d5700492ad9c618688) +--- + src/nm-cloud-setup/nm-http-client.c | 142 +++++++++++----------- + src/nm-cloud-setup/nm-http-client.h | 8 +- + src/nm-cloud-setup/nmcs-provider-aliyun.c | 20 +-- + src/nm-cloud-setup/nmcs-provider-azure.c | 24 ++-- + src/nm-cloud-setup/nmcs-provider-ec2.c | 14 +-- + src/nm-cloud-setup/nmcs-provider-gcp.c | 20 +-- + 6 files changed, 114 insertions(+), 114 deletions(-) + +diff --git a/src/nm-cloud-setup/nm-http-client.c b/src/nm-cloud-setup/nm-http-client.c +index e6cc20fa75..ed7914df8f 100644 +--- a/src/nm-cloud-setup/nm-http-client.c ++++ b/src/nm-cloud-setup/nm-http-client.c +@@ -104,12 +104,12 @@ typedef struct { + } GetResult; + + static void +-_get_result_free(gpointer data) ++_req_result_free(gpointer data) + { +- GetResult *get_result = data; ++ GetResult *req_result = data; + +- g_bytes_unref(get_result->response_data); +- nm_g_slice_free(get_result); ++ g_bytes_unref(req_result->response_data); ++ nm_g_slice_free(req_result); + } + + typedef struct { +@@ -154,7 +154,7 @@ _ehandle_free(EHandleData *edata) + static void + _ehandle_complete(EHandleData *edata, GError *error_take) + { +- GetResult *get_result; ++ GetResult *req_result; + gs_free char *str_tmp_1 = NULL; + long response_code = -1; + +@@ -200,15 +200,15 @@ _ehandle_complete(EHandleData *edata, GError *error_take) + + _ehandle_free_ehandle(edata); + +- get_result = g_slice_new(GetResult); +- *get_result = (GetResult){ ++ req_result = g_slice_new(GetResult); ++ *req_result = (GetResult){ + .response_code = response_code, + /* This ensures that response_data is always NUL terminated. This is an important guarantee + * that NMHttpClient makes. */ + .response_data = nm_str_buf_finalize_to_gbytes(&edata->recv_data), + }; + +- g_task_return_pointer(edata->task, get_result, _get_result_free); ++ g_task_return_pointer(edata->task, req_result, _req_result_free); + + _ehandle_free(edata); + } +@@ -257,7 +257,7 @@ _get_cancelled_cb(GObject *object, gpointer user_data) + } + + static void +-nm_http_client_get(NMHttpClient *self, ++nm_http_client_req(NMHttpClient *self, + const char *url, + int timeout_msec, + gssize max_data, +@@ -280,7 +280,7 @@ nm_http_client_get(NMHttpClient *self, + + edata = g_slice_new(EHandleData); + *edata = (EHandleData){ +- .task = nm_g_task_new(self, cancellable, nm_http_client_get, callback, user_data), ++ .task = nm_g_task_new(self, cancellable, nm_http_client_req, callback, user_data), + .recv_data = NM_STR_BUF_INIT(0, FALSE), + .max_data = max_data, + .url = g_strdup(url), +@@ -352,7 +352,7 @@ nm_http_client_get(NMHttpClient *self, + } + + /** +- * nm_http_client_get_finish: ++ * nm_http_client_req_finish: + * @self: the #NMHttpClient instance + * @result: the #GAsyncResult which to complete. + * @out_response_code: (allow-none) (out): the HTTP response code or -1 on other error. +@@ -367,33 +367,33 @@ nm_http_client_get(NMHttpClient *self, + * Returns: %TRUE on success or %FALSE with an error code. + */ + static gboolean +-nm_http_client_get_finish(NMHttpClient *self, ++nm_http_client_req_finish(NMHttpClient *self, + GAsyncResult *result, + long *out_response_code, + GBytes **out_response_data, + GError **error) + { +- GetResult *get_result; ++ GetResult *req_result; + + g_return_val_if_fail(NM_IS_HTTP_CLIENT(self), FALSE); +- g_return_val_if_fail(nm_g_task_is_valid(result, self, nm_http_client_get), FALSE); ++ g_return_val_if_fail(nm_g_task_is_valid(result, self, nm_http_client_req), FALSE); + +- get_result = g_task_propagate_pointer(G_TASK(result), error); ++ req_result = g_task_propagate_pointer(G_TASK(result), error); + +- nm_assert(!error || (!!get_result) == (!*error)); ++ nm_assert(!error || (!!req_result) == (!*error)); + +- if (!get_result) { ++ if (!req_result) { + NM_SET_OUT(out_response_code, -1); + NM_SET_OUT(out_response_data, NULL); + return FALSE; + } + +- NM_SET_OUT(out_response_code, get_result->response_code); ++ NM_SET_OUT(out_response_code, req_result->response_code); + + /* response_data is binary, but is also guaranteed to be NUL terminated! */ +- NM_SET_OUT(out_response_data, g_steal_pointer(&get_result->response_data)); ++ NM_SET_OUT(out_response_data, g_steal_pointer(&req_result->response_data)); + +- _get_result_free(get_result); ++ _req_result_free(req_result); + return TRUE; + } + +@@ -403,63 +403,63 @@ typedef struct { + GTask *task; + char *uri; + const char *const *http_headers; +- NMHttpClientPollGetCheckFcn check_fcn; ++ NMHttpClientPollReqCheckFcn check_fcn; + gpointer check_user_data; + GBytes *response_data; + gsize request_max_data; + long response_code; + int request_timeout_ms; +-} PollGetData; ++} PollReqData; + + static void +-_poll_get_data_free(gpointer data) ++_poll_req_data_free(gpointer data) + { +- PollGetData *poll_get_data = data; ++ PollReqData *poll_req_data = data; + +- g_free(poll_get_data->uri); ++ g_free(poll_req_data->uri); + +- nm_clear_pointer(&poll_get_data->response_data, g_bytes_unref); +- g_free((gpointer) poll_get_data->http_headers); ++ nm_clear_pointer(&poll_req_data->response_data, g_bytes_unref); ++ g_free((gpointer) poll_req_data->http_headers); + +- nm_g_slice_free(poll_get_data); ++ nm_g_slice_free(poll_req_data); + } + + static void +-_poll_get_probe_start_fcn(GCancellable *cancellable, ++_poll_req_probe_start_fcn(GCancellable *cancellable, + gpointer probe_user_data, + GAsyncReadyCallback callback, + gpointer user_data) + { +- PollGetData *poll_get_data = probe_user_data; ++ PollReqData *poll_req_data = probe_user_data; + +- /* balanced by _poll_get_probe_finish_fcn() */ +- g_object_ref(poll_get_data->task); ++ /* balanced by _poll_req_probe_finish_fcn() */ ++ g_object_ref(poll_req_data->task); + +- nm_http_client_get(g_task_get_source_object(poll_get_data->task), +- poll_get_data->uri, +- poll_get_data->request_timeout_ms, +- poll_get_data->request_max_data, +- poll_get_data->http_headers, ++ nm_http_client_req(g_task_get_source_object(poll_req_data->task), ++ poll_req_data->uri, ++ poll_req_data->request_timeout_ms, ++ poll_req_data->request_max_data, ++ poll_req_data->http_headers, + cancellable, + callback, + user_data); + } + + static gboolean +-_poll_get_probe_finish_fcn(GObject *source, ++_poll_req_probe_finish_fcn(GObject *source, + GAsyncResult *result, + gpointer probe_user_data, + GError **error) + { +- PollGetData *poll_get_data = probe_user_data; ++ PollReqData *poll_req_data = probe_user_data; + _nm_unused gs_unref_object GTask *task = +- poll_get_data->task; /* balance ref from _poll_get_probe_start_fcn() */ ++ poll_req_data->task; /* balance ref from _poll_req_probe_start_fcn() */ + gboolean success; + gs_free_error GError *local_error = NULL; + gs_unref_bytes GBytes *response_data = NULL; + long response_code = -1; + +- success = nm_http_client_get_finish(g_task_get_source_object(poll_get_data->task), ++ success = nm_http_client_req_finish(g_task_get_source_object(poll_req_data->task), + result, + &response_code, + &response_data, +@@ -476,10 +476,10 @@ _poll_get_probe_finish_fcn(GObject *source, + return FALSE; + } + +- if (poll_get_data->check_fcn) { +- success = poll_get_data->check_fcn(response_code, ++ if (poll_req_data->check_fcn) { ++ success = poll_req_data->check_fcn(response_code, + response_data, +- poll_get_data->check_user_data, ++ poll_req_data->check_user_data, + &local_error); + } else + success = (response_code == 200); +@@ -494,15 +494,15 @@ _poll_get_probe_finish_fcn(GObject *source, + return FALSE; + } + +- poll_get_data->response_code = response_code; +- poll_get_data->response_data = g_steal_pointer(&response_data); ++ poll_req_data->response_code = response_code; ++ poll_req_data->response_data = g_steal_pointer(&response_data); + return TRUE; + } + + static void +-_poll_get_done_cb(GObject *source, GAsyncResult *result, gpointer user_data) ++_poll_req_done_cb(GObject *source, GAsyncResult *result, gpointer user_data) + { +- PollGetData *poll_get_data = user_data; ++ PollReqData *poll_req_data = user_data; + gs_free_error GError *error = NULL; + gboolean success; + +@@ -511,15 +511,15 @@ _poll_get_done_cb(GObject *source, GAsyncResult *result, gpointer user_data) + nm_assert((!!success) == (!error)); + + if (error) +- g_task_return_error(poll_get_data->task, g_steal_pointer(&error)); ++ g_task_return_error(poll_req_data->task, g_steal_pointer(&error)); + else +- g_task_return_boolean(poll_get_data->task, TRUE); ++ g_task_return_boolean(poll_req_data->task, TRUE); + +- g_object_unref(poll_get_data->task); ++ g_object_unref(poll_req_data->task); + } + + void +-nm_http_client_poll_get(NMHttpClient *self, ++nm_http_client_poll_req(NMHttpClient *self, + const char *uri, + int request_timeout_ms, + gssize request_max_data, +@@ -527,13 +527,13 @@ nm_http_client_poll_get(NMHttpClient *self, + int ratelimit_timeout_ms, + const char *const *http_headers, + GCancellable *cancellable, +- NMHttpClientPollGetCheckFcn check_fcn, ++ NMHttpClientPollReqCheckFcn check_fcn, + gpointer check_user_data, + GAsyncReadyCallback callback, + gpointer user_data) + { + nm_auto_pop_gmaincontext GMainContext *context = NULL; +- PollGetData *poll_get_data; ++ PollReqData *poll_req_data; + + g_return_if_fail(NM_IS_HTTP_CLIENT(self)); + g_return_if_fail(uri && uri[0]); +@@ -543,9 +543,9 @@ nm_http_client_poll_get(NMHttpClient *self, + g_return_if_fail(ratelimit_timeout_ms >= -1); + g_return_if_fail(!cancellable || G_CANCELLABLE(cancellable)); + +- poll_get_data = g_slice_new(PollGetData); +- *poll_get_data = (PollGetData){ +- .task = nm_g_task_new(self, cancellable, nm_http_client_poll_get, callback, user_data), ++ poll_req_data = g_slice_new(PollReqData); ++ *poll_req_data = (PollReqData){ ++ .task = nm_g_task_new(self, cancellable, nm_http_client_poll_req, callback, user_data), + .uri = g_strdup(uri), + .request_timeout_ms = request_timeout_ms, + .request_max_data = request_max_data, +@@ -556,13 +556,13 @@ nm_http_client_poll_get(NMHttpClient *self, + }; + + if (http_headers) { +- poll_get_data->http_headers = ++ poll_req_data->http_headers = + nm_strv_dup_packed(http_headers, -1) ?: g_new(const char *, 1); + } + +- nmcs_wait_for_objects_register(poll_get_data->task); ++ nmcs_wait_for_objects_register(poll_req_data->task); + +- g_task_set_task_data(poll_get_data->task, poll_get_data, _poll_get_data_free); ++ g_task_set_task_data(poll_req_data->task, poll_req_data, _poll_req_data_free); + + context = + nm_g_main_context_push_thread_default_if_necessary(nm_http_client_get_main_context(self)); +@@ -570,28 +570,28 @@ nm_http_client_poll_get(NMHttpClient *self, + nmcs_utils_poll(poll_timeout_ms, + ratelimit_timeout_ms, + 0, +- _poll_get_probe_start_fcn, +- _poll_get_probe_finish_fcn, +- poll_get_data, ++ _poll_req_probe_start_fcn, ++ _poll_req_probe_finish_fcn, ++ poll_req_data, + cancellable, +- _poll_get_done_cb, +- poll_get_data); ++ _poll_req_done_cb, ++ poll_req_data); + } + + gboolean +-nm_http_client_poll_get_finish(NMHttpClient *self, ++nm_http_client_poll_req_finish(NMHttpClient *self, + GAsyncResult *result, + long *out_response_code, + GBytes **out_response_data, + GError **error) + { +- PollGetData *poll_get_data; ++ PollReqData *poll_req_data; + GTask *task; + gboolean success; + gs_free_error GError *local_error = NULL; + + g_return_val_if_fail(NM_HTTP_CLIENT(self), FALSE); +- g_return_val_if_fail(nm_g_task_is_valid(result, self, nm_http_client_poll_get), FALSE); ++ g_return_val_if_fail(nm_g_task_is_valid(result, self, nm_http_client_poll_req), FALSE); + + task = G_TASK(result); + +@@ -606,10 +606,10 @@ nm_http_client_poll_get_finish(NMHttpClient *self, + return FALSE; + } + +- poll_get_data = g_task_get_task_data(task); ++ poll_req_data = g_task_get_task_data(task); + +- NM_SET_OUT(out_response_code, poll_get_data->response_code); +- NM_SET_OUT(out_response_data, g_steal_pointer(&poll_get_data->response_data)); ++ NM_SET_OUT(out_response_code, poll_req_data->response_code); ++ NM_SET_OUT(out_response_data, g_steal_pointer(&poll_req_data->response_data)); + return TRUE; + } + +diff --git a/src/nm-cloud-setup/nm-http-client.h b/src/nm-cloud-setup/nm-http-client.h +index 6cc08ba97c..c8d3ffb458 100644 +--- a/src/nm-cloud-setup/nm-http-client.h ++++ b/src/nm-cloud-setup/nm-http-client.h +@@ -27,12 +27,12 @@ GMainContext *nm_http_client_get_main_context(NMHttpClient *self); + + /*****************************************************************************/ + +-typedef gboolean (*NMHttpClientPollGetCheckFcn)(long response_code, ++typedef gboolean (*NMHttpClientPollReqCheckFcn)(long response_code, + GBytes *response_data, + gpointer check_user_data, + GError **error); + +-void nm_http_client_poll_get(NMHttpClient *self, ++void nm_http_client_poll_req(NMHttpClient *self, + const char *uri, + int request_timeout_ms, + gssize request_max_data, +@@ -40,12 +40,12 @@ void nm_http_client_poll_get(NMHttpClient *self, + int ratelimit_timeout_ms, + const char *const *http_headers, + GCancellable *cancellable, +- NMHttpClientPollGetCheckFcn check_fcn, ++ NMHttpClientPollReqCheckFcn check_fcn, + gpointer check_user_data, + GAsyncReadyCallback callback, + gpointer user_data); + +-gboolean nm_http_client_poll_get_finish(NMHttpClient *self, ++gboolean nm_http_client_poll_req_finish(NMHttpClient *self, + GAsyncResult *result, + long *out_response_code, + GBytes **out_response_data, +diff --git a/src/nm-cloud-setup/nmcs-provider-aliyun.c b/src/nm-cloud-setup/nmcs-provider-aliyun.c +index 34ab5ecc87..93f26e7505 100644 +--- a/src/nm-cloud-setup/nmcs-provider-aliyun.c ++++ b/src/nm-cloud-setup/nmcs-provider-aliyun.c +@@ -77,7 +77,7 @@ _detect_get_meta_data_done_cb(GObject *source, GAsyncResult *result, gpointer us + gs_free_error GError *get_error = NULL; + gs_free_error GError *error = NULL; + +- nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &get_error); ++ nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &get_error); + + if (nm_utils_error_is_cancelled(get_error)) { + g_task_return_error(task, g_steal_pointer(&get_error)); +@@ -104,7 +104,7 @@ detect(NMCSProvider *provider, GTask *task) + + http_client = nmcs_provider_get_http_client(provider); + +- nm_http_client_poll_get(http_client, ++ nm_http_client_poll_req(http_client, + (uri = _aliyun_uri_concat(NM_ALIYUN_API_VERSION "/meta-data/")), + HTTP_TIMEOUT_MS, + 256 * 1024, +@@ -144,7 +144,7 @@ _get_config_fetch_done_cb(NMHttpClient *http_client, + gsize i; + gsize len; + +- nm_http_client_poll_get_finish(http_client, result, NULL, &response, &error); ++ nm_http_client_poll_req_finish(http_client, result, NULL, &response, &error); + + if (nm_utils_error_is_cancelled(error)) + return; +@@ -308,7 +308,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us + GHashTableIter h_iter; + NMHttpClient *http_client; + +- nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &error); ++ nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &error); + + if (nm_utils_error_is_cancelled(error)) + return; +@@ -362,7 +362,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us + v_mac_data->path); + + get_config_data->n_pending++; +- nm_http_client_poll_get( ++ nm_http_client_poll_req( + http_client, + (uri1 = _aliyun_uri_interfaces(v_mac_data->path, + NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/", +@@ -379,7 +379,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us + config_iface_data); + + get_config_data->n_pending++; +- nm_http_client_poll_get( ++ nm_http_client_poll_req( + http_client, + (uri2 = _aliyun_uri_interfaces(v_mac_data->path, + NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/", +@@ -396,7 +396,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us + config_iface_data); + + get_config_data->n_pending++; +- nm_http_client_poll_get( ++ nm_http_client_poll_req( + http_client, + (uri3 = _aliyun_uri_interfaces(v_mac_data->path, + NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/", +@@ -413,7 +413,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us + config_iface_data); + + get_config_data->n_pending++; +- nm_http_client_poll_get( ++ nm_http_client_poll_req( + http_client, + (uri4 = _aliyun_uri_interfaces(v_mac_data->path, + NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/", +@@ -430,7 +430,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us + config_iface_data); + + get_config_data->n_pending++; +- nm_http_client_poll_get( ++ nm_http_client_poll_req( + http_client, + (uri5 = _aliyun_uri_interfaces(v_mac_data->path, + NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/", +@@ -530,7 +530,7 @@ get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_dat + * MAC addresses, then we poll until we see them. They might not yet be + * around from the start... + */ +- nm_http_client_poll_get(nmcs_provider_get_http_client(provider), ++ nm_http_client_poll_req(nmcs_provider_get_http_client(provider), + (uri = _aliyun_uri_interfaces()), + HTTP_TIMEOUT_MS, + 256 * 1024, +diff --git a/src/nm-cloud-setup/nmcs-provider-azure.c b/src/nm-cloud-setup/nmcs-provider-azure.c +index 9b27af288a..b1f48f5c18 100644 +--- a/src/nm-cloud-setup/nmcs-provider-azure.c ++++ b/src/nm-cloud-setup/nmcs-provider-azure.c +@@ -42,7 +42,7 @@ _detect_get_meta_data_done_cb(GObject *source, GAsyncResult *result, gpointer us + gs_free_error GError *get_error = NULL; + gs_free_error GError *error = NULL; + +- nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &get_error); ++ nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &get_error); + + if (nm_utils_error_is_cancelled(get_error)) { + g_task_return_error(task, g_steal_pointer(&get_error)); +@@ -69,7 +69,7 @@ detect(NMCSProvider *provider, GTask *task) + + http_client = nmcs_provider_get_http_client(provider); + +- nm_http_client_poll_get(http_client, ++ nm_http_client_poll_req(http_client, + (uri = _azure_uri_concat("/metadata/instance")), + HTTP_TIMEOUT_MS, + 256 * 1024, +@@ -121,7 +121,7 @@ _get_config_fetch_done_cb(NMHttpClient *http_client, + in_addr_t tmp_addr; + int tmp_prefix = -1; + +- nm_http_client_poll_get_finish(http_client, result, NULL, &response, &error); ++ nm_http_client_poll_req_finish(http_client, result, NULL, &response, &error); + + if (nm_utils_error_is_cancelled(error)) + return; +@@ -241,7 +241,7 @@ _get_config_ips_prefix_list_cb(GObject *source, GAsyncResult *result, gpointer u + gsize line_len; + char iface_idx_str[30]; + +- nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); ++ nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); + + if (nm_utils_error_is_cancelled(error)) + return; +@@ -283,7 +283,7 @@ _get_config_ips_prefix_list_cb(GObject *source, GAsyncResult *result, gpointer u + + iface_data->n_iface_data_pending++; + +- nm_http_client_poll_get( ++ nm_http_client_poll_req( + NM_HTTP_CLIENT(source), + (uri = _azure_uri_interfaces(iface_idx_str, + "/ipv4/ipAddress/", +@@ -308,7 +308,7 @@ _get_config_ips_prefix_list_cb(GObject *source, GAsyncResult *result, gpointer u + gs_free char *uri = NULL; + + iface_data->n_iface_data_pending++; +- nm_http_client_poll_get( ++ nm_http_client_poll_req( + NM_HTTP_CLIENT(source), + (uri = _azure_uri_interfaces(iface_idx_str, "/ipv4/subnet/0/address/")), + HTTP_TIMEOUT_MS, +@@ -325,7 +325,7 @@ _get_config_ips_prefix_list_cb(GObject *source, GAsyncResult *result, gpointer u + nm_clear_g_free(&uri); + + iface_data->n_iface_data_pending++; +- nm_http_client_poll_get( ++ nm_http_client_poll_req( + NM_HTTP_CLIENT(source), + (uri = _azure_uri_interfaces(iface_idx_str, "/ipv4/subnet/0/prefix/")), + HTTP_TIMEOUT_MS, +@@ -357,7 +357,7 @@ _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data) + gs_free const char *uri = NULL; + char buf[100]; + +- nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); ++ nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); + + if (nm_utils_error_is_cancelled(error)) + return; +@@ -408,7 +408,7 @@ _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data) + + nm_sprintf_buf(buf, "%" G_GSSIZE_FORMAT "/ipv4/ipAddress/", iface_data->intern_iface_idx); + +- nm_http_client_poll_get(NM_HTTP_CLIENT(source), ++ nm_http_client_poll_req(NM_HTTP_CLIENT(source), + (uri = _azure_uri_interfaces(buf)), + HTTP_TIMEOUT_MS, + 512 * 1024, +@@ -441,7 +441,7 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat + guint i; + gssize extern_iface_idx_cnt = 0; + +- nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); ++ nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); + + if (nm_utils_error_is_cancelled(error)) + return; +@@ -508,7 +508,7 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat + nm_sprintf_buf(buf, "%" G_GSSIZE_FORMAT "/macAddress", iface_data->intern_iface_idx); + + get_config_data->n_pending++; +- nm_http_client_poll_get(NM_HTTP_CLIENT(source), ++ nm_http_client_poll_req(NM_HTTP_CLIENT(source), + (uri = _azure_uri_interfaces(buf)), + HTTP_TIMEOUT_MS, + 512 * 1024, +@@ -531,7 +531,7 @@ get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_dat + { + gs_free const char *uri = NULL; + +- nm_http_client_poll_get(nmcs_provider_get_http_client(provider), ++ nm_http_client_poll_req(nmcs_provider_get_http_client(provider), + (uri = _azure_uri_interfaces()), + HTTP_TIMEOUT_MS, + 256 * 1024, +diff --git a/src/nm-cloud-setup/nmcs-provider-ec2.c b/src/nm-cloud-setup/nmcs-provider-ec2.c +index d6fa03118d..35f7176c4d 100644 +--- a/src/nm-cloud-setup/nmcs-provider-ec2.c ++++ b/src/nm-cloud-setup/nmcs-provider-ec2.c +@@ -72,7 +72,7 @@ _detect_get_meta_data_done_cb(GObject *source, GAsyncResult *result, gpointer us + gs_free_error GError *get_error = NULL; + gs_free_error GError *error = NULL; + +- nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &get_error); ++ nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &get_error); + + if (nm_utils_error_is_cancelled(get_error)) { + g_task_return_error(task, g_steal_pointer(&get_error)); +@@ -99,7 +99,7 @@ detect(NMCSProvider *provider, GTask *task) + + http_client = nmcs_provider_get_http_client(provider); + +- nm_http_client_poll_get(http_client, ++ nm_http_client_poll_req(http_client, + (uri = _ec2_uri_concat("latest/meta-data/")), + HTTP_TIMEOUT_MS, + 256 * 1024, +@@ -126,7 +126,7 @@ _get_config_fetch_done_cb(NMHttpClient *http_client, + in_addr_t tmp_addr; + int tmp_prefix; + +- nm_http_client_poll_get_finish(http_client, result, NULL, &response, &error); ++ nm_http_client_poll_req_finish(http_client, result, NULL, &response, &error); + + if (nm_utils_error_is_cancelled(error)) + return; +@@ -204,7 +204,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us + GHashTableIter h_iter; + NMHttpClient *http_client; + +- nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &error); ++ nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &error); + + if (nm_utils_error_is_cancelled(error)) + return; +@@ -254,7 +254,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us + v_mac_data->path); + + get_config_data->n_pending++; +- nm_http_client_poll_get( ++ nm_http_client_poll_req( + http_client, + (uri1 = _ec2_uri_interfaces(v_mac_data->path, + NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/", +@@ -271,7 +271,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us + config_iface_data); + + get_config_data->n_pending++; +- nm_http_client_poll_get( ++ nm_http_client_poll_req( + http_client, + (uri2 = _ec2_uri_interfaces(v_mac_data->path, + NM_STR_HAS_SUFFIX(v_mac_data->path, "/") ? "" : "/", +@@ -371,7 +371,7 @@ get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_dat + * MAC addresses, then we poll until we see them. They might not yet be + * around from the start... + */ +- nm_http_client_poll_get(nmcs_provider_get_http_client(provider), ++ nm_http_client_poll_req(nmcs_provider_get_http_client(provider), + (uri = _ec2_uri_interfaces()), + HTTP_TIMEOUT_MS, + 256 * 1024, +diff --git a/src/nm-cloud-setup/nmcs-provider-gcp.c b/src/nm-cloud-setup/nmcs-provider-gcp.c +index a325f31a17..571c0fb826 100644 +--- a/src/nm-cloud-setup/nmcs-provider-gcp.c ++++ b/src/nm-cloud-setup/nmcs-provider-gcp.c +@@ -45,7 +45,7 @@ _detect_get_meta_data_done_cb(GObject *source, GAsyncResult *result, gpointer us + gs_free_error GError *get_error = NULL; + gs_free_error GError *error = NULL; + +- nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &get_error); ++ nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &get_error); + + if (nm_utils_error_is_cancelled(get_error)) { + g_task_return_error(task, g_steal_pointer(&get_error)); +@@ -72,7 +72,7 @@ detect(NMCSProvider *provider, GTask *task) + + http_client = nmcs_provider_get_http_client(provider); + +- nm_http_client_poll_get(http_client, ++ nm_http_client_poll_req(http_client, + (uri = _gcp_uri_concat("id")), + HTTP_TIMEOUT_MS, + 256 * 1024, +@@ -114,7 +114,7 @@ _get_config_fip_cb(GObject *source, GAsyncResult *result, gpointer user_data) + NMIPRoute **routes_arr; + NMIPRoute *route_new; + +- nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); ++ nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); + + if (nm_utils_error_is_cancelled(error)) + return; +@@ -171,7 +171,7 @@ _get_config_ips_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat + gsize line_len; + guint i; + +- nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); ++ nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); + + if (nm_utils_error_is_cancelled(error)) + return; +@@ -220,7 +220,7 @@ _get_config_ips_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat + const char *str = uri_arr->pdata[i]; + gs_free const char *uri = NULL; + +- nm_http_client_poll_get(NM_HTTP_CLIENT(source), ++ nm_http_client_poll_req(NM_HTTP_CLIENT(source), + (uri = _gcp_uri_interfaces(str)), + HTTP_TIMEOUT_MS, + HTTP_REQ_MAX_DATA, +@@ -252,7 +252,7 @@ _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data) + NMCSProviderGetConfigTaskData *get_config_data; + gboolean is_requested; + +- nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); ++ nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); + + if (nm_utils_error_is_cancelled(error)) + return; +@@ -306,7 +306,7 @@ _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data) + + nm_sprintf_buf(sbuf, "%" G_GSSIZE_FORMAT "/forwarded-ips/", iface_data->intern_iface_idx); + +- nm_http_client_poll_get(NM_HTTP_CLIENT(source), ++ nm_http_client_poll_req(NM_HTTP_CLIENT(source), + (uri = _gcp_uri_interfaces(sbuf)), + HTTP_TIMEOUT_MS, + HTTP_REQ_MAX_DATA, +@@ -339,7 +339,7 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat + guint i; + gssize extern_iface_idx_cnt = 0; + +- nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); ++ nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); + + if (nm_utils_error_is_cancelled(error)) + return; +@@ -405,7 +405,7 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat + nm_sprintf_buf(sbuf, "%" G_GSSIZE_FORMAT "/mac", data->intern_iface_idx); + + get_config_data->n_pending++; +- nm_http_client_poll_get(NM_HTTP_CLIENT(source), ++ nm_http_client_poll_req(NM_HTTP_CLIENT(source), + (uri = _gcp_uri_interfaces(sbuf)), + HTTP_TIMEOUT_MS, + HTTP_REQ_MAX_DATA, +@@ -428,7 +428,7 @@ get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_dat + { + gs_free const char *uri = NULL; + +- nm_http_client_poll_get(nmcs_provider_get_http_client(provider), ++ nm_http_client_poll_req(nmcs_provider_get_http_client(provider), + (uri = _gcp_uri_interfaces()), + HTTP_TIMEOUT_MS, + HTTP_REQ_MAX_DATA, +-- +2.39.2 + + +From aaf66e9174eb04d2df1f45530ebdca16e77a6ec5 Mon Sep 17 00:00:00 2001 +From: Lubomir Rintel +Date: Mon, 27 Feb 2023 00:13:31 +0100 +Subject: [PATCH 4/7] cloud-setup: make nm_http_client_req() accept a method + argument + +We'll need to be able to issue PUT calls. + +(cherry picked from commit cd74d75002783a79d1a4fca24b2fbe99ced933a8) +(cherry picked from commit eff4372045290ad380bddf03e5075ab671a7cff6) +(cherry picked from commit aaf66e9174eb04d2df1f45530ebdca16e77a6ec5) +--- + src/nm-cloud-setup/nm-http-client.c | 7 +++++++ + src/nm-cloud-setup/nm-http-client.h | 1 + + src/nm-cloud-setup/nmcs-provider-aliyun.c | 7 +++++++ + src/nm-cloud-setup/nmcs-provider-azure.c | 7 +++++++ + src/nm-cloud-setup/nmcs-provider-ec2.c | 4 ++++ + src/nm-cloud-setup/nmcs-provider-gcp.c | 5 +++++ + 6 files changed, 31 insertions(+) + +diff --git a/src/nm-cloud-setup/nm-http-client.c b/src/nm-cloud-setup/nm-http-client.c +index ed7914df8f..b3db93e058 100644 +--- a/src/nm-cloud-setup/nm-http-client.c ++++ b/src/nm-cloud-setup/nm-http-client.c +@@ -262,6 +262,7 @@ nm_http_client_req(NMHttpClient *self, + int timeout_msec, + gssize max_data, + const char *const *http_headers, ++ const char *http_method, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +@@ -328,6 +329,9 @@ nm_http_client_req(NMHttpClient *self, + curl_easy_setopt(edata->ehandle, CURLOPT_HTTPHEADER, edata->headers); + } + ++ if (http_method) ++ curl_easy_setopt(edata->ehandle, CURLOPT_CUSTOMREQUEST, http_method); ++ + if (timeout_msec > 0) { + edata->timeout_source = _source_attach(self, + nm_g_timeout_source_new(timeout_msec, +@@ -403,6 +407,7 @@ typedef struct { + GTask *task; + char *uri; + const char *const *http_headers; ++ const char *http_method; + NMHttpClientPollReqCheckFcn check_fcn; + gpointer check_user_data; + GBytes *response_data; +@@ -440,6 +445,7 @@ _poll_req_probe_start_fcn(GCancellable *cancellable, + poll_req_data->request_timeout_ms, + poll_req_data->request_max_data, + poll_req_data->http_headers, ++ poll_req_data->http_method, + cancellable, + callback, + user_data); +@@ -526,6 +532,7 @@ nm_http_client_poll_req(NMHttpClient *self, + int poll_timeout_ms, + int ratelimit_timeout_ms, + const char *const *http_headers, ++ const char *http_method, + GCancellable *cancellable, + NMHttpClientPollReqCheckFcn check_fcn, + gpointer check_user_data, +diff --git a/src/nm-cloud-setup/nm-http-client.h b/src/nm-cloud-setup/nm-http-client.h +index c8d3ffb458..641efb1f47 100644 +--- a/src/nm-cloud-setup/nm-http-client.h ++++ b/src/nm-cloud-setup/nm-http-client.h +@@ -39,6 +39,7 @@ void nm_http_client_poll_req(NMHttpClient *self, + int poll_timeout_ms, + int ratelimit_timeout_ms, + const char *const *http_headers, ++ const char *http_method, + GCancellable *cancellable, + NMHttpClientPollReqCheckFcn check_fcn, + gpointer check_user_data, +diff --git a/src/nm-cloud-setup/nmcs-provider-aliyun.c b/src/nm-cloud-setup/nmcs-provider-aliyun.c +index 93f26e7505..0500922058 100644 +--- a/src/nm-cloud-setup/nmcs-provider-aliyun.c ++++ b/src/nm-cloud-setup/nmcs-provider-aliyun.c +@@ -111,6 +111,7 @@ detect(NMCSProvider *provider, GTask *task) + 7000, + 1000, + NULL, ++ NULL, + g_task_get_cancellable(task), + NULL, + NULL, +@@ -372,6 +373,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us + 10000, + 1000, + NULL, ++ NULL, + get_config_data->intern_cancellable, + NULL, + NULL, +@@ -389,6 +391,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us + 10000, + 1000, + NULL, ++ NULL, + get_config_data->intern_cancellable, + NULL, + NULL, +@@ -406,6 +409,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us + 10000, + 1000, + NULL, ++ NULL, + get_config_data->intern_cancellable, + NULL, + NULL, +@@ -423,6 +427,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us + 10000, + 1000, + NULL, ++ NULL, + get_config_data->intern_cancellable, + NULL, + NULL, +@@ -440,6 +445,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us + 10000, + 1000, + NULL, ++ NULL, + get_config_data->intern_cancellable, + NULL, + NULL, +@@ -537,6 +543,7 @@ get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_dat + 15000, + 1000, + NULL, ++ NULL, + get_config_data->intern_cancellable, + _get_config_metadata_ready_check, + get_config_data, +diff --git a/src/nm-cloud-setup/nmcs-provider-azure.c b/src/nm-cloud-setup/nmcs-provider-azure.c +index b1f48f5c18..e74d042026 100644 +--- a/src/nm-cloud-setup/nmcs-provider-azure.c ++++ b/src/nm-cloud-setup/nmcs-provider-azure.c +@@ -76,6 +76,7 @@ detect(NMCSProvider *provider, GTask *task) + 7000, + 1000, + NM_MAKE_STRV(NM_AZURE_METADATA_HEADER), ++ NULL, + g_task_get_cancellable(task), + NULL, + NULL, +@@ -294,6 +295,7 @@ _get_config_ips_prefix_list_cb(GObject *source, GAsyncResult *result, gpointer u + 10000, + 1000, + NM_MAKE_STRV(NM_AZURE_METADATA_HEADER), ++ NULL, + get_config_data->intern_cancellable, + NULL, + NULL, +@@ -316,6 +318,7 @@ _get_config_ips_prefix_list_cb(GObject *source, GAsyncResult *result, gpointer u + 10000, + 1000, + NM_MAKE_STRV(NM_AZURE_METADATA_HEADER), ++ NULL, + get_config_data->intern_cancellable, + NULL, + NULL, +@@ -333,6 +336,7 @@ _get_config_ips_prefix_list_cb(GObject *source, GAsyncResult *result, gpointer u + 10000, + 1000, + NM_MAKE_STRV(NM_AZURE_METADATA_HEADER), ++ NULL, + get_config_data->intern_cancellable, + NULL, + NULL, +@@ -415,6 +419,7 @@ _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data) + 10000, + 1000, + NM_MAKE_STRV(NM_AZURE_METADATA_HEADER), ++ NULL, + get_config_data->intern_cancellable, + NULL, + NULL, +@@ -515,6 +520,7 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat + 10000, + 1000, + NM_MAKE_STRV(NM_AZURE_METADATA_HEADER), ++ NULL, + get_config_data->intern_cancellable, + NULL, + NULL, +@@ -538,6 +544,7 @@ get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_dat + 15000, + 1000, + NM_MAKE_STRV(NM_AZURE_METADATA_HEADER), ++ NULL, + get_config_data->intern_cancellable, + NULL, + NULL, +diff --git a/src/nm-cloud-setup/nmcs-provider-ec2.c b/src/nm-cloud-setup/nmcs-provider-ec2.c +index 35f7176c4d..c3c527cfd4 100644 +--- a/src/nm-cloud-setup/nmcs-provider-ec2.c ++++ b/src/nm-cloud-setup/nmcs-provider-ec2.c +@@ -106,6 +106,7 @@ detect(NMCSProvider *provider, GTask *task) + 7000, + 1000, + NULL, ++ NULL, + g_task_get_cancellable(task), + _detect_get_meta_data_check_cb, + NULL, +@@ -264,6 +265,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us + 10000, + 1000, + NULL, ++ NULL, + get_config_data->intern_cancellable, + NULL, + NULL, +@@ -281,6 +283,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us + 10000, + 1000, + NULL, ++ NULL, + get_config_data->intern_cancellable, + NULL, + NULL, +@@ -378,6 +381,7 @@ get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_dat + 15000, + 1000, + NULL, ++ NULL, + get_config_data->intern_cancellable, + _get_config_metadata_ready_check, + get_config_data, +diff --git a/src/nm-cloud-setup/nmcs-provider-gcp.c b/src/nm-cloud-setup/nmcs-provider-gcp.c +index 571c0fb826..ca354865dd 100644 +--- a/src/nm-cloud-setup/nmcs-provider-gcp.c ++++ b/src/nm-cloud-setup/nmcs-provider-gcp.c +@@ -79,6 +79,7 @@ detect(NMCSProvider *provider, GTask *task) + 7000, + 1000, + NM_MAKE_STRV(NM_GCP_METADATA_HEADER), ++ NULL, + g_task_get_cancellable(task), + NULL, + NULL, +@@ -227,6 +228,7 @@ _get_config_ips_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat + HTTP_POLL_TIMEOUT_MS, + HTTP_RATE_LIMIT_MS, + NM_MAKE_STRV(NM_GCP_METADATA_HEADER), ++ NULL, + get_config_data->intern_cancellable, + NULL, + NULL, +@@ -313,6 +315,7 @@ _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data) + HTTP_POLL_TIMEOUT_MS, + HTTP_RATE_LIMIT_MS, + NM_MAKE_STRV(NM_GCP_METADATA_HEADER), ++ NULL, + get_config_data->intern_cancellable, + NULL, + NULL, +@@ -412,6 +415,7 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat + HTTP_POLL_TIMEOUT_MS, + HTTP_RATE_LIMIT_MS, + NM_MAKE_STRV(NM_GCP_METADATA_HEADER), ++ NULL, + get_config_data->intern_cancellable, + NULL, + NULL, +@@ -435,6 +439,7 @@ get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_dat + HTTP_POLL_TIMEOUT_MS, + HTTP_RATE_LIMIT_MS, + NM_MAKE_STRV(NM_GCP_METADATA_HEADER), ++ NULL, + get_config_data->intern_cancellable, + NULL, + NULL, +-- +2.39.2 + + +From 06fc0ef35dc7e5e6295ab9beecba6071e556d55e Mon Sep 17 00:00:00 2001 +From: Lubomir Rintel +Date: Tue, 7 Mar 2023 13:51:57 +0100 +Subject: [PATCH 5/7] cloud-setup: document detect() and get_config() methods + +Clarify that detect() needs to succeed before get_config(). + +I thought it's sort of common sense, but it's better to be explicit as +we're going to rely on that. + +(cherry picked from commit 088bfd817ab5eb8aa0fb9cffe52fa3f456030ecc) +(cherry picked from commit d99864ccba6d7c9bac66dcbbcc49c01be0ddd719) +(cherry picked from commit 06fc0ef35dc7e5e6295ab9beecba6071e556d55e) +--- + src/nm-cloud-setup/nmcs-provider.h | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/src/nm-cloud-setup/nmcs-provider.h b/src/nm-cloud-setup/nmcs-provider.h +index 502f1d0323..3662fbe391 100644 +--- a/src/nm-cloud-setup/nmcs-provider.h ++++ b/src/nm-cloud-setup/nmcs-provider.h +@@ -152,8 +152,36 @@ typedef struct { + const char *_name; + const char *_env_provider_enabled; + ++ /** ++ * detect: ++ * @self: the #NMCSProvider ++ * @task: a #GTask that's completed when the detection finishes. ++ * ++ * Checks whether the metadata of a particular cloud provider is ++ * accessible on the host machine. The check runs asynchronously. ++ * ++ * When the check finishes, @task is completed. If the check was ++ * successful, @task returns a gboolean of %TRUE. Otherwise ++ * a %FALSE value or an error is returned. ++ * ++ * The routine has to be called before the get_config() can be ++ * used. ++ */ + void (*detect)(NMCSProvider *self, GTask *task); + ++ /** ++ * get_config: ++ * @self: the #NMCSProvider ++ * @get_config_data: encapsulates a #GTask and network configuration data ++ * ++ * Collects the network configuration from metadata service of a ++ * particular cloud provider. The metadata is traversed and checked ++ * asynchronously, completing a task encapsulated in @get_config_data ++ * upon finishing. ++ * ++ * Call to detect() with a successful result is necessary before ++ * using this routine. ++ */ + void (*get_config)(NMCSProvider *self, NMCSProviderGetConfigTaskData *get_config_data); + + } NMCSProviderClass; +-- +2.39.2 + + +From e3ac982b32361105708d489a73eaed2bc4dc5f9f Mon Sep 17 00:00:00 2001 +From: Lubomir Rintel +Date: Mon, 27 Feb 2023 00:15:11 +0100 +Subject: [PATCH 6/7] cloud-setup/ec2: start with requesting a IMDSv2 token + +The present version of the EC2 metadata API (IMDSv2) requires a header +with a token to be present in all requests. The token is essentially a +cookie that's not actually a cookie that's obtained with a PUT call that +doesn't put anything. Apparently it's too easy to trick someone into +calling a GET method. + +EC2 now supports IMDSv2 everywhere with IMDSv1 being optional, so let's +just use IMDSv2 unconditionally. Also, the presence of a token API can +be used to detect the AWS EC2 cloud. + +https://bugzilla.redhat.com/show_bug.cgi?id=2151986 +(cherry picked from commit 8b7e12c2d631c47292258c29429cd565715ea186) +(cherry picked from commit 429f36cd81ddbe337f04c09a352fd78cd29e394d) +(cherry picked from commit e3ac982b32361105708d489a73eaed2bc4dc5f9f) +--- + src/nm-cloud-setup/nmcs-provider-ec2.c | 74 +++++++++++++++++++------- + 1 file changed, 54 insertions(+), 20 deletions(-) + +diff --git a/src/nm-cloud-setup/nmcs-provider-ec2.c b/src/nm-cloud-setup/nmcs-provider-ec2.c +index c3c527cfd4..3a27a30e68 100644 +--- a/src/nm-cloud-setup/nmcs-provider-ec2.c ++++ b/src/nm-cloud-setup/nmcs-provider-ec2.c +@@ -16,6 +16,11 @@ + #define NM_EC2_METADATA_URL_BASE /* $NM_EC2_BASE/$NM_EC2_API_VERSION */ \ + "/meta-data/network/interfaces/macs/" + ++/* Token TTL of 180 seconds is chosen abitrarily, in hope that it is ++ * surely more than enough to read all relevant metadata. */ ++#define NM_EC2_TOKEN_TTL_HEADER "X-aws-ec2-metadata-token-ttl-seconds: 180" ++#define NM_EC2_TOKEN_HEADER "X-aws-ec2-metadata-token: " ++ + static const char * + _ec2_base(void) + { +@@ -44,8 +49,15 @@ again: + + /*****************************************************************************/ + ++enum { ++ NM_EC2_HTTP_HEADER_TOKEN, ++ NM_EC2_HTTP_HEADER_SENTINEL, ++ _NM_EC2_HTTP_HEADER_NUM, ++}; ++ + struct _NMCSProviderEC2 { + NMCSProvider parent; ++ char *token; + }; + + struct _NMCSProviderEC2Class { +@@ -56,23 +68,18 @@ G_DEFINE_TYPE(NMCSProviderEC2, nmcs_provider_ec2, NMCS_TYPE_PROVIDER); + + /*****************************************************************************/ + +-static gboolean +-_detect_get_meta_data_check_cb(long response_code, +- GBytes *response, +- gpointer check_user_data, +- GError **error) +-{ +- return response_code == 200 && nmcs_utils_parse_get_full_line(response, "ami-id"); +-} +- + static void +-_detect_get_meta_data_done_cb(GObject *source, GAsyncResult *result, gpointer user_data) ++_detect_get_token_done_cb(GObject *source, GAsyncResult *result, gpointer user_data) + { + gs_unref_object GTask *task = user_data; ++ NMCSProviderEC2 *self = NMCS_PROVIDER_EC2(g_task_get_source_object(task)); ++ gs_unref_bytes GBytes *response = NULL; + gs_free_error GError *get_error = NULL; + gs_free_error GError *error = NULL; + +- nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, NULL, &get_error); ++ nm_clear_g_free(&self->token); ++ ++ nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &get_error); + + if (nm_utils_error_is_cancelled(get_error)) { + g_task_return_error(task, g_steal_pointer(&get_error)); +@@ -88,6 +95,12 @@ _detect_get_meta_data_done_cb(GObject *source, GAsyncResult *result, gpointer us + return; + } + ++ /* We use the token as-is. Special characters can cause confusion (e.g. ++ * response splitting), but we're not crossing a security boundary. ++ * None of the examples in AWS documentation does any sort of ++ * sanitization either. */ ++ self->token = g_strconcat(NM_EC2_TOKEN_HEADER, g_bytes_get_data(response, NULL), NULL); ++ + g_task_return_boolean(task, TRUE); + } + +@@ -100,17 +113,17 @@ detect(NMCSProvider *provider, GTask *task) + http_client = nmcs_provider_get_http_client(provider); + + nm_http_client_poll_req(http_client, +- (uri = _ec2_uri_concat("latest/meta-data/")), ++ (uri = _ec2_uri_concat("latest/api/token")), + HTTP_TIMEOUT_MS, + 256 * 1024, + 7000, + 1000, +- NULL, +- NULL, ++ NM_MAKE_STRV(NM_EC2_TOKEN_TTL_HEADER), ++ "PUT", + g_task_get_cancellable(task), +- _detect_get_meta_data_check_cb, + NULL, +- _detect_get_meta_data_done_cb, ++ NULL, ++ _detect_get_token_done_cb, + task); + } + +@@ -198,6 +211,7 @@ static void + _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer user_data) + { + NMCSProviderGetConfigTaskData *get_config_data; ++ NMCSProviderEC2 *self; + gs_unref_hashtable GHashTable *response_parsed = NULL; + gs_free_error GError *error = NULL; + GetConfigMetadataMac *v_mac_data; +@@ -211,6 +225,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us + return; + + get_config_data = user_data; ++ self = NMCS_PROVIDER_EC2(get_config_data->self); + + response_parsed = g_steal_pointer(&get_config_data->extra_data); + get_config_data->extra_data_destroy = NULL; +@@ -264,7 +279,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us + 512 * 1024, + 10000, + 1000, +- NULL, ++ NM_MAKE_STRV(self->token), + NULL, + get_config_data->intern_cancellable, + NULL, +@@ -282,7 +297,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us + 512 * 1024, + 10000, + 1000, +- NULL, ++ NM_MAKE_STRV(self->token), + NULL, + get_config_data->intern_cancellable, + NULL, +@@ -368,7 +383,13 @@ _get_config_metadata_ready_check(long response_code, + static void + get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_data) + { +- gs_free char *uri = NULL; ++ NMCSProviderEC2 *self = NMCS_PROVIDER_EC2(provider); ++ gs_free char *uri = NULL; ++ ++ /* This can be called only if detect() succeeded, which implies ++ * there must be a token. ++ */ ++ nm_assert(self->token); + + /* First we fetch the "macs/". If the caller requested some particular + * MAC addresses, then we poll until we see them. They might not yet be +@@ -380,7 +401,7 @@ get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_dat + 256 * 1024, + 15000, + 1000, +- NULL, ++ NM_MAKE_STRV(self->token), + NULL, + get_config_data->intern_cancellable, + _get_config_metadata_ready_check, +@@ -395,11 +416,24 @@ static void + nmcs_provider_ec2_init(NMCSProviderEC2 *self) + {} + ++static void ++dispose(GObject *object) ++{ ++ NMCSProviderEC2 *self = NMCS_PROVIDER_EC2(object); ++ ++ nm_clear_g_free(&self->token); ++ ++ G_OBJECT_CLASS(nmcs_provider_ec2_parent_class)->dispose(object); ++} ++ + static void + nmcs_provider_ec2_class_init(NMCSProviderEC2Class *klass) + { ++ GObjectClass *object_class = G_OBJECT_CLASS(klass); + NMCSProviderClass *provider_class = NMCS_PROVIDER_CLASS(klass); + ++ object_class->dispose = dispose; ++ + provider_class->_name = "ec2"; + provider_class->_env_provider_enabled = NMCS_ENV_VARIABLE("NM_CLOUD_SETUP_EC2"); + provider_class->detect = detect; +-- +2.39.2 + + +From 6abbdaaa64bad00acb65ba7049dcea6bb7ae1084 Mon Sep 17 00:00:00 2001 +From: Lubomir Rintel +Date: Tue, 21 Mar 2023 22:47:27 +0100 +Subject: [PATCH 7/7] cloud-setup: actually pass the HTTP method in + nm_http_client_poll_req() + +https://bugzilla.redhat.com/show_bug.cgi?id=2179718 +https://bugzilla.redhat.com/show_bug.cgi?id=2181466 + +Fixes: 8b7e12c2d631 ('cloud-setup/ec2: start with requesting a IMDSv2 token') +Fixes: cd74d7500278 ('cloud-setup: make nm_http_client_req() accept a method argument') +(cherry picked from commit f07da04cd9f16ac9e90d3d57d970ac935ad87b4d) +(cherry picked from commit d787c0c59dce57dfacc6602a4f1d5f8d8ed3b193) +(cherry picked from commit 6abbdaaa64bad00acb65ba7049dcea6bb7ae1084) +--- + src/nm-cloud-setup/nm-http-client.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/nm-cloud-setup/nm-http-client.c b/src/nm-cloud-setup/nm-http-client.c +index b3db93e058..db123f1033 100644 +--- a/src/nm-cloud-setup/nm-http-client.c ++++ b/src/nm-cloud-setup/nm-http-client.c +@@ -290,7 +290,7 @@ nm_http_client_req(NMHttpClient *self, + + nmcs_wait_for_objects_register(edata->task); + +- _LOG2D(edata, "start get ..."); ++ _LOG2D(edata, "start %s ...", http_method ?: "get"); + + edata->ehandle = curl_easy_init(); + if (!edata->ehandle) { +@@ -560,6 +560,7 @@ nm_http_client_poll_req(NMHttpClient *self, + .check_user_data = check_user_data, + .response_code = -1, + .http_headers = NULL, ++ .http_method = http_method, + }; + + if (http_headers) { +-- +2.39.2 + diff --git a/SOURCES/1002-dns-add-support-to-no-aaaa-option-rh2144521.patch b/SOURCES/1002-dns-add-support-to-no-aaaa-option-rh2144521.patch new file mode 100644 index 0000000..e6a42a4 --- /dev/null +++ b/SOURCES/1002-dns-add-support-to-no-aaaa-option-rh2144521.patch @@ -0,0 +1,104 @@ +From 53a9c6027f739daf8f49e2180e4ac51f73eae697 Mon Sep 17 00:00:00 2001 +From: Fernando Fernandez Mancera +Date: Tue, 21 Mar 2023 16:39:38 +0000 +Subject: [PATCH] dns: add support to no-aaaa option + +Users can set `no-aaaa` DNS option to suppress AAAA queries made by the +stub resolver, including AAAA lookups triggered by NSS-based interfaces +such as getaddrinfo. Only DNS lookups are affected. + +(cherry picked from commit 9d4bbf78f0b3a80eec9115663bd9db2c6460b369) +(cherry picked from commit f71cd2eb72d97ee9119e812bba7bbd581c587114) +(cherry picked from commit 920ab658b259d940072c61ae43f7013bbb431440) +--- + src/libnm-core-impl/nm-setting-ip-config.c | 8 +++++--- + src/libnm-core-public/nm-setting-ip-config.h | 1 + + src/libnmc-setting/settings-docs.h.in | 4 ++-- + src/nmcli/generate-docs-nm-settings-nmcli.xml.in | 4 ++-- + 4 files changed, 10 insertions(+), 7 deletions(-) + +diff --git a/src/libnm-core-impl/nm-setting-ip-config.c b/src/libnm-core-impl/nm-setting-ip-config.c +index c8fc461396..0e163094f5 100644 +--- a/src/libnm-core-impl/nm-setting-ip-config.c ++++ b/src/libnm-core-impl/nm-setting-ip-config.c +@@ -51,6 +51,7 @@ const NMUtilsDNSOptionDesc _nm_utils_dns_option_descs[] = { + {NM_SETTING_DNS_OPTION_USE_VC, FALSE, FALSE}, + {NM_SETTING_DNS_OPTION_NO_RELOAD, FALSE, FALSE}, + {NM_SETTING_DNS_OPTION_TRUST_AD, FALSE, FALSE}, ++ {NM_SETTING_DNS_OPTION_NO_AAAA, FALSE, FALSE}, + {NULL, FALSE, FALSE}}; + + static char * +@@ -6202,9 +6203,10 @@ nm_setting_ip_config_class_init(NMSettingIPConfigClass *klass) + * distinct from an empty list of properties. + * + * The currently supported options are "attempts", "debug", "edns0", +- * "inet6", "ip6-bytestring", "ip6-dotint", "ndots", "no-check-names", +- * "no-ip6-dotint", "no-reload", "no-tld-query", "rotate", "single-request", +- * "single-request-reopen", "timeout", "trust-ad", "use-vc". ++ * "inet6", "ip6-bytestring", "ip6-dotint", "ndots", "no-aaaa", ++ * "no-check-names", "no-ip6-dotint", "no-reload", "no-tld-query", ++ * "rotate", "single-request", "single-request-reopen", "timeout", ++ * "trust-ad", "use-vc". + * + * The "trust-ad" setting is only honored if the profile contributes + * name servers to resolv.conf, and if all contributing profiles have +diff --git a/src/libnm-core-public/nm-setting-ip-config.h b/src/libnm-core-public/nm-setting-ip-config.h +index acbdec0f61..b42c56a8f3 100644 +--- a/src/libnm-core-public/nm-setting-ip-config.h ++++ b/src/libnm-core-public/nm-setting-ip-config.h +@@ -359,6 +359,7 @@ char *nm_ip_routing_rule_to_string(const NMIPRoutingRule *self, + #define NM_SETTING_DNS_OPTION_USE_VC "use-vc" + #define NM_SETTING_DNS_OPTION_NO_RELOAD "no-reload" + #define NM_SETTING_DNS_OPTION_TRUST_AD "trust-ad" ++#define NM_SETTING_DNS_OPTION_NO_AAAA "no-aaaa" + + typedef struct _NMSettingIPConfigClass NMSettingIPConfigClass; + +diff --git a/src/libnmc-setting/settings-docs.h.in b/src/libnmc-setting/settings-docs.h.in +index 35dfa49f00..62edc77f6b 100644 +--- a/src/libnmc-setting/settings-docs.h.in ++++ b/src/libnmc-setting/settings-docs.h.in +@@ -168,7 +168,7 @@ + #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds). Set to 2147483647 (MAXINT32) for infinity.") + #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_VENDOR_CLASS_IDENTIFIER N_("The Vendor Class Identifier DHCP option (60). Special characters in the data string may be escaped using C-style escapes, nevertheless this property cannot contain nul bytes. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the DHCP option is not sent to the server.") + #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS N_("Array of IP addresses of DNS servers.") +-#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties. The currently supported options are \"attempts\", \"debug\", \"edns0\", \"inet6\", \"ip6-bytestring\", \"ip6-dotint\", \"ndots\", \"no-check-names\", \"no-ip6-dotint\", \"no-reload\", \"no-tld-query\", \"rotate\", \"single-request\", \"single-request-reopen\", \"timeout\", \"trust-ad\", \"use-vc\". The \"trust-ad\" setting is only honored if the profile contributes name servers to resolv.conf, and if all contributing profiles have \"trust-ad\" enabled. When using a caching DNS plugin (dnsmasq or systemd-resolved in NetworkManager.conf) then \"edns0\" and \"trust-ad\" are automatically added.") ++#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties. The currently supported options are \"attempts\", \"debug\", \"edns0\", \"inet6\", \"ip6-bytestring\", \"ip6-dotint\", \"ndots\", \"no-aaaa\", \"no-check-names\", \"no-ip6-dotint\", \"no-reload\", \"no-tld-query\", \"rotate\", \"single-request\", \"single-request-reopen\", \"timeout\", \"trust-ad\", \"use-vc\". The \"trust-ad\" setting is only honored if the profile contributes name servers to resolv.conf, and if all contributing profiles have \"trust-ad\" enabled. When using a caching DNS plugin (dnsmasq or systemd-resolved in NetworkManager.conf) then \"edns0\" and \"trust-ad\" are automatically added.") + #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting. A lower numerical value is better (higher priority). Negative values have the special effect of excluding other configurations with a greater numerical priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. To avoid all DNS leaks, set the priority of the profile that should be used to the most negative value of all active connections profiles. Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices. When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. Note that commonly the resolver tries name servers in /etc/resolv.conf in the order listed, proceeding with the next server in the list on failure. See for example the \"rotate\" option of the dns-options setting. If there are any negative DNS priorities, then only name servers from the devices with that lowest priority will be considered. When using a DNS resolver that supports Conditional Forwarding or Split DNS (with dns=dnsmasq or dns=systemd-resolved settings), each connection is used to query domains in its search list. The search domains determine which name servers to ask, and the DNS priority is used to prioritize name servers based on the domain. Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually). When multiple connections specify the same domain, the one with the best priority (lowest numerical value) wins. If a sub domain is configured on another interface it will be accepted regardless the priority, unless parent domain on the other interface has a negative priority, which causes the sub domain to be shadowed. With Split DNS one can avoid undesired DNS leaks by properly configuring DNS priorities and the search domains, so that only name servers of the desired interface are configured.") + #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_SEARCH N_("List of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting. When set on a profile that also enabled DHCP, the DNS search list received automatically (option 119 for DHCPv4 and option 24 for DHCPv6) gets merged with the manual list. This can be prevented by setting \"ignore-auto-dns\". Note that if no DNS searches are configured, the fallback will be derived from the domain from DHCP (option 15).") + #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set. Setting the gateway causes NetworkManager to configure a standard default route with the gateway as next hop. This is ignored if \"never-default\" is set. An alternative is to configure the default route explicitly with a manual route and /0 as prefix length. Note that the gateway usually conflicts with routing that NetworkManager configures for WireGuard interfaces, so usually it should not be set in that case. See \"ip4-auto-default-route\".") +@@ -194,7 +194,7 @@ + #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_SEND_HOSTNAME N_("If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer. If the \"dhcp-hostname\" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent.") + #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds). Set to 2147483647 (MAXINT32) for infinity.") + #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS N_("Array of IP addresses of DNS servers.") +-#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties. The currently supported options are \"attempts\", \"debug\", \"edns0\", \"inet6\", \"ip6-bytestring\", \"ip6-dotint\", \"ndots\", \"no-check-names\", \"no-ip6-dotint\", \"no-reload\", \"no-tld-query\", \"rotate\", \"single-request\", \"single-request-reopen\", \"timeout\", \"trust-ad\", \"use-vc\". The \"trust-ad\" setting is only honored if the profile contributes name servers to resolv.conf, and if all contributing profiles have \"trust-ad\" enabled. When using a caching DNS plugin (dnsmasq or systemd-resolved in NetworkManager.conf) then \"edns0\" and \"trust-ad\" are automatically added.") ++#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties. The currently supported options are \"attempts\", \"debug\", \"edns0\", \"inet6\", \"ip6-bytestring\", \"ip6-dotint\", \"ndots\", \"no-aaaa\", \"no-check-names\", \"no-ip6-dotint\", \"no-reload\", \"no-tld-query\", \"rotate\", \"single-request\", \"single-request-reopen\", \"timeout\", \"trust-ad\", \"use-vc\". The \"trust-ad\" setting is only honored if the profile contributes name servers to resolv.conf, and if all contributing profiles have \"trust-ad\" enabled. When using a caching DNS plugin (dnsmasq or systemd-resolved in NetworkManager.conf) then \"edns0\" and \"trust-ad\" are automatically added.") + #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting. A lower numerical value is better (higher priority). Negative values have the special effect of excluding other configurations with a greater numerical priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. To avoid all DNS leaks, set the priority of the profile that should be used to the most negative value of all active connections profiles. Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices. When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. Note that commonly the resolver tries name servers in /etc/resolv.conf in the order listed, proceeding with the next server in the list on failure. See for example the \"rotate\" option of the dns-options setting. If there are any negative DNS priorities, then only name servers from the devices with that lowest priority will be considered. When using a DNS resolver that supports Conditional Forwarding or Split DNS (with dns=dnsmasq or dns=systemd-resolved settings), each connection is used to query domains in its search list. The search domains determine which name servers to ask, and the DNS priority is used to prioritize name servers based on the domain. Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually). When multiple connections specify the same domain, the one with the best priority (lowest numerical value) wins. If a sub domain is configured on another interface it will be accepted regardless the priority, unless parent domain on the other interface has a negative priority, which causes the sub domain to be shadowed. With Split DNS one can avoid undesired DNS leaks by properly configuring DNS priorities and the search domains, so that only name servers of the desired interface are configured.") + #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_SEARCH N_("List of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting. When set on a profile that also enabled DHCP, the DNS search list received automatically (option 119 for DHCPv4 and option 24 for DHCPv6) gets merged with the manual list. This can be prevented by setting \"ignore-auto-dns\". Note that if no DNS searches are configured, the fallback will be derived from the domain from DHCP (option 15).") + #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set. Setting the gateway causes NetworkManager to configure a standard default route with the gateway as next hop. This is ignored if \"never-default\" is set. An alternative is to configure the default route explicitly with a manual route and /0 as prefix length. Note that the gateway usually conflicts with routing that NetworkManager configures for WireGuard interfaces, so usually it should not be set in that case. See \"ip4-auto-default-route\".") +diff --git a/src/nmcli/generate-docs-nm-settings-nmcli.xml.in b/src/nmcli/generate-docs-nm-settings-nmcli.xml.in +index 9acb76481e..03e6c0b54b 100644 +--- a/src/nmcli/generate-docs-nm-settings-nmcli.xml.in ++++ b/src/nmcli/generate-docs-nm-settings-nmcli.xml.in +@@ -656,7 +656,7 @@ + + ++ description="Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties. The currently supported options are "attempts", "debug", "edns0", "inet6", "ip6-bytestring", "ip6-dotint", "ndots", "no-aaaa", "no-check-names", "no-ip6-dotint", "no-reload", "no-tld-query", "rotate", "single-request", "single-request-reopen", "timeout", "trust-ad", "use-vc". The "trust-ad" setting is only honored if the profile contributes name servers to resolv.conf, and if all contributing profiles have "trust-ad" enabled. When using a caching DNS plugin (dnsmasq or systemd-resolved in NetworkManager.conf) then "edns0" and "trust-ad" are automatically added." /> + + + ++ description="Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties. The currently supported options are "attempts", "debug", "edns0", "inet6", "ip6-bytestring", "ip6-dotint", "ndots", "no-aaaa", "no-check-names", "no-ip6-dotint", "no-reload", "no-tld-query", "rotate", "single-request", "single-request-reopen", "timeout", "trust-ad", "use-vc". The "trust-ad" setting is only honored if the profile contributes name servers to resolv.conf, and if all contributing profiles have "trust-ad" enabled. When using a caching DNS plugin (dnsmasq or systemd-resolved in NetworkManager.conf) then "edns0" and "trust-ad" are automatically added." /> + + +Date: Fri, 17 Mar 2023 15:59:27 +0100 +Subject: [PATCH 1/8] libnm: fix ifcfg variable documentation at queue-id + property + +The correct variable for queue-id in ifcfg is BOND_PORT_QUEUE_ID. + +(cherry picked from commit 762cd06ffa4ff56b096128c26c931843429dc8c5) +(cherry picked from commit 87316737f36202902df76e5da6ba130e7bec4dfe) +(cherry picked from commit 40c523cd78ff322954f7b696afee8baee37da810) +--- + src/libnm-core-impl/nm-setting-bond-port.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libnm-core-impl/nm-setting-bond-port.c b/src/libnm-core-impl/nm-setting-bond-port.c +index 7ea82a763e..d1656a31ac 100644 +--- a/src/libnm-core-impl/nm-setting-bond-port.c ++++ b/src/libnm-core-impl/nm-setting-bond-port.c +@@ -148,7 +148,7 @@ nm_setting_bond_port_class_init(NMSettingBondPortClass *klass) + **/ + /* ---ifcfg-rh--- + * property: queue-id +- * variable: BONDING_OPTS: queue-id= ++ * variable: BOND_PORT_QUEUE_ID(+) + * values: 0 - 65535 + * default: 0 + * description: Queue ID. +-- +2.40.1 + + +From 495f3f1918bcde6105b74482613c51fd3b9185b0 Mon Sep 17 00:00:00 2001 +From: Beniamino Galvani +Date: Mon, 27 Feb 2023 10:55:29 +0100 +Subject: [PATCH 2/8] platform: rename link_change() to link_change_extra() + +There are many functions to replace properties of a link +(link_set_address, link_set_mtu, link_set_name, link_change, +etc.). Eventually, they will be replaced by a function that does +everything and removes all the code duplication. + +That function will be named link_change(); rename the current +link_change() to link_change_extra(). + +(cherry picked from commit babe2bacd3e23e03d5066b82ac0bb57c60b9db6f) +(cherry picked from commit 9ae85f6541505300ac811dff4671fe56a6d11ab7) +(cherry picked from commit 0a158141d3423173df0ba6983caed5d3aea8a9c8) +--- + src/libnm-platform/nm-linux-platform.c | 8 ++++---- + src/libnm-platform/nm-platform.c | 7 +++++-- + src/libnm-platform/nm-platform.h | 17 ++++++++++------- + 3 files changed, 19 insertions(+), 13 deletions(-) + +diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c +index b798d12d2a..527d509498 100644 +--- a/src/libnm-platform/nm-linux-platform.c ++++ b/src/libnm-platform/nm-linux-platform.c +@@ -7984,7 +7984,7 @@ out: + } + + static int +-link_change(NMPlatform *platform, NMLinkType type, int ifindex, gconstpointer extra_data) ++link_change_extra(NMPlatform *platform, NMLinkType type, int ifindex, gconstpointer extra_data) + { + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + +@@ -10824,9 +10824,9 @@ nm_linux_platform_class_init(NMLinuxPlatformClass *klass) + platform_class->sysctl_set_async = sysctl_set_async; + platform_class->sysctl_get = sysctl_get; + +- platform_class->link_add = link_add; +- platform_class->link_change = link_change; +- platform_class->link_delete = link_delete; ++ platform_class->link_add = link_add; ++ platform_class->link_change_extra = link_change_extra; ++ platform_class->link_delete = link_delete; + + platform_class->link_refresh = link_refresh; + +diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c +index 198e5f0afb..ab98491b45 100644 +--- a/src/libnm-platform/nm-platform.c ++++ b/src/libnm-platform/nm-platform.c +@@ -1388,7 +1388,10 @@ nm_platform_link_add(NMPlatform *self, + } + + int +-nm_platform_link_change(NMPlatform *self, NMLinkType type, int ifindex, gconstpointer extra_data) ++nm_platform_link_change_extra(NMPlatform *self, ++ NMLinkType type, ++ int ifindex, ++ gconstpointer extra_data) + { + char buf[512]; + const char *name = nm_platform_link_get_name(self, ifindex); +@@ -1429,7 +1432,7 @@ nm_platform_link_change(NMPlatform *self, NMLinkType type, int ifindex, gconstpo + buf; + })); + +- return klass->link_change(self, type, ifindex, extra_data); ++ return klass->link_change_extra(self, type, ifindex, extra_data); + } + + /** +diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h +index 30d0b5067c..d87eba3a63 100644 +--- a/src/libnm-platform/nm-platform.h ++++ b/src/libnm-platform/nm-platform.h +@@ -1222,9 +1222,10 @@ typedef struct { + guint32 mtu, + gconstpointer extra_data, + const NMPlatformLink **out_link); +- +- int (*link_change)(NMPlatform *self, NMLinkType type, int ifindex, gconstpointer extra_data); +- ++ int (*link_change_extra)(NMPlatform *self, ++ NMLinkType type, ++ int ifindex, ++ gconstpointer extra_data); + gboolean (*link_delete)(NMPlatform *self, int ifindex); + gboolean (*link_refresh)(NMPlatform *self, int ifindex); + gboolean (*link_set_netns)(NMPlatform *self, int ifindex, int netns_fd); +@@ -1749,8 +1750,10 @@ int nm_platform_link_add(NMPlatform *self, + gconstpointer extra_data, + const NMPlatformLink **out_link); + +-int +-nm_platform_link_change(NMPlatform *self, NMLinkType type, int ifindex, gconstpointer extra_data); ++int nm_platform_link_change_extra(NMPlatform *self, ++ NMLinkType type, ++ int ifindex, ++ gconstpointer extra_data); + + static inline int + nm_platform_link_veth_add(NMPlatform *self, +@@ -1790,13 +1793,13 @@ nm_platform_link_bridge_add(NMPlatform *self, + static inline int + nm_platform_link_bridge_change(NMPlatform *self, int ifindex, const NMPlatformLnkBridge *props) + { +- return nm_platform_link_change(self, NM_LINK_TYPE_BRIDGE, ifindex, props); ++ return nm_platform_link_change_extra(self, NM_LINK_TYPE_BRIDGE, ifindex, props); + } + + static inline int + nm_platform_link_bond_change(NMPlatform *self, int ifindex, const NMPlatformLnkBond *props) + { +- return nm_platform_link_change(self, NM_LINK_TYPE_BOND, ifindex, props); ++ return nm_platform_link_change_extra(self, NM_LINK_TYPE_BOND, ifindex, props); + } + + static inline int +-- +2.40.1 + + +From b58c3ee56f67c6e6e1e4fe0358d95df57537e6b0 Mon Sep 17 00:00:00 2001 +From: Lubomir Rintel +Date: Fri, 30 Sep 2022 22:40:03 +0200 +Subject: [PATCH 3/8] bond,bridge,team: use uuid for con.master when generating + connection + +If we're generating a connection for an externally configured slave, +refer the master by the UUID instead of the device name. + +This doesn't matter most of the time. However, on a checkpoint restore +we need to make sure that a connection that is unambiguously the original +master is up. + +Otherwise it could happen that a different connection was activated on the +same master device and the slaves being restored don't agree on which master +connection to bring up. + +I can't think of any thing that would rely on this but I've been wrong +about more serious things before. + +Fixes-test: @libnm_snapshot_reattach_unmanaged_ports_to_bridge + +https://bugzilla.redhat.com/show_bug.cgi?id=2125615 +(cherry picked from commit dc254f90e2b306700a0b81f7194e9b0438c62f4c) +(cherry picked from commit 836d7511e8b7d9660b18ee9876c635b8512f6966) +--- + src/core/devices/nm-device-bond.c | 9 +++++---- + src/core/devices/nm-device-bridge.c | 9 +++++---- + src/core/devices/team/nm-device-team.c | 9 +++++---- + 3 files changed, 15 insertions(+), 12 deletions(-) + +diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c +index 10765b609c..9556c57321 100644 +--- a/src/core/devices/nm-device-bond.c ++++ b/src/core/devices/nm-device-bond.c +@@ -224,9 +224,10 @@ controller_update_port_connection(NMDevice *self, + GError **error) + { + NMSettingBondPort *s_port; +- int ifindex_port = nm_device_get_ifindex(port); +- uint queue_id = NM_BOND_PORT_QUEUE_ID_DEF; +- gs_free char *queue_id_str = NULL; ++ int ifindex_port = nm_device_get_ifindex(port); ++ NMConnection *applied_connection = nm_device_get_applied_connection(self); ++ uint queue_id = NM_BOND_PORT_QUEUE_ID_DEF; ++ gs_free char *queue_id_str = NULL; + + g_return_val_if_fail(ifindex_port > 0, FALSE); + +@@ -243,7 +244,7 @@ controller_update_port_connection(NMDevice *self, + + g_object_set(nm_connection_get_setting_connection(connection), + NM_SETTING_CONNECTION_MASTER, +- nm_device_get_iface(self), ++ nm_connection_get_uuid(applied_connection), + NM_SETTING_CONNECTION_SLAVE_TYPE, + NM_SETTING_BOND_SETTING_NAME, + NULL); +diff --git a/src/core/devices/nm-device-bridge.c b/src/core/devices/nm-device-bridge.c +index 31cf361e8e..d8f1337058 100644 +--- a/src/core/devices/nm-device-bridge.c ++++ b/src/core/devices/nm-device-bridge.c +@@ -679,9 +679,10 @@ master_update_slave_connection(NMDevice *device, + NMDeviceBridge *self = NM_DEVICE_BRIDGE(device); + NMSettingConnection *s_con; + NMSettingBridgePort *s_port; +- int ifindex_slave = nm_device_get_ifindex(slave); +- const char *iface = nm_device_get_iface(device); +- const Option *option; ++ int ifindex_slave = nm_device_get_ifindex(slave); ++ NMConnection *applied_connection = nm_device_get_applied_connection(device); ++ ++ const Option *option; + + g_return_val_if_fail(ifindex_slave > 0, FALSE); + +@@ -717,7 +718,7 @@ master_update_slave_connection(NMDevice *device, + + g_object_set(s_con, + NM_SETTING_CONNECTION_MASTER, +- iface, ++ nm_connection_get_uuid(applied_connection), + NM_SETTING_CONNECTION_SLAVE_TYPE, + NM_SETTING_BRIDGE_SETTING_NAME, + NULL); +diff --git a/src/core/devices/team/nm-device-team.c b/src/core/devices/team/nm-device-team.c +index 9eca008a10..b745158ef8 100644 +--- a/src/core/devices/team/nm-device-team.c ++++ b/src/core/devices/team/nm-device-team.c +@@ -258,9 +258,10 @@ master_update_slave_connection(NMDevice *device, + gs_free_error GError *connect_error = NULL; + int err = 0; + struct teamdctl *tdc; +- const char *team_port_config = NULL; +- const char *iface = nm_device_get_iface(device); +- const char *iface_slave = nm_device_get_iface(slave); ++ const char *team_port_config = NULL; ++ const char *iface = nm_device_get_iface(device); ++ const char *iface_slave = nm_device_get_iface(slave); ++ NMConnection *applied_connection = nm_device_get_applied_connection(device); + + tdc = _tdc_connect_new(self, iface, &connect_error); + if (!tdc) { +@@ -299,7 +300,7 @@ master_update_slave_connection(NMDevice *device, + + g_object_set(nm_connection_get_setting_connection(connection), + NM_SETTING_CONNECTION_MASTER, +- iface, ++ nm_connection_get_uuid(applied_connection), + NM_SETTING_CONNECTION_SLAVE_TYPE, + NM_SETTING_TEAM_SETTING_NAME, + NULL); +-- +2.40.1 + + +From 8a02a950e1e23f584e5f3750ceb8a69efd7b3328 Mon Sep 17 00:00:00 2001 +From: Fernando Fernandez Mancera +Date: Fri, 3 Mar 2023 16:36:23 +0100 +Subject: [PATCH 4/8] platform: add netlink support for bond port options + +sysfs is deprecated and kernel will not add new bond port options to +sysfs. Netlink is a stable API and therefore is the right method to +communicate with kernel in order to set the link options. + +(cherry picked from commit bb435674b56e876084d4c31138ea95cb3174759f) +(cherry picked from commit 1bce7f0dec6c558fff8c6689d79cb7839eb925fe) +(cherry picked from commit ee592c02dd42ccf6bd45b8927716df5715fa45f8) +--- + src/core/devices/nm-device-bond.c | 42 ++++-------- + src/core/platform/nm-fake-platform.c | 24 +++++++ + src/core/platform/tests/test-link.c | 15 +++++ + src/libnm-glib-aux/nm-shared-utils.h | 8 +++ + src/libnm-platform/nm-linux-platform.c | 79 +++++++++++++++++++++- + src/libnm-platform/nm-platform.c | 90 ++++++++++++++++++++++++++ + src/libnm-platform/nm-platform.h | 25 +++++++ + 7 files changed, 250 insertions(+), 33 deletions(-) + +diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c +index 9556c57321..0485689d10 100644 +--- a/src/core/devices/nm-device-bond.c ++++ b/src/core/devices/nm-device-bond.c +@@ -223,24 +223,18 @@ controller_update_port_connection(NMDevice *self, + NMConnection *connection, + GError **error) + { +- NMSettingBondPort *s_port; +- int ifindex_port = nm_device_get_ifindex(port); +- NMConnection *applied_connection = nm_device_get_applied_connection(self); +- uint queue_id = NM_BOND_PORT_QUEUE_ID_DEF; +- gs_free char *queue_id_str = NULL; ++ NMSettingBondPort *s_port; ++ int ifindex_port = nm_device_get_ifindex(port); ++ NMConnection *applied_connection = nm_device_get_applied_connection(self); ++ const NMPlatformLink *pllink; + + g_return_val_if_fail(ifindex_port > 0, FALSE); + + s_port = _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_BOND_PORT); ++ pllink = nm_platform_link_get(nm_device_get_platform(port), ifindex_port); + +- queue_id_str = +- nm_platform_sysctl_slave_get_option(nm_device_get_platform(self), ifindex_port, "queue_id"); +- if (queue_id_str) { +- queue_id = +- _nm_utils_ascii_str_to_int64(queue_id_str, 10, 0, 65535, NM_BOND_PORT_QUEUE_ID_DEF); +- g_object_set(s_port, NM_SETTING_BOND_PORT_QUEUE_ID, queue_id, NULL); +- } else +- _LOGW(LOGD_BOND, "failed to read bond port setting '%s'", NM_SETTING_BOND_PORT_QUEUE_ID); ++ if (pllink && pllink->port_kind == NM_PORT_KIND_BOND) ++ g_object_set(s_port, NM_SETTING_BOND_PORT_QUEUE_ID, pllink->port_data.bond.queue_id, NULL); + + g_object_set(nm_connection_get_setting_connection(connection), + NM_SETTING_CONNECTION_MASTER, +@@ -501,23 +495,11 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) + static void + commit_port_options(NMDevice *bond_device, NMDevice *port, NMSettingBondPort *s_port) + { +- char queue_id_str[IFNAMSIZ + NM_STRLEN(":") + 5 + 100]; +- +- /* +- * The queue-id of bond port is read only, we should modify bond interface using: +- * echo "eth1:2" > /sys/class/net/bond0/bonding/queue_id +- * Kernel allows parital editing, so no need to care about other bond ports. +- */ +- g_snprintf(queue_id_str, +- sizeof(queue_id_str), +- "%s:%" G_GUINT32_FORMAT, +- nm_device_get_iface(port), +- s_port ? nm_setting_bond_port_get_queue_id(s_port) : NM_BOND_PORT_QUEUE_ID_DEF); +- +- nm_platform_sysctl_master_set_option(nm_device_get_platform(bond_device), +- nm_device_get_ifindex(bond_device), +- "queue_id", +- queue_id_str); ++ nm_platform_link_change( ++ nm_device_get_platform(port), ++ nm_device_get_ifindex(port), ++ &((NMPlatformLinkBondPort){.queue_id = s_port ? nm_setting_bond_port_get_queue_id(s_port) ++ : NM_BOND_PORT_QUEUE_ID_DEF})); + } + + static NMTernary +diff --git a/src/core/platform/nm-fake-platform.c b/src/core/platform/nm-fake-platform.c +index a1ca5434cb..c39c45e586 100644 +--- a/src/core/platform/nm-fake-platform.c ++++ b/src/core/platform/nm-fake-platform.c +@@ -667,6 +667,29 @@ link_supports_sriov(NMPlatform *platform, int ifindex) + } + } + ++static gboolean ++link_change(NMPlatform *platform, ++ int ifindex, ++ NMPortKind port_kind, ++ const NMPlatformLinkPortData *port_data) ++{ ++ NMFakePlatformLink *device = link_get(platform, ifindex); ++ nm_auto_nmpobj NMPObject *obj_tmp = NULL; ++ ++ switch (port_kind) { ++ case NM_PORT_KIND_BOND: ++ obj_tmp = nmp_object_clone(device->obj, FALSE); ++ obj_tmp->link.port_kind = NM_PORT_KIND_BOND; ++ obj_tmp->link.port_data.bond.queue_id = port_data->bond.queue_id; ++ link_set_obj(platform, device, obj_tmp); ++ return TRUE; ++ case NM_PORT_KIND_NONE: ++ return TRUE; ++ } ++ ++ return nm_assert_unreachable_val(TRUE); ++} ++ + static gboolean + link_enslave(NMPlatform *platform, int master, int slave) + { +@@ -1322,6 +1345,7 @@ nm_fake_platform_class_init(NMFakePlatformClass *klass) + platform_class->link_set_address = link_set_address; + platform_class->link_set_mtu = link_set_mtu; + ++ platform_class->link_change = link_change; + platform_class->link_change_flags = link_change_flags; + + platform_class->link_get_driver_info = link_get_driver_info; +diff --git a/src/core/platform/tests/test-link.c b/src/core/platform/tests/test-link.c +index b72bcb65b2..bdbfbea34f 100644 +--- a/src/core/platform/tests/test-link.c ++++ b/src/core/platform/tests/test-link.c +@@ -257,6 +257,21 @@ test_slave(int master, int type, SignalData *master_changed) + else + g_assert(!nm_platform_link_is_up(NM_PLATFORM_GET, ifindex)); + ++ if (NM_IN_SET(link_type, NM_LINK_TYPE_BOND)) { ++ const NMPlatformLink *link; ++ NMPlatformLinkBondPort bond_port; ++ ++ bond_port = (NMPlatformLinkBondPort){ ++ .queue_id = 5, ++ }; ++ g_assert(nm_platform_link_change(NM_PLATFORM_GET, ifindex, &bond_port)); ++ accept_signals(link_changed, 1, 3); ++ ++ link = nmtstp_link_get(NM_PLATFORM_GET, ifindex, SLAVE_NAME); ++ g_assert(link); ++ g_assert_cmpint(link->port_data.bond.queue_id, ==, 5); ++ } ++ + test_link_changed_signal_arg1 = FALSE; + test_link_changed_signal_arg2 = FALSE; + g_signal_connect(NM_PLATFORM_GET, +diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h +index 53cf7f3e57..b6cbf95504 100644 +--- a/src/libnm-glib-aux/nm-shared-utils.h ++++ b/src/libnm-glib-aux/nm-shared-utils.h +@@ -93,6 +93,14 @@ G_STATIC_ASSERT(sizeof(int) == sizeof(gint32)); + + /*****************************************************************************/ + ++typedef enum _nm_packed { ++ /* No type, empty value */ ++ NM_PORT_KIND_NONE, ++ NM_PORT_KIND_BOND, ++} NMPortKind; ++ ++/*****************************************************************************/ ++ + typedef enum { + + /* No type, used as error value */ +diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c +index 527d509498..8158f364d2 100644 +--- a/src/libnm-platform/nm-linux-platform.c ++++ b/src/libnm-platform/nm-linux-platform.c +@@ -3241,9 +3241,11 @@ _new_from_nl_link(NMPlatform *platform, + + if (tb[IFLA_LINKINFO]) { + static const struct nla_policy policy_link_info[] = { +- [IFLA_INFO_KIND] = {.type = NLA_STRING}, +- [IFLA_INFO_DATA] = {.type = NLA_NESTED}, +- [IFLA_INFO_XSTATS] = {.type = NLA_NESTED}, ++ [IFLA_INFO_KIND] = {.type = NLA_STRING}, ++ [IFLA_INFO_DATA] = {.type = NLA_NESTED}, ++ [IFLA_INFO_XSTATS] = {.type = NLA_NESTED}, ++ [IFLA_INFO_SLAVE_KIND] = {.type = NLA_STRING}, ++ [IFLA_INFO_SLAVE_DATA] = {.type = NLA_NESTED}, + }; + struct nlattr *li[G_N_ELEMENTS(policy_link_info)]; + +@@ -3254,6 +3256,33 @@ _new_from_nl_link(NMPlatform *platform, + nl_info_kind = nla_get_string(li[IFLA_INFO_KIND]); + + nl_info_data = li[IFLA_INFO_DATA]; ++ ++ if (li[IFLA_INFO_SLAVE_KIND]) { ++ const char *s = nla_get_string(li[IFLA_INFO_SLAVE_KIND]); ++ ++ if (nm_streq(s, "bond")) ++ obj->link.port_kind = NM_PORT_KIND_BOND; ++ } ++ ++ if (li[IFLA_INFO_SLAVE_DATA]) { ++ static const struct nla_policy policy_bond_port[] = { ++ [IFLA_BOND_SLAVE_QUEUE_ID] = {.type = NLA_U16}, ++ }; ++ struct nlattr *bp[G_N_ELEMENTS(policy_bond_port)]; ++ ++ switch (obj->link.port_kind) { ++ case NM_PORT_KIND_BOND: ++ if (nla_parse_nested_arr(bp, li[IFLA_INFO_SLAVE_DATA], policy_bond_port) < 0) ++ return NULL; ++ ++ if (bp[IFLA_BOND_SLAVE_QUEUE_ID]) ++ obj->link.port_data.bond.queue_id = nla_get_u16(bp[IFLA_BOND_SLAVE_QUEUE_ID]); ++ ++ break; ++ case NM_PORT_KIND_NONE: ++ break; ++ } ++ } + } + + if (tb[IFLA_STATS64]) { +@@ -8061,6 +8090,48 @@ link_delete(NMPlatform *platform, int ifindex) + return do_delete_object(platform, &obj_id, nlmsg); + } + ++static gboolean ++link_change(NMPlatform *platform, ++ int ifindex, ++ NMPortKind port_kind, ++ const NMPlatformLinkPortData *port_data) ++{ ++ nm_auto_nlmsg struct nl_msg *nlmsg = NULL; ++ struct nlattr *nl_info; ++ struct nlattr *nl_port_data; ++ ++ nlmsg = _nl_msg_new_link(RTM_NEWLINK, 0, ifindex, NULL); ++ if (!nlmsg) ++ return FALSE; ++ ++ switch (port_kind) { ++ case NM_PORT_KIND_BOND: ++ ++ nm_assert(port_data); ++ ++ if (!(nl_info = nla_nest_start(nlmsg, IFLA_LINKINFO))) ++ goto nla_put_failure; ++ ++ nm_assert(nm_streq0("bond", nm_link_type_to_rtnl_type_string(NM_LINK_TYPE_BOND))); ++ NLA_PUT_STRING(nlmsg, IFLA_INFO_SLAVE_KIND, "bond"); ++ ++ if (!(nl_port_data = nla_nest_start(nlmsg, IFLA_INFO_SLAVE_DATA))) ++ goto nla_put_failure; ++ ++ NLA_PUT_U16(nlmsg, IFLA_BOND_SLAVE_QUEUE_ID, port_data->bond.queue_id); ++ ++ nla_nest_end(nlmsg, nl_port_data); ++ nla_nest_end(nlmsg, nl_info); ++ break; ++ case NM_PORT_KIND_NONE: ++ break; ++ } ++ ++ return do_change_link(platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) == 0; ++nla_put_failure: ++ g_return_val_if_reached(FALSE); ++} ++ + static gboolean + link_refresh(NMPlatform *platform, int ifindex) + { +@@ -10828,6 +10899,8 @@ nm_linux_platform_class_init(NMLinuxPlatformClass *klass) + platform_class->link_change_extra = link_change_extra; + platform_class->link_delete = link_delete; + ++ platform_class->link_change = link_change; ++ + platform_class->link_refresh = link_refresh; + + platform_class->link_set_netns = link_set_netns; +diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c +index ab98491b45..01568243a3 100644 +--- a/src/libnm-platform/nm-platform.c ++++ b/src/libnm-platform/nm-platform.c +@@ -61,6 +61,31 @@ G_STATIC_ASSERT(sizeof(((NMPlatformLink *) NULL)->l_address.data) == _NM_UTILS_H + G_STATIC_ASSERT(sizeof(((NMPlatformLink *) NULL)->l_perm_address.data) == _NM_UTILS_HWADDR_LEN_MAX); + G_STATIC_ASSERT(sizeof(((NMPlatformLink *) NULL)->l_broadcast.data) == _NM_UTILS_HWADDR_LEN_MAX); + ++static const char * ++_nmp_link_port_data_to_string(NMPortKind port_kind, ++ const NMPlatformLinkPortData *port_data, ++ char *sbuf, ++ gsize sbuf_len) ++{ ++ const char *sbuf0 = sbuf; ++ ++ nm_assert(port_data); ++ ++ switch (port_kind) { ++ case NM_PORT_KIND_NONE: ++ nm_strbuf_append_c(&sbuf, &sbuf_len, '\0'); ++ goto out; ++ case NM_PORT_KIND_BOND: ++ nm_strbuf_append(&sbuf, &sbuf_len, "port bond queue-id %u", port_data->bond.queue_id); ++ goto out; ++ } ++ ++ nm_strbuf_append(&sbuf, &sbuf_len, "invalid-port-type %d", (int) port_kind); ++ ++out: ++ return sbuf0; ++} ++ + static const char * + _nmp_link_address_to_string(const NMPLinkAddress *addr, + char buf[static(_NM_UTILS_HWADDR_LEN_MAX * 3)]) +@@ -2092,6 +2117,31 @@ nm_platform_link_set_name(NMPlatform *self, int ifindex, const char *name) + return klass->link_set_name(self, ifindex, name); + } + ++gboolean ++nm_platform_link_change(NMPlatform *self, int ifindex, NMPlatformLinkBondPort *bond_port) ++{ ++ _CHECK_SELF(self, klass, FALSE); ++ ++ g_return_val_if_fail(ifindex >= 0, FALSE); ++ ++ if (_LOGD_ENABLED()) { ++ nm_auto_free_gstring GString *str = g_string_new(""); ++ ++ if (bond_port) ++ g_string_append_printf(str, "bond-port queue-id %d", bond_port->queue_id); ++ ++ if (str->len > 0 && str->str[str->len - 1] == ' ') ++ g_string_truncate(str, str->len - 1); ++ ++ _LOG3D("link: change: %s", str->str); ++ } ++ ++ return klass->link_change(self, ++ ifindex, ++ bond_port ? NM_PORT_KIND_BOND : NM_PORT_KIND_NONE, ++ (const NMPlatformLinkPortData *) bond_port); ++} ++ + /** + * nm_platform_link_get_physical_port_id: + * @self: platform instance +@@ -5893,6 +5943,7 @@ nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len) + char *s; + gsize l; + char str_addrmode[30]; ++ char str_port_data[200]; + char str_address[_NM_UTILS_HWADDR_LEN_MAX * 3]; + char str_perm_address[_NM_UTILS_HWADDR_LEN_MAX * 3]; + char str_broadcast[_NM_UTILS_HWADDR_LEN_MAX * 3]; +@@ -5936,6 +5987,11 @@ nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len) + _nmp_link_address_to_string(&link->l_perm_address, str_perm_address); + _nmp_link_address_to_string(&link->l_broadcast, str_broadcast); + ++ _nmp_link_port_data_to_string(link->port_kind, ++ &link->port_data, ++ str_port_data, ++ sizeof(str_port_data)); ++ + str_link_type = nm_link_type_to_string(link->type); + + g_snprintf( +@@ -5957,6 +6013,7 @@ nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len) + "%s%s" /* l_broadcast */ + "%s%s" /* inet6_token */ + "%s%s" /* driver */ ++ "%s%s" /* port_data */ + " rx:%" G_GUINT64_FORMAT ",%" G_GUINT64_FORMAT " tx:%" G_GUINT64_FORMAT + ",%" G_GUINT64_FORMAT, + link->ifindex, +@@ -5989,6 +6046,7 @@ nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len) + : "", + link->driver ? " driver " : "", + link->driver ?: "", ++ NM_PRINT_FMT_QUOTED2(str_port_data[0] != '\0', " ", str_port_data, ""), + link->rx_packets, + link->rx_bytes, + link->tx_packets, +@@ -7927,6 +7985,7 @@ nm_platform_link_hash_update(const NMPlatformLink *obj, NMHashState *h) + obj->arptype, + obj->inet6_addr_gen_mode_inv, + obj->inet6_token, ++ obj->port_kind, + obj->rx_packets, + obj->rx_bytes, + obj->tx_packets, +@@ -7945,6 +8004,20 @@ nm_platform_link_hash_update(const NMPlatformLink *obj, NMHashState *h) + nm_hash_update_mem(h, + obj->l_broadcast.data, + NM_MIN(obj->l_broadcast.len, sizeof(obj->l_broadcast.data))); ++ ++ switch (obj->port_kind) { ++ case NM_PORT_KIND_NONE: ++ break; ++ case NM_PORT_KIND_BOND: ++ nm_platform_link_bond_port_hash_update(&obj->port_data.bond, h); ++ break; ++ } ++} ++ ++void ++nm_platform_link_bond_port_hash_update(const NMPlatformLinkBondPort *obj, NMHashState *h) ++{ ++ nm_hash_update_vals(h, obj->queue_id); + } + + int +@@ -7974,6 +8047,14 @@ nm_platform_link_cmp(const NMPlatformLink *a, const NMPlatformLink *b) + if (a->l_broadcast.len) + NM_CMP_FIELD_MEMCMP_LEN(a, b, l_broadcast.data, a->l_broadcast.len); + NM_CMP_FIELD_MEMCMP(a, b, inet6_token); ++ NM_CMP_FIELD(a, b, port_kind); ++ switch (a->port_kind) { ++ case NM_PORT_KIND_NONE: ++ break; ++ case NM_PORT_KIND_BOND: ++ NM_CMP_RETURN(nm_platform_link_bond_port_cmp(&a->port_data.bond, &b->port_data.bond)); ++ break; ++ } + NM_CMP_FIELD(a, b, rx_packets); + NM_CMP_FIELD(a, b, rx_bytes); + NM_CMP_FIELD(a, b, tx_packets); +@@ -8053,6 +8134,15 @@ nm_platform_lnk_bond_hash_update(const NMPlatformLnkBond *obj, NMHashState *h) + nm_hash_update(h, obj->arp_ip_target, obj->arp_ip_targets_num * sizeof(obj->arp_ip_target[0])); + } + ++int ++nm_platform_link_bond_port_cmp(const NMPlatformLinkBondPort *a, const NMPlatformLinkBondPort *b) ++{ ++ NM_CMP_SELF(a, b); ++ NM_CMP_FIELD(a, b, queue_id); ++ ++ return 0; ++} ++ + int + nm_platform_lnk_bond_cmp(const NMPlatformLnkBond *a, const NMPlatformLnkBond *b) + { +diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h +index d87eba3a63..f48662d900 100644 +--- a/src/libnm-platform/nm-platform.h ++++ b/src/libnm-platform/nm-platform.h +@@ -216,6 +216,14 @@ struct _NMPlatformObjWithIfindex { + __NMPlatformObjWithIfindex_COMMON; + }; + ++typedef struct { ++ guint16 queue_id; ++} NMPlatformLinkBondPort; ++ ++typedef union { ++ NMPlatformLinkBondPort bond; ++} NMPlatformLinkPortData; ++ + struct _NMPlatformLink { + __NMPlatformObjWithIfindex_COMMON; + char name[NMP_IFNAMSIZ]; +@@ -266,6 +274,12 @@ struct _NMPlatformLink { + guint64 tx_packets; + guint64 tx_bytes; + ++ /* IFLA_INFO_SLAVE_KIND */ ++ NMPortKind port_kind; ++ ++ /* an interface can only hold IFLA_INFO_SLAVE_DATA for one link type */ ++ NMPlatformLinkPortData port_data; ++ + /* @connected is mostly identical to (@n_ifi_flags & IFF_UP). Except for bridge/bond masters, + * where we coerce the link as disconnect if it has no slaves. */ + bool connected : 1; +@@ -1226,6 +1240,10 @@ typedef struct { + NMLinkType type, + int ifindex, + gconstpointer extra_data); ++ gboolean (*link_change)(NMPlatform *self, ++ int ifindex, ++ NMPortKind port_kind, ++ const NMPlatformLinkPortData *port_data); + gboolean (*link_delete)(NMPlatform *self, int ifindex); + gboolean (*link_refresh)(NMPlatform *self, int ifindex); + gboolean (*link_set_netns)(NMPlatform *self, int ifindex, int netns_fd); +@@ -2073,6 +2091,8 @@ nm_platform_link_change_flags(NMPlatform *self, int ifindex, unsigned value, gbo + return nm_platform_link_change_flags_full(self, ifindex, value, set ? value : 0u); + } + ++gboolean nm_platform_link_change(NMPlatform *self, int ifindex, NMPlatformLinkBondPort *bond_port); ++ + gboolean nm_platform_link_get_udev_property(NMPlatform *self, + int ifindex, + const char *name, +@@ -2563,6 +2583,11 @@ int nm_platform_tfilter_cmp(const NMPlatformTfilter *a, const NMPlatformTfilter + int nm_platform_mptcp_addr_cmp(const NMPlatformMptcpAddr *a, const NMPlatformMptcpAddr *b); + + void nm_platform_link_hash_update(const NMPlatformLink *obj, NMHashState *h); ++ ++void nm_platform_link_bond_port_hash_update(const NMPlatformLinkBondPort *obj, NMHashState *h); ++int nm_platform_link_bond_port_cmp(const NMPlatformLinkBondPort *a, ++ const NMPlatformLinkBondPort *b); ++ + void nm_platform_ip4_address_hash_update(const NMPlatformIP4Address *obj, NMHashState *h); + void nm_platform_ip6_address_hash_update(const NMPlatformIP6Address *obj, NMHashState *h); + void nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj, +-- +2.40.1 + + +From 2ed620bce381b612cff7a14871b8939b48fdaca3 Mon Sep 17 00:00:00 2001 +From: Fernando Fernandez Mancera +Date: Thu, 9 Mar 2023 12:18:14 +0100 +Subject: [PATCH 5/8] platform: add support to prio property in bond ports + +(cherry picked from commit e200b162914d3bda4c03a19652124330a99bb3ae) +(cherry picked from commit 84f17a2fbb73d592a29645003d7d76a9e8b332ca) +(cherry picked from commit c787d22fc8194dc6d07c6b842b5a8a5944f42dc7) +--- + src/core/platform/nm-fake-platform.c | 2 ++ + src/core/platform/tests/test-link.c | 23 +++++++++++++++--- + src/libnm-platform/nm-linux-platform.c | 21 +++++++++++++++++ + src/libnm-platform/nm-platform.c | 32 ++++++++++++++++++++++---- + src/libnm-platform/nm-platform.h | 10 +++++--- + 5 files changed, 78 insertions(+), 10 deletions(-) + +diff --git a/src/core/platform/nm-fake-platform.c b/src/core/platform/nm-fake-platform.c +index c39c45e586..46f374d95c 100644 +--- a/src/core/platform/nm-fake-platform.c ++++ b/src/core/platform/nm-fake-platform.c +@@ -681,6 +681,8 @@ link_change(NMPlatform *platform, + obj_tmp = nmp_object_clone(device->obj, FALSE); + obj_tmp->link.port_kind = NM_PORT_KIND_BOND; + obj_tmp->link.port_data.bond.queue_id = port_data->bond.queue_id; ++ obj_tmp->link.port_data.bond.prio_has = port_data->bond.prio_has; ++ obj_tmp->link.port_data.bond.prio = port_data->bond.prio; + link_set_obj(platform, device, obj_tmp); + return TRUE; + case NM_PORT_KIND_NONE: +diff --git a/src/core/platform/tests/test-link.c b/src/core/platform/tests/test-link.c +index bdbfbea34f..ac1f0d6ff6 100644 +--- a/src/core/platform/tests/test-link.c ++++ b/src/core/platform/tests/test-link.c +@@ -112,7 +112,7 @@ software_add(NMLinkType link_type, const char *name) + gboolean bond0_exists = !!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "bond0"); + int r; + const NMPlatformLnkBond nm_platform_lnk_bond_default = { +- .mode = 3, ++ .mode = nmtst_rand_select(3, 1), + }; + + r = nm_platform_link_bond_add(NM_PLATFORM_GET, name, &nm_platform_lnk_bond_default, NULL); +@@ -258,18 +258,35 @@ test_slave(int master, int type, SignalData *master_changed) + g_assert(!nm_platform_link_is_up(NM_PLATFORM_GET, ifindex)); + + if (NM_IN_SET(link_type, NM_LINK_TYPE_BOND)) { +- const NMPlatformLink *link; +- NMPlatformLinkBondPort bond_port; ++ NMPlatformLinkBondPort bond_port; ++ gboolean prio_has; ++ gboolean prio_supported; ++ const NMPlatformLink *link; ++ const NMPlatformLnkBond *lnk; ++ ++ link = nmtstp_link_get_typed(NM_PLATFORM_GET, 0, SLAVE_NAME, NM_LINK_TYPE_DUMMY); ++ g_assert(link); ++ ++ lnk = nm_platform_link_get_lnk_bond(NM_PLATFORM_GET, master, NULL); ++ g_assert(lnk); ++ ++ g_assert(NM_IN_SET(lnk->mode, 3, 1)); ++ prio_supported = (lnk->mode == 1); ++ prio_has = nmtst_get_rand_bool() && prio_supported; + + bond_port = (NMPlatformLinkBondPort){ + .queue_id = 5, ++ .prio_has = prio_has, ++ .prio = prio_has ? 6 : 0, + }; ++ + g_assert(nm_platform_link_change(NM_PLATFORM_GET, ifindex, &bond_port)); + accept_signals(link_changed, 1, 3); + + link = nmtstp_link_get(NM_PLATFORM_GET, ifindex, SLAVE_NAME); + g_assert(link); + g_assert_cmpint(link->port_data.bond.queue_id, ==, 5); ++ g_assert(link->port_data.bond.prio_has || link->port_data.bond.prio == 0); + } + + test_link_changed_signal_arg1 = FALSE; +diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c +index 8158f364d2..19ccb09a86 100644 +--- a/src/libnm-platform/nm-linux-platform.c ++++ b/src/libnm-platform/nm-linux-platform.c +@@ -177,6 +177,8 @@ G_STATIC_ASSERT(RTA_MAX == (__RTA_MAX - 1)); + + /*****************************************************************************/ + ++#define IFLA_BOND_SLAVE_PRIO 9 ++ + #define IFLA_BOND_PEER_NOTIF_DELAY 28 + + #undef IFLA_BOND_MAX +@@ -3267,6 +3269,7 @@ _new_from_nl_link(NMPlatform *platform, + if (li[IFLA_INFO_SLAVE_DATA]) { + static const struct nla_policy policy_bond_port[] = { + [IFLA_BOND_SLAVE_QUEUE_ID] = {.type = NLA_U16}, ++ [IFLA_BOND_SLAVE_PRIO] = {.type = NLA_S32}, + }; + struct nlattr *bp[G_N_ELEMENTS(policy_bond_port)]; + +@@ -3278,6 +3281,21 @@ _new_from_nl_link(NMPlatform *platform, + if (bp[IFLA_BOND_SLAVE_QUEUE_ID]) + obj->link.port_data.bond.queue_id = nla_get_u16(bp[IFLA_BOND_SLAVE_QUEUE_ID]); + ++ if (bp[IFLA_BOND_SLAVE_PRIO]) { ++ obj->link.port_data.bond.prio = nla_get_s32(bp[IFLA_BOND_SLAVE_PRIO]); ++ obj->link.port_data.bond.prio_has = TRUE; ++ if (!_nm_platform_kernel_support_detected( ++ NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_BOND_SLAVE_PRIO)) { ++ /* support for IFLA_BOND_SLAVE_PRIO was added in 0a2ff7cc8ad48a86939a91bd3457f38e59e741a1, ++ * kernel 6.0, 2 October 2022. ++ * ++ * We can only detect support if the attribute is present. A missing attribute ++ * is not conclusive. */ ++ _nm_platform_kernel_support_init( ++ NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_BOND_SLAVE_PRIO, ++ 1); ++ } ++ } + break; + case NM_PORT_KIND_NONE: + break; +@@ -8120,6 +8138,9 @@ link_change(NMPlatform *platform, + + NLA_PUT_U16(nlmsg, IFLA_BOND_SLAVE_QUEUE_ID, port_data->bond.queue_id); + ++ if (port_data->bond.prio_has) ++ NLA_PUT_S32(nlmsg, IFLA_BOND_SLAVE_PRIO, port_data->bond.prio); ++ + nla_nest_end(nlmsg, nl_port_data); + nla_nest_end(nlmsg, nl_info); + break; +diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c +index 01568243a3..d64c85674a 100644 +--- a/src/libnm-platform/nm-platform.c ++++ b/src/libnm-platform/nm-platform.c +@@ -68,6 +68,7 @@ _nmp_link_port_data_to_string(NMPortKind port_kind, + gsize sbuf_len) + { + const char *sbuf0 = sbuf; ++ char s0[120]; + + nm_assert(port_data); + +@@ -76,7 +77,16 @@ _nmp_link_port_data_to_string(NMPortKind port_kind, + nm_strbuf_append_c(&sbuf, &sbuf_len, '\0'); + goto out; + case NM_PORT_KIND_BOND: +- nm_strbuf_append(&sbuf, &sbuf_len, "port bond queue-id %u", port_data->bond.queue_id); ++ nm_strbuf_append(&sbuf, ++ &sbuf_len, ++ "port bond queue-id %u%s", ++ port_data->bond.queue_id, ++ port_data->bond.prio_has || port_data->bond.prio != 0 ++ ? nm_sprintf_buf(s0, ++ " prio%s %u", ++ port_data->bond.prio_has ? "" : "?", ++ port_data->bond.prio) ++ : ""); + goto out; + } + +@@ -2120,6 +2130,8 @@ nm_platform_link_set_name(NMPlatform *self, int ifindex, const char *name) + gboolean + nm_platform_link_change(NMPlatform *self, int ifindex, NMPlatformLinkBondPort *bond_port) + { ++ char sbuf_prio[100]; ++ + _CHECK_SELF(self, klass, FALSE); + + g_return_val_if_fail(ifindex >= 0, FALSE); +@@ -2127,8 +2139,18 @@ nm_platform_link_change(NMPlatform *self, int ifindex, NMPlatformLinkBondPort *b + if (_LOGD_ENABLED()) { + nm_auto_free_gstring GString *str = g_string_new(""); + +- if (bond_port) +- g_string_append_printf(str, "bond-port queue-id %d", bond_port->queue_id); ++ if (bond_port) { ++ nm_assert(bond_port->prio_has || bond_port->prio == 0); ++ g_string_append_printf(str, ++ "bond-port queue-id %d %s", ++ bond_port->queue_id, ++ bond_port->prio_has || bond_port->prio != 0 ++ ? nm_sprintf_buf(sbuf_prio, ++ "prio%s %" G_GINT32_FORMAT, ++ !bond_port->prio_has ? "?" : "", ++ bond_port->prio) ++ : ""); ++ } + + if (str->len > 0 && str->str[str->len - 1] == ' ') + g_string_truncate(str, str->len - 1); +@@ -8017,7 +8039,7 @@ nm_platform_link_hash_update(const NMPlatformLink *obj, NMHashState *h) + void + nm_platform_link_bond_port_hash_update(const NMPlatformLinkBondPort *obj, NMHashState *h) + { +- nm_hash_update_vals(h, obj->queue_id); ++ nm_hash_update_vals(h, obj->prio, obj->queue_id, NM_HASH_COMBINE_BOOLS(guint8, obj->prio_has)); + } + + int +@@ -8139,6 +8161,8 @@ nm_platform_link_bond_port_cmp(const NMPlatformLinkBondPort *a, const NMPlatform + { + NM_CMP_SELF(a, b); + NM_CMP_FIELD(a, b, queue_id); ++ NM_CMP_FIELD(a, b, prio); ++ NM_CMP_FIELD_BOOL(a, b, prio_has); + + return 0; + } +diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h +index f48662d900..611f50f901 100644 +--- a/src/libnm-platform/nm-platform.h ++++ b/src/libnm-platform/nm-platform.h +@@ -217,7 +217,9 @@ struct _NMPlatformObjWithIfindex { + }; + + typedef struct { ++ gint32 prio; + guint16 queue_id; ++ bool prio_has : 1; + } NMPlatformLinkBondPort; + + typedef union { +@@ -274,12 +276,12 @@ struct _NMPlatformLink { + guint64 tx_packets; + guint64 tx_bytes; + +- /* IFLA_INFO_SLAVE_KIND */ +- NMPortKind port_kind; +- + /* an interface can only hold IFLA_INFO_SLAVE_DATA for one link type */ + NMPlatformLinkPortData port_data; + ++ /* IFLA_INFO_SLAVE_KIND */ ++ NMPortKind port_kind; ++ + /* @connected is mostly identical to (@n_ifi_flags & IFF_UP). Except for bridge/bond masters, + * where we coerce the link as disconnect if it has no slaves. */ + bool connected : 1; +@@ -1140,6 +1142,8 @@ typedef enum { + * were added at the same time. */ + NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_IP_PROTO, + ++ NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_BOND_SLAVE_PRIO, ++ + _NM_PLATFORM_KERNEL_SUPPORT_NUM, + } NMPlatformKernelSupportType; + +-- +2.40.1 + + +From 17badd932a2422a1d493ec3ad962d811f3854136 Mon Sep 17 00:00:00 2001 +From: Fernando Fernandez Mancera +Date: Tue, 9 May 2023 12:46:09 +0200 +Subject: [PATCH 6/8] libnm: add NM_VERSION_1_40_20 + +(cherry picked from commit 4fd186bbf6cf9f791c7166a04c9ef4b7ec101a80) +--- + src/libnm-core-public/nm-version-macros.h.in | 1 + + src/libnm-core-public/nm-version.h | 6 ++++++ + 2 files changed, 7 insertions(+) + +diff --git a/src/libnm-core-public/nm-version-macros.h.in b/src/libnm-core-public/nm-version-macros.h.in +index fc854aef86..cb3350f19c 100644 +--- a/src/libnm-core-public/nm-version-macros.h.in ++++ b/src/libnm-core-public/nm-version-macros.h.in +@@ -73,6 +73,7 @@ + #define NM_VERSION_1_38 (NM_ENCODE_VERSION (1, 38, 0)) + #define NM_VERSION_1_40 (NM_ENCODE_VERSION (1, 40, 0)) + #define NM_VERSION_1_40_4 (NM_ENCODE_VERSION (1, 40, 4)) ++#define NM_VERSION_1_40_20 (NM_ENCODE_VERSION (1, 40, 20)) + + /* For releases, NM_API_VERSION is equal to NM_VERSION. + * +diff --git a/src/libnm-core-public/nm-version.h b/src/libnm-core-public/nm-version.h +index d9f9a12121..5b924ce620 100644 +--- a/src/libnm-core-public/nm-version.h ++++ b/src/libnm-core-public/nm-version.h +@@ -347,6 +347,12 @@ + #define NM_AVAILABLE_IN_1_40_4 + #endif + ++#if NM_VERSION_MAX_ALLOWED < NM_VERSION_1_40_20 ++#define NM_AVAILABLE_IN_1_40_20 G_UNAVAILABLE(1, 40.20) ++#else ++#define NM_AVAILABLE_IN_1_40_20 ++#endif ++ + /* + * Synchronous API for calling D-Bus in libnm is deprecated. See + * https://networkmanager.dev/docs/libnm/latest/usage.html#sync-api +-- +2.40.1 + + +From 7f3f3f50cf7d71c16c532dd73e0d4a2d6ffc129f Mon Sep 17 00:00:00 2001 +From: Fernando Fernandez Mancera +Date: Thu, 9 Mar 2023 12:18:14 +0100 +Subject: [PATCH 7/8] bonding: add support to prio property in bond ports + +Add per port priority support for bond active port re-selection during +failover. A higher number means a higher priority in selection. The +primary port still has the highest priority. This option is only +compatible with active-backup, balance-tlb and balance-alb modes. + +(cherry picked from commit 2f0571f1930ff2c11de4f48b4433ca5fe6c897a0) +(cherry picked from commit 748f6388aa0217b2c1c8bf879697ce48bcba8317) +(cherry picked from commit d36620e654b20146e49209c191b7230936cc1596) +--- + src/core/devices/nm-device-bond.c | 58 +++++++++++++++++-- + .../plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 23 ++++++-- + .../plugins/ifcfg-rh/nms-ifcfg-rh-utils.c | 1 + + .../plugins/ifcfg-rh/nms-ifcfg-rh-utils.h | 2 +- + .../plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 4 +- + .../plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 1 + + src/libnm-base/nm-base.h | 1 + + src/libnm-client-impl/libnm.ver | 5 ++ + src/libnm-client-impl/tests/test-gir.py | 4 +- + src/libnm-core-impl/nm-setting-bond-port.c | 48 ++++++++++++++- + src/libnm-core-public/nm-setting-bond-port.h | 4 ++ + src/libnmc-setting/nm-meta-setting-desc.c | 6 ++ + src/libnmc-setting/settings-docs.h.in | 1 + + .../generate-docs-nm-settings-nmcli.xml.in | 3 + + 14 files changed, 146 insertions(+), 15 deletions(-) + +diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c +index 0485689d10..9ecb2ac7ae 100644 +--- a/src/core/devices/nm-device-bond.c ++++ b/src/core/devices/nm-device-bond.c +@@ -234,7 +234,12 @@ controller_update_port_connection(NMDevice *self, + pllink = nm_platform_link_get(nm_device_get_platform(port), ifindex_port); + + if (pllink && pllink->port_kind == NM_PORT_KIND_BOND) +- g_object_set(s_port, NM_SETTING_BOND_PORT_QUEUE_ID, pllink->port_data.bond.queue_id, NULL); ++ g_object_set(s_port, ++ NM_SETTING_BOND_PORT_QUEUE_ID, ++ pllink->port_data.bond.queue_id, ++ NM_SETTING_BOND_PORT_PRIO, ++ pllink->port_data.bond.prio, ++ NULL); + + g_object_set(nm_connection_get_setting_connection(connection), + NM_SETTING_CONNECTION_MASTER, +@@ -495,11 +500,52 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) + static void + commit_port_options(NMDevice *bond_device, NMDevice *port, NMSettingBondPort *s_port) + { +- nm_platform_link_change( +- nm_device_get_platform(port), +- nm_device_get_ifindex(port), +- &((NMPlatformLinkBondPort){.queue_id = s_port ? nm_setting_bond_port_get_queue_id(s_port) +- : NM_BOND_PORT_QUEUE_ID_DEF})); ++ NMBondMode mode = NM_BOND_MODE_UNKNOWN; ++ const char *value; ++ NMSettingBond *s_bond; ++ gint32 prio; ++ gboolean prio_has; ++ ++ s_bond = nm_device_get_applied_setting(bond_device, NM_TYPE_SETTING_BOND); ++ if (s_bond) { ++ value = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_MODE); ++ mode = _nm_setting_bond_mode_from_string(value); ++ } ++ ++ prio = s_port ? nm_setting_bond_port_get_prio(s_port) : NM_BOND_PORT_PRIO_DEF; ++ ++ if (prio != 0) { ++ /* The profile explicitly sets the priority. No matter what, we try to set it ++ * in netlink. */ ++ prio_has = TRUE; ++ } else if (!NM_IN_SET(mode, NM_BOND_MODE_ACTIVEBACKUP, NM_BOND_MODE_TLB, NM_BOND_MODE_ALB)) { ++ /* The priority only is configurable with certain modes. If we don't have ++ * one of those modes, don't try to set the priority explicitly to zero. */ ++ prio_has = FALSE; ++ } else if (nm_platform_kernel_support_get_full( ++ NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_BOND_SLAVE_PRIO, ++ FALSE) ++ == NM_OPTION_BOOL_TRUE) { ++ /* We can only detect support if we have it. We cannot detect lack of support if ++ * we don't have it. ++ * ++ * But we did explicitly detect support, so explicitly set the prio to zero. */ ++ prio_has = TRUE; ++ } else { ++ /* We either have an unsuitable mode or didn't detect kernel support for the ++ * priority. Don't explicitly set priority to zero. It is already the default, ++ * so it shouldn't be necessary. */ ++ prio_has = FALSE; ++ } ++ ++ nm_platform_link_change(nm_device_get_platform(port), ++ nm_device_get_ifindex(port), ++ &((NMPlatformLinkBondPort){ ++ .queue_id = s_port ? nm_setting_bond_port_get_queue_id(s_port) ++ : NM_BOND_PORT_QUEUE_ID_DEF, ++ .prio = prio_has ? prio : 0, ++ .prio_has = prio_has, ++ })); + } + + static NMTernary +diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +index 4d8e7bd69b..02ba843201 100644 +--- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c ++++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +@@ -5557,6 +5557,7 @@ make_bond_port_setting(shvarFile *ifcfg) + gs_free char *value_to_free = NULL; + const char *value; + guint queue_id; ++ gint32 prio; + + g_return_val_if_fail(ifcfg != NULL, FALSE); + +@@ -5565,11 +5566,23 @@ make_bond_port_setting(shvarFile *ifcfg) + s_port = nm_setting_bond_port_new(); + queue_id = + _nm_utils_ascii_str_to_uint64(value, 10, 0, G_MAXUINT16, NM_BOND_PORT_QUEUE_ID_DEF); +- if (errno != 0) { +- PARSE_WARNING("Invalid bond port queue_id value '%s'", value); +- return s_port; +- } +- g_object_set(G_OBJECT(s_port), NM_SETTING_BOND_PORT_QUEUE_ID, queue_id, NULL); ++ if (errno != 0) ++ PARSE_WARNING("Invalid bond port queue_id value BOND_PORT_QUEUE_ID '%s'", value); ++ else ++ g_object_set(G_OBJECT(s_port), NM_SETTING_BOND_PORT_QUEUE_ID, queue_id, NULL); ++ } ++ ++ nm_clear_g_free(&value_to_free); ++ value = svGetValue(ifcfg, "BOND_PORT_PRIO", &value_to_free); ++ if (value) { ++ if (!s_port) ++ s_port = nm_setting_bond_port_new(); ++ prio = ++ _nm_utils_ascii_str_to_int64(value, 10, G_MININT32, G_MAXINT32, NM_BOND_PORT_PRIO_DEF); ++ if (errno != 0) ++ PARSE_WARNING("Invalid bond port prio value BOND_PORT_PRIO '%s'", value); ++ else ++ g_object_set(G_OBJECT(s_port), NM_SETTING_BOND_PORT_PRIO, prio, NULL); + } + + return s_port; +diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c +index e1ef817478..ef4276da73 100644 +--- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c ++++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c +@@ -827,6 +827,7 @@ const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = { + _KEY_TYPE("BAND", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("BONDING_MASTER", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("BONDING_OPTS", NMS_IFCFG_KEY_TYPE_IS_PLAIN), ++ _KEY_TYPE("BOND_PORT_PRIO", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("BOND_PORT_QUEUE_ID", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("BOOTPROTO", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("BRIDGE", NMS_IFCFG_KEY_TYPE_IS_PLAIN), +diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h +index d1f8dbad9c..e3d3d87321 100644 +--- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h ++++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h +@@ -33,7 +33,7 @@ typedef struct { + NMSIfcfgKeyTypeFlags key_flags; + } NMSIfcfgKeyTypeInfo; + +-extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[256]; ++extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[257]; + + const NMSIfcfgKeyTypeInfo *nms_ifcfg_well_known_key_find_info(const char *key, gssize *out_idx); + +diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +index e8948c3dd0..e340c9fe13 100644 +--- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c ++++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +@@ -1910,8 +1910,10 @@ write_bond_port_setting(NMConnection *connection, shvarFile *ifcfg) + NMSettingBondPort *s_port; + + s_port = _nm_connection_get_setting(connection, NM_TYPE_SETTING_BOND_PORT); +- if (s_port) ++ if (s_port) { + svSetValueInt64(ifcfg, "BOND_PORT_QUEUE_ID", nm_setting_bond_port_get_queue_id(s_port)); ++ svSetValueInt64(ifcfg, "BOND_PORT_PRIO", nm_setting_bond_port_get_prio(s_port)); ++ } + } + + static gboolean +diff --git a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +index 886a605fb2..d2ac2b29db 100644 +--- a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c ++++ b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +@@ -8325,6 +8325,7 @@ test_write_bond_port(void) + + s_bond_port = _nm_connection_new_setting(connection, NM_TYPE_SETTING_BOND_PORT); + g_object_set(s_bond_port, NM_SETTING_BOND_PORT_QUEUE_ID, 1, NULL); ++ g_object_set(s_bond_port, NM_SETTING_BOND_PORT_PRIO, 10, NULL); + + nmtst_assert_connection_verifies(connection); + +diff --git a/src/libnm-base/nm-base.h b/src/libnm-base/nm-base.h +index 28feb48429..b9161c7680 100644 +--- a/src/libnm-base/nm-base.h ++++ b/src/libnm-base/nm-base.h +@@ -392,6 +392,7 @@ typedef struct { + /****************************************************************************/ + + #define NM_BOND_PORT_QUEUE_ID_DEF 0 ++#define NM_BOND_PORT_PRIO_DEF 0 + + /*****************************************************************************/ + +diff --git a/src/libnm-client-impl/libnm.ver b/src/libnm-client-impl/libnm.ver +index 2478defa34..7c98646253 100644 +--- a/src/libnm-client-impl/libnm.ver ++++ b/src/libnm-client-impl/libnm.ver +@@ -1878,3 +1878,8 @@ global: + nm_utils_ip_routes_to_variant; + nm_vpn_plugin_info_supports_multiple; + } libnm_1_40_0; ++ ++libnm_1_40_20_bondp { ++global: ++ nm_setting_bond_port_get_prio; ++} libnm_1_40_0; +diff --git a/src/libnm-client-impl/tests/test-gir.py b/src/libnm-client-impl/tests/test-gir.py +index d91849b8fe..84919dd533 100755 +--- a/src/libnm-client-impl/tests/test-gir.py ++++ b/src/libnm-client-impl/tests/test-gir.py +@@ -97,8 +97,10 @@ def syms_from_ver(verfile): + ): + c_syms[str_removesuffix(line, ";")] = version + +- # This one is... messy. ++ # These are exceptions and we cannot know the version for the symbol so we ++ # harcode it. + c_syms["nm_ethtool_optname_is_feature"] = "1.20" ++ c_syms["nm_setting_bond_port_get_prio"] = "1.44" + + return c_syms + +diff --git a/src/libnm-core-impl/nm-setting-bond-port.c b/src/libnm-core-impl/nm-setting-bond-port.c +index d1656a31ac..a6daad8b19 100644 +--- a/src/libnm-core-impl/nm-setting-bond-port.c ++++ b/src/libnm-core-impl/nm-setting-bond-port.c +@@ -22,9 +22,10 @@ + + /*****************************************************************************/ + +-NM_GOBJECT_PROPERTIES_DEFINE(NMSettingBondPort, PROP_QUEUE_ID, ); ++NM_GOBJECT_PROPERTIES_DEFINE(NMSettingBondPort, PROP_QUEUE_ID, PROP_PRIO, ); + + typedef struct { ++ gint32 prio; + guint32 queue_id; + } NMSettingBondPortPrivate; + +@@ -65,6 +66,22 @@ nm_setting_bond_port_get_queue_id(NMSettingBondPort *setting) + return NM_SETTING_BOND_PORT_GET_PRIVATE(setting)->queue_id; + } + ++/** ++ * nm_setting_bond_port_get_prio: ++ * @setting: the #NMSettingBondPort ++ * ++ * Returns: the #NMSettingBondPort:prio property of the setting ++ * ++ * Since: 1.44, 1.42.8, 1.40.20, rhel-8.9 ++ **/ ++gint32 ++nm_setting_bond_port_get_prio(NMSettingBondPort *setting) ++{ ++ g_return_val_if_fail(NM_IS_SETTING_BOND_PORT(setting), 0); ++ ++ return NM_SETTING_BOND_PORT_GET_PRIVATE(setting)->prio; ++} ++ + /*****************************************************************************/ + + static gboolean +@@ -165,6 +182,35 @@ nm_setting_bond_port_class_init(NMSettingBondPortClass *klass) + NMSettingBondPort, + _priv.queue_id); + ++ /** ++ * NMSettingBondPort:prio: ++ * ++ * The port priority for bond active port re-selection during failover. A ++ * higher number means a higher priority in selection. The primary port has ++ * the highest priority. This option is only compatible with active-backup, ++ * balance-tlb and balance-alb modes. ++ * ++ * Since: 1.44, 1.42.8, 1.40.20, rhel-8.9 ++ **/ ++ /* ---ifcfg-rh--- ++ * property: prio ++ * variable: BOND_PORT_PRIO(+) ++ * values: -2147483648 - 2147483647 ++ * default: 0 ++ * description: Port priority. ++ * ---end--- ++ */ ++ _nm_setting_property_define_direct_int32(properties_override, ++ obj_properties, ++ NM_SETTING_BOND_PORT_PRIO, ++ PROP_PRIO, ++ G_MININT32, ++ G_MAXINT32, ++ NM_BOND_PORT_PRIO_DEF, ++ NM_SETTING_PARAM_INFERRABLE, ++ NMSettingBondPort, ++ _priv.prio); ++ + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + _nm_setting_class_commit(setting_class, +diff --git a/src/libnm-core-public/nm-setting-bond-port.h b/src/libnm-core-public/nm-setting-bond-port.h +index 0b20e4a8cb..abaedfcd6d 100644 +--- a/src/libnm-core-public/nm-setting-bond-port.h ++++ b/src/libnm-core-public/nm-setting-bond-port.h +@@ -29,6 +29,7 @@ G_BEGIN_DECLS + #define NM_SETTING_BOND_PORT_SETTING_NAME "bond-port" + + #define NM_SETTING_BOND_PORT_QUEUE_ID "queue-id" ++#define NM_SETTING_BOND_PORT_PRIO "prio" + + typedef struct _NMSettingBondPortClass NMSettingBondPortClass; + +@@ -41,6 +42,9 @@ NMSetting *nm_setting_bond_port_new(void); + NM_AVAILABLE_IN_1_34 + guint32 nm_setting_bond_port_get_queue_id(NMSettingBondPort *setting); + ++NM_AVAILABLE_IN_1_40_20 ++gint32 nm_setting_bond_port_get_prio(NMSettingBondPort *setting); ++ + G_END_DECLS + + #endif /* __NM_SETTING_BOND_PORT_H__ */ +diff --git a/src/libnmc-setting/nm-meta-setting-desc.c b/src/libnmc-setting/nm-meta-setting-desc.c +index 31beb65ef9..5714722de2 100644 +--- a/src/libnmc-setting/nm-meta-setting-desc.c ++++ b/src/libnmc-setting/nm-meta-setting-desc.c +@@ -5154,6 +5154,12 @@ static const NMMetaPropertyInfo *const property_infos_BOND_PORT[] = { + .prompt = N_("Queue ID"), + .property_type = &_pt_gobject_int, + ), ++ PROPERTY_INFO_WITH_DESC (NM_SETTING_BOND_PORT_PRIO, ++ .is_cli_option = TRUE, ++ .property_alias = "prio", ++ .prompt = N_("Port Priority"), ++ .property_type= &_pt_gobject_int, ++ ), + NULL + }; + +diff --git a/src/libnmc-setting/settings-docs.h.in b/src/libnmc-setting/settings-docs.h.in +index 62edc77f6b..6a5f416348 100644 +--- a/src/libnmc-setting/settings-docs.h.in ++++ b/src/libnmc-setting/settings-docs.h.in +@@ -426,6 +426,7 @@ + #define DESCRIBE_DOC_NM_SETTING_WPAN_PAGE N_("IEEE 802.15.4 channel page. A positive integer or -1, meaning \"do not set, use whatever the device is already set to\".") + #define DESCRIBE_DOC_NM_SETTING_WPAN_PAN_ID N_("IEEE 802.15.4 Personal Area Network (PAN) identifier.") + #define DESCRIBE_DOC_NM_SETTING_WPAN_SHORT_ADDRESS N_("Short IEEE 802.15.4 address to be used within a restricted environment.") ++#define DESCRIBE_DOC_NM_SETTING_BOND_PORT_PRIO N_("The port priority for bond active port re-selection during failover. A higher number means a higher priority in selection. The primary port has the highest priority. This option is only compatible with active-backup, balance-tlb and balance-alb modes.") + #define DESCRIBE_DOC_NM_SETTING_BOND_PORT_QUEUE_ID N_("The queue ID of this bond port. The maximum value of queue ID is the number of TX queues currently active in device.") + #define DESCRIBE_DOC_NM_SETTING_HOSTNAME_FROM_DHCP N_("Whether the system hostname can be determined from DHCP on this connection. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1).") + #define DESCRIBE_DOC_NM_SETTING_HOSTNAME_FROM_DNS_LOOKUP N_("Whether the system hostname can be determined from reverse DNS lookup of addresses on this device. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1).") +diff --git a/src/nmcli/generate-docs-nm-settings-nmcli.xml.in b/src/nmcli/generate-docs-nm-settings-nmcli.xml.in +index 03e6c0b54b..adf7895f0d 100644 +--- a/src/nmcli/generate-docs-nm-settings-nmcli.xml.in ++++ b/src/nmcli/generate-docs-nm-settings-nmcli.xml.in +@@ -271,6 +271,9 @@ + ++ + + + +Date: Wed, 10 May 2023 18:18:18 +0200 +Subject: [PATCH 8/8] tests: adjust test-gir.py to allow extra elements in + section name + +(cherry picked from commit 9b8220c9fa6c26257fe809171355b29219efe26a) +(cherry picked from commit 56e19bdf685ebc152eaf0cc8d2571387b8ea669b) +(cherry picked from commit ca41be98a075e03e61dc7e898d772792c0a65619) +--- + src/libnm-client-impl/tests/test-gir.py | 18 +++++------------- + 1 file changed, 5 insertions(+), 13 deletions(-) + +diff --git a/src/libnm-client-impl/tests/test-gir.py b/src/libnm-client-impl/tests/test-gir.py +index 84919dd533..50b2fade6b 100755 +--- a/src/libnm-client-impl/tests/test-gir.py ++++ b/src/libnm-client-impl/tests/test-gir.py +@@ -7,6 +7,7 @@ + from __future__ import print_function + import xml.etree.ElementTree as ET + import argparse ++import re + import sys + + C_NS = "http://www.gtk.org/introspection/c/1.0" +@@ -60,17 +61,6 @@ def str_removesuffix(string, suffix): + return string + + +-# Older Python doesn't have str.removeprefix() +-def str_removeprefix(string, prefix): +- try: +- return string.removeprefix(prefix) +- except AttributeError: +- if string.startswith(prefix): +- return string[len(prefix) :] +- else: +- return string +- +- + def syms_from_ver(verfile): + c_syms = {} + for line in open(verfile).readlines(): +@@ -78,8 +68,10 @@ def syms_from_ver(verfile): + + if line.endswith("{"): + line = str_removesuffix(line, " {") +- line = str_removeprefix(line, "libnm_") +- (major, minor, micro) = line.split("_") ++ m = re.search(r"^libnm_([0-9]+)_([0-9]+)_([0-9]+)$", line) ++ if not m: ++ continue ++ (major, minor, micro) = m.groups() + if int(major) > 1 or int(minor) > 0: + if int(micro) > 0: + # Snap to next major version. Perhaps not +-- +2.40.1 + diff --git a/SOURCES/1004-team-don-t-try-to-connect-to-teamd-in-update_connect-rh2182029.patch b/SOURCES/1004-team-don-t-try-to-connect-to-teamd-in-update_connect-rh2182029.patch new file mode 100644 index 0000000..48a3c92 --- /dev/null +++ b/SOURCES/1004-team-don-t-try-to-connect-to-teamd-in-update_connect-rh2182029.patch @@ -0,0 +1,52 @@ +From 4a9d5b23ab513f0ee0b8f490e522f60d4ef3e4cd Mon Sep 17 00:00:00 2001 +From: Beniamino Galvani +Date: Thu, 4 May 2023 15:11:49 +0200 +Subject: [PATCH] team: don't try to connect to teamd in update_connection() + +In constructed(), NMDevice starts watching the D-Bus name owner or +monitoring the unix socket, and so it is always aware if teamd is +running. When it is, NMDevice connects to it and initializes +priv->tdc. + +It is not useful to try to connect to teamd in update_connection() +because warnings will be generated by NM and by libteam if teamd is +not running. As explained above the connection is always initialized +when teamd is available, and so we can just check priv->tdc. + +Fixes: ab586236e36b ('core: implement update_connection() for Team') + +https://bugzilla.redhat.com/show_bug.cgi?id=2182029 +https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1631 +(cherry picked from commit 93430627c245a0b33b873edca329fa716ccfb7d6) +(cherry picked from commit b60f0dd0a20db232c7edc01faa4562ce510ed107) +(cherry picked from commit f6f1a44559990765a5cbc940a74f54df5d8a30d0) +--- + src/core/devices/team/nm-device-team.c | 9 +-------- + 1 file changed, 1 insertion(+), 8 deletions(-) + +diff --git a/src/core/devices/team/nm-device-team.c b/src/core/devices/team/nm-device-team.c +index b745158ef8..1d2beb5e8a 100644 +--- a/src/core/devices/team/nm-device-team.c ++++ b/src/core/devices/team/nm-device-team.c +@@ -228,17 +228,10 @@ update_connection(NMDevice *device, NMConnection *connection) + NMDeviceTeam *self = NM_DEVICE_TEAM(device); + NMSettingTeam *s_team = _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_TEAM); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); +- struct teamdctl *tdc = priv->tdc; + + /* Read the configuration only if not already set */ +- if (!priv->config && ensure_teamd_connection(device)) ++ if (!priv->config && priv->tdc) { + teamd_read_config(self); +- +- /* Restore previous tdc state */ +- if (priv->tdc && !tdc) { +- teamdctl_disconnect(priv->tdc); +- teamdctl_free(priv->tdc); +- priv->tdc = NULL; + } + + g_object_set(G_OBJECT(s_team), NM_SETTING_TEAM_CONFIG, _get_config(self), NULL); +-- +2.40.1 + diff --git a/SOURCES/1005-ipv6ll-don-t-regenerate-the-address-when-removed-rh2209353.patch b/SOURCES/1005-ipv6ll-don-t-regenerate-the-address-when-removed-rh2209353.patch new file mode 100644 index 0000000..b322c77 --- /dev/null +++ b/SOURCES/1005-ipv6ll-don-t-regenerate-the-address-when-removed-rh2209353.patch @@ -0,0 +1,140 @@ +From 3fcb1a072f230b53c6fdf6e106e0972293a2f742 Mon Sep 17 00:00:00 2001 +From: Beniamino Galvani +Date: Thu, 11 May 2023 13:32:13 +0200 +Subject: [PATCH] ipv6ll: don't regenerate the address when it's removed + externally + +Currently if the IPv6 link-local address is removed after it passed +DAD, NetworkManager tries to generate a new link-local address. If +this fails, which is always the case for EUI64, ipv6ll is considered +as failed and the connection can go down (depending on may-fail). + +This is particularly bad for virtual interfaces because if somebody +removes the link-local address, the activation can fail and destroy +the interface, breaking all services that require it. Also, it's a +change in behavior introduced in 1.36.0. + +It seems that a better approach here is to re-add the address that was +removed externally. + +[bgalvani@redhat.com: since the branch is missing commit 7ca95cee15b3 +('platform: always reconfigure IP routes even if removed externally'), +we need to set flag NM_L3CFG_CONFIG_FLAGS_FORCE_ONCE when committing +the address, otherwise it's not re-added] + +Fixes: aa070fb82190 ('core: add NML3IPv6LL helper') +https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1622 +(cherry picked from commit 53ba9f4701f30b12637df2c7215a0b7da845b34c) +(cherry picked from commit 2976e4c3b7fcee06051ce83c9a7fa911ad192dc4) +(cherry picked from commit 4a13b5f52217c81ddf2329ba343796bfa4ed5ef9) +--- + src/core/nm-l3-ipv6ll.c | 34 ++++++++++++++++++++++------------ + 1 file changed, 22 insertions(+), 12 deletions(-) + +diff --git a/src/core/nm-l3-ipv6ll.c b/src/core/nm-l3-ipv6ll.c +index 2640c07554..6e5e460258 100644 +--- a/src/core/nm-l3-ipv6ll.c ++++ b/src/core/nm-l3-ipv6ll.c +@@ -391,7 +391,7 @@ _pladdr_find_ll(NML3IPv6LL *self, gboolean *out_cur_addr_failed) + /*****************************************************************************/ + + static void +-_lladdr_handle_changed(NML3IPv6LL *self) ++_lladdr_handle_changed(NML3IPv6LL *self, gboolean force_commit) + { + const NML3ConfigData *l3cd; + gboolean changed = FALSE; +@@ -420,7 +420,9 @@ _lladdr_handle_changed(NML3IPv6LL *self) + NM_DNS_PRIORITY_DEFAULT_NORMAL, + NM_L3_ACD_DEFEND_TYPE_ALWAYS, + 0, +- NM_L3CFG_CONFIG_FLAGS_NONE, ++ /* Even if the address was removed from platform, it must ++ * be re-added, hence FORCE_ONCE. */ ++ NM_L3CFG_CONFIG_FLAGS_FORCE_ONCE, + NM_L3_CONFIG_MERGE_FLAGS_NONE)) + changed = TRUE; + } else { +@@ -434,7 +436,7 @@ _lladdr_handle_changed(NML3IPv6LL *self) + self->l3cfg_commit_handle, + "ipv6ll"); + +- if (changed) ++ if (changed || force_commit) + nm_l3cfg_commit_on_idle_schedule(self->l3cfg, NM_L3_CFG_COMMIT_TYPE_AUTO); + + if (!self->emit_changed_idle_source) { +@@ -515,6 +517,7 @@ _check(NML3IPv6LL *self) + const NMPlatformIP6Address *pladdr; + char sbuf[INET6_ADDRSTRLEN]; + gboolean cur_addr_failed; ++ gboolean restarted = FALSE; + struct in6_addr lladdr; + + pladdr = _pladdr_find_ll(self, &cur_addr_failed); +@@ -526,14 +529,14 @@ _check(NML3IPv6LL *self) + if (_set_cur_lladdr_obj(self, NM_L3_IPV6LL_STATE_DAD_IN_PROGRESS, pladdr)) { + _LOGT("changed: waiting for address %s to complete DAD", + _nm_utils_inet6_ntop(&self->cur_lladdr, sbuf)); +- _lladdr_handle_changed(self); ++ _lladdr_handle_changed(self, FALSE); + } + return; + } + + if (_set_cur_lladdr_obj(self, NM_L3_IPV6LL_STATE_READY, pladdr)) { + _LOGT("changed: address %s is ready", _nm_utils_inet6_ntop(&self->cur_lladdr, sbuf)); +- _lladdr_handle_changed(self); ++ _lladdr_handle_changed(self, FALSE); + } + return; + } +@@ -543,11 +546,17 @@ _check(NML3IPv6LL *self) + * Prematurely abort DAD to generate a new address below. */ + nm_assert( + NM_IN_SET(self->state, NM_L3_IPV6LL_STATE_DAD_IN_PROGRESS, NM_L3_IPV6LL_STATE_READY)); +- if (self->state == NM_L3_IPV6LL_STATE_DAD_IN_PROGRESS) +- _LOGT("changed: address %s did not complete DAD", +- _nm_utils_inet6_ntop(&self->cur_lladdr, sbuf)); +- else { ++ ++ if (cur_addr_failed) { ++ /* On DAD failure, we always try to regenerate a new address. */ ++ _LOGT("changed: address %s failed", _nm_utils_inet6_ntop(&self->cur_lladdr, sbuf)); ++ } else { + _LOGT("changed: address %s is gone", _nm_utils_inet6_ntop(&self->cur_lladdr, sbuf)); ++ /* When the address is removed, we always try to re-add it. */ ++ nm_clear_g_source_inst(&self->wait_for_addr_source); ++ lladdr = self->cur_lladdr; ++ restarted = TRUE; ++ goto commit; + } + + /* reset the state here, so that we are sure that the following +@@ -569,19 +578,20 @@ _check(NML3IPv6LL *self) + if (_set_cur_lladdr_bin(self, NM_L3_IPV6LL_STATE_DAD_FAILED, NULL)) { + _LOGW("changed: no IPv6 link local address to retry after Duplicate Address Detection " + "failures (back off)"); +- _lladdr_handle_changed(self); ++ _lladdr_handle_changed(self, FALSE); + } + return; + } + ++commit: + /* we give NML3Cfg 2 seconds to configure the address on the interface. We + * thus very soon expect to see this address configured (and kernel started DAD). + * If that does not happen within timeout, we assume that this address failed DAD. */ + self->wait_for_addr_source = nm_g_timeout_add_source(2000, _wait_for_addr_timeout_cb, self); +- if (_set_cur_lladdr_bin(self, NM_L3_IPV6LL_STATE_DAD_IN_PROGRESS, &lladdr)) { ++ if (_set_cur_lladdr_bin(self, NM_L3_IPV6LL_STATE_DAD_IN_PROGRESS, &lladdr) || restarted) { + _LOGT("changed: starting DAD for address %s", + _nm_utils_inet6_ntop(&self->cur_lladdr, sbuf)); +- _lladdr_handle_changed(self); ++ _lladdr_handle_changed(self, restarted); + } + return; + } +-- +2.39.2 + diff --git a/SOURCES/1006-fix-read-infiniband-from-ifcfg-rh2209164.patch b/SOURCES/1006-fix-read-infiniband-from-ifcfg-rh2209164.patch new file mode 100644 index 0000000..78fe54f --- /dev/null +++ b/SOURCES/1006-fix-read-infiniband-from-ifcfg-rh2209164.patch @@ -0,0 +1,1299 @@ +From 651cdebe373603ec14d7268452d6661acfdc413f Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Wed, 24 May 2023 09:44:59 +0200 +Subject: [PATCH 1/8] Revert "infiniband: avoid normalizing the p-key when + reading from ifcfg" + +Historically, initscripts' ifup-ib would set the highest bit of +PKEY_ID=. That changed and needs to be restored. + +Note that it probably makes little sense to ever configure p-keys +without the highest bit set, because that flag indicates full membership +and kernel will automatically add it. At least, kernel will add the flag +for the p-key, but not for the automatically chosen interface name. + +Meaning, writing 0x00f0 to create_child sysctl, results in an interface +"$parent.00f0", but `ip -d link` shows pkey 0x80f0. + +As NetworkManager otherwise supports p-keys without the highest bit set, +and since that high bit is honored for the interface name, we cannot +just always add the high bit. NetworkManager always assuming the highest +bit is set, would change the interface names of existing configuration. + +With this revert, when a user configures a small p-key and the profile +is stored in ifcfg-rh format, the settings backend will automatically +mangle the profile and set 0x8000. That is different from when the +profile is stored in keyfile format. Since using small p-keys is +probably an odd case, we don't try to workaround that any other way +(like that ifcfg format could represent the orignal value of the profile +and not doing such mangling, or to add the high bit throughout +NetworkManager to the p-key). It's an inconsistency, but given the +existing behaviors it seems best to stick (revert) to it. + +This reverts commit a4fe16a426097eee263cb3ef831dcea468b1ca26. + +Affected versions were 1.42.2+ and 1.40.2+. + +See-also: https://src.fedoraproject.org/rpms/rdma/blob/05333c3602aa3c1d82a6363521bdd5a498eac6d0/f/rdma.ifup-ib#_75 + +https://bugzilla.redhat.com/show_bug.cgi?id=2209164 +(cherry picked from commit f8e5e07355e23b6d59b1b1c9cd2387c6b40b214b) +(cherry picked from commit a1b73d823f5ec30c240418137d62d183b6ff8ca7) +--- + .../plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 18 ++++++ + .../plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 57 ++++++++++++++----- + 2 files changed, 60 insertions(+), 15 deletions(-) + +diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +index 02ba84320134..533379c67868 100644 +--- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c ++++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +@@ -5387,6 +5387,24 @@ parse_infiniband_p_key(shvarFile *ifcfg, int *out_p_key, char **out_parent, GErr + return FALSE; + } + ++ /* The highest bit 0x8000 indicates full membership, which kernel always ++ * automatically sets. ++ * ++ * NetworkManager supports p-keys without the high bit set. That affects ++ * the interface name (nmp_utils_new_infiniband_name()) and is what ++ * we write to "create_child"/"delete_child" sysctl. Kernel will honor ++ * such p-keys for the interface name, but for other purposes it adds the ++ * highest bit. That makes using p-keys without the highest bit odd. ++ * ++ * Historically, /etc/sysconfig/network-scripts/ifup-ib would always add "|=0x8000". ++ * The reader does that too. ++ * ++ * Note that this means ifcfg cannot handle p-keys without the highest bit set, ++ * and when trying to store that to ifcfg format, the profile will be mangled/modified ++ * by the ifcg plugin (unlike keyfile backend, which preserves the original p-key value). ++ */ ++ id |= 0x8000; ++ + *out_p_key = id; + *out_parent = g_steal_pointer(&physdev); + return TRUE; +diff --git a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +index d2ac2b29dbc8..01eb24216aec 100644 +--- a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c ++++ b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +@@ -8383,21 +8383,21 @@ test_read_ipoib(void) + s_infiniband = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_INFINIBAND); + + pkey = nm_setting_infiniband_get_p_key(s_infiniband); +- g_assert(pkey); +- g_assert_cmpint(pkey, ==, 12); ++ g_assert_cmpint(pkey, ==, 0x800c); + + transport_mode = nm_setting_infiniband_get_transport_mode(s_infiniband); +- g_assert(transport_mode); + g_assert_cmpstr(transport_mode, ==, "connected"); + } + + static void + test_write_infiniband(gconstpointer test_data) + { +- const int TEST_IDX = GPOINTER_TO_INT(test_data); +- nmtst_auto_unlinkfile char *testfile = NULL; +- gs_unref_object NMConnection *connection = NULL; +- gs_unref_object NMConnection *reread = NULL; ++ const int TEST_IDX = GPOINTER_TO_INT(test_data); ++ nmtst_auto_unlinkfile char *testfile = NULL; ++ gs_unref_object NMConnection *connection = NULL; ++ gs_unref_object NMConnection *expected = NULL; ++ gs_unref_object NMConnection *reread = NULL; ++ gboolean reread_same = FALSE; + NMSettingConnection *s_con; + NMSettingInfiniband *s_infiniband; + NMSettingIPConfig *s_ip4; +@@ -8407,6 +8407,7 @@ test_write_infiniband(gconstpointer test_data) + NMIPAddress *addr; + GError *error = NULL; + const char *interface_name = NULL; ++ int p_key; + + connection = nm_simple_connection_new(); + +@@ -8422,14 +8423,21 @@ test_write_infiniband(gconstpointer test_data) + NM_SETTING_INFINIBAND_SETTING_NAME, + NULL); + +- if (NM_IN_SET(TEST_IDX, 1, 3)) +- interface_name = "ib0.000c"; ++ if (NM_IN_SET(TEST_IDX, 1, 2)) ++ p_key = nmtst_get_rand_bool() ? 0x000c : 0x800c; ++ else ++ p_key = -1; ++ ++ if (NM_IN_SET(TEST_IDX, 1, 3)) { ++ if (p_key >= 0x8000) ++ interface_name = "ib0.800c"; ++ } + + g_object_set(s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, interface_name, NULL); + + s_infiniband = _nm_connection_new_setting(connection, NM_TYPE_SETTING_INFINIBAND); + g_object_set(s_infiniband, NM_SETTING_INFINIBAND_TRANSPORT_MODE, "connected", NULL); +- if (NM_IN_SET(TEST_IDX, 1, 2)) { ++ if (p_key == -1) { + g_object_set(s_infiniband, + NM_SETTING_INFINIBAND_MAC_ADDRESS, + mac, +@@ -8439,7 +8447,7 @@ test_write_infiniband(gconstpointer test_data) + } else { + g_object_set(s_infiniband, + NM_SETTING_INFINIBAND_P_KEY, +- 12, ++ p_key, + NM_SETTING_INFINIBAND_PARENT, + "ib0", + NULL); +@@ -8468,13 +8476,32 @@ test_write_infiniband(gconstpointer test_data) + + nmtst_assert_connection_verifies(connection); + +- _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile); +- +- reread = _connection_from_file(testfile, NULL, TYPE_INFINIBAND, NULL); ++ if (p_key != -1 && p_key < 0x8000) { ++ expected = nm_simple_connection_new_clone(connection); ++ g_object_set(nm_connection_get_setting(expected, NM_TYPE_SETTING_INFINIBAND), ++ NM_SETTING_INFINIBAND_P_KEY, ++ (int) (p_key | 0x8000), ++ NULL); ++ } else ++ expected = g_object_ref(connection); + +- nmtst_assert_connection_equals(connection, TRUE, reread, FALSE); ++ _writer_new_connection_reread(connection, ++ TEST_SCRATCH_DIR, ++ &testfile, ++ NO_EXPECTED, ++ &reread, ++ &reread_same); ++ _assert_reread_same(expected, reread); ++ if (p_key == -1 || p_key > 0x8000) ++ g_assert(reread_same); ++ else ++ g_assert(!reread_same); + + g_assert_cmpstr(interface_name, ==, nm_connection_get_interface_name(reread)); ++ g_assert_cmpint(nm_setting_infiniband_get_p_key( ++ _nm_connection_get_setting(reread, NM_TYPE_SETTING_INFINIBAND)), ++ ==, ++ p_key == -1 ? -1 : (p_key | 0x8000)); + } + + static void +-- +2.40.1 + + +From 9f0fe4115af06f434443e2f9a7409011f09bd383 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Wed, 24 May 2023 10:44:58 +0200 +Subject: [PATCH 2/8] libnm/docs: clarify behavior of infiniband.p-key property + +(cherry picked from commit ea18e66ef657b55eca941dca3de4949b950e656b) +(cherry picked from commit 1e014d466a7008725e0b2c7cb41b1e00cb7868de) +--- + src/libnm-core-impl/nm-setting-infiniband.c | 19 ++++++++++++++++--- + src/libnmc-setting/settings-docs.h.in | 2 +- + .../generate-docs-nm-settings-nmcli.xml.in | 2 +- + 3 files changed, 18 insertions(+), 5 deletions(-) + +diff --git a/src/libnm-core-impl/nm-setting-infiniband.c b/src/libnm-core-impl/nm-setting-infiniband.c +index 787b838b7694..df296becbaae 100644 +--- a/src/libnm-core-impl/nm-setting-infiniband.c ++++ b/src/libnm-core-impl/nm-setting-infiniband.c +@@ -448,9 +448,20 @@ nm_setting_infiniband_class_init(NMSettingInfinibandClass *klass) + * NMSettingInfiniband:p-key: + * + * The InfiniBand P_Key to use for this device. A value of -1 means to use +- * the default P_Key (aka "the P_Key at index 0"). Otherwise, it is a 16-bit +- * unsigned integer, whose high bit is set if it is a "full membership" +- * P_Key. ++ * the default P_Key (aka "the P_Key at index 0"). Otherwise, it is a ++ * 16-bit unsigned integer, whose high bit 0x8000 is set if it is a "full ++ * membership" P_Key. The values 0 and 0x8000 are not allowed. ++ * ++ * With the p-key set, the interface name is always "$parent.$p_key". ++ * Setting "connection.interface-name" to another name is not supported. ++ * ++ * Note that kernel will internally always set the full membership bit, ++ * although the interface name does not reflect that. Thus, not setting ++ * the high bit is probably not useful. ++ * ++ * If the profile is stored in ifcfg-rh format, then the full membership ++ * bit is automatically added. To get consistent behavior, it is ++ * best to only use p-key values with the full membership bit set. + **/ + /* ---ifcfg-rh--- + * property: p-key +@@ -459,6 +470,8 @@ nm_setting_infiniband_class_init(NMSettingInfinibandClass *klass) + * description: InfiniBand P_Key. The value can be a hex number prefixed with "0x" + * or a decimal number. + * When PKEY_ID is specified, PHYSDEV and DEVICE also must be specified. ++ * Note that ifcfg-rh format will always automatically set the full membership ++ * bit 0x8000. Other p-key cannot be stored. + * example: PKEY=yes PKEY_ID=2 PHYSDEV=mlx4_ib0 DEVICE=mlx4_ib0.8002 + * ---end--- + */ +diff --git a/src/libnmc-setting/settings-docs.h.in b/src/libnmc-setting/settings-docs.h.in +index 6a5f4163485d..172f9b15bb98 100644 +--- a/src/libnmc-setting/settings-docs.h.in ++++ b/src/libnmc-setting/settings-docs.h.in +@@ -153,7 +153,7 @@ + #define DESCRIBE_DOC_NM_SETTING_GSM_USERNAME N_("The username used to authenticate with the network, if required. Many providers do not require a username, or accept any username. But if a username is required, it is specified here.") + #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_MAC_ADDRESS N_("If specified, this connection will only apply to the IPoIB device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing).") + #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple frames.") +-#define DESCRIBE_DOC_NM_SETTING_INFINIBAND_P_KEY N_("The InfiniBand P_Key to use for this device. A value of -1 means to use the default P_Key (aka \"the P_Key at index 0\"). Otherwise, it is a 16-bit unsigned integer, whose high bit is set if it is a \"full membership\" P_Key.") ++#define DESCRIBE_DOC_NM_SETTING_INFINIBAND_P_KEY N_("The InfiniBand P_Key to use for this device. A value of -1 means to use the default P_Key (aka \"the P_Key at index 0\"). Otherwise, it is a 16-bit unsigned integer, whose high bit 0x8000 is set if it is a \"full membership\" P_Key. The values 0 and 0x8000 are not allowed. With the p-key set, the interface name is always \"$parent.$p_key\". Setting \"connection.interface-name\" to another name is not supported. Note that kernel will internally always set the full membership bit, although the interface name does not reflect that. Thus, not setting the high bit is probably not useful. If the profile is stored in ifcfg-rh format, then the full membership bit is automatically added. To get consistent behavior, it is best to only use p-key values with the full membership bit set.") + #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_PARENT N_("The interface name of the parent device of this device. Normally NULL, but if the \"p_key\" property is set, then you must specify the base device by setting either this property or \"mac-address\".") + #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_TRANSPORT_MODE N_("The IP-over-InfiniBand transport mode. Either \"datagram\" or \"connected\".") + #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ADDRESSES N_("A list of IPv4 addresses and their prefix length. Multiple addresses can be separated by comma. For example \"192.168.1.5/24, 10.1.0.5/24\". The addresses are listed in decreasing priority, meaning the first address will be the primary address.") +diff --git a/src/nmcli/generate-docs-nm-settings-nmcli.xml.in b/src/nmcli/generate-docs-nm-settings-nmcli.xml.in +index adf7895f0d02..a59dacf2430d 100644 +--- a/src/nmcli/generate-docs-nm-settings-nmcli.xml.in ++++ b/src/nmcli/generate-docs-nm-settings-nmcli.xml.in +@@ -614,7 +614,7 @@ + description="The IP-over-InfiniBand transport mode. Either "datagram" or "connected"." /> + ++ description="The InfiniBand P_Key to use for this device. A value of -1 means to use the default P_Key (aka "the P_Key at index 0"). Otherwise, it is a 16-bit unsigned integer, whose high bit 0x8000 is set if it is a "full membership" P_Key. The values 0 and 0x8000 are not allowed. With the p-key set, the interface name is always "$parent.$p_key". Setting "connection.interface-name" to another name is not supported. Note that kernel will internally always set the full membership bit, although the interface name does not reflect that. Thus, not setting the high bit is probably not useful. If the profile is stored in ifcfg-rh format, then the full membership bit is automatically added. To get consistent behavior, it is best to only use p-key values with the full membership bit set." /> + +-- +2.40.1 + + +From 703b0cf4eb355844821b9e6463458dcada692a65 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Wed, 24 May 2023 17:32:19 +0200 +Subject: [PATCH 3/8] libnm: normalize interface-name for infiniband profiles + +NetworkManager does not support changing the interface name for +infiniband interfaces. Consequently, we verify that +"connection.interface-name" is either unset or set to the expected +"$parent.$p_key". Anything else wouldn't work anyway and is rejected as +invalid configuration. That brings problems however. + +Rejecting invalid configuration seems fine at first: + + $ nmcli --offline connection add type infiniband infiniband.parent ib0 infiniband.p-key 0x8010 connection.interface-name xxx + Error: Error writing connection: connection.interface-name: interface name of software infiniband device must be 'ib0.8010' or unset (instead it is 'xxx') + +However, when we modify the p-key, we also get an error message: + + $ nmcli --offline connection add type infiniband infiniband.parent ib0 infiniband.p-key 0x8010 connection.interface-name ib0.8010 | + nmcli --offline connection modify infiniband.p-key 5 + Error: Error writing connection: connection.interface-name: interface name of software infiniband device must be 'ib0.0005' or unset (instead it is 'ib0.8010') + +It's worse, because ifcfg-rh reader will mangle the PKEY_ID with |=0x8000 to set +the full membership flag. That means, if you add a profile like + + $ nmcli --offline connection add type infiniband infiniband.parent ib0 infiniband.p-key 0x0010 connection.interface-name ib0.0010 + +it gets written to ifcfg-rh file. Then upon reload it's invalid (as the +interface name mismatches). + +There are multiple solutions for this. For example, ifcfg-rh reader could also +mangle the connection.interface-name, so that the overall result is valid. Or +we could just not validate at all, and accept any bogus interface-name. + +With this patch instead we will just normalize the invalid configuration to +make it right. + + $ nmcli --offline connection add type infiniband infiniband.parent ib0 infiniband.p-key 0x8010 connection.interface-name ib0.8010 | + nmcli --offline connection modify infiniband.p-key 5 + ... + +The downside is that this happens silently, so a user doesn't +notice that configuration is ignored: + + $ nmcli --offline connection add type infiniband infiniband.parent ib0 infiniband.p-key 0x8010 connection.interface-name foo + ... + interface-name=ib0.8010 + +This approach still seems preferable, because setting +"connection.interface-name" for infiniband profiles makes little sense, +so what we care here is to avoid problems. + +(cherry picked from commit 4610fd67e6e795131a358b292ec3fc1ba2a2250f) +(cherry picked from commit 8b2612bfe630cdb676566a8249a14900910f82c5) +--- + src/libnm-core-impl/nm-connection.c | 39 ++++++++++++++++----- + src/libnm-core-impl/nm-setting-infiniband.c | 14 ++++---- + src/libnm-core-impl/tests/test-general.c | 30 +++++++++++++--- + 3 files changed, 63 insertions(+), 20 deletions(-) + +diff --git a/src/libnm-core-impl/nm-connection.c b/src/libnm-core-impl/nm-connection.c +index 2f5bf3570935..67a9034dccba 100644 +--- a/src/libnm-core-impl/nm-connection.c ++++ b/src/libnm-core-impl/nm-connection.c +@@ -1358,18 +1358,41 @@ _normalize_ip_config(NMConnection *self, GHashTable *parameters) + } + + static gboolean +-_normalize_infiniband_mtu(NMConnection *self) ++_normalize_infiniband(NMConnection *self) + { + NMSettingInfiniband *s_infini = nm_connection_get_setting_infiniband(self); ++ gboolean changed = FALSE; ++ const char *interface_name; ++ int p_key; + +- if (!s_infini || nm_setting_infiniband_get_mtu(s_infini) <= NM_INFINIBAND_MAX_MTU +- || !NM_IN_STRSET(nm_setting_infiniband_get_transport_mode(s_infini), +- "datagram", +- "connected")) ++ if (!s_infini) + return FALSE; + +- g_object_set(s_infini, NM_SETTING_INFINIBAND_MTU, (guint) NM_INFINIBAND_MAX_MTU, NULL); +- return TRUE; ++ if (nm_setting_infiniband_get_mtu(s_infini) > NM_INFINIBAND_MAX_MTU) { ++ if (NM_IN_STRSET(nm_setting_infiniband_get_transport_mode(s_infini), ++ "datagram", ++ "connected")) { ++ g_object_set(s_infini, NM_SETTING_INFINIBAND_MTU, (guint) NM_INFINIBAND_MAX_MTU, NULL); ++ changed = TRUE; ++ } ++ } ++ ++ if ((p_key = nm_setting_infiniband_get_p_key(s_infini)) != -1 ++ && (interface_name = nm_connection_get_interface_name(self))) { ++ const char *virtual_iface_name; ++ ++ virtual_iface_name = nm_setting_infiniband_get_virtual_interface_name(s_infini); ++ ++ if (!nm_streq0(interface_name, virtual_iface_name)) { ++ g_object_set(nm_connection_get_setting_connection(self), ++ NM_SETTING_CONNECTION_INTERFACE_NAME, ++ virtual_iface_name, ++ NULL); ++ changed = TRUE; ++ } ++ } ++ ++ return changed; + } + + static gboolean +@@ -2000,7 +2023,7 @@ _connection_normalize(NMConnection *connection, + was_modified |= _normalize_invalid_slave_port_settings(connection); + was_modified |= _normalize_ip_config(connection, parameters); + was_modified |= _normalize_ethernet_link_neg(connection); +- was_modified |= _normalize_infiniband_mtu(connection); ++ was_modified |= _normalize_infiniband(connection); + was_modified |= _normalize_bond_mode(connection); + was_modified |= _normalize_bond_options(connection); + was_modified |= _normalize_wireless_mac_address_randomization(connection); +diff --git a/src/libnm-core-impl/nm-setting-infiniband.c b/src/libnm-core-impl/nm-setting-infiniband.c +index df296becbaae..7b242a539314 100644 +--- a/src/libnm-core-impl/nm-setting-infiniband.c ++++ b/src/libnm-core-impl/nm-setting-infiniband.c +@@ -181,8 +181,8 @@ nm_setting_infiniband_get_virtual_interface_name(NMSettingInfiniband *setting) + static gboolean + verify(NMSetting *setting, NMConnection *connection, GError **error) + { +- NMSettingConnection *s_con = NULL; +- NMSettingInfinibandPrivate *priv = NM_SETTING_INFINIBAND_GET_PRIVATE(setting); ++ NMSettingConnection *s_con; ++ NMSettingInfinibandPrivate *priv = NM_SETTING_INFINIBAND_GET_PRIVATE(setting); + + if (priv->mac_address && !nm_utils_hwaddr_valid(priv->mac_address, INFINIBAND_ALEN)) { + g_set_error_literal(error, +@@ -251,8 +251,10 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) + } + } + +- if (connection) +- s_con = nm_connection_get_setting_connection(connection); ++ /* *** errors above here should be always fatal, below NORMALIZABLE_ERROR *** */ ++ ++ s_con = connection ? nm_connection_get_setting_connection(connection) : NULL; ++ + if (s_con) { + const char *interface_name = nm_setting_connection_get_interface_name(s_con); + +@@ -287,13 +289,11 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) + "%s.%s: ", + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_INTERFACE_NAME); +- return FALSE; ++ return NM_SETTING_VERIFY_NORMALIZABLE_ERROR; + } + } + } + +- /* *** errors above here should be always fatal, below NORMALIZABLE_ERROR *** */ +- + if (priv->mtu > NM_INFINIBAND_MAX_MTU) { + /* Traditionally, MTU for "datagram" mode was limited to 2044 + * and for "connected" mode it was 65520. +diff --git a/src/libnm-core-impl/tests/test-general.c b/src/libnm-core-impl/tests/test-general.c +index 1ff3b972a7a0..1feaae3ff5a7 100644 +--- a/src/libnm-core-impl/tests/test-general.c ++++ b/src/libnm-core-impl/tests/test-general.c +@@ -6149,16 +6149,17 @@ test_connection_normalize_slave_type_2(void) + } + + static void +-test_connection_normalize_infiniband_mtu(void) ++test_connection_normalize_infiniband(void) + { + gs_unref_object NMConnection *con = NULL; + NMSettingInfiniband *s_infini; ++ NMSettingConnection *s_con; + guint mtu_regular = nmtst_rand_select(2044, 2045, 65520); + +- con = nmtst_create_minimal_connection("test_connection_normalize_infiniband_mtu", ++ con = nmtst_create_minimal_connection("test_connection_normalize_infiniband", + NULL, + NM_SETTING_INFINIBAND_SETTING_NAME, +- NULL); ++ &s_con); + + s_infini = nm_connection_get_setting_infiniband(con); + g_object_set(s_infini, NM_SETTING_INFINIBAND_TRANSPORT_MODE, "connected", NULL); +@@ -6206,6 +6207,25 @@ test_connection_normalize_infiniband_mtu(void) + NM_CONNECTION_ERROR_INVALID_PROPERTY); + nmtst_connection_normalize(con); + g_assert_cmpint(65520, ==, nm_setting_infiniband_get_mtu(s_infini)); ++ ++ g_object_set(s_infini, ++ NM_SETTING_INFINIBAND_PARENT, ++ "foo", ++ NM_SETTING_INFINIBAND_P_KEY, ++ 0x005c, ++ NULL); ++ nmtst_assert_connection_verifies_without_normalization(con); ++ ++ g_object_set(s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, "foo.005c", NULL); ++ nmtst_assert_connection_verifies_without_normalization(con); ++ ++ g_object_set(s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, "foo", NULL); ++ nmtst_assert_connection_verifies_after_normalization(con, ++ NM_CONNECTION_ERROR, ++ NM_CONNECTION_ERROR_INVALID_PROPERTY); ++ ++ nmtst_connection_normalize(con); ++ g_assert_cmpstr(nm_connection_get_interface_name(con), ==, "foo.005c"); + } + + static void +@@ -11109,8 +11129,8 @@ main(int argc, char **argv) + test_connection_normalize_slave_type_1); + g_test_add_func("/core/general/test_connection_normalize_slave_type_2", + test_connection_normalize_slave_type_2); +- g_test_add_func("/core/general/test_connection_normalize_infiniband_mtu", +- test_connection_normalize_infiniband_mtu); ++ g_test_add_func("/core/general/test_connection_normalize_infiniband", ++ test_connection_normalize_infiniband); + g_test_add_func("/core/general/test_connection_normalize_gateway_never_default", + test_connection_normalize_gateway_never_default); + g_test_add_func("/core/general/test_connection_normalize_may_fail", +-- +2.40.1 + + +From 72e6cbce4a8cbd5060edc5503214dab5cd46ba88 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Wed, 24 May 2023 21:33:57 +0200 +Subject: [PATCH 4/8] libnm: add + nm_setting_infiniband_create_virtual_interface_name() helper + +(cherry picked from commit fa05d1c1695aacd2d7144a71795463a1f793288a) +(cherry picked from commit e0ed06edefc3eac268f347a9c5aa6208bb9abb77) +--- + src/libnm-core-impl/nm-setting-infiniband.c | 9 ++++++++- + src/libnm-core-intern/nm-core-internal.h | 2 ++ + 2 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/src/libnm-core-impl/nm-setting-infiniband.c b/src/libnm-core-impl/nm-setting-infiniband.c +index 7b242a539314..6d2ed7fb4828 100644 +--- a/src/libnm-core-impl/nm-setting-infiniband.c ++++ b/src/libnm-core-impl/nm-setting-infiniband.c +@@ -144,6 +144,12 @@ nm_setting_infiniband_get_parent(NMSettingInfiniband *setting) + return NM_SETTING_INFINIBAND_GET_PRIVATE(setting)->parent; + } + ++char * ++nm_setting_infiniband_create_virtual_interface_name(const char *parent, int p_key) ++{ ++ return g_strdup_printf("%s.%04x", parent, p_key); ++} ++ + /** + * nm_setting_infiniband_get_virtual_interface_name: + * @setting: the #NMSettingInfiniband +@@ -172,7 +178,8 @@ nm_setting_infiniband_get_virtual_interface_name(NMSettingInfiniband *setting) + priv->virtual_iface_name_p_key = priv->p_key; + priv->virtual_iface_name_parent_length = len; + g_free(priv->virtual_iface_name); +- priv->virtual_iface_name = g_strdup_printf("%s.%04x", priv->parent, priv->p_key); ++ priv->virtual_iface_name = ++ nm_setting_infiniband_create_virtual_interface_name(priv->parent, priv->p_key); + } + + return priv->virtual_iface_name; +diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h +index 4e1bab4723df..1857e03bbd60 100644 +--- a/src/libnm-core-intern/nm-core-internal.h ++++ b/src/libnm-core-intern/nm-core-internal.h +@@ -321,6 +321,8 @@ typedef gpointer (*NMUtilsCopyFunc)(gpointer); + const char ** + _nm_ip_address_get_attribute_names(const NMIPAddress *addr, gboolean sorted, guint *out_length); + ++char *nm_setting_infiniband_create_virtual_interface_name(const char *parent, int p_key); ++ + #define NM_SETTING_WIRED_S390_OPTION_MAX_LEN 200u + + void _nm_setting_wired_clear_s390_options(NMSettingWired *setting); +-- +2.40.1 + + +From 0bbaa344c57468a57b9f83887fd755fd67701f75 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Wed, 24 May 2023 21:38:27 +0200 +Subject: [PATCH 5/8] libnm: truncate too long interface name in + nm_setting_infiniband_create_virtual_interface_name() + +This is the same what kernel does, when the parent name is so long +that it would result in a too long overall name. + +We need that the result is still a valid interface name. + +(cherry picked from commit 1009f1f11f991e41f856f2616c0972652f812a85) +(cherry picked from commit 37994cef357506c246f3061d50474c14e425d9a9) +--- + src/libnm-core-impl/nm-setting-infiniband.c | 9 +++++- + src/libnm-core-impl/tests/test-general.c | 32 +++++++++++++++++++++ + 2 files changed, 40 insertions(+), 1 deletion(-) + +diff --git a/src/libnm-core-impl/nm-setting-infiniband.c b/src/libnm-core-impl/nm-setting-infiniband.c +index 6d2ed7fb4828..0753a8db2d81 100644 +--- a/src/libnm-core-impl/nm-setting-infiniband.c ++++ b/src/libnm-core-impl/nm-setting-infiniband.c +@@ -8,8 +8,10 @@ + #include "nm-setting-infiniband.h" + + #include ++#include + #include + ++#include "libnm-platform/nmp-base.h" + #include "nm-utils.h" + #include "nm-utils-private.h" + #include "nm-setting-private.h" +@@ -147,7 +149,12 @@ nm_setting_infiniband_get_parent(NMSettingInfiniband *setting) + char * + nm_setting_infiniband_create_virtual_interface_name(const char *parent, int p_key) + { +- return g_strdup_printf("%s.%04x", parent, p_key); ++ char *s; ++ ++ s = g_strdup_printf("%s.%04x", parent, (guint) p_key); ++ if (strlen(s) >= IFNAMSIZ) ++ s[IFNAMSIZ - 1] = '\0'; ++ return s; + } + + /** +diff --git a/src/libnm-core-impl/tests/test-general.c b/src/libnm-core-impl/tests/test-general.c +index 1feaae3ff5a7..fe070c3ea1f3 100644 +--- a/src/libnm-core-impl/tests/test-general.c ++++ b/src/libnm-core-impl/tests/test-general.c +@@ -6226,6 +6226,38 @@ test_connection_normalize_infiniband(void) + + nmtst_connection_normalize(con); + g_assert_cmpstr(nm_connection_get_interface_name(con), ==, "foo.005c"); ++ ++ g_object_set(s_infini, ++ NM_SETTING_INFINIBAND_PARENT, ++ "x234567890123", ++ NM_SETTING_INFINIBAND_P_KEY, ++ 0x005c, ++ NULL); ++ nmtst_assert_connection_verifies_after_normalization(con, ++ NM_CONNECTION_ERROR, ++ NM_CONNECTION_ERROR_INVALID_PROPERTY); ++ ++ nmtst_connection_normalize(con); ++ g_assert_cmpstr(nm_connection_get_interface_name(con), ==, "x234567890123.0"); ++ ++#define iface_name(parent, p_key, expected) \ ++ G_STMT_START \ ++ { \ ++ gs_free char *_s = nm_setting_infiniband_create_virtual_interface_name((parent), (p_key)); \ ++ \ ++ g_assert(nm_utils_ifname_valid_kernel(_s, NULL)); \ ++ g_assert_cmpstr(_s, ==, (expected)); \ ++ } \ ++ G_STMT_END ++ ++ iface_name("foo", 15, "foo.000f"); ++ iface_name("x23456789012345", 15, "x23456789012345"); ++ iface_name("x2345678901234", 15, "x2345678901234."); ++ iface_name("x234567890123", 15, "x234567890123.0"); ++ iface_name("x23456789012", 15, "x23456789012.00"); ++ iface_name("x2345678901", 15, "x2345678901.000"); ++ iface_name("x234567890", 15, "x234567890.000f"); ++ iface_name("x23456789", 15, "x23456789.000f"); + } + + static void +-- +2.40.1 + + +From 15cb222ac1acfa0e40bcfb15747c32211337c76c Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Wed, 24 May 2023 21:34:00 +0200 +Subject: [PATCH 6/8] ifcfg-rh: adjust infiniband p-key for later normalization + when writing to file + +(cherry picked from commit 82f5bff882a58226c22df1b735d4b434af883102) +(cherry picked from commit a6316c61f09ab2cd169040815faae007077dcbe8) +--- + .../plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 36 +++++++++++++++---- + 1 file changed, 29 insertions(+), 7 deletions(-) + +diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +index e340c9fe1374..9610cd647114 100644 +--- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c ++++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +@@ -1023,7 +1023,10 @@ write_wireless_setting(NMConnection *connection, + } + + static gboolean +-write_infiniband_setting(NMConnection *connection, shvarFile *ifcfg, GError **error) ++write_infiniband_setting(NMConnection *connection, ++ shvarFile *ifcfg, ++ char **out_interface_name, ++ GError **error) + { + NMSettingInfiniband *s_infiniband; + const char *mac, *transport_mode, *parent; +@@ -1051,12 +1054,28 @@ write_infiniband_setting(NMConnection *connection, shvarFile *ifcfg, GError **er + + p_key = nm_setting_infiniband_get_p_key(s_infiniband); + if (p_key != -1) { ++ /* The reader normalizes KKEY_ID with |=0x8000. Also do that when ++ * writing the profile so that what we write, is consistent with what ++ * we would read. */ ++ p_key |= 0x8000; ++ + svSetValueStr(ifcfg, "PKEY", "yes"); + svSetValueInt64(ifcfg, "PKEY_ID", p_key); + + parent = nm_setting_infiniband_get_parent(s_infiniband); +- if (parent) +- svSetValueStr(ifcfg, "PHYSDEV", parent); ++ svSetValueStr(ifcfg, "PHYSDEV", parent); ++ ++ if (parent && nm_connection_get_interface_name(connection)) { ++ /* The connection.interface-name depends on the p-key. Also, ++ * nm_connection_normalize() will automatically adjust the ++ * interface-name to match the p-key. ++ * ++ * As we patched the p-key above, also anticipate that change, and ++ * don't write a DEVICE= to the file, which would we normalize ++ * differently, when reading it back. */ ++ *out_interface_name = ++ nm_setting_infiniband_create_virtual_interface_name(parent, p_key); ++ } + } + + svSetValueStr(ifcfg, "TYPE", TYPE_INFINIBAND); +@@ -2094,7 +2113,7 @@ write_dcb_setting(NMConnection *connection, shvarFile *ifcfg, GError **error) + } + + static void +-write_connection_setting(NMSettingConnection *s_con, shvarFile *ifcfg) ++write_connection_setting(NMSettingConnection *s_con, shvarFile *ifcfg, const char *interface_name) + { + guint32 n, i; + nm_auto_free_gstring GString *str = NULL; +@@ -2111,7 +2130,9 @@ write_connection_setting(NMSettingConnection *s_con, shvarFile *ifcfg) + svSetValueStr(ifcfg, "NAME", nm_setting_connection_get_id(s_con)); + svSetValueStr(ifcfg, "UUID", nm_setting_connection_get_uuid(s_con)); + svSetValueStr(ifcfg, "STABLE_ID", nm_setting_connection_get_stable_id(s_con)); +- svSetValueStr(ifcfg, "DEVICE", nm_setting_connection_get_interface_name(s_con)); ++ svSetValueStr(ifcfg, ++ "DEVICE", ++ interface_name ?: nm_setting_connection_get_interface_name(s_con)); + svSetValueBoolean(ifcfg, "ONBOOT", nm_setting_connection_get_autoconnect(s_con)); + + vint = nm_setting_connection_get_autoconnect_priority(s_con); +@@ -3294,6 +3315,7 @@ do_write_construct(NMConnection *connection, + nm_auto_shvar_file_close shvarFile *route_content_svformat = NULL; + nm_auto_free_gstring GString *route_content = NULL; + nm_auto_free_gstring GString *route6_content = NULL; ++ gs_free char *interface_name = NULL; + + nm_assert(NM_IS_CONNECTION(connection)); + nm_assert(_nm_connection_verify(connection, NULL) == NM_SETTING_VERIFY_SUCCESS); +@@ -3399,7 +3421,7 @@ do_write_construct(NMConnection *connection, + if (!write_wireless_setting(connection, ifcfg, secrets, &no_8021x, error)) + return FALSE; + } else if (!strcmp(type, NM_SETTING_INFINIBAND_SETTING_NAME)) { +- if (!write_infiniband_setting(connection, ifcfg, error)) ++ if (!write_infiniband_setting(connection, ifcfg, &interface_name, error)) + return FALSE; + } else if (!strcmp(type, NM_SETTING_BOND_SETTING_NAME)) { + if (!write_bond_setting(connection, ifcfg, &wired, error)) +@@ -3504,7 +3526,7 @@ do_write_construct(NMConnection *connection, + + write_ip_routing_rules(connection, ifcfg, route_ignore); + +- write_connection_setting(s_con, ifcfg); ++ write_connection_setting(s_con, ifcfg, interface_name); + + NM_SET_OUT(out_ifcfg, g_steal_pointer(&ifcfg)); + NM_SET_OUT(out_blobs, g_steal_pointer(&blobs)); +-- +2.40.1 + + +From fe3789da37f394112bdb07ffc7935d935449e17a Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Mon, 5 Jun 2023 08:52:09 +0200 +Subject: [PATCH 7/8] ifcfg-rh/tests: add test for infiniband profile with + PKEY_ID in ifcfg format + +https://bugzilla.redhat.com/show_bug.cgi?id=2209164 +(cherry picked from commit 0d0704eaa02c45e10917ce503f50b4ca885285aa) +(cherry picked from commit 0b56618b198c6cb3f99e84554487dc6eea66d468) +(cherry picked from commit 2cc34244e1d53b4f2ca8efa59755aa68cd663365) +--- + Makefile.am | 4 +- + ...test-infiniband => ifcfg-test-infiniband0} | 0 + .../network-scripts/ifcfg-test-infiniband1 | 12 ++++++ + .../network-scripts/ifcfg-test-infiniband2 | 12 ++++++ + .../plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 38 ++++++++++++++++--- + 5 files changed, 59 insertions(+), 7 deletions(-) + rename src/core/settings/plugins/ifcfg-rh/tests/network-scripts/{ifcfg-test-infiniband => ifcfg-test-infiniband0} (100%) + create mode 100644 src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-infiniband1 + create mode 100644 src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-infiniband2 + +diff --git a/Makefile.am b/Makefile.am +index 7cdb1120ccc3..a42474b714be 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3457,7 +3457,9 @@ EXTRA_DIST += \ + src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-fcoe-fabric \ + src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-fcoe-vn2vn \ + src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ibft \ +- src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-infiniband \ ++ src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-infiniband0 \ ++ src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-infiniband1 \ ++ src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-infiniband2 \ + src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ip6-disabled.cexpected \ + src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ipoib \ + src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-link_local \ +diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-infiniband b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-infiniband0 +similarity index 100% +rename from src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-infiniband +rename to src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-infiniband0 +diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-infiniband1 b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-infiniband1 +new file mode 100644 +index 000000000000..dcb7758e6ed9 +--- /dev/null ++++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-infiniband1 +@@ -0,0 +1,12 @@ ++TYPE=InfiniBand ++HWADDR=80:00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22 ++CONNECTED_MODE=yes ++MTU=65520 ++IPADDR=192.168.2.2 ++NETMASK=255.255.255.0 ++GATEWAY=192.168.2.1 ++ ++DEVICE=ib0.80c1 ++PKEY=yes ++PKEY_ID=0x00c1 ++PHYSDEV=ib0 +diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-infiniband2 b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-infiniband2 +new file mode 100644 +index 000000000000..2e6d9edf3ac4 +--- /dev/null ++++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-infiniband2 +@@ -0,0 +1,12 @@ ++TYPE=InfiniBand ++HWADDR=80:00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22 ++CONNECTED_MODE=yes ++MTU=65520 ++IPADDR=192.168.2.2 ++NETMASK=255.255.255.0 ++GATEWAY=192.168.2.1 ++ ++DEVICE=ib0.00c1 ++PKEY=yes ++PKEY_ID=0x00c1 ++PHYSDEV=ib0 +diff --git a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +index 01eb24216aec..b391aa2392a8 100644 +--- a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c ++++ b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +@@ -8337,8 +8337,9 @@ test_write_bond_port(void) + } + + static void +-test_read_infiniband(void) ++test_read_infiniband(gconstpointer test_data) + { ++ const guint TEST_IDX = GPOINTER_TO_UINT(test_data); + gs_unref_object NMConnection *connection = NULL; + NMSettingInfiniband *s_infiniband; + char *unmanaged = NULL; +@@ -8347,11 +8348,15 @@ test_read_infiniband(void) + 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, + 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22}; + const char *transport_mode; ++ const char *test_files[] = { ++ TEST_IFCFG_DIR "/ifcfg-test-infiniband0", ++ TEST_IFCFG_DIR "/ifcfg-test-infiniband1", ++ TEST_IFCFG_DIR "/ifcfg-test-infiniband2", ++ }; + +- connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-infiniband", +- NULL, +- TYPE_INFINIBAND, +- &unmanaged); ++ g_assert(TEST_IDX < G_N_ELEMENTS(test_files)); ++ ++ connection = _connection_from_file(test_files[TEST_IDX], NULL, TYPE_INFINIBAND, &unmanaged); + g_assert(!unmanaged); + + s_infiniband = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_INFINIBAND); +@@ -8363,6 +8368,25 @@ test_read_infiniband(void) + transport_mode = nm_setting_infiniband_get_transport_mode(s_infiniband); + g_assert(transport_mode); + g_assert_cmpstr(transport_mode, ==, "connected"); ++ ++ nmtst_assert_connection_verifies_without_normalization(connection); ++ ++ switch (TEST_IDX) { ++ case 0: ++ g_assert_cmpint(nm_setting_infiniband_get_p_key(s_infiniband), ==, -1); ++ g_assert_cmpstr(nm_setting_infiniband_get_parent(s_infiniband), ==, NULL); ++ g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "ib0"); ++ break; ++ case 1: ++ case 2: ++ g_assert_cmpint(nm_setting_infiniband_get_p_key(s_infiniband), ==, 0x80c1); ++ g_assert_cmpstr(nm_setting_infiniband_get_parent(s_infiniband), ==, "ib0"); ++ g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "ib0.80c1"); ++ break; ++ default: ++ g_assert_not_reached(); ++ break; ++ } + } + + static void +@@ -10673,7 +10697,9 @@ main(int argc, char **argv) + + g_test_add_func(TPATH "wifi/read/wep-no-keys", test_read_wifi_wep_no_keys); + g_test_add_func(TPATH "wifi/read/wep-agent-keys", test_read_wifi_wep_agent_keys); +- g_test_add_func(TPATH "infiniband/read", test_read_infiniband); ++ g_test_add_data_func(TPATH "infiniband/read/0", GUINT_TO_POINTER(0), test_read_infiniband); ++ g_test_add_data_func(TPATH "infiniband/read/1", GUINT_TO_POINTER(1), test_read_infiniband); ++ g_test_add_data_func(TPATH "infiniband/read/2", GUINT_TO_POINTER(2), test_read_infiniband); + g_test_add_func(TPATH "ipoib/read", test_read_ipoib); + g_test_add_func(TPATH "vlan/read", test_read_vlan_interface); + g_test_add_func(TPATH "vlan/read-flags-1", test_read_vlan_flags_1); +-- +2.40.1 + + +From 5263adc4c930edb9b0a7e7e38d4fa5682c63fe2d Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Tue, 30 May 2023 17:51:02 +0200 +Subject: [PATCH 8/8] ifcfg: better handle non-full-membership PKEY_ID with new + PKEY_ID_NM variable + +Infiniband profiles can have a p-key set. Both in kernel API +("create_child" sysctl) and in NetworkManager API, that key can range +from 0x0001 to 0xFFFF (0x8000 excluded). NetworkManager does not support +renaming the interface, so kernel always assigns the interface name +"$PHYSDEV.$PKEY_ID" (with $PKEY_ID as 4 character hex digits). + +Note that the highest bit in the p-key (0x8000) is the full-membership +flag. Internally, kernel only supports full-membership so when we create +for example "ib0.00c1" and "ib0.80c1" interfaces, their actually used +p-key is in both cases 0x80c1 and you can see it with `ip -d link`. +Nonetheless, kernel and NetworkManager allow to configure the p-key +without the highest bit set, and the result differs in the interface +name. + +Note that initscripts' ifup-ib0 would always internally coerce the +PKEY_ID variable to have the high bit set ([1]). It also would require +that the `DEVICE=` variable is specified and matches the expected +interface name. So both these configurations are identical and valid: + + DEVICE=ib0.80c1 + PHYSDEV=ib0 + PKEY_ID=0x80c1 + +and + + DEVICE=ib0.80c1 + PHYSDEV=ib0 + PKEY_ID=0x00c1 + +Historically, NetworkManager would also implement the same restrictions +([2], [3], [4]). That meant, not all valid NetworkManager infiniband +profiles could be expressed as ifcfg file. For example, NetworkManager +allows to have "connection.interface-name" (`DEVICE=`) unset (which +ifup-ib and ifcfg reader did not allow). Also, NetworkManager would +allow configuring a "infiniband.p-key" without full membership flag, and +the reader would mangle that. + +This caused various problems to the point that when you configure an +infiniband.p-key with a non-full-membership key, the ifcfg-rh written by +NetworkManager was invalid. Either, you could leave +"connection.interface-name" unset, but then the reader would complain +about missing `DEVICE=`. Or, we could write `DEVICE=ib0.00c1; +PKEY_ID=0x00c1`, which was invalid as we expected `DEVICE=ib0.80c1`. + +This was addressed by rhbz 2122703 ([5]). The fix was to + + - not require a `DEVICE=` ([6]). + - don't mangle the `PKEY_ID=` in the reader ([7]). + +which happened in 1.41.2 and 1.40.2 (rhel-8.8). + +With this change, we could persist any valid infiniband profile to ifcfg +format. We also could read back any valid ifcfg file that NetworkManager +would have written in the past (note that it could not write valid ifcfg +files previously, if the p-key didn't have the full-membership key set). + +The problem is, that users were used to edit ifcfg files by hand, and +users would have files with: + + DEVICE=ib0.80c1 + PHYSDEV=ib0 + PKEY_ID=0x00c1 + +This files had worked before, but now failed to verify as we would +expect `DEVICE=ib0.00c1`. Also, there was a change in behavior that +PKEY_ID is now interpreted without the high bit set. This is reported as +rhbz 2209164 ([8]). + +We will do several things to fix that: + +1) we now normalize the "connection.interface-name" to be valid. It was + not useful to set it anyway, as it was redundant. Complaining about a + redundant setting, which makes little sense to configure, is not useful. + This is done by [9]. + +2) we now again treat PKEY_ID= as if it had 0x8000 flag set. This was done by + [10]. + +With step 1) and 2), we are able to read any existing ifcfg files out +there in the way we did before 1.41.2. + +There is however one piece missing. When we now create a profile using +nmcli/libnm/D-Bus, which has a non-full-membership p-key, then the +profile gets mangled in the process. + +If the user uses NetworkManager API to configure an interface and +chooses a non-full-membership p-key, then this should work the same as +with keyfile plugin (or on rhel-9, where keyfile is the default). Note +that before 1.41.2 it didn't work at all, when the user used ifcfg-rh +backend. Likely(?) there are no users who rely on creating such a profile +with nmcli/libnm/D-Bus and expect to automatically have the p-key +normalized. That didn't work before 1.41.2 and didn't behave that way +between 1.41.2 and now. + +This patch fixes that by introducing a new key PKEY_ID_NM= for holding +the real p-key. Now ifcfg backend is consistent with handling infiniband +profiles, and old, hand-written ifcfg files still work as before. + +There is of course change in behavior, that ifcfg files between 1.41.2 +and now were interpreted differently. But that is bug 2209164 ([8]) and +what we fix here. + +For now strong reasons, we keep writing the PKEY_ID to file too. It's +redundant, but that is what a human might expect there. + +[1] https://src.fedoraproject.org/rpms/rdma/blob/05333c3602aa3c1d82a6363521bdd5a498eac6d0/f/rdma.ifup-ib#_75 +[2] https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/1.40.0/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c#L5386 +[3] https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/commit/cb5606cf1c7a1638fea2858ddd3493a7364f5738#a7a78fccb2c8c945fd09038656ae734c1b0349ab_3493_3532 +[4] https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/commit/cb5606cf1c7a1638fea2858ddd3493a7364f5738#a7a78fccb2c8c945fd09038656ae734c1b0349ab_3493_3506 +[5] https://bugzilla.redhat.com/show_bug.cgi?id=2122703 +[6] https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/commit/4c32dd9d252959b9bab5de6277418939b64d1bb1 +[7] https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/commit/a4fe16a426097eee263cb3ef831dcea468b1ca26 +[8] https://bugzilla.redhat.com/show_bug.cgi?id=2209164 +[9] https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/commit/4610fd67e6e795131a358b292ec3fc1ba2a2250f +[10] https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/commit/f8e5e07355e23b6d59b1b1c9cd2387c6b40b214b + +(cherry picked from commit 5e3e38f291a5bb1499602721401335b1cb585cab) +(cherry picked from commit d8f7fec9e0d395461eab58185398557dc476c716) +(cherry picked from commit cb73ae3f0bbc2a7e083f79f2a0c64a503dc85510) +--- + .../plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 28 +++++++---------- + .../plugins/ifcfg-rh/nms-ifcfg-rh-utils.c | 1 + + .../plugins/ifcfg-rh/nms-ifcfg-rh-utils.h | 2 +- + .../plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 30 ++++++++----------- + .../plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 19 ++---------- + src/libnm-core-impl/nm-setting-infiniband.c | 24 +++++++-------- + src/libnmc-setting/settings-docs.h.in | 2 +- + .../generate-docs-nm-settings-nmcli.xml.in | 2 +- + 8 files changed, 42 insertions(+), 66 deletions(-) + +diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +index 533379c67868..ad14209a3c94 100644 +--- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c ++++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +@@ -5358,6 +5358,7 @@ parse_infiniband_p_key(shvarFile *ifcfg, int *out_p_key, char **out_parent, GErr + gs_free char *physdev = NULL; + gs_free char *pkey_id = NULL; + int id; ++ int fixup_id = 0; + + physdev = svGetValueStr_cp(ifcfg, "PHYSDEV"); + if (!physdev) { +@@ -5368,7 +5369,14 @@ parse_infiniband_p_key(shvarFile *ifcfg, int *out_p_key, char **out_parent, GErr + return FALSE; + } + +- pkey_id = svGetValueStr_cp(ifcfg, "PKEY_ID"); ++ pkey_id = svGetValueStr_cp(ifcfg, "PKEY_ID_NM"); ++ if (!pkey_id) { ++ /* Only check for "$PKEY_ID". That key is interpreted as having the ++ * full membership flag set ("fixup_id"). */ ++ fixup_id = 0x8000; ++ pkey_id = svGetValueStr_cp(ifcfg, "PKEY_ID"); ++ } ++ + if (!pkey_id) { + g_set_error(error, + NM_SETTINGS_ERROR, +@@ -5387,23 +5395,7 @@ parse_infiniband_p_key(shvarFile *ifcfg, int *out_p_key, char **out_parent, GErr + return FALSE; + } + +- /* The highest bit 0x8000 indicates full membership, which kernel always +- * automatically sets. +- * +- * NetworkManager supports p-keys without the high bit set. That affects +- * the interface name (nmp_utils_new_infiniband_name()) and is what +- * we write to "create_child"/"delete_child" sysctl. Kernel will honor +- * such p-keys for the interface name, but for other purposes it adds the +- * highest bit. That makes using p-keys without the highest bit odd. +- * +- * Historically, /etc/sysconfig/network-scripts/ifup-ib would always add "|=0x8000". +- * The reader does that too. +- * +- * Note that this means ifcfg cannot handle p-keys without the highest bit set, +- * and when trying to store that to ifcfg format, the profile will be mangled/modified +- * by the ifcg plugin (unlike keyfile backend, which preserves the original p-key value). +- */ +- id |= 0x8000; ++ id |= fixup_id; + + *out_p_key = id; + *out_parent = g_steal_pointer(&physdev); +diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c +index ef4276da7377..7fc33967acb0 100644 +--- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c ++++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c +@@ -1028,6 +1028,7 @@ const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = { + _KEY_TYPE("PHYSDEV", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("PKEY", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("PKEY_ID", NMS_IFCFG_KEY_TYPE_IS_PLAIN), ++ _KEY_TYPE("PKEY_ID_NM", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("PMF", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("PORTNAME", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("POWERSAVE", NMS_IFCFG_KEY_TYPE_IS_PLAIN), +diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h +index e3d3d8732103..7302625cc13b 100644 +--- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h ++++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h +@@ -33,7 +33,7 @@ typedef struct { + NMSIfcfgKeyTypeFlags key_flags; + } NMSIfcfgKeyTypeInfo; + +-extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[257]; ++extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[258]; + + const NMSIfcfgKeyTypeInfo *nms_ifcfg_well_known_key_find_info(const char *key, gssize *out_idx); + +diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +index 9610cd647114..b78bbe416655 100644 +--- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c ++++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +@@ -1054,28 +1054,24 @@ write_infiniband_setting(NMConnection *connection, + + p_key = nm_setting_infiniband_get_p_key(s_infiniband); + if (p_key != -1) { +- /* The reader normalizes KKEY_ID with |=0x8000. Also do that when +- * writing the profile so that what we write, is consistent with what +- * we would read. */ +- p_key |= 0x8000; +- + svSetValueStr(ifcfg, "PKEY", "yes"); +- svSetValueInt64(ifcfg, "PKEY_ID", p_key); + +- parent = nm_setting_infiniband_get_parent(s_infiniband); +- svSetValueStr(ifcfg, "PHYSDEV", parent); ++ svSetValueInt64(ifcfg, "PKEY_ID", p_key); + +- if (parent && nm_connection_get_interface_name(connection)) { +- /* The connection.interface-name depends on the p-key. Also, +- * nm_connection_normalize() will automatically adjust the +- * interface-name to match the p-key. ++ if (!NM_FLAGS_HAS(p_key, 0x8000)) { ++ /* initscripts' ifup-ib used to always interpret the PKEY_ID with ++ * the full membership flag (0x8000) set. For compatibility, we do ++ * interpret PKEY_ID as having that flag set. + * +- * As we patched the p-key above, also anticipate that change, and +- * don't write a DEVICE= to the file, which would we normalize +- * differently, when reading it back. */ +- *out_interface_name = +- nm_setting_infiniband_create_virtual_interface_name(parent, p_key); ++ * However, now we want to persist a p-key which doesn't have the ++ * flag. Use a NetworkManager specific variable for that. This configuration ++ * is not supported by initscripts' ifup-ib. ++ */ ++ svSetValueInt64(ifcfg, "PKEY_ID_NM", p_key); + } ++ ++ parent = nm_setting_infiniband_get_parent(s_infiniband); ++ svSetValueStr(ifcfg, "PHYSDEV", parent); + } + + svSetValueStr(ifcfg, "TYPE", TYPE_INFINIBAND); +diff --git a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +index b391aa2392a8..b5f830c8660a 100644 +--- a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c ++++ b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +@@ -8419,7 +8419,6 @@ test_write_infiniband(gconstpointer test_data) + const int TEST_IDX = GPOINTER_TO_INT(test_data); + nmtst_auto_unlinkfile char *testfile = NULL; + gs_unref_object NMConnection *connection = NULL; +- gs_unref_object NMConnection *expected = NULL; + gs_unref_object NMConnection *reread = NULL; + gboolean reread_same = FALSE; + NMSettingConnection *s_con; +@@ -8500,32 +8499,20 @@ test_write_infiniband(gconstpointer test_data) + + nmtst_assert_connection_verifies(connection); + +- if (p_key != -1 && p_key < 0x8000) { +- expected = nm_simple_connection_new_clone(connection); +- g_object_set(nm_connection_get_setting(expected, NM_TYPE_SETTING_INFINIBAND), +- NM_SETTING_INFINIBAND_P_KEY, +- (int) (p_key | 0x8000), +- NULL); +- } else +- expected = g_object_ref(connection); +- + _writer_new_connection_reread(connection, + TEST_SCRATCH_DIR, + &testfile, + NO_EXPECTED, + &reread, + &reread_same); +- _assert_reread_same(expected, reread); +- if (p_key == -1 || p_key > 0x8000) +- g_assert(reread_same); +- else +- g_assert(!reread_same); ++ _assert_reread_same(connection, reread); ++ g_assert(reread_same); + + g_assert_cmpstr(interface_name, ==, nm_connection_get_interface_name(reread)); + g_assert_cmpint(nm_setting_infiniband_get_p_key( + _nm_connection_get_setting(reread, NM_TYPE_SETTING_INFINIBAND)), + ==, +- p_key == -1 ? -1 : (p_key | 0x8000)); ++ p_key); + } + + static void +diff --git a/src/libnm-core-impl/nm-setting-infiniband.c b/src/libnm-core-impl/nm-setting-infiniband.c +index 0753a8db2d81..6df92ceb4777 100644 +--- a/src/libnm-core-impl/nm-setting-infiniband.c ++++ b/src/libnm-core-impl/nm-setting-infiniband.c +@@ -461,31 +461,31 @@ nm_setting_infiniband_class_init(NMSettingInfinibandClass *klass) + /** + * NMSettingInfiniband:p-key: + * +- * The InfiniBand P_Key to use for this device. A value of -1 means to use +- * the default P_Key (aka "the P_Key at index 0"). Otherwise, it is a ++ * The InfiniBand p-key to use for this device. A value of -1 means to use ++ * the default p-key (aka "the p-key at index 0"). Otherwise, it is a + * 16-bit unsigned integer, whose high bit 0x8000 is set if it is a "full +- * membership" P_Key. The values 0 and 0x8000 are not allowed. ++ * membership" p-key. The values 0 and 0x8000 are not allowed. + * + * With the p-key set, the interface name is always "$parent.$p_key". + * Setting "connection.interface-name" to another name is not supported. + * + * Note that kernel will internally always set the full membership bit, +- * although the interface name does not reflect that. Thus, not setting +- * the high bit is probably not useful. +- * +- * If the profile is stored in ifcfg-rh format, then the full membership +- * bit is automatically added. To get consistent behavior, it is +- * best to only use p-key values with the full membership bit set. ++ * although the interface name does not reflect that. Usually the user ++ * would want to configure a full membership p-key with 0x8000 flag set. + **/ + /* ---ifcfg-rh--- + * property: p-key +- * variable: PKEY_ID (and PKEY=yes) ++ * variable: PKEY_ID or PKEY_ID_NM(*) (requires PKEY=yes) + * default: PKEY=no + * description: InfiniBand P_Key. The value can be a hex number prefixed with "0x" + * or a decimal number. +- * When PKEY_ID is specified, PHYSDEV and DEVICE also must be specified. ++ * When PKEY_ID is specified, PHYSDEV must be specified. + * Note that ifcfg-rh format will always automatically set the full membership +- * bit 0x8000. Other p-key cannot be stored. ++ * flag 0x8000 for the PKEY_ID variable. To express IDs without the full membership ++ * flag, use PKEY_ID_NM. Note that kernel internally treats the interface as ++ * having the full membership flag set, this mainly affects the interface name. ++ * For the ifcfg file to be supported by initscripts' ifup-ib, the DEVICE= ++ * must always be set. NetworkManager does not require that. + * example: PKEY=yes PKEY_ID=2 PHYSDEV=mlx4_ib0 DEVICE=mlx4_ib0.8002 + * ---end--- + */ +diff --git a/src/libnmc-setting/settings-docs.h.in b/src/libnmc-setting/settings-docs.h.in +index 172f9b15bb98..c3fa316cf65a 100644 +--- a/src/libnmc-setting/settings-docs.h.in ++++ b/src/libnmc-setting/settings-docs.h.in +@@ -153,7 +153,7 @@ + #define DESCRIBE_DOC_NM_SETTING_GSM_USERNAME N_("The username used to authenticate with the network, if required. Many providers do not require a username, or accept any username. But if a username is required, it is specified here.") + #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_MAC_ADDRESS N_("If specified, this connection will only apply to the IPoIB device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing).") + #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple frames.") +-#define DESCRIBE_DOC_NM_SETTING_INFINIBAND_P_KEY N_("The InfiniBand P_Key to use for this device. A value of -1 means to use the default P_Key (aka \"the P_Key at index 0\"). Otherwise, it is a 16-bit unsigned integer, whose high bit 0x8000 is set if it is a \"full membership\" P_Key. The values 0 and 0x8000 are not allowed. With the p-key set, the interface name is always \"$parent.$p_key\". Setting \"connection.interface-name\" to another name is not supported. Note that kernel will internally always set the full membership bit, although the interface name does not reflect that. Thus, not setting the high bit is probably not useful. If the profile is stored in ifcfg-rh format, then the full membership bit is automatically added. To get consistent behavior, it is best to only use p-key values with the full membership bit set.") ++#define DESCRIBE_DOC_NM_SETTING_INFINIBAND_P_KEY N_("The InfiniBand p-key to use for this device. A value of -1 means to use the default p-key (aka \"the p-key at index 0\"). Otherwise, it is a 16-bit unsigned integer, whose high bit 0x8000 is set if it is a \"full membership\" p-key. The values 0 and 0x8000 are not allowed. With the p-key set, the interface name is always \"$parent.$p_key\". Setting \"connection.interface-name\" to another name is not supported. Note that kernel will internally always set the full membership bit, although the interface name does not reflect that. Usually the user would want to configure a full membership p-key with 0x8000 flag set.") + #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_PARENT N_("The interface name of the parent device of this device. Normally NULL, but if the \"p_key\" property is set, then you must specify the base device by setting either this property or \"mac-address\".") + #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_TRANSPORT_MODE N_("The IP-over-InfiniBand transport mode. Either \"datagram\" or \"connected\".") + #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ADDRESSES N_("A list of IPv4 addresses and their prefix length. Multiple addresses can be separated by comma. For example \"192.168.1.5/24, 10.1.0.5/24\". The addresses are listed in decreasing priority, meaning the first address will be the primary address.") +diff --git a/src/nmcli/generate-docs-nm-settings-nmcli.xml.in b/src/nmcli/generate-docs-nm-settings-nmcli.xml.in +index a59dacf2430d..373d39a60b9d 100644 +--- a/src/nmcli/generate-docs-nm-settings-nmcli.xml.in ++++ b/src/nmcli/generate-docs-nm-settings-nmcli.xml.in +@@ -614,7 +614,7 @@ + description="The IP-over-InfiniBand transport mode. Either "datagram" or "connected"." /> + ++ description="The InfiniBand p-key to use for this device. A value of -1 means to use the default p-key (aka "the p-key at index 0"). Otherwise, it is a 16-bit unsigned integer, whose high bit 0x8000 is set if it is a "full membership" p-key. The values 0 and 0x8000 are not allowed. With the p-key set, the interface name is always "$parent.$p_key". Setting "connection.interface-name" to another name is not supported. Note that kernel will internally always set the full membership bit, although the interface name does not reflect that. Usually the user would want to configure a full membership p-key with 0x8000 flag set." /> + +-- +2.40.1 + diff --git a/SOURCES/1007-unblock-autoconnect-on-reapply-rh2207690.patch b/SOURCES/1007-unblock-autoconnect-on-reapply-rh2207690.patch new file mode 100644 index 0000000..9349998 --- /dev/null +++ b/SOURCES/1007-unblock-autoconnect-on-reapply-rh2207690.patch @@ -0,0 +1,47 @@ +From 04c0fffdc3a24b66fcfd2e55714bc1308c219c24 Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Tue, 27 Jun 2023 15:02:54 +0800 +Subject: [PATCH 1/1] setting-connection: Unblock autoconnect upon finish of + `Reapply` + +The activation of a connection will clear the block of autoconnect, +we should do the same for reapply. + +Signed-off-by: Gris Ge +(cherry picked from commit 0486efd3584c70179072f611e63b9c0ff6851b80) +(cherry picked from commit 18ce5f43bd16b3cc394424619652c782cb3795c3) +(cherry picked from commit 2695396939d2a867145f7db569aaf5cc6b0d742c) +--- + src/core/devices/nm-device.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c +index 31acc1c1fe6b..2ac55fa83cbe 100644 +--- a/src/core/devices/nm-device.c ++++ b/src/core/devices/nm-device.c +@@ -12826,6 +12826,7 @@ check_and_reapply_connection(NMDevice *self, + NMConnection *con_old; + NMConnection *con_new; + GHashTableIter iter; ++ NMSettingsConnection *sett_conn; + + if (priv->state < NM_DEVICE_STATE_PREPARE || priv->state > NM_DEVICE_STATE_ACTIVATED) { + g_set_error_literal(error, +@@ -12998,6 +12999,14 @@ check_and_reapply_connection(NMDevice *self, + if (priv->state >= NM_DEVICE_STATE_ACTIVATED) + nm_device_update_metered(self); + ++ sett_conn = nm_device_get_settings_connection(self); ++ if (sett_conn) { ++ nm_settings_connection_autoconnect_blocked_reason_set( ++ sett_conn, ++ NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST, ++ FALSE); ++ } ++ + return TRUE; + } + +-- +2.40.1 + diff --git a/SOURCES/1008-cloud-setup-fix-terminating-in-reconfig-rh2221903.patch b/SOURCES/1008-cloud-setup-fix-terminating-in-reconfig-rh2221903.patch new file mode 100644 index 0000000..a9f7b86 --- /dev/null +++ b/SOURCES/1008-cloud-setup-fix-terminating-in-reconfig-rh2221903.patch @@ -0,0 +1,190 @@ +From 1e74f06a69d0f01753d6f2f071202a41b92239bc Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Wed, 31 May 2023 13:06:22 +0200 +Subject: [PATCH 1/2] cloud-setup: fix terminating in the middle of + reconfiguring the system + +Once we start reconfiguring the system, we need to finish on all +interfaces. Otherwise, we might reconfigure some interfaces, abort +and leave the network broken. When that happens, a subsequent run +might also be unable to recover, because we are unable to reach the +HTTP meta data service. + +https://bugzilla.redhat.com/show_bug.cgi?id=2207812 + +Fixes: 69f048bf0ca3 ('cloud-setup: add tool for automatic IP configuration in cloud') +(cherry picked from commit dab114f038f39e07080f71426d70e84449890088) +(cherry picked from commit 0a033798ac646c80669ab5d8a15362583f4d8ba4) +(cherry picked from commit fe243025e5751dda2e5a3694953f92c87372e008) +--- + src/nm-cloud-setup/main.c | 49 ++++++++++++++++++++++++++------------- + 1 file changed, 33 insertions(+), 16 deletions(-) + +diff --git a/src/nm-cloud-setup/main.c b/src/nm-cloud-setup/main.c +index e1cbd1d4d8..01e41bd72e 100644 +--- a/src/nm-cloud-setup/main.c ++++ b/src/nm-cloud-setup/main.c +@@ -15,6 +15,12 @@ + + /*****************************************************************************/ + ++typedef struct { ++ GCancellable *cancellable; ++ gboolean enabled; ++ gboolean signal_received; ++} SigTermData; ++ + typedef struct { + GMainLoop *main_loop; + GCancellable *cancellable; +@@ -444,7 +450,7 @@ _nmc_mangle_connection(NMDevice *device, + /*****************************************************************************/ + + static gboolean +-_config_one(GCancellable *sigterm_cancellable, ++_config_one(SigTermData *sigterm_data, + NMClient *nmc, + const NMCSProviderGetConfigResult *result, + guint idx) +@@ -464,7 +470,7 @@ _config_one(GCancellable *sigterm_cancellable, + + g_main_context_iteration(NULL, FALSE); + +- if (g_cancellable_is_cancelled(sigterm_cancellable)) ++ if (g_cancellable_is_cancelled(sigterm_data->cancellable)) + return FALSE; + + device = nm_g_object_ref(_nmc_get_device_by_hwaddr(nmc, hwaddr)); +@@ -498,7 +504,7 @@ try_again: + g_clear_error(&error); + + applied_connection = nmcs_device_get_applied_connection(device, +- sigterm_cancellable, ++ sigterm_data->cancellable, + &applied_version_id, + &error); + if (!applied_connection) { +@@ -560,8 +566,12 @@ try_again: + * during package upgrade. */ + maybe_no_preserved_external_ip = TRUE; + ++ /* Once we start reconfiguring the system, we cannot abort in the middle. From now on, ++ * any SIGTERM gets ignored until we are done. */ ++ sigterm_data->enabled = FALSE; ++ + if (!nmcs_device_reapply(device, +- sigterm_cancellable, ++ NULL, + applied_connection, + applied_version_id, + maybe_no_preserved_external_ip, +@@ -592,15 +602,13 @@ try_again: + } + + static gboolean +-_config_all(GCancellable *sigterm_cancellable, +- NMClient *nmc, +- const NMCSProviderGetConfigResult *result) ++_config_all(SigTermData *sigterm_data, NMClient *nmc, const NMCSProviderGetConfigResult *result) + { + gboolean any_changes = FALSE; + guint i; + + for (i = 0; i < result->n_iface_datas; i++) { +- if (_config_one(sigterm_cancellable, nmc, result, i)) ++ if (_config_one(sigterm_data, nmc, result, i)) + any_changes = TRUE; + } + +@@ -612,13 +620,16 @@ _config_all(GCancellable *sigterm_cancellable, + static gboolean + sigterm_handler(gpointer user_data) + { +- GCancellable *sigterm_cancellable = user_data; ++ SigTermData *sigterm_data = user_data; + +- if (!g_cancellable_is_cancelled(sigterm_cancellable)) { +- _LOGD("SIGTERM received"); +- g_cancellable_cancel(user_data); +- } else +- _LOGD("SIGTERM received (again)"); ++ _LOGD("SIGTERM received (%s) (%s)", ++ sigterm_data->signal_received ? "first time" : "again", ++ sigterm_data->enabled ? "cancel operation" : "ignore"); ++ ++ sigterm_data->signal_received = TRUE; ++ ++ if (sigterm_data->enabled) ++ g_cancellable_cancel(sigterm_data->cancellable); + return G_SOURCE_CONTINUE; + } + +@@ -633,6 +644,7 @@ main(int argc, const char *const *argv) + gs_unref_object NMClient *nmc = NULL; + nm_auto_free_nmcs_provider_get_config_result NMCSProviderGetConfigResult *result = NULL; + gs_free_error GError *error = NULL; ++ SigTermData sigterm_data; + + _nm_logging_enabled_init(g_getenv(NMCS_ENV_VARIABLE("NM_CLOUD_SETUP_LOG"))); + +@@ -645,7 +657,12 @@ main(int argc, const char *const *argv) + + sigterm_cancellable = g_cancellable_new(); + +- sigterm_source = nm_g_unix_signal_add_source(SIGTERM, sigterm_handler, sigterm_cancellable); ++ sigterm_data = (SigTermData){ ++ .cancellable = sigterm_cancellable, ++ .enabled = TRUE, ++ .signal_received = FALSE, ++ }; ++ sigterm_source = nm_g_unix_signal_add_source(SIGTERM, sigterm_handler, &sigterm_data); + + provider = _provider_detect(sigterm_cancellable); + if (!provider) +@@ -676,7 +693,7 @@ main(int argc, const char *const *argv) + if (!result) + goto done; + +- if (_config_all(sigterm_cancellable, nmc, result)) ++ if (_config_all(&sigterm_data, nmc, result)) + _LOGI("some changes were applied for provider %s", nmcs_provider_get_name(provider)); + else + _LOGD("no changes were applied for provider %s", nmcs_provider_get_name(provider)); +-- +2.40.1 + +From 1d148ee9592e1292a62f1d932c85d4ca94e9d642 Mon Sep 17 00:00:00 2001 +From: Thomas Haller +Date: Mon, 5 Jun 2023 13:04:53 +0200 +Subject: [PATCH 2/2] cloud-setup: clear error variable in + nmcs_device_reapply() + +This is rather bad, because if we reach the "goto again" case, +the error variable is not cleared. Subsequently passing the +error location to nm_device_reapply_finish() will trigger a glib +warning. + +Fixes: 29b0420be72f ('nm-cloud-setup: set preserve-external-ip flag during reapply') +(cherry picked from commit c70a5470be034c660b426ebdbef9e8e67609ece7) +(cherry picked from commit 98be3dd5acafa88e7477dcbb9d6420cb2e73ec01) +(cherry picked from commit 5cc38d1c6b1d76b1fa93cba021cf6a5472f12fa4) +--- + src/nm-cloud-setup/nm-cloud-setup-utils.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/nm-cloud-setup/nm-cloud-setup-utils.c b/src/nm-cloud-setup/nm-cloud-setup-utils.c +index 7cf7959241..1410ecf7c1 100644 +--- a/src/nm-cloud-setup/nm-cloud-setup-utils.c ++++ b/src/nm-cloud-setup/nm-cloud-setup-utils.c +@@ -833,6 +833,8 @@ nmcs_device_reapply(NMDevice *device, + NMDeviceReapplyFlags reapply_flags = NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP; + + again: ++ g_clear_error(&data.error); ++ + nm_device_reapply_async(device, + connection, + version_id, +-- +2.40.1 + diff --git a/SPECS/NetworkManager.spec b/SPECS/NetworkManager.spec index de56a7d..da9be6f 100644 --- a/SPECS/NetworkManager.spec +++ b/SPECS/NetworkManager.spec @@ -6,7 +6,7 @@ %global epoch_version 1 %global real_version 1.40.16 %global rpm_version %{real_version} -%global release_version 1 +%global release_version 9 %global snapshot %{nil} %global git_sha %{nil} %global bcond_default_debug 0 @@ -196,6 +196,14 @@ Patch3: 0003-order-ipv6-addresses.patch # Bugfixes that are only relevant until next rebase of the package. # Patch1001: 1001-some.patch +Patch1001: 1001-cloud-setup-IMDSv2-rh2151987.patch +Patch1002: 1002-dns-add-support-to-no-aaaa-option-rh2144521.patch +Patch1003: 1003-suppport-bond-port-prio-rh1920398.patch +Patch1004: 1004-team-don-t-try-to-connect-to-teamd-in-update_connect-rh2182029.patch +Patch1005: 1005-ipv6ll-don-t-regenerate-the-address-when-removed-rh2209353.patch +Patch1006: 1006-fix-read-infiniband-from-ifcfg-rh2209164.patch +Patch1007: 1007-unblock-autoconnect-on-reapply-rh2207690.patch +Patch1008: 1008-cloud-setup-fix-terminating-in-reconfig-rh2221903.patch Requires(post): systemd %if 0%{?fedora} || 0%{?rhel} >= 8 @@ -1231,6 +1239,31 @@ fi %changelog +* Wed Jul 19 2023 Beniamino Galvani - 1:1.40.16-9 +- cloud-setup: fix terminating in the middle of reconfiguration (rh #2221903) + +* Wed Jun 28 2023 Thomas Haller - 1:1.40.16-8 +- unblock autoconnect of profile on reapply (rh #2207690) + +* Mon Jun 5 2023 Thomas Haller - 1:1.40.16-7 +- fix reading infiniband p-key from ifcfg files (rh #2209164) + +* Wed May 24 2023 Beniamino Galvani - 1:1.40.16-6 +- don't fail when the IPv6 link-local address is removed (rh #2209353) + +* Wed May 17 2023 Fernando Fernandez Mancera - 1:1.40.16-5 +- support bond port prio property (rh #1920398) +- team: don't try to connect to teamd in update_connection() (rh #2182029) + +* Wed Apr 19 2023 Beniamino Galvani - 1:1.40.16-4 +- support the "no-aaaa" resolv.conf option (rh #2144521) + +* Mon Mar 13 2023 Lubomir Rintel - 1:1.40.16-3 +- cloud-setup/ec2: fix regression with IMDSv2 support (rh #2181466) + +* Mon Mar 13 2023 Lubomir Rintel - 1:1.40.16-2 +- cloud-setup/ec2: add IMDSv2 support (rh #2151986) + * Thu Feb 23 2023 Beniamino Galvani - 1:1.40.16-1 - Update to 1.40.16 release