NetworkManager/SOURCES/1003-cloud-setup-better-han...

1621 lines
73 KiB
Diff

From f79d5a903b769f45f084d81a732ec9b3dcc3f2a9 Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Wed, 1 Sep 2021 09:30:29 +0200
Subject: [PATCH 01/10] cloud-setup: return structure for get_config() result
instead of generic hash table
Returning a struct seems easier to understand, because then the result
is typed.
Also, we might return additional results, which are system wide and not
per-interface.
(cherry picked from commit 323e18276894591712a5e29f6e907562c79c5216)
(cherry picked from commit c94b1c43d4b5c5b88d67d7966d23a005028e78d8)
---
src/nm-cloud-setup/main.c | 54 ++++++++++++++++--------------
src/nm-cloud-setup/nmcs-provider.c | 28 ++++++++++++++--
src/nm-cloud-setup/nmcs-provider.h | 20 ++++++++++-
3 files changed, 72 insertions(+), 30 deletions(-)
diff --git a/src/nm-cloud-setup/main.c b/src/nm-cloud-setup/main.c
index 8dc67851794c..04b29f8a4b74 100644
--- a/src/nm-cloud-setup/main.c
+++ b/src/nm-cloud-setup/main.c
@@ -200,30 +200,30 @@ _nmc_get_device_by_hwaddr(NMClient *nmc, const char *hwaddr)
/*****************************************************************************/
typedef struct {
- GMainLoop * main_loop;
- GHashTable *config_dict;
+ GMainLoop * main_loop;
+ NMCSProviderGetConfigResult *result;
} GetConfigData;
static void
-_get_config_cb(GObject *source, GAsyncResult *result, gpointer user_data)
+_get_config_cb(GObject *source, GAsyncResult *res, gpointer user_data)
{
- GetConfigData * data = user_data;
- gs_unref_hashtable GHashTable *config_dict = NULL;
- gs_free_error GError *error = NULL;
+ GetConfigData * data = user_data;
+ nm_auto_free_nmcs_provider_get_config_result NMCSProviderGetConfigResult *result = NULL;
+ gs_free_error GError *error = NULL;
- config_dict = nmcs_provider_get_config_finish(NMCS_PROVIDER(source), result, &error);
+ result = nmcs_provider_get_config_finish(NMCS_PROVIDER(source), res, &error);
- if (!config_dict) {
+ if (!result) {
if (!nm_utils_error_is_cancelled(error))
_LOGI("failure to get meta data: %s", error->message);
} else
_LOGD("meta data received");
- data->config_dict = g_steal_pointer(&config_dict);
+ data->result = g_steal_pointer(&result);
g_main_loop_quit(data->main_loop);
}
-static GHashTable *
+static NMCSProviderGetConfigResult *
_get_config(GCancellable *sigterm_cancellable, NMCSProvider *provider, NMClient *nmc)
{
nm_auto_unref_gmainloop GMainLoop *main_loop = g_main_loop_new(NULL, FALSE);
@@ -243,7 +243,7 @@ _get_config(GCancellable *sigterm_cancellable, NMCSProvider *provider, NMClient
g_main_loop_run(main_loop);
- return data.config_dict;
+ return data.result;
}
/*****************************************************************************/
@@ -396,13 +396,13 @@ _nmc_mangle_connection(NMDevice * device,
/*****************************************************************************/
static guint
-_config_data_get_num_valid(GHashTable *config_dict)
+_config_data_get_num_valid(const NMCSProviderGetConfigResult *result)
{
const NMCSProviderGetConfigIfaceData *config_data;
GHashTableIter h_iter;
guint n = 0;
- g_hash_table_iter_init(&h_iter, config_dict);
+ g_hash_table_iter_init(&h_iter, result->iface_datas);
while (g_hash_table_iter_next(&h_iter, NULL, (gpointer *) &config_data)) {
if (nmcs_provider_get_config_iface_data_is_valid(config_data))
n++;
@@ -525,7 +525,9 @@ try_again:
}
static gboolean
-_config_all(GCancellable *sigterm_cancellable, NMClient *nmc, GHashTable *config_dict)
+_config_all(GCancellable * sigterm_cancellable,
+ NMClient * nmc,
+ const NMCSProviderGetConfigResult *result)
{
GHashTableIter h_iter;
const NMCSProviderGetConfigIfaceData *c_config_data;
@@ -533,9 +535,9 @@ _config_all(GCancellable *sigterm_cancellable, NMClient *nmc, GHashTable *config
gboolean is_single_nic;
gboolean any_changes = FALSE;
- is_single_nic = (_config_data_get_num_valid(config_dict) <= 1);
+ is_single_nic = (_config_data_get_num_valid(result) <= 1);
- g_hash_table_iter_init(&h_iter, config_dict);
+ g_hash_table_iter_init(&h_iter, result->iface_datas);
while (g_hash_table_iter_next(&h_iter, (gpointer *) &c_hwaddr, (gpointer *) &c_config_data)) {
if (_config_one(sigterm_cancellable, nmc, is_single_nic, c_hwaddr, c_config_data))
any_changes = TRUE;
@@ -564,12 +566,12 @@ sigterm_handler(gpointer user_data)
int
main(int argc, const char *const *argv)
{
- gs_unref_object GCancellable * sigterm_cancellable = NULL;
- nm_auto_destroy_and_unref_gsource GSource *sigterm_source = NULL;
- gs_unref_object NMCSProvider *provider = NULL;
- gs_unref_object NMClient *nmc = NULL;
- gs_unref_hashtable GHashTable *config_dict = NULL;
- gs_free_error GError *error = NULL;
+ gs_unref_object GCancellable * sigterm_cancellable = NULL;
+ nm_auto_destroy_and_unref_gsource GSource *sigterm_source = NULL;
+ gs_unref_object NMCSProvider *provider = NULL;
+ gs_unref_object NMClient * nmc = NULL;
+ nm_auto_free_nmcs_provider_get_config_result NMCSProviderGetConfigResult *result = NULL;
+ gs_free_error GError *error = NULL;
_nm_logging_enabled_init(g_getenv(NMCS_ENV_VARIABLE("NM_CLOUD_SETUP_LOG")));
@@ -614,17 +616,17 @@ main(int argc, const char *const *argv)
goto done;
}
- config_dict = _get_config(sigterm_cancellable, provider, nmc);
- if (!config_dict)
+ result = _get_config(sigterm_cancellable, provider, nmc);
+ if (!result)
goto done;
- if (_config_all(sigterm_cancellable, nmc, config_dict))
+ if (_config_all(sigterm_cancellable, 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));
done:
- nm_clear_pointer(&config_dict, g_hash_table_unref);
+ nm_clear_pointer(&result, nmcs_provider_get_config_result_free);
g_clear_object(&nmc);
g_clear_object(&provider);
diff --git a/src/nm-cloud-setup/nmcs-provider.c b/src/nm-cloud-setup/nmcs-provider.c
index 678152aa95e0..77f8090a8225 100644
--- a/src/nm-cloud-setup/nmcs-provider.c
+++ b/src/nm-cloud-setup/nmcs-provider.c
@@ -49,6 +49,28 @@ nmcs_provider_get_main_context(NMCSProvider *self)
return nm_http_client_get_main_context(NMCS_PROVIDER_GET_PRIVATE(self)->http_client);
}
+/*****************************************************************************/
+
+static NMCSProviderGetConfigResult *
+nmcs_provider_get_config_result_new(GHashTable *iface_datas)
+{
+ NMCSProviderGetConfigResult *result;
+
+ result = g_new(NMCSProviderGetConfigResult, 1);
+ *result = (NMCSProviderGetConfigResult){
+ .iface_datas = g_hash_table_ref(iface_datas),
+ };
+ return result;
+}
+
+void
+nmcs_provider_get_config_result_free(NMCSProviderGetConfigResult *result)
+{
+ if (result) {
+ nm_g_hash_table_unref(result->iface_datas);
+ g_free(result);
+ }
+}
/*****************************************************************************/
@@ -137,8 +159,8 @@ _get_config_task_maybe_return(NMCSProviderGetConfigTaskData *get_config_data, GE
} else {
_LOGD("get-config: success");
g_task_return_pointer(get_config_data->task,
- g_hash_table_ref(get_config_data->result_dict),
- (GDestroyNotify) g_hash_table_unref);
+ nmcs_provider_get_config_result_new(get_config_data->result_dict),
+ (GDestroyNotify) nmcs_provider_get_config_result_free);
}
nm_clear_g_signal_handler(g_task_get_cancellable(get_config_data->task),
@@ -217,7 +239,7 @@ nmcs_provider_get_config(NMCSProvider * self,
NMCS_PROVIDER_GET_CLASS(self)->get_config(self, get_config_data);
}
-GHashTable *
+NMCSProviderGetConfigResult *
nmcs_provider_get_config_finish(NMCSProvider *self, GAsyncResult *result, GError **error)
{
g_return_val_if_fail(NMCS_IS_PROVIDER(self), FALSE);
diff --git a/src/nm-cloud-setup/nmcs-provider.h b/src/nm-cloud-setup/nmcs-provider.h
index 13212b8e4cb4..730ddc9d8f09 100644
--- a/src/nm-cloud-setup/nmcs-provider.h
+++ b/src/nm-cloud-setup/nmcs-provider.h
@@ -43,6 +43,24 @@ nmcs_provider_get_config_iface_data_is_valid(const NMCSProviderGetConfigIfaceDat
NMCSProviderGetConfigIfaceData *nmcs_provider_get_config_iface_data_new(gboolean was_requested);
+/*****************************************************************************/
+
+typedef struct {
+ /* A dictionary of (const char *) -> (NMCSProviderGetConfigIfaceData *).
+ * This is the per-interface result of get_config(). */
+ GHashTable *iface_datas;
+} NMCSProviderGetConfigResult;
+
+void nmcs_provider_get_config_result_free(NMCSProviderGetConfigResult *result);
+
+NM_AUTO_DEFINE_FCN0(NMCSProviderGetConfigResult *,
+ _nm_auto_free_nmcs_provider_get_config_result,
+ nmcs_provider_get_config_result_free);
+#define nm_auto_free_nmcs_provider_get_config_result \
+ nm_auto(_nm_auto_free_nmcs_provider_get_config_result)
+
+/*****************************************************************************/
+
typedef struct {
GTask *task;
@@ -124,7 +142,7 @@ void nmcs_provider_get_config(NMCSProvider * provider,
GAsyncReadyCallback callback,
gpointer user_data);
-GHashTable *
+NMCSProviderGetConfigResult *
nmcs_provider_get_config_finish(NMCSProvider *provider, GAsyncResult *result, GError **error);
#endif /* __NMCS_PROVIDER_H__ */
--
2.31.1
From 165dd652446673c826ef0da33b865da359aa22ee Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Wed, 1 Sep 2021 09:42:37 +0200
Subject: [PATCH 02/10] cloud-setup: cache number of valid interfaces in
get-config result
Now that we return a struct from get_config(), we can have system-wide
properties returned.
Let it count and cache the number of valid iface_datas.
Currently that is not yet used, but it will be.
(cherry picked from commit a3cd66d3fadcecab9b186cc7f634f6ec6a5a92ee)
(cherry picked from commit e74375fc3b68b07d1ed5f6ebca40cbe5b20ed47b)
---
src/nm-cloud-setup/main.c | 22 +---------------------
src/nm-cloud-setup/nmcs-provider.c | 15 +++++++++++++--
src/nm-cloud-setup/nmcs-provider.h | 3 +++
3 files changed, 17 insertions(+), 23 deletions(-)
diff --git a/src/nm-cloud-setup/main.c b/src/nm-cloud-setup/main.c
index 04b29f8a4b74..686cd2fc0c84 100644
--- a/src/nm-cloud-setup/main.c
+++ b/src/nm-cloud-setup/main.c
@@ -395,26 +395,9 @@ _nmc_mangle_connection(NMDevice * device,
/*****************************************************************************/
-static guint
-_config_data_get_num_valid(const NMCSProviderGetConfigResult *result)
-{
- const NMCSProviderGetConfigIfaceData *config_data;
- GHashTableIter h_iter;
- guint n = 0;
-
- g_hash_table_iter_init(&h_iter, result->iface_datas);
- while (g_hash_table_iter_next(&h_iter, NULL, (gpointer *) &config_data)) {
- if (nmcs_provider_get_config_iface_data_is_valid(config_data))
- n++;
- }
-
- return n;
-}
-
static gboolean
_config_one(GCancellable * sigterm_cancellable,
NMClient * nmc,
- gboolean is_single_nic,
const char * hwaddr,
const NMCSProviderGetConfigIfaceData *config_data)
{
@@ -532,14 +515,11 @@ _config_all(GCancellable * sigterm_cancellable,
GHashTableIter h_iter;
const NMCSProviderGetConfigIfaceData *c_config_data;
const char * c_hwaddr;
- gboolean is_single_nic;
gboolean any_changes = FALSE;
- is_single_nic = (_config_data_get_num_valid(result) <= 1);
-
g_hash_table_iter_init(&h_iter, result->iface_datas);
while (g_hash_table_iter_next(&h_iter, (gpointer *) &c_hwaddr, (gpointer *) &c_config_data)) {
- if (_config_one(sigterm_cancellable, nmc, is_single_nic, c_hwaddr, c_config_data))
+ if (_config_one(sigterm_cancellable, nmc, c_hwaddr, c_config_data))
any_changes = TRUE;
}
diff --git a/src/nm-cloud-setup/nmcs-provider.c b/src/nm-cloud-setup/nmcs-provider.c
index 77f8090a8225..8f82ddb493ea 100644
--- a/src/nm-cloud-setup/nmcs-provider.c
+++ b/src/nm-cloud-setup/nmcs-provider.c
@@ -54,12 +54,23 @@ nmcs_provider_get_main_context(NMCSProvider *self)
static NMCSProviderGetConfigResult *
nmcs_provider_get_config_result_new(GHashTable *iface_datas)
{
- NMCSProviderGetConfigResult *result;
+ const NMCSProviderGetConfigIfaceData *iface_data;
+ NMCSProviderGetConfigResult * result;
+ GHashTableIter h_iter;
+ guint num_valid_ifaces = 0;
+
+ g_hash_table_iter_init(&h_iter, iface_datas);
+ while (g_hash_table_iter_next(&h_iter, NULL, (gpointer *) &iface_data)) {
+ if (nmcs_provider_get_config_iface_data_is_valid(iface_data))
+ num_valid_ifaces++;
+ }
result = g_new(NMCSProviderGetConfigResult, 1);
*result = (NMCSProviderGetConfigResult){
- .iface_datas = g_hash_table_ref(iface_datas),
+ .iface_datas = g_hash_table_ref(iface_datas),
+ .num_valid_ifaces = num_valid_ifaces,
};
+
return result;
}
diff --git a/src/nm-cloud-setup/nmcs-provider.h b/src/nm-cloud-setup/nmcs-provider.h
index 730ddc9d8f09..2e4c8d167a73 100644
--- a/src/nm-cloud-setup/nmcs-provider.h
+++ b/src/nm-cloud-setup/nmcs-provider.h
@@ -49,6 +49,9 @@ typedef struct {
/* A dictionary of (const char *) -> (NMCSProviderGetConfigIfaceData *).
* This is the per-interface result of get_config(). */
GHashTable *iface_datas;
+
+ /* The number of iface_datas that are nmcs_provider_get_config_iface_data_is_valid(). */
+ guint num_valid_ifaces;
} NMCSProviderGetConfigResult;
void nmcs_provider_get_config_result_free(NMCSProviderGetConfigResult *result);
--
2.31.1
From 2e6d23ef2496b7a26f6406fab1d274eee66467af Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Wed, 1 Sep 2021 10:11:31 +0200
Subject: [PATCH 03/10] cloud-setup: count numbers of valid IPv4 addresses in
get-config result
Will be used next.
(cherry picked from commit 7969ae1a82b90c3a9dbe33875d138c7b55cf6ac8)
(cherry picked from commit ae504433f11480fde2436d3a5acba026db6c47bd)
---
src/nm-cloud-setup/nmcs-provider.c | 6 +++++-
src/nm-cloud-setup/nmcs-provider.h | 3 +++
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/nm-cloud-setup/nmcs-provider.c b/src/nm-cloud-setup/nmcs-provider.c
index 8f82ddb493ea..8901100378d0 100644
--- a/src/nm-cloud-setup/nmcs-provider.c
+++ b/src/nm-cloud-setup/nmcs-provider.c
@@ -58,17 +58,21 @@ nmcs_provider_get_config_result_new(GHashTable *iface_datas)
NMCSProviderGetConfigResult * result;
GHashTableIter h_iter;
guint num_valid_ifaces = 0;
+ guint num_ipv4s = 0;
g_hash_table_iter_init(&h_iter, iface_datas);
while (g_hash_table_iter_next(&h_iter, NULL, (gpointer *) &iface_data)) {
- if (nmcs_provider_get_config_iface_data_is_valid(iface_data))
+ if (nmcs_provider_get_config_iface_data_is_valid(iface_data)) {
num_valid_ifaces++;
+ num_ipv4s += iface_data->ipv4s_len;
+ }
}
result = g_new(NMCSProviderGetConfigResult, 1);
*result = (NMCSProviderGetConfigResult){
.iface_datas = g_hash_table_ref(iface_datas),
.num_valid_ifaces = num_valid_ifaces,
+ .num_ipv4s = num_ipv4s,
};
return result;
diff --git a/src/nm-cloud-setup/nmcs-provider.h b/src/nm-cloud-setup/nmcs-provider.h
index 2e4c8d167a73..31fec4449f9e 100644
--- a/src/nm-cloud-setup/nmcs-provider.h
+++ b/src/nm-cloud-setup/nmcs-provider.h
@@ -52,6 +52,9 @@ typedef struct {
/* The number of iface_datas that are nmcs_provider_get_config_iface_data_is_valid(). */
guint num_valid_ifaces;
+
+ /* the number of IPv4 addresses over all valid iface_datas. */
+ guint num_ipv4s;
} NMCSProviderGetConfigResult;
void nmcs_provider_get_config_result_free(NMCSProviderGetConfigResult *result);
--
2.31.1
From d80ef34f9390eb2baecb863cbbeded3dbffa1d8e Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Wed, 1 Sep 2021 10:15:37 +0200
Subject: [PATCH 04/10] cloud-setup: skip configuring policy routing if there
is only one interface/address
nm-cloud-setup automatically configures the network. That may conflict
with what the user wants. In case the user configures some specific
setup, they are encouraged to disable nm-cloud-setup (and its
automatism).
Still, what we do by default matters, and should play as well with
user's expectations. Configuring policy routing and a higher priority
table (30400+) that hijacks the traffic can cause problems.
If the system only has one IPv4 address and one interface, then there
is no point in configuring policy routing at all. Detect that, and skip
the change in that case.
Note that of course we need to handle the case where previously multiple
IP addresses were configured and an update gives only one address. In
that case we need to clear the previously configured rules/routes. The
patch achieves this.
(cherry picked from commit 5f047968d7a48999d20001f83e2005caa43c80ce)
(cherry picked from commit 8bc8a0f56b97c28cf26fd678a549db41399adcb7)
---
src/nm-cloud-setup/main.c | 41 +++++++++++++++++++++++++++++++--------
1 file changed, 33 insertions(+), 8 deletions(-)
diff --git a/src/nm-cloud-setup/main.c b/src/nm-cloud-setup/main.c
index 686cd2fc0c84..bb5c0d5ded9d 100644
--- a/src/nm-cloud-setup/main.c
+++ b/src/nm-cloud-setup/main.c
@@ -269,7 +269,9 @@ _nmc_skip_connection(NMConnection *connection)
static gboolean
_nmc_mangle_connection(NMDevice * device,
NMConnection * connection,
+ const NMCSProviderGetConfigResult * result,
const NMCSProviderGetConfigIfaceData *config_data,
+ gboolean * out_skipped_single_addr,
gboolean * out_changed)
{
NMSettingIPConfig * s_ip;
@@ -288,6 +290,9 @@ _nmc_mangle_connection(NMDevice * device,
gs_unref_ptrarray GPtrArray *rules_new = NULL;
gs_unref_ptrarray GPtrArray *routes_new = NULL;
+ NM_SET_OUT(out_skipped_single_addr, FALSE);
+ NM_SET_OUT(out_changed, FALSE);
+
if (!nm_streq0(nm_connection_get_connection_type(connection), NM_SETTING_WIRED_SETTING_NAME))
return FALSE;
@@ -329,7 +334,11 @@ _nmc_mangle_connection(NMDevice * device,
}
}
- if (config_data->has_ipv4s && config_data->has_cidr) {
+ if (result->num_valid_ifaces <= 1 && result->num_ipv4s <= 1) {
+ /* this setup only has one interface and one IPv4 address (or less).
+ * We don't need to configure policy routing in this case. */
+ NM_SET_OUT(out_skipped_single_addr, TRUE);
+ } else if (config_data->has_ipv4s && config_data->has_cidr) {
for (i = 0; i < config_data->ipv4s_len; i++) {
NMIPAddress *entry;
@@ -398,6 +407,7 @@ _nmc_mangle_connection(NMDevice * device,
static gboolean
_config_one(GCancellable * sigterm_cancellable,
NMClient * nmc,
+ const NMCSProviderGetConfigResult * result,
const char * hwaddr,
const NMCSProviderGetConfigIfaceData *config_data)
{
@@ -406,6 +416,7 @@ _config_one(GCancellable * sigterm_cancellable,
guint64 applied_version_id;
gs_free_error GError *error = NULL;
gboolean changed;
+ gboolean skipped_single_addr;
gboolean version_id_changed;
guint try_count;
gboolean any_changes = FALSE;
@@ -454,16 +465,30 @@ try_again:
return any_changes;
}
- if (!_nmc_mangle_connection(device, applied_connection, config_data, &changed)) {
+ if (!_nmc_mangle_connection(device,
+ applied_connection,
+ result,
+ config_data,
+ &skipped_single_addr,
+ &changed)) {
_LOGD("config device %s: device has no suitable applied connection. Skip", hwaddr);
return any_changes;
}
if (!changed) {
- _LOGD("config device %s: device needs no update to applied connection \"%s\" (%s). Skip",
- hwaddr,
- nm_connection_get_id(applied_connection),
- nm_connection_get_uuid(applied_connection));
+ if (skipped_single_addr) {
+ _LOGD("config device %s: device needs no update to applied connection \"%s\" (%s) "
+ "because there are not multiple IP addresses. Skip",
+ hwaddr,
+ nm_connection_get_id(applied_connection),
+ nm_connection_get_uuid(applied_connection));
+ } else {
+ _LOGD(
+ "config device %s: device needs no update to applied connection \"%s\" (%s). Skip",
+ hwaddr,
+ nm_connection_get_id(applied_connection),
+ nm_connection_get_uuid(applied_connection));
+ }
return any_changes;
}
@@ -472,7 +497,7 @@ try_again:
nm_connection_get_id(applied_connection),
nm_connection_get_uuid(applied_connection));
- /* we are about to call Reapply(). If if that fails, it counts as if we changed something. */
+ /* we are about to call Reapply(). Even if that fails, it counts as if we changed something. */
any_changes = TRUE;
if (!nmcs_device_reapply(device,
@@ -519,7 +544,7 @@ _config_all(GCancellable * sigterm_cancellable,
g_hash_table_iter_init(&h_iter, result->iface_datas);
while (g_hash_table_iter_next(&h_iter, (gpointer *) &c_hwaddr, (gpointer *) &c_config_data)) {
- if (_config_one(sigterm_cancellable, nmc, c_hwaddr, c_config_data))
+ if (_config_one(sigterm_cancellable, nmc, result, c_hwaddr, c_config_data))
any_changes = TRUE;
}
--
2.31.1
From 0042bff5e16e71f548dcb8d046a5dbd3f694de8f Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Wed, 1 Sep 2021 14:34:51 +0200
Subject: [PATCH 05/10] cloud-setup: add "hwaddr" to
NMCSProviderGetConfigIfaceData struct
get-config() gives a NMCSProviderGetConfigResult structure, and the
main part of data is the GHashTable of MAC addresses and
NMCSProviderGetConfigIfaceData instances.
Let NMCSProviderGetConfigIfaceData also have a reference to the MAC
address. This way, I'll be able to create a (sorted) list of interface
datas, that also contain the MAC address.
(cherry picked from commit ec56fe60fbf31768d0d1cae8bb325c1fdf7dbf07)
(cherry picked from commit cc289e53699872a3617aef321453ef6a885d0148)
---
src/nm-cloud-setup/nmcs-provider-aliyun.c | 32 ++++++++++-------------
src/nm-cloud-setup/nmcs-provider-azure.c | 21 +++++++--------
src/nm-cloud-setup/nmcs-provider-ec2.c | 27 ++++++++-----------
src/nm-cloud-setup/nmcs-provider-gcp.c | 20 +++++++-------
src/nm-cloud-setup/nmcs-provider.c | 22 +++++++++++-----
src/nm-cloud-setup/nmcs-provider.h | 12 +++++++--
6 files changed, 68 insertions(+), 66 deletions(-)
diff --git a/src/nm-cloud-setup/nmcs-provider-aliyun.c b/src/nm-cloud-setup/nmcs-provider-aliyun.c
index 01a4af0ff5b8..126980fdfe44 100644
--- a/src/nm-cloud-setup/nmcs-provider-aliyun.c
+++ b/src/nm-cloud-setup/nmcs-provider-aliyun.c
@@ -134,7 +134,6 @@ _get_config_fetch_done_cb(NMHttpClient * http_client,
GetConfigFetchDoneType fetch_type)
{
NMCSProviderGetConfigTaskData *get_config_data;
- const char * hwaddr = NULL;
gs_unref_bytes GBytes *response = NULL;
gs_free_error GError * error = NULL;
NMCSProviderGetConfigIfaceData *config_iface_data;
@@ -146,7 +145,7 @@ _get_config_fetch_done_cb(NMHttpClient * http_client,
gsize i;
gsize len;
- nm_utils_user_data_unpack(user_data, &get_config_data, &hwaddr);
+ nm_utils_user_data_unpack(user_data, &get_config_data, &config_iface_data);
nm_http_client_poll_get_finish(http_client, result, NULL, &response, &error);
@@ -156,8 +155,6 @@ _get_config_fetch_done_cb(NMHttpClient * http_client,
if (error)
goto out;
- config_iface_data = g_hash_table_lookup(get_config_data->result_dict, hwaddr);
-
switch (fetch_type) {
case GET_CONFIG_FETCH_DONE_TYPE_PRIVATE_IPV4S:
@@ -300,22 +297,21 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
gs_free char * uri2 = NULL;
gs_free char * uri3 = NULL;
gs_free char * uri4 = NULL;
- const char * hwaddr;
- if (!g_hash_table_lookup_extended(get_config_data->result_dict,
- v_hwaddr,
- (gpointer *) &hwaddr,
- (gpointer *) &config_iface_data)) {
+ config_iface_data = g_hash_table_lookup(get_config_data->result_dict, v_hwaddr);
+
+ if (!config_iface_data) {
if (!get_config_data->any) {
_LOGD("get-config: skip fetching meta data for %s (%s)",
v_hwaddr,
v_mac_data->path);
continue;
}
- config_iface_data = nmcs_provider_get_config_iface_data_new(FALSE);
- g_hash_table_insert(get_config_data->result_dict,
- (char *) (hwaddr = g_strdup(v_hwaddr)),
- config_iface_data);
+
+ config_iface_data =
+ nmcs_provider_get_config_iface_data_create(get_config_data->result_dict,
+ FALSE,
+ v_hwaddr);
}
nm_assert(config_iface_data->iface_idx == -1);
@@ -324,7 +320,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
_LOGD("get-config: start fetching meta data for #%" G_GSSIZE_FORMAT ", %s (%s)",
config_iface_data->iface_idx,
- hwaddr,
+ config_iface_data->hwaddr,
v_mac_data->path);
get_config_data->n_pending++;
@@ -342,7 +338,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
NULL,
NULL,
_get_config_fetch_done_cb_vpc_cidr_block,
- nm_utils_user_data_pack(get_config_data, hwaddr));
+ nm_utils_user_data_pack(get_config_data, config_iface_data));
get_config_data->n_pending++;
nm_http_client_poll_get(
@@ -359,7 +355,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
NULL,
NULL,
_get_config_fetch_done_cb_private_ipv4s,
- nm_utils_user_data_pack(get_config_data, hwaddr));
+ nm_utils_user_data_pack(get_config_data, config_iface_data));
get_config_data->n_pending++;
nm_http_client_poll_get(
@@ -376,7 +372,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
NULL,
NULL,
_get_config_fetch_done_cb_netmask,
- nm_utils_user_data_pack(get_config_data, hwaddr));
+ nm_utils_user_data_pack(get_config_data, config_iface_data));
get_config_data->n_pending++;
nm_http_client_poll_get(
@@ -393,7 +389,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
NULL,
NULL,
_get_config_fetch_done_cb_gateway,
- nm_utils_user_data_pack(get_config_data, hwaddr));
+ nm_utils_user_data_pack(get_config_data, config_iface_data));
}
_nmcs_provider_get_config_task_maybe_return(get_config_data, NULL);
diff --git a/src/nm-cloud-setup/nmcs-provider-azure.c b/src/nm-cloud-setup/nmcs-provider-azure.c
index 69785d64a8ac..b3f0c68ba666 100644
--- a/src/nm-cloud-setup/nmcs-provider-azure.c
+++ b/src/nm-cloud-setup/nmcs-provider-azure.c
@@ -97,7 +97,6 @@ typedef struct {
gssize intern_iface_idx;
gssize extern_iface_idx;
guint n_iface_data_pending;
- const char * hwaddr;
} AzureIfaceData;
static void
@@ -378,25 +377,24 @@ _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data)
goto out_done;
}
- if (!g_hash_table_lookup_extended(get_config_data->result_dict,
- v_hwaddr,
- (gpointer *) &iface_data->hwaddr,
- (gpointer *) &iface_data->iface_get_config)) {
+ iface_data->iface_get_config = g_hash_table_lookup(get_config_data->result_dict, v_hwaddr);
+
+ if (!iface_data->iface_get_config) {
if (!get_config_data->any) {
_LOGD("get-config: skip fetching meta data for %s (%" G_GSSIZE_FORMAT ")",
v_hwaddr,
iface_data->intern_iface_idx);
goto out_done;
}
- iface_data->iface_get_config = nmcs_provider_get_config_iface_data_new(FALSE);
- g_hash_table_insert(get_config_data->result_dict,
- (char *) (iface_data->hwaddr = g_steal_pointer(&v_hwaddr)),
- iface_data->iface_get_config);
+ iface_data->iface_get_config =
+ nmcs_provider_get_config_iface_data_create(get_config_data->result_dict,
+ FALSE,
+ v_hwaddr);
} else {
if (iface_data->iface_get_config->iface_idx >= 0) {
_LOGI("interface[%" G_GSSIZE_FORMAT "]: duplicate MAC address %s returned",
iface_data->intern_iface_idx,
- iface_data->hwaddr);
+ iface_data->iface_get_config->hwaddr);
error = nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN,
"duplicate MAC address for index %" G_GSSIZE_FORMAT,
iface_data->intern_iface_idx);
@@ -408,7 +406,7 @@ _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data)
_LOGD("interface[%" G_GSSIZE_FORMAT "]: found a matching device with hwaddr %s",
iface_data->intern_iface_idx,
- iface_data->hwaddr);
+ iface_data->iface_get_config->hwaddr);
nm_sprintf_buf(buf, "%" G_GSSIZE_FORMAT "/ipv4/ipAddress/", iface_data->intern_iface_idx);
@@ -488,7 +486,6 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat
.intern_iface_idx = intern_iface_idx,
.extern_iface_idx = extern_iface_idx_cnt++,
.n_iface_data_pending = 0,
- .hwaddr = NULL,
};
g_ptr_array_add(ifaces_arr, iface_data);
}
diff --git a/src/nm-cloud-setup/nmcs-provider-ec2.c b/src/nm-cloud-setup/nmcs-provider-ec2.c
index 6f83238d6871..9fe625182c35 100644
--- a/src/nm-cloud-setup/nmcs-provider-ec2.c
+++ b/src/nm-cloud-setup/nmcs-provider-ec2.c
@@ -122,14 +122,13 @@ _get_config_fetch_done_cb(NMHttpClient *http_client,
gboolean is_local_ipv4)
{
NMCSProviderGetConfigTaskData *get_config_data;
- const char * hwaddr = NULL;
gs_unref_bytes GBytes *response = NULL;
gs_free_error GError * error = NULL;
NMCSProviderGetConfigIfaceData *config_iface_data;
in_addr_t tmp_addr;
int tmp_prefix;
- nm_utils_user_data_unpack(user_data, &get_config_data, &hwaddr);
+ nm_utils_user_data_unpack(user_data, &get_config_data, &config_iface_data);
nm_http_client_poll_get_finish(http_client, result, NULL, &response, &error);
@@ -139,8 +138,6 @@ _get_config_fetch_done_cb(NMHttpClient *http_client,
if (error)
goto out;
- config_iface_data = g_hash_table_lookup(get_config_data->result_dict, hwaddr);
-
if (is_local_ipv4) {
gs_free const char **s_addrs = NULL;
gsize i, len;
@@ -236,22 +233,20 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
NMCSProviderGetConfigIfaceData *config_iface_data;
gs_free char * uri1 = NULL;
gs_free char * uri2 = NULL;
- const char * hwaddr;
- if (!g_hash_table_lookup_extended(get_config_data->result_dict,
- v_hwaddr,
- (gpointer *) &hwaddr,
- (gpointer *) &config_iface_data)) {
+ config_iface_data = g_hash_table_lookup(get_config_data->result_dict, v_hwaddr);
+
+ if (!config_iface_data) {
if (!get_config_data->any) {
_LOGD("get-config: skip fetching meta data for %s (%s)",
v_hwaddr,
v_mac_data->path);
continue;
}
- config_iface_data = nmcs_provider_get_config_iface_data_new(FALSE);
- g_hash_table_insert(get_config_data->result_dict,
- (char *) (hwaddr = g_strdup(v_hwaddr)),
- config_iface_data);
+ config_iface_data =
+ nmcs_provider_get_config_iface_data_create(get_config_data->result_dict,
+ FALSE,
+ v_hwaddr);
}
nm_assert(config_iface_data->iface_idx == -1);
@@ -260,7 +255,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
_LOGD("get-config: start fetching meta data for #%" G_GSSIZE_FORMAT ", %s (%s)",
config_iface_data->iface_idx,
- hwaddr,
+ config_iface_data->hwaddr,
v_mac_data->path);
get_config_data->n_pending++;
@@ -278,7 +273,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
NULL,
NULL,
_get_config_fetch_done_cb_subnet_ipv4_cidr_block,
- nm_utils_user_data_pack(get_config_data, hwaddr));
+ nm_utils_user_data_pack(get_config_data, config_iface_data));
get_config_data->n_pending++;
nm_http_client_poll_get(
@@ -295,7 +290,7 @@ _get_config_metadata_ready_cb(GObject *source, GAsyncResult *result, gpointer us
NULL,
NULL,
_get_config_fetch_done_cb_local_ipv4s,
- nm_utils_user_data_pack(get_config_data, hwaddr));
+ nm_utils_user_data_pack(get_config_data, config_iface_data));
}
_nmcs_provider_get_config_task_maybe_return(get_config_data, NULL);
diff --git a/src/nm-cloud-setup/nmcs-provider-gcp.c b/src/nm-cloud-setup/nmcs-provider-gcp.c
index eacfd5e24805..60425ad97868 100644
--- a/src/nm-cloud-setup/nmcs-provider-gcp.c
+++ b/src/nm-cloud-setup/nmcs-provider-gcp.c
@@ -247,7 +247,6 @@ _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data)
GCPIfaceData * iface_data = user_data;
gs_free_error GError * error = NULL;
gs_free char * v_hwaddr = NULL;
- const char * hwaddr = NULL;
gs_free const char * uri = NULL;
char sbuf[100];
NMCSProviderGetConfigTaskData *get_config_data;
@@ -273,26 +272,25 @@ _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data)
goto out_done;
}
- if (!g_hash_table_lookup_extended(get_config_data->result_dict,
- v_hwaddr,
- (gpointer *) &hwaddr,
- (gpointer *) &iface_data->iface_get_config)) {
+ iface_data->iface_get_config = g_hash_table_lookup(get_config_data->result_dict, v_hwaddr);
+
+ if (!iface_data->iface_get_config) {
if (!get_config_data->any) {
_LOGD("get-config: skip fetching meta data for %s (%" G_GSSIZE_FORMAT ")",
v_hwaddr,
iface_data->intern_iface_idx);
goto out_done;
}
- iface_data->iface_get_config = nmcs_provider_get_config_iface_data_new(FALSE);
- g_hash_table_insert(get_config_data->result_dict,
- (char *) (hwaddr = g_steal_pointer(&v_hwaddr)),
- iface_data->iface_get_config);
+ iface_data->iface_get_config =
+ nmcs_provider_get_config_iface_data_create(get_config_data->result_dict,
+ FALSE,
+ v_hwaddr);
is_requested = FALSE;
} else {
if (iface_data->iface_get_config->iface_idx >= 0) {
_LOGI("GCP interface[%" G_GSSIZE_FORMAT "]: duplicate MAC address %s returned",
iface_data->intern_iface_idx,
- hwaddr);
+ iface_data->iface_get_config->hwaddr);
error = nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN,
"duplicate MAC address for index %" G_GSSIZE_FORMAT,
iface_data->intern_iface_idx);
@@ -306,7 +304,7 @@ _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data)
_LOGI("GCP interface[%" G_GSSIZE_FORMAT "]: found a %sdevice with hwaddr %s",
iface_data->intern_iface_idx,
is_requested ? "requested " : "",
- hwaddr);
+ iface_data->iface_get_config->hwaddr);
nm_sprintf_buf(sbuf, "%" G_GSSIZE_FORMAT "/forwarded-ips/", iface_data->intern_iface_idx);
diff --git a/src/nm-cloud-setup/nmcs-provider.c b/src/nm-cloud-setup/nmcs-provider.c
index 8901100378d0..56f36646bb8a 100644
--- a/src/nm-cloud-setup/nmcs-provider.c
+++ b/src/nm-cloud-setup/nmcs-provider.c
@@ -127,15 +127,25 @@ nmcs_provider_detect_finish(NMCSProvider *self, GAsyncResult *result, GError **e
/*****************************************************************************/
NMCSProviderGetConfigIfaceData *
-nmcs_provider_get_config_iface_data_new(gboolean was_requested)
+nmcs_provider_get_config_iface_data_create(GHashTable *iface_datas,
+ gboolean was_requested,
+ const char *hwaddr)
{
NMCSProviderGetConfigIfaceData *iface_data;
+ nm_assert(hwaddr);
+
iface_data = g_slice_new(NMCSProviderGetConfigIfaceData);
*iface_data = (NMCSProviderGetConfigIfaceData){
+ .hwaddr = g_strdup(hwaddr),
.iface_idx = -1,
.was_requested = was_requested,
};
+
+ /* the has does not own the key (iface_datta->hwaddr), the lifetime of the
+ * key is associated with the iface_data instance. */
+ g_hash_table_replace(iface_datas, (char *) iface_data->hwaddr, iface_data);
+
return iface_data;
}
@@ -146,6 +156,7 @@ _iface_data_free(gpointer data)
g_free(iface_data->ipv4s_arr);
g_free(iface_data->iproutes_arr);
+ g_free((char *) iface_data->hwaddr);
nm_g_slice_free(iface_data);
}
@@ -224,16 +235,13 @@ nmcs_provider_get_config(NMCSProvider * self,
*get_config_data = (NMCSProviderGetConfigTaskData){
.task = nm_g_task_new(self, cancellable, nmcs_provider_get_config, callback, user_data),
.any = any,
- .result_dict = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, _iface_data_free),
+ .result_dict = g_hash_table_new_full(nm_str_hash, g_str_equal, NULL, _iface_data_free),
};
nmcs_wait_for_objects_register(get_config_data->task);
- for (; hwaddrs && hwaddrs[0]; hwaddrs++) {
- g_hash_table_insert(get_config_data->result_dict,
- g_strdup(hwaddrs[0]),
- nmcs_provider_get_config_iface_data_new(TRUE));
- }
+ for (; hwaddrs && hwaddrs[0]; hwaddrs++)
+ nmcs_provider_get_config_iface_data_create(get_config_data->result_dict, TRUE, hwaddrs[0]);
if (cancellable) {
gulong cancelled_id;
diff --git a/src/nm-cloud-setup/nmcs-provider.h b/src/nm-cloud-setup/nmcs-provider.h
index 31fec4449f9e..c67184679949 100644
--- a/src/nm-cloud-setup/nmcs-provider.h
+++ b/src/nm-cloud-setup/nmcs-provider.h
@@ -10,6 +10,10 @@
/*****************************************************************************/
typedef struct {
+ /* And it's exactly the same pointer that is also the key for the iface_datas
+ * dictionary. */
+ const char *hwaddr;
+
in_addr_t *ipv4s_arr;
gsize ipv4s_len;
@@ -41,13 +45,17 @@ nmcs_provider_get_config_iface_data_is_valid(const NMCSProviderGetConfigIfaceDat
&& ((config_data->has_ipv4s && config_data->has_cidr) || config_data->iproutes_len);
}
-NMCSProviderGetConfigIfaceData *nmcs_provider_get_config_iface_data_new(gboolean was_requested);
+NMCSProviderGetConfigIfaceData *nmcs_provider_get_config_iface_data_create(GHashTable *iface_datas,
+ gboolean was_requested,
+ const char *hwaddr);
/*****************************************************************************/
typedef struct {
/* A dictionary of (const char *) -> (NMCSProviderGetConfigIfaceData *).
- * This is the per-interface result of get_config(). */
+ * This is the per-interface result of get_config().
+ *
+ * The key is the same pointer as NMCSProviderGetConfigIfaceData's hwaddr. */
GHashTable *iface_datas;
/* The number of iface_datas that are nmcs_provider_get_config_iface_data_is_valid(). */
--
2.31.1
From 351ff60c9fb34ac6010fd895ad290db536a756a7 Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Wed, 1 Sep 2021 16:59:19 +0200
Subject: [PATCH 06/10] cloud-setup: track sorted list of
NMCSProviderGetConfigIfaceData
Sorted by iface_idx. The iface_idx is probably something useful and
stable, provided by the provider. E.g. it's the order in which
interfaces are exposed on the meta data.
(cherry picked from commit 1c5cb9d3c2be5addd3b011873cfc6b99204955d1)
(cherry picked from commit 0a2ed627038349d838add8f3fd72e2d282e74693)
---
src/nm-cloud-setup/nmcs-provider.c | 49 +++++++++++++++++++++++++++++-
src/nm-cloud-setup/nmcs-provider.h | 8 +++++
2 files changed, 56 insertions(+), 1 deletion(-)
diff --git a/src/nm-cloud-setup/nmcs-provider.c b/src/nm-cloud-setup/nmcs-provider.c
index 56f36646bb8a..138e78d41b56 100644
--- a/src/nm-cloud-setup/nmcs-provider.c
+++ b/src/nm-cloud-setup/nmcs-provider.c
@@ -51,6 +51,19 @@ nmcs_provider_get_main_context(NMCSProvider *self)
}
/*****************************************************************************/
+static int
+_result_new_sort_iface_data(gconstpointer pa, gconstpointer pb)
+{
+ const NMCSProviderGetConfigIfaceData *a = *((const NMCSProviderGetConfigIfaceData *const *) pa);
+ const NMCSProviderGetConfigIfaceData *b = *((const NMCSProviderGetConfigIfaceData *const *) pb);
+
+ /* negative iface_idx are sorted to the end. */
+ NM_CMP_DIRECT((a->iface_idx < 0), (b->iface_idx < 0));
+
+ NM_CMP_FIELD(a, b, iface_idx);
+ return 0;
+}
+
static NMCSProviderGetConfigResult *
nmcs_provider_get_config_result_new(GHashTable *iface_datas)
{
@@ -59,6 +72,12 @@ nmcs_provider_get_config_result_new(GHashTable *iface_datas)
GHashTableIter h_iter;
guint num_valid_ifaces = 0;
guint num_ipv4s = 0;
+ GPtrArray * ptrarr;
+ guint n_iface_datas;
+
+ n_iface_datas = g_hash_table_size(iface_datas);
+
+ ptrarr = g_ptr_array_sized_new(n_iface_datas + 1u);
g_hash_table_iter_init(&h_iter, iface_datas);
while (g_hash_table_iter_next(&h_iter, NULL, (gpointer *) &iface_data)) {
@@ -66,15 +85,42 @@ nmcs_provider_get_config_result_new(GHashTable *iface_datas)
num_valid_ifaces++;
num_ipv4s += iface_data->ipv4s_len;
}
+ g_ptr_array_add(ptrarr, (gpointer) iface_data);
}
+ g_ptr_array_sort(ptrarr, _result_new_sort_iface_data);
+
+ nm_assert(n_iface_datas == ptrarr->len);
+
+ g_ptr_array_add(ptrarr, NULL);
+
result = g_new(NMCSProviderGetConfigResult, 1);
*result = (NMCSProviderGetConfigResult){
- .iface_datas = g_hash_table_ref(iface_datas),
+ .iface_datas = g_hash_table_ref(iface_datas),
+ .n_iface_datas = n_iface_datas,
+ .iface_datas_arr =
+ (const NMCSProviderGetConfigIfaceData **) g_ptr_array_free(ptrarr, FALSE),
.num_valid_ifaces = num_valid_ifaces,
.num_ipv4s = num_ipv4s,
};
+#if NM_MORE_ASSERTS > 5
+ {
+ gsize iface_idx_expected = 0;
+ guint i;
+
+ for (i = 0; i < result->n_iface_datas; i++) {
+ if (result->iface_datas_arr[i]->iface_idx < 0) {
+ nm_assert(result->iface_datas_arr[i]->iface_idx == -1);
+ iface_idx_expected = -1;
+ continue;
+ }
+ nm_assert(result->iface_datas_arr[i]->iface_idx == iface_idx_expected);
+ iface_idx_expected++;
+ }
+ }
+#endif
+
return result;
}
@@ -83,6 +129,7 @@ nmcs_provider_get_config_result_free(NMCSProviderGetConfigResult *result)
{
if (result) {
nm_g_hash_table_unref(result->iface_datas);
+ g_free((gpointer) result->iface_datas_arr);
g_free(result);
}
}
diff --git a/src/nm-cloud-setup/nmcs-provider.h b/src/nm-cloud-setup/nmcs-provider.h
index c67184679949..366320596492 100644
--- a/src/nm-cloud-setup/nmcs-provider.h
+++ b/src/nm-cloud-setup/nmcs-provider.h
@@ -63,6 +63,14 @@ typedef struct {
/* the number of IPv4 addresses over all valid iface_datas. */
guint num_ipv4s;
+
+ guint n_iface_datas;
+
+ /* The sorted value of @iface_datas, sorted by iface_idx.
+ *
+ * Not found entries (iface_idx == -1) are sorted at the end. */
+ const NMCSProviderGetConfigIfaceData *const *iface_datas_arr;
+
} NMCSProviderGetConfigResult;
void nmcs_provider_get_config_result_free(NMCSProviderGetConfigResult *result);
--
2.31.1
From d6832b24cfdb07b3acd2d92dd1ca47df46eeaba4 Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Wed, 1 Sep 2021 17:23:09 +0200
Subject: [PATCH 07/10] cloud-setup: process iface-datas in sorted order
The routes/rules that are configured are independent of the
order in which we process the devices. That is, because they
use the "iface_idx" for cases where there is ambiguity.
Still, it feels nicer to always process them in a defined order.
(cherry picked from commit a95ea0eb294d646f17b5e1cf4f17cb1540f8af3a)
(cherry picked from commit 6302cd416d92a8c2f5b4a6be9dded71af4cf7ced)
---
src/nm-cloud-setup/main.c | 28 +++++++++++++---------------
1 file changed, 13 insertions(+), 15 deletions(-)
diff --git a/src/nm-cloud-setup/main.c b/src/nm-cloud-setup/main.c
index bb5c0d5ded9d..403c8d759794 100644
--- a/src/nm-cloud-setup/main.c
+++ b/src/nm-cloud-setup/main.c
@@ -405,14 +405,15 @@ _nmc_mangle_connection(NMDevice * device,
/*****************************************************************************/
static gboolean
-_config_one(GCancellable * sigterm_cancellable,
- NMClient * nmc,
- const NMCSProviderGetConfigResult * result,
- const char * hwaddr,
- const NMCSProviderGetConfigIfaceData *config_data)
+_config_one(GCancellable * sigterm_cancellable,
+ NMClient * nmc,
+ const NMCSProviderGetConfigResult *result,
+ guint idx)
{
- gs_unref_object NMDevice *device = NULL;
- gs_unref_object NMConnection *applied_connection = NULL;
+ const NMCSProviderGetConfigIfaceData *config_data = result->iface_datas_arr[idx];
+ const char * hwaddr = config_data->hwaddr;
+ gs_unref_object NMDevice *device = NULL;
+ gs_unref_object NMConnection *applied_connection = NULL;
guint64 applied_version_id;
gs_free_error GError *error = NULL;
gboolean changed;
@@ -537,14 +538,11 @@ _config_all(GCancellable * sigterm_cancellable,
NMClient * nmc,
const NMCSProviderGetConfigResult *result)
{
- GHashTableIter h_iter;
- const NMCSProviderGetConfigIfaceData *c_config_data;
- const char * c_hwaddr;
- gboolean any_changes = FALSE;
-
- g_hash_table_iter_init(&h_iter, result->iface_datas);
- while (g_hash_table_iter_next(&h_iter, (gpointer *) &c_hwaddr, (gpointer *) &c_config_data)) {
- if (_config_one(sigterm_cancellable, nmc, result, c_hwaddr, c_config_data))
+ gboolean any_changes = FALSE;
+ guint i;
+
+ for (i = 0; i < result->n_iface_datas; i++) {
+ if (_config_one(sigterm_cancellable, nmc, result, i))
any_changes = TRUE;
}
--
2.31.1
From 167faa59d23ab8b2db471169860c4387da625d21 Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Wed, 1 Sep 2021 19:23:46 +0200
Subject: [PATCH 08/10] cloud-setup: limit number of supported interfaces to
avoid overlapping table numbers
The table number is chosen as 30400 + iface_idx. That is, the range is
limited and we shouldn't handle more than 100 devices. Add a check for
that and error out.
(cherry picked from commit b68d694b78fd9b4b63b0592a2518f387aaa35f87)
(cherry picked from commit 292233e16ed1f60499c2676611d59c271352e2c3)
---
src/nm-cloud-setup/main.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/nm-cloud-setup/main.c b/src/nm-cloud-setup/main.c
index 403c8d759794..6be8c145f3c9 100644
--- a/src/nm-cloud-setup/main.c
+++ b/src/nm-cloud-setup/main.c
@@ -438,6 +438,14 @@ _config_one(GCancellable * sigterm_cancellable,
return FALSE;
}
+ if (config_data->iface_idx >= 100) {
+ /* since we use the iface_idx to select a table number, the range is limited from
+ * 0 to 99. Note that the providers are required to provide increasing numbers,
+ * so this means we bail out after the first 100 devices. */
+ _LOGD("config device %s: skip because number of supported interfaces reached", hwaddr);
+ return FALSE;
+ }
+
_LOGD("config device %s: configuring \"%s\" (%s)...",
hwaddr,
nm_device_get_iface(device) ?: "/unknown/",
--
2.31.1
From 5d8ac7f10fd9b4a467e8afd7e082acb4b2d33eed Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Mon, 6 Sep 2021 10:35:36 +0200
Subject: [PATCH 09/10] cloud-setup: cleanup configuring addresses/routes/rules
in _nmc_mangle_connection()
(cherry picked from commit 0978be5e43f142ec5c6062dcfe1c2f4aa834464b)
(cherry picked from commit ce24b4bca5d3fbad65d4065325cfa80ac05fbfdb)
---
src/nm-cloud-setup/main.c | 52 +++++++++++++++++----------------------
1 file changed, 23 insertions(+), 29 deletions(-)
diff --git a/src/nm-cloud-setup/main.c b/src/nm-cloud-setup/main.c
index 6be8c145f3c9..260d111205f5 100644
--- a/src/nm-cloud-setup/main.c
+++ b/src/nm-cloud-setup/main.c
@@ -279,10 +279,6 @@ _nmc_mangle_connection(NMDevice * device,
NMConnection * remote_connection;
NMSettingIPConfig * remote_s_ip = NULL;
gsize i;
- in_addr_t gateway;
- gint64 rt_metric;
- guint32 rt_table;
- NMIPRoute * route_entry;
gboolean addrs_changed = FALSE;
gboolean rules_changed = FALSE;
gboolean routes_changed = FALSE;
@@ -339,47 +335,45 @@ _nmc_mangle_connection(NMDevice * device,
* We don't need to configure policy routing in this case. */
NM_SET_OUT(out_skipped_single_addr, TRUE);
} else if (config_data->has_ipv4s && config_data->has_cidr) {
+ NMIPAddress * addr_entry;
+ NMIPRoute * route_entry;
+ NMIPRoutingRule *rule_entry;
+ in_addr_t gateway;
+ char sbuf[NM_UTILS_INET_ADDRSTRLEN];
+
for (i = 0; i < config_data->ipv4s_len; i++) {
- NMIPAddress *entry;
-
- entry = nm_ip_address_new_binary(AF_INET,
- &config_data->ipv4s_arr[i],
- config_data->cidr_prefix,
- NULL);
- if (entry)
- g_ptr_array_add(addrs_new, entry);
+ addr_entry = nm_ip_address_new_binary(AF_INET,
+ &config_data->ipv4s_arr[i],
+ config_data->cidr_prefix,
+ NULL);
+ nm_assert(addr_entry);
+ g_ptr_array_add(addrs_new, addr_entry);
}
+
if (config_data->has_gateway && config_data->gateway) {
gateway = config_data->gateway;
} else {
gateway = nm_utils_ip4_address_clear_host_address(config_data->cidr_addr,
config_data->cidr_prefix);
- ((guint8 *) &gateway)[3] += 1;
+ if (config_data->cidr_prefix < 32)
+ ((guint8 *) &gateway)[3] += 1;
}
- rt_metric = 10;
- rt_table = 30400 + config_data->iface_idx;
- route_entry =
- nm_ip_route_new_binary(AF_INET, &nm_ip_addr_zero, 0, &gateway, rt_metric, NULL);
+ route_entry = nm_ip_route_new_binary(AF_INET, &nm_ip_addr_zero, 0, &gateway, 10, NULL);
nm_ip_route_set_attribute(route_entry,
NM_IP_ROUTE_ATTRIBUTE_TABLE,
- g_variant_new_uint32(rt_table));
+ g_variant_new_uint32(30400 + config_data->iface_idx));
g_ptr_array_add(routes_new, route_entry);
for (i = 0; i < config_data->ipv4s_len; i++) {
- NMIPRoutingRule *entry;
- char sbuf[NM_UTILS_INET_ADDRSTRLEN];
-
- entry = nm_ip_routing_rule_new(AF_INET);
- nm_ip_routing_rule_set_priority(entry, rt_table);
- nm_ip_routing_rule_set_from(entry,
+ rule_entry = nm_ip_routing_rule_new(AF_INET);
+ nm_ip_routing_rule_set_priority(rule_entry, 30400 + config_data->iface_idx);
+ nm_ip_routing_rule_set_from(rule_entry,
_nm_utils_inet4_ntop(config_data->ipv4s_arr[i], sbuf),
32);
- nm_ip_routing_rule_set_table(entry, rt_table);
-
- nm_assert(nm_ip_routing_rule_validate(entry, NULL));
-
- g_ptr_array_add(rules_new, entry);
+ nm_ip_routing_rule_set_table(rule_entry, 30400 + config_data->iface_idx);
+ nm_assert(nm_ip_routing_rule_validate(rule_entry, NULL));
+ g_ptr_array_add(rules_new, rule_entry);
}
}
--
2.31.1
From c2402be45e2dec931690aef555de43292b015422 Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Wed, 1 Sep 2021 10:31:55 +0200
Subject: [PATCH 10/10] cloud-setup: use suppress_prefixlength rule to honor
non-default-routes in the main table
Background
==========
Imagine you run a container on your machine. Then the routing table
might look like:
default via 10.0.10.1 dev eth0 proto dhcp metric 100
10.0.10.0/28 dev eth0 proto kernel scope link src 10.0.10.5 metric 100
[...]
10.42.0.0/24 via 10.42.0.0 dev flannel.1 onlink
10.42.1.2 dev cali02ad7e68ce1 scope link
10.42.1.3 dev cali8fcecf5aaff scope link
10.42.2.0/24 via 10.42.2.0 dev flannel.1 onlink
10.42.3.0/24 via 10.42.3.0 dev flannel.1 onlink
That is, there are another interfaces with subnets and specific routes.
If nm-cloud-setup now configures rules:
0: from all lookup local
30400: from 10.0.10.5 lookup 30400
32766: from all lookup main
32767: from all lookup default
and
default via 10.0.10.1 dev eth0 table 30400 proto static metric 10
10.0.10.1 dev eth0 table 30400 proto static scope link metric 10
then these other subnets will also be reached via the default route.
This container example is just one case where this is a problem. In
general, if you have specific routes on another interface, then the
default route in the 30400+ table will interfere badly.
The idea of nm-cloud-setup is to automatically configure the network for
secondary IP addresses. When the user has special requirements, then
they should disable nm-cloud-setup and configure whatever they want.
But the container use case is popular and important. It is not something
where the user actively configures the network. This case needs to work better,
out of the box. In general, nm-cloud-setup should work better with the
existing network configuration.
Change
======
Add new routing tables 30200+ with the individual subnets of the
interface:
10.0.10.0/24 dev eth0 table 30200 proto static metric 10
[...]
default via 10.0.10.1 dev eth0 table 30400 proto static metric 10
10.0.10.1 dev eth0 table 30400 proto static scope link metric 10
Also add more important routing rules with priority 30200+, which select
these tables based on the source address:
30200: from 10.0.10.5 lookup 30200
These will do source based routing for the subnets on these
interfaces.
Then, add a rule with priority 30350
30350: lookup main suppress_prefixlength 0
which processes the routes from the main table, but ignores the default
routes. 30350 was chosen, because it's in between the rules 30200+ and
30400+, leaving a range for the user to configure their own rules.
Then, as before, the rules 30400+ again look at the corresponding 30400+
table, to find a default route.
Finally, process the main table again, this time honoring the default
route. That is for packets that have a different source address.
This change means that the source based routing is used for the
subnets that are configured on the interface and for the default route.
Whereas, if there are any more specific routes in the main table, they will
be preferred over the default route.
Apparently Amazon Linux solves this differently, by not configuring a
routing table for addresses on interface "eth0". That might be an
alternative, but it's not clear to me what is special about eth0 to
warrant this treatment. It also would imply that we somehow recognize
this primary interface. In practise that would be doable by selecting
the interface with "iface_idx" zero.
Instead choose this approach. This is remotely similar to what WireGuard does
for configuring the default route ([1]), however WireGuard uses fwmark to match
the packets instead of the source address.
[1] https://www.wireguard.com/netns/#improved-rule-based-routing
(cherry picked from commit fe80b2d1ecd94639573a944633a5d960db316f60)
(cherry picked from commit 58e58361bd1666e5af822a4bc970bebb8a44bd6e)
---
man/nm-cloud-setup.xml | 66 +++++++++++++++------------------------
src/nm-cloud-setup/main.c | 36 +++++++++++++++++++++
2 files changed, 62 insertions(+), 40 deletions(-)
diff --git a/man/nm-cloud-setup.xml b/man/nm-cloud-setup.xml
index 7493cc1d7f26..976fc6472464 100644
--- a/man/nm-cloud-setup.xml
+++ b/man/nm-cloud-setup.xml
@@ -256,7 +256,9 @@ ln -s /etc/systemd/system/timers.target.wants/nm-cloud-setup.timer /usr/lib/syst
Also, if the device is currently not activated in NetworkManager or if the currently
activated profile has a user-data <literal>org.freedesktop.nm-cloud-setup.skip=yes</literal>,
it is skipped.</para>
- <para>Then, the tool will change the runtime configuration of the device.
+ <para>If only one interface and one address is configured, then the tool does nothing
+ and leaves the automatic configuration that was obtained via DHCP.</para>
+ <para>Otherwise, the tool will change the runtime configuration of the device.
<itemizedlist>
<listitem>
<para>Add static IPv4 addresses for all the configured addresses from <literal>local-ipv4s</literal> with
@@ -267,15 +269,25 @@ ln -s /etc/systemd/system/timers.target.wants/nm-cloud-setup.timer /usr/lib/syst
<para>Choose a route table 30400 + the index of the interface and
add a default route <literal>0.0.0.0/0</literal>. The gateway
is the first IP address in the CIDR subnet block. For
- example, we might get a route <literal>"0.0.0.0/0 172.16.5.1 10 table=30401"</literal>.</para>
+ example, we might get a route <literal>"0.0.0.0/0 172.16.5.1 10 table=30400"</literal>.</para>
+ <para>Also choose a route table 30200 + the interface index. This
+ contains a direct routes to the subnets of this interface.</para>
</listitem>
<listitem>
<para>Finally, add a policy routing rule for each address. For example
- <literal>"priority 30401 from 172.16.5.3/32 table 30401, priority 30401 from 172.16.5.4/32 table 30401"</literal>.</para>
+ <literal>"priority 30200 from 172.16.5.3/32 table 30200, priority 30200 from 172.16.5.4/32 table 30200"</literal>.
+ and
+ <literal>"priority 30400 from 172.16.5.3/32 table 30400, priority 30400 from 172.16.5.4/32 table 30400"</literal>
+ The 30200+ rules select the table to reach the subnet directly, while the 30400+ rules use the
+ default route. Also add a rule
+ <literal>"priority 30350 table main suppress_prefixlength 0"</literal>. This has a priority between
+ the two previous rules and causes a lookup of routes in the main table while ignoring the default
+ route. The purpose of this is so that other specific routes in the main table are honored over
+ the default route in table 30400+.</para>
</listitem>
</itemizedlist>
With above example, this roughly corresponds for interface <literal>eth0</literal> to
- <command>nmcli device modify "eth0" ipv4.addresses "172.16.5.3/24,172.16.5.4/24" ipv4.routes "0.0.0.0/0 172.16.5.1 10 table=30401" ipv4.routing-rules "priority 30401 from 172.16.5.3/32 table 30401, priority 30401 from 172.16.5.4/32 table 30401"</command>.
+ <command>nmcli device modify "eth0" ipv4.addresses "172.16.5.3/24,172.16.5.4/24" ipv4.routes "172.16.5.0/24 0.0.0.0 10 table=30200, 0.0.0.0/0 172.16.5.1 10 table=30400" ipv4.routing-rules "priority 30200 from 172.16.5.3/32 table 30200, priority 30200 from 172.16.5.4/32 table 30200, priority 20350 table main suppress_prefixlength 0, priority 30400 from 172.16.5.3/32 table 30400, priority 30400 from 172.16.5.4/32 table 30400"</command>.
Note that this replaces the previous addresses, routes and rules with the new information.
But also note that this only changes the run time configuration of the device. The
connection profile on disk is not affected.
@@ -360,14 +372,8 @@ ln -s /etc/systemd/system/timers.target.wants/nm-cloud-setup.timer /usr/lib/syst
</listitem>
<listitem>
<para>At this point, we have a list of all interfaces (by MAC address) and their configured IPv4 addresses.</para>
- <para>For each device, we lookup the currently applied connection in NetworkManager. That implies, that the device is currently activated
- in NetworkManager. If no such device was in NetworkManager, or if the profile has user-data <literal>org.freedesktop.nm-cloud-setup.skip=yes</literal>,
- we skip the device. Now for each found IP address we add a static address "$ADDR/$SUBNET_PREFIX". Also we configure policy routing
- by adding a static route "$ADDR/$SUBNET_PREFIX $GATEWAY 10, table=$TABLE" where $GATEWAY is the first IP address in the subnet and table
- is 30400 plus the interface index. Also we add a policy routing rule "priority $TABLE from $ADDR/32 table $TABLE".</para>
- <para>The effect is not unlike calling
- <command>nmcli device modify "$DEVICE" ipv4.addresses "$ADDR/$SUBNET [,...]" ipv4.routes "$ADDR/32 $GATEWAY 10 table=$TABLE" ipv4.routing-rules "priority $TABLE from $ADDR/32 table $TABLE"</command>
- for all relevant devices and all found addresses.</para>
+ <para>Then the tool configures the system like doing for AWS environment. That is, using source based policy routing
+ with the tables/rules 30200/30400.</para>
</listitem>
</itemizedlist>
</refsect2>
@@ -389,9 +395,10 @@ ln -s /etc/systemd/system/timers.target.wants/nm-cloud-setup.timer /usr/lib/syst
of available interface. Interfaces are identified by their MAC address.</para>
</listitem>
<listitem>
- <para>Then for each interface fetch <literal>http://100.100.100.200/2016-01-01/meta-data/network/interfaces/macs/$MAC/vpc-cidr-block</literal>
- , <literal>http://100.100.100.200/2016-01-01/meta-data/network/interfaces/macs/$MAC/private-ipv4s</literal> and
- <literal>http://100.100.100.200/2016-01-01/meta-data/network/interfaces/macs/$MAC/netmask</literal>.
+ <para>Then for each interface fetch <literal>http://100.100.100.200/2016-01-01/meta-data/network/interfaces/macs/$MAC/vpc-cidr-block</literal>,
+ <literal>http://100.100.100.200/2016-01-01/meta-data/network/interfaces/macs/$MAC/private-ipv4s</literal>,
+ <literal>http://100.100.100.200/2016-01-01/meta-data/network/interfaces/macs/$MAC/netmask</literal> and
+ <literal>http://100.100.100.200/2016-01-01/meta-data/network/interfaces/macs/$MAC/gateway</literal>.
Thereby we get a list of private IPv4 addresses, one CIDR subnet block and private IPv4 addresses prefix.</para>
</listitem>
<listitem>
@@ -399,31 +406,10 @@ ln -s /etc/systemd/system/timers.target.wants/nm-cloud-setup.timer /usr/lib/syst
If no ethernet device for the respective MAC address is found, it is skipped.
Also, if the device is currently not activated in NetworkManager or if the currently
activated profile has a user-data <literal>org.freedesktop.nm-cloud-setup.skip=yes</literal>,
- it is skipped.</para>
- <para>Then, the tool will change the runtime configuration of the device.
- <itemizedlist>
- <listitem>
- <para>Add static IPv4 addresses for all the configured addresses from <literal>private-ipv4s</literal> with
- prefix length according to <literal>netmask</literal>. For example,
- we might have here 2 IP addresses like <literal>"10.0.0.150/24,10.0.0.152/24"</literal>.</para>
- </listitem>
- <listitem>
- <para>Choose a route table 30400 + the index of the interface and
- add a default route <literal>0.0.0.0/0</literal>. The gateway
- is the default gateway retrieved from metadata server. For
- example, we might get a route <literal>"0.0.0.0/0 10.0.0.253 10 table=30400"</literal>.</para>
- </listitem>
- <listitem>
- <para>Finally, add a policy routing rule for each address. For example
- <literal>"priority 30400 from 10.0.0.150/32 table 30400, priority 30400 from 10.0.0.152/32 table 30400"</literal>.</para>
- </listitem>
- </itemizedlist>
- With above example, this roughly corresponds for interface <literal>eth0</literal> to
- <command>nmcli device modify "eth0" ipv4.addresses "10.0.0.150/24,10.0.0.152/24" ipv4.routes "0.0.0.0/0 10.0.0.253 10 table=30400" ipv4.routing-rules "priority 30400 from 10.0.0.150/32 table 30400, priority 30400 from 10.0.0.152/32 table 30400"</command>.
- Note that this replaces the previous addresses, routes and rules with the new information.
- But also note that this only changes the run time configuration of the device. The
- connection profile on disk is not affected.
- </para>
+ it is skipped. Also, there is only one interface and one IP address, the tool does nothing.</para>
+ <para>Then the tool configures the system like doing for AWS environment. That is, using source based policy routing
+ with the tables/rules 30200/30400. One difference to AWS is that the gateway is also fetched via metadata instead
+ of using the first IP address in the subnet.</para>
</listitem>
</itemizedlist>
</refsect2>
diff --git a/src/nm-cloud-setup/main.c b/src/nm-cloud-setup/main.c
index 260d111205f5..916f41da91d3 100644
--- a/src/nm-cloud-setup/main.c
+++ b/src/nm-cloud-setup/main.c
@@ -4,6 +4,8 @@
#include "libnm-client-aux-extern/nm-libnm-aux.h"
+#include <linux/rtnetlink.h>
+
#include "nm-cloud-setup-utils.h"
#include "nmcs-provider-ec2.h"
#include "nmcs-provider-gcp.h"
@@ -335,6 +337,8 @@ _nmc_mangle_connection(NMDevice * device,
* We don't need to configure policy routing in this case. */
NM_SET_OUT(out_skipped_single_addr, TRUE);
} else if (config_data->has_ipv4s && config_data->has_cidr) {
+ gs_unref_hashtable GHashTable *unique_subnets =
+ g_hash_table_new(nm_direct_hash, g_direct_equal);
NMIPAddress * addr_entry;
NMIPRoute * route_entry;
NMIPRoutingRule *rule_entry;
@@ -359,6 +363,38 @@ _nmc_mangle_connection(NMDevice * device,
((guint8 *) &gateway)[3] += 1;
}
+ for (i = 0; i < config_data->ipv4s_len; i++) {
+ in_addr_t a = config_data->ipv4s_arr[i];
+
+ a = nm_utils_ip4_address_clear_host_address(a, config_data->cidr_prefix);
+
+ G_STATIC_ASSERT_EXPR(sizeof(gsize) >= sizeof(in_addr_t));
+ if (g_hash_table_add(unique_subnets, GSIZE_TO_POINTER(a))) {
+ route_entry =
+ nm_ip_route_new_binary(AF_INET, &a, config_data->cidr_prefix, NULL, 10, NULL);
+ nm_ip_route_set_attribute(route_entry,
+ NM_IP_ROUTE_ATTRIBUTE_TABLE,
+ g_variant_new_uint32(30200 + config_data->iface_idx));
+ g_ptr_array_add(routes_new, route_entry);
+ }
+
+ rule_entry = nm_ip_routing_rule_new(AF_INET);
+ nm_ip_routing_rule_set_priority(rule_entry, 30200 + config_data->iface_idx);
+ nm_ip_routing_rule_set_from(rule_entry,
+ _nm_utils_inet4_ntop(config_data->ipv4s_arr[i], sbuf),
+ 32);
+ nm_ip_routing_rule_set_table(rule_entry, 30200 + config_data->iface_idx);
+ nm_assert(nm_ip_routing_rule_validate(rule_entry, NULL));
+ g_ptr_array_add(rules_new, rule_entry);
+ }
+
+ rule_entry = nm_ip_routing_rule_new(AF_INET);
+ nm_ip_routing_rule_set_priority(rule_entry, 30350);
+ nm_ip_routing_rule_set_table(rule_entry, RT_TABLE_MAIN);
+ nm_ip_routing_rule_set_suppress_prefixlength(rule_entry, 0);
+ nm_assert(nm_ip_routing_rule_validate(rule_entry, NULL));
+ g_ptr_array_add(rules_new, rule_entry);
+
route_entry = nm_ip_route_new_binary(AF_INET, &nm_ip_addr_zero, 0, &gateway, 10, NULL);
nm_ip_route_set_attribute(route_entry,
NM_IP_ROUTE_ATTRIBUTE_TABLE,
--
2.31.1