summary refs log tree commit diff
path: root/src/nm-cloud-setup/main.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2023-08-09 21:55:35 +0200
committerMichael Biebl <biebl@debian.org>2023-08-09 21:55:35 +0200
commit05e4a733f2141995181a551854d5df929f084adf (patch)
tree83bb937740a6667525ba0df046748ecaa829c269 /src/nm-cloud-setup/main.c
parent14b0f3a9dc9ea90d60a3b057350fd4d637dc021a (diff)
New upstream version 1.44.0 upstream/1.44.0
Diffstat (limited to 'src/nm-cloud-setup/main.c')
-rw-r--r--src/nm-cloud-setup/main.c183
1 files changed, 147 insertions, 36 deletions
diff --git a/src/nm-cloud-setup/main.c b/src/nm-cloud-setup/main.c
index 630f26ef..084b5f62 100644
--- a/src/nm-cloud-setup/main.c
+++ b/src/nm-cloud-setup/main.c
@@ -22,10 +22,12 @@ typedef struct {
 } SigTermData;
 
 typedef struct {
+    SigTermData  *sigterm_data;
     GMainLoop    *main_loop;
     GCancellable *cancellable;
     NMCSProvider *provider_result;
     guint         detect_count;
+    gboolean      any_provider_enabled;
 } ProviderDetectData;
 
 static void
@@ -33,38 +35,45 @@ _provider_detect_cb(GObject *source, GAsyncResult *result, gpointer user_data)
 {
     gs_unref_object NMCSProvider *provider = NMCS_PROVIDER(source);
     gs_free_error GError         *error    = NULL;
-    ProviderDetectData           *dd;
+    ProviderDetectData           *dd       = user_data;
     gboolean                      success;
 
+    nm_assert(dd->detect_count > 0);
+    dd->detect_count--;
+
     success = nmcs_provider_detect_finish(provider, result, &error);
 
     nm_assert(success != (!!error));
 
-    if (nm_utils_error_is_cancelled(error))
-        return;
-
-    dd = user_data;
-
-    nm_assert(dd->detect_count > 0);
-    dd->detect_count--;
-
+    if (nm_utils_error_is_cancelled(error)) {
+        _LOGD("provider %s detection cancelled", nmcs_provider_get_name(provider));
+        goto out;
+    }
     if (error) {
+        if (nm_g_error_matches(error, NM_UTILS_ERROR, NM_UTILS_ERROR_NOT_READY)) {
+            /* This error tells us, that the provider was not enabled in configuration. */
+        } else
+            dd->any_provider_enabled = TRUE;
         _LOGI("provider %s not detected: %s", nmcs_provider_get_name(provider), error->message);
-        if (dd->detect_count > 0) {
-            /* wait longer. */
-            return;
-        }
-
-        _LOGI("no provider detected");
-        goto done;
+        goto out;
     }
 
     _LOGI("provider %s detected", nmcs_provider_get_name(provider));
     dd->provider_result = g_steal_pointer(&provider);
-
-done:
     g_cancellable_cancel(dd->cancellable);
-    g_main_loop_quit(dd->main_loop);
+
+out:
+    if (dd->detect_count == 0) {
+        if (!dd->provider_result) {
+            NMLogLevel level = LOGL_INFO;
+
+            if (dd->any_provider_enabled && !dd->sigterm_data->signal_received)
+                level = LOGL_WARN;
+
+            _NMLOG(level, "no provider detected");
+        }
+        g_main_loop_quit(dd->main_loop);
+    }
 }
 
 static void
@@ -74,21 +83,21 @@ _provider_detect_sigterm_cb(GCancellable *source, gpointer user_data)
 
     g_cancellable_cancel(dd->cancellable);
     g_clear_object(&dd->provider_result);
-    dd->detect_count = 0;
-    g_main_loop_quit(dd->main_loop);
 }
 
 static NMCSProvider *
-_provider_detect(GCancellable *sigterm_cancellable)
+_provider_detect(SigTermData *sigterm_data)
 {
     nm_auto_unref_gmainloop GMainLoop *main_loop   = g_main_loop_new(NULL, FALSE);
     gs_unref_object GCancellable      *cancellable = g_cancellable_new();
     gs_unref_object NMHttpClient      *http_client = NULL;
     ProviderDetectData                 dd          = {
-                                 .cancellable     = cancellable,
-                                 .main_loop       = main_loop,
-                                 .detect_count    = 0,
-                                 .provider_result = NULL,
+                                 .sigterm_data         = sigterm_data,
+                                 .cancellable          = cancellable,
+                                 .main_loop            = main_loop,
+                                 .detect_count         = 0,
+                                 .provider_result      = NULL,
+                                 .any_provider_enabled = FALSE,
     };
     const GType gtypes[] = {
         NMCS_TYPE_PROVIDER_EC2,
@@ -99,7 +108,7 @@ _provider_detect(GCancellable *sigterm_cancellable)
     int    i;
     gulong cancellable_signal_id;
 
-    cancellable_signal_id = g_cancellable_connect(sigterm_cancellable,
+    cancellable_signal_id = g_cancellable_connect(sigterm_data->cancellable,
                                                   G_CALLBACK(_provider_detect_sigterm_cb),
                                                   &dd,
                                                   NULL);
@@ -123,12 +132,113 @@ _provider_detect(GCancellable *sigterm_cancellable)
         g_main_loop_run(main_loop);
 
 out:
-    nm_clear_g_signal_handler(sigterm_cancellable, &cancellable_signal_id);
+    nm_clear_g_signal_handler(sigterm_data->cancellable, &cancellable_signal_id);
     return dd.provider_result;
 }
 
 /*****************************************************************************/
 
+static NMUtilsNamedValue *
+_map_interfaces_parse(void)
+{
+    gs_free const char **split = NULL;
+    NMUtilsNamedValue   *map_interfaces;
+    const char          *env_var;
+    gsize                i;
+    gsize                j;
+    gsize                alloc_len;
+
+    env_var = g_getenv(NMCS_ENV_NM_CLOUD_SETUP_MAP_INTERFACES);
+
+    if (nm_str_is_empty(env_var))
+        return NULL;
+
+    split = nm_strsplit_set_full(env_var, ";", NM_STRSPLIT_SET_FLAGS_STRSTRIP);
+
+    alloc_len = NM_PTRARRAY_LEN(split) + 1u;
+
+    map_interfaces = g_new(NMUtilsNamedValue, alloc_len);
+
+    _LOGD("test: map interfaces via NM_CLOUD_SETUP_MAP_INTERFACES=\"%s\"", env_var);
+
+    for (i = 0, j = 0; split && split[i]; i++) {
+        NMUtilsNamedValue *m;
+        const char        *str = split[i];
+        char              *hwaddr;
+        const char        *s;
+
+        s = strchr(str, '=');
+        if (!s || str == s)
+            continue;
+
+        hwaddr = nmcs_utils_hwaddr_normalize(&s[1], -1);
+        if (!hwaddr)
+            continue;
+
+        nm_assert(j < alloc_len);
+        m = &map_interfaces[j++];
+
+        *m = (NMUtilsNamedValue){
+            .name      = g_strndup(str, s - str),
+            .value_str = hwaddr,
+        };
+
+        _LOGD("test:  map \"%s\" -> %s", m->name, m->value_str);
+    }
+
+    nm_assert(j < alloc_len);
+    map_interfaces[j++] = (NMUtilsNamedValue){
+        .name      = NULL,
+        .value_str = NULL,
+    };
+
+    return g_steal_pointer(&map_interfaces);
+}
+
+static const char *
+_device_get_hwaddr(NMDeviceEthernet *device)
+{
+    static const NMUtilsNamedValue *gl_map_interfaces_map = NULL;
+    static gsize                    gl_initialized        = 0;
+    const NMUtilsNamedValue        *map                   = NULL;
+
+    nm_assert(NM_IS_DEVICE_ETHERNET(device));
+
+    /* Network interfaces in cloud environments are identified by their permanent
+     * MAC address.
+     *
+     * For testing, we can set NMCS_ENV_NM_CLOUD_SETUP_MAP_INTERFACES
+     * to a ';' separate list of "$INTERFACE=$HWADDR", which means that we
+     * pretend that device with ip-interface "$INTERFACE" has the specified permanent
+     * MAC address. */
+
+    if (g_once_init_enter(&gl_initialized)) {
+        gl_map_interfaces_map = _map_interfaces_parse();
+        g_once_init_leave(&gl_initialized, 1);
+    }
+
+    map = gl_map_interfaces_map;
+    if (G_UNLIKELY(map)) {
+        const char *const iface = nm_device_get_iface(NM_DEVICE(device));
+
+        /* For testing, the device<->hwaddr is remapped and the actual permanent
+         * MAC address of the device ignored. This mapping is configured via
+         * NMCS_ENV_NM_CLOUD_SETUP_MAP_INTERFACES environment variable. */
+
+        if (!iface)
+            return NULL;
+
+        for (; map->name; map++) {
+            if (nm_streq(map->name, iface))
+                return map->value_str;
+        }
+
+        return NULL;
+    }
+
+    return nm_device_ethernet_get_permanent_hw_address(device);
+}
+
 static char **
 _nmc_get_hwaddrs(NMClient *nmc)
 {
@@ -151,7 +261,7 @@ _nmc_get_hwaddrs(NMClient *nmc)
         if (nm_device_get_state(device) < NM_DEVICE_STATE_UNAVAILABLE)
             continue;
 
-        hwaddr = nm_device_ethernet_get_permanent_hw_address(NM_DEVICE_ETHERNET(device));
+        hwaddr = _device_get_hwaddr(NM_DEVICE_ETHERNET(device));
         if (!hwaddr)
             continue;
 
@@ -193,7 +303,7 @@ _nmc_get_device_by_hwaddr(NMClient *nmc, const char *hwaddr)
         if (!NM_IS_DEVICE_ETHERNET(device))
             continue;
 
-        hwaddr_dev = nm_device_ethernet_get_permanent_hw_address(NM_DEVICE_ETHERNET(device));
+        hwaddr_dev = _device_get_hwaddr(NM_DEVICE_ETHERNET(device));
         if (!hwaddr_dev)
             continue;
 
@@ -321,8 +431,9 @@ _nmc_mangle_connection(NMDevice                             *device,
     addrs_new = g_ptr_array_new_full(config_data->ipv4s_len, (GDestroyNotify) nm_ip_address_unref);
     rules_new =
         g_ptr_array_new_full(config_data->ipv4s_len, (GDestroyNotify) nm_ip_routing_rule_unref);
-    routes_new = g_ptr_array_new_full(config_data->iproutes_len + !!config_data->ipv4s_len,
-                                      (GDestroyNotify) nm_ip_route_unref);
+    routes_new =
+        g_ptr_array_new_full(nm_g_ptr_array_len(config_data->iproutes) + !!config_data->ipv4s_len,
+                             (GDestroyNotify) nm_ip_route_unref);
 
     if (remote_s_ip) {
         guint len;
@@ -428,8 +539,8 @@ _nmc_mangle_connection(NMDevice                             *device,
         }
     }
 
-    for (i = 0; i < config_data->iproutes_len; ++i)
-        g_ptr_array_add(routes_new, config_data->iproutes_arr[i]);
+    for (i = 0; i < nm_g_ptr_array_len(config_data->iproutes); i++)
+        g_ptr_array_add(routes_new, _nm_ip_route_ref(config_data->iproutes->pdata[i]));
 
     addrs_changed = nmcs_setting_ip_replace_ipv4_addresses(s_ip,
                                                            (NMIPAddress **) addrs_new->pdata,
@@ -644,7 +755,7 @@ main(int argc, const char *const *argv)
     gs_free_error GError                                                     *error  = NULL;
     SigTermData                                                               sigterm_data;
 
-    _nm_logging_enabled_init(g_getenv(NMCS_ENV_VARIABLE("NM_CLOUD_SETUP_LOG")));
+    _nm_logging_enabled_init(g_getenv(NMCS_ENV_NM_CLOUD_SETUP_LOG));
 
     _LOGD("nm-cloud-setup %s starting...", NM_DIST_VERSION);
 
@@ -662,7 +773,7 @@ main(int argc, const char *const *argv)
     };
     sigterm_source = nm_g_unix_signal_add_source(SIGTERM, sigterm_handler, &sigterm_data);
 
-    provider = _provider_detect(sigterm_cancellable);
+    provider = _provider_detect(&sigterm_data);
     if (!provider)
         goto done;