Blame SOURCES/1003-cloud-setup-better-handle-other-routes-rh1977984.patch

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