diff options
Diffstat (limited to 'clients/cloud-setup/nmcs-provider-gcp.c')
| -rw-r--r-- | clients/cloud-setup/nmcs-provider-gcp.c | 278 |
1 files changed, 144 insertions, 134 deletions
diff --git a/clients/cloud-setup/nmcs-provider-gcp.c b/clients/cloud-setup/nmcs-provider-gcp.c index b4398fb8..1deaea10 100644 --- a/clients/cloud-setup/nmcs-provider-gcp.c +++ b/clients/cloud-setup/nmcs-provider-gcp.c @@ -1,6 +1,6 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include "nm-default.h" +#include "libnm/nm-default-client.h" #include "nmcs-provider-gcp.h" @@ -89,126 +89,97 @@ detect(NMCSProvider *provider, GTask *task) /*****************************************************************************/ typedef struct { - NMCSProviderGetConfigTaskData *config_data; - guint n_ifaces_pending; - GError * error; -} GCPData; - -typedef struct { + NMCSProviderGetConfigTaskData * get_config_data; NMCSProviderGetConfigIfaceData *iface_get_config; - GCPData * gcp_data; - gssize iface_idx; + gssize intern_iface_idx; + gssize extern_iface_idx; guint n_fips_pending; } GCPIfaceData; static void -_get_config_maybe_task_return(GCPData *gcp_data, GError *error_take) +_gcp_iface_data_destroy(GCPIfaceData *iface_data) { - NMCSProviderGetConfigTaskData *config_data = gcp_data->config_data; - - if (error_take) { - if (!gcp_data->error) - gcp_data->error = error_take; - else if (!nm_utils_error_is_cancelled(gcp_data->error) - && nm_utils_error_is_cancelled(error_take)) { - nm_clear_error(&gcp_data->error); - gcp_data->error = error_take; - } else - g_error_free(error_take); - } - - if (gcp_data->n_ifaces_pending > 0) - return; - - if (gcp_data->error) { - if (nm_utils_error_is_cancelled(gcp_data->error)) - _LOGD("get-config: cancelled"); - else - _LOGD("get-config: failed: %s", gcp_data->error->message); - g_task_return_error(config_data->task, g_steal_pointer(&gcp_data->error)); - } else { - _LOGD("get-config: success"); - g_task_return_pointer(config_data->task, - g_hash_table_ref(config_data->result_dict), - (GDestroyNotify) g_hash_table_unref); - } - - nm_g_slice_free(gcp_data); - g_object_unref(config_data->task); + nm_g_slice_free(iface_data); } static void _get_config_fip_cb(GObject *source, GAsyncResult *result, gpointer user_data) { + NMCSProviderGetConfigTaskData * get_config_data; NMCSProviderGetConfigIfaceData *iface_get_config; gs_unref_bytes GBytes *response = NULL; GCPIfaceData * iface_data = user_data; gs_free_error GError *error = NULL; - const char * fip_str = NULL; + gs_free char * ipaddr = NULL; NMIPRoute ** routes_arr; NMIPRoute * route_new; - GCPData * gcp_data; - - gcp_data = iface_data->gcp_data; nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); + if (nm_utils_error_is_cancelled(error)) + return; + + get_config_data = iface_data->get_config_data; + if (error) - goto iface_done; + goto out_done; - fip_str = g_bytes_get_data(response, NULL); - if (!nm_utils_ipaddr_valid(AF_INET, fip_str)) { + ipaddr = nmcs_utils_ipaddr_normalize_gbytes(AF_INET, response); + if (!ipaddr) { error = nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "forwarded-ip is not a valid ip address"); - goto iface_done; + goto out_done; } _LOGI("GCP interface[%" G_GSSIZE_FORMAT "]: adding forwarded-ip %s", - iface_data->iface_idx, - fip_str); + iface_data->intern_iface_idx, + ipaddr); - iface_get_config = iface_data->iface_get_config; - iface_get_config->iface_idx = iface_data->iface_idx; - routes_arr = iface_get_config->iproutes_arr; + iface_get_config = iface_data->iface_get_config; + routes_arr = iface_get_config->iproutes_arr; - route_new = nm_ip_route_new(AF_INET, fip_str, 32, NULL, 100, &error); + route_new = nm_ip_route_new(AF_INET, ipaddr, 32, NULL, 100, &error); if (error) - goto iface_done; + goto out_done; nm_ip_route_set_attribute(route_new, NM_IP_ROUTE_ATTRIBUTE_TYPE, g_variant_new_string("local")); routes_arr[iface_get_config->iproutes_len] = route_new; ++iface_get_config->iproutes_len; -iface_done: - --iface_data->n_fips_pending; - if (iface_data->n_fips_pending == 0) { - nm_g_slice_free(iface_data); - --gcp_data->n_ifaces_pending; +out_done: + if (!error) { + --iface_data->n_fips_pending; + if (iface_data->n_fips_pending > 0) + return; } - _get_config_maybe_task_return(gcp_data, g_steal_pointer(&error)); + --get_config_data->n_pending; + _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error)); } static void _get_config_ips_list_cb(GObject *source, GAsyncResult *result, gpointer user_data) { + NMCSProviderGetConfigTaskData *get_config_data; gs_unref_ptrarray GPtrArray *uri_arr = NULL; gs_unref_bytes GBytes *response = NULL; GCPIfaceData * iface_data = user_data; gs_free_error GError *error = NULL; const char * response_str = NULL; gsize response_len; - GCPData * gcp_data; const char * line; gsize line_len; guint i; - gcp_data = iface_data->gcp_data; - nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); + if (nm_utils_error_is_cancelled(error)) + return; + + get_config_data = iface_data->get_config_data; + if (error) - goto fips_error; + goto out_error; response_str = g_bytes_get_data(response, &response_len); /* NMHttpClient guarantees that there is a trailing NUL after the data. */ @@ -218,7 +189,7 @@ _get_config_ips_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat while (nm_utils_parse_next_line(&response_str, &response_len, &line, &line_len)) { gint64 fip_index; - /* Truncate the string. It's safe to do, because we own @response_data an it has an + /* Truncate the string. It's safe to do, because we own @response an it has an * extra NUL character after the buffer. */ ((char *) line)[line_len] = '\0'; @@ -228,19 +199,19 @@ _get_config_ips_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat g_ptr_array_add(uri_arr, g_strdup_printf("%" G_GSSIZE_FORMAT "/forwarded-ips/%" G_GINT64_FORMAT, - iface_data->iface_idx, + iface_data->intern_iface_idx, fip_index)); } iface_data->n_fips_pending = uri_arr->len; _LOGI("GCP interface[%" G_GSSIZE_FORMAT "]: found %u forwarded ips", - iface_data->iface_idx, + iface_data->intern_iface_idx, iface_data->n_fips_pending); if (iface_data->n_fips_pending == 0) { error = nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "found no forwarded ip"); - goto fips_error; + goto out_error; } iface_data->iface_get_config->iproutes_arr = g_new(NMIPRoute *, iface_data->n_fips_pending); @@ -256,7 +227,7 @@ _get_config_ips_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat HTTP_POLL_TIMEOUT_MS, HTTP_RATE_LIMIT_MS, NM_MAKE_STRV(NM_GCP_METADATA_HEADER), - g_task_get_cancellable(gcp_data->config_data->task), + get_config_data->intern_cancellable, NULL, NULL, _get_config_fip_cb, @@ -264,45 +235,80 @@ _get_config_ips_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat } return; -fips_error: - nm_g_slice_free(iface_data); - --gcp_data->n_ifaces_pending; - _get_config_maybe_task_return(gcp_data, g_steal_pointer(&error)); +out_error: + --get_config_data->n_pending; + _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error)); } static void _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data) { - gs_unref_bytes GBytes *response = NULL; - GCPIfaceData * iface_data = user_data; - gs_free_error GError *error = NULL; - gs_free const char * hwaddr = NULL; - gs_free const char * uri = NULL; - char sbuf[100]; - GCPData * gcp_data; - - gcp_data = iface_data->gcp_data; + gs_unref_bytes GBytes *response = NULL; + GCPIfaceData * iface_data = user_data; + gs_free_error GError * error = NULL; + gs_free char * v_hwaddr = NULL; + const char * hwaddr = NULL; + gs_free const char * uri = NULL; + char sbuf[100]; + NMCSProviderGetConfigTaskData *get_config_data; + gboolean is_requested; nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); + if (nm_utils_error_is_cancelled(error)) + return; + + get_config_data = iface_data->get_config_data; + if (error) - goto iface_error; + goto out_done; - hwaddr = nmcs_utils_hwaddr_normalize(g_bytes_get_data(response, NULL), -1); - iface_data->iface_get_config = g_hash_table_lookup(gcp_data->config_data->result_dict, hwaddr); - if (!iface_data->iface_get_config) { - _LOGI("GCP interface[%" G_GSSIZE_FORMAT "]: did not find a matching device", - iface_data->iface_idx); + v_hwaddr = nmcs_utils_hwaddr_normalize_gbytes(response); + if (!v_hwaddr) { + _LOGI("GCP interface[%" G_GSSIZE_FORMAT "]: invalid MAC address returned", + iface_data->intern_iface_idx); error = nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, - "no matching hwaddr found for GCP interface"); - goto iface_error; + "invalid MAC address for index %" G_GSSIZE_FORMAT, + iface_data->intern_iface_idx); + goto out_done; + } + + if (!g_hash_table_lookup_extended(get_config_data->result_dict, + v_hwaddr, + (gpointer *) &hwaddr, + (gpointer *) &iface_data->iface_get_config)) { + if (!get_config_data->any) { + _LOGD("get-config: skip fetching meta data for %s (%" G_GSSIZE_FORMAT ")", + v_hwaddr, + iface_data->intern_iface_idx); + goto out_done; + } + iface_data->iface_get_config = nmcs_provider_get_config_iface_data_new(FALSE); + g_hash_table_insert(get_config_data->result_dict, + (char *) (hwaddr = g_steal_pointer(&v_hwaddr)), + iface_data->iface_get_config); + is_requested = FALSE; + } else { + if (iface_data->iface_get_config->iface_idx >= 0) { + _LOGI("GCP interface[%" G_GSSIZE_FORMAT "]: duplicate MAC address %s returned", + iface_data->intern_iface_idx, + hwaddr); + error = nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, + "duplicate MAC address for index %" G_GSSIZE_FORMAT, + iface_data->intern_iface_idx); + goto out_done; + } + is_requested = TRUE; } - _LOGI("GCP interface[%" G_GSSIZE_FORMAT "]: found a matching device with hwaddr %s", - iface_data->iface_idx, + iface_data->iface_get_config->iface_idx = iface_data->extern_iface_idx; + + _LOGI("GCP interface[%" G_GSSIZE_FORMAT "]: found a %sdevice with hwaddr %s", + iface_data->intern_iface_idx, + is_requested ? "requested " : "", hwaddr); - nm_sprintf_buf(sbuf, "%" G_GSSIZE_FORMAT "/forwarded-ips/", iface_data->iface_idx); + nm_sprintf_buf(sbuf, "%" G_GSSIZE_FORMAT "/forwarded-ips/", iface_data->intern_iface_idx); nm_http_client_poll_get(NM_HTTP_CLIENT(source), (uri = _gcp_uri_interfaces(sbuf)), @@ -311,17 +317,16 @@ _get_config_iface_cb(GObject *source, GAsyncResult *result, gpointer user_data) HTTP_POLL_TIMEOUT_MS, HTTP_RATE_LIMIT_MS, NM_MAKE_STRV(NM_GCP_METADATA_HEADER), - g_task_get_cancellable(gcp_data->config_data->task), + get_config_data->intern_cancellable, NULL, NULL, _get_config_ips_list_cb, iface_data); return; -iface_error: - nm_g_slice_free(iface_data); - --gcp_data->n_ifaces_pending; - _get_config_maybe_task_return(gcp_data, g_steal_pointer(&error)); +out_done: + --get_config_data->n_pending; + _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error)); } static void @@ -329,18 +334,24 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat { gs_unref_ptrarray GPtrArray *ifaces_arr = NULL; gs_unref_bytes GBytes *response = NULL; - gs_free_error GError *error = NULL; - GCPData * gcp_data = user_data; - const char * response_str; - gsize response_len; - const char * line; - gsize line_len; - guint i; + gs_free_error GError * error = NULL; + NMCSProviderGetConfigTaskData *get_config_data; + const char * response_str; + gsize response_len; + const char * line; + gsize line_len; + guint i; + gssize extern_iface_idx_cnt = 0; nm_http_client_poll_get_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); + if (nm_utils_error_is_cancelled(error)) + return; + + get_config_data = user_data; + if (error) { - _get_config_maybe_task_return(gcp_data, g_steal_pointer(&error)); + _nmcs_provider_get_config_task_maybe_return(get_config_data, g_steal_pointer(&error)); return; } @@ -348,47 +359,56 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat /* NMHttpClient guarantees that there is a trailing NUL after the data. */ nm_assert(response_str[response_len] == 0); - ifaces_arr = g_ptr_array_new(); + ifaces_arr = g_ptr_array_new_with_free_func((GDestroyNotify) _gcp_iface_data_destroy); while (nm_utils_parse_next_line(&response_str, &response_len, &line, &line_len)) { GCPIfaceData *iface_data; - gssize iface_idx; + gssize intern_iface_idx; if (line_len == 0) continue; - /* Truncate the string. It's safe to do, because we own @response_data an it has an + /* Truncate the string. It's safe to do, because we own @response an it has an * extra NUL character after the buffer. */ ((char *) line)[line_len] = '\0'; if (line[line_len - 1] == '/') ((char *) line)[--line_len] = '\0'; - iface_idx = _nm_utils_ascii_str_to_int64(line, 10, 0, G_MAXSSIZE, -1); - if (iface_idx < 0) + intern_iface_idx = _nm_utils_ascii_str_to_int64(line, 10, 0, G_MAXSSIZE, -1); + if (intern_iface_idx < 0) continue; iface_data = g_slice_new(GCPIfaceData); *iface_data = (GCPIfaceData){ + .get_config_data = get_config_data, .iface_get_config = NULL, - .gcp_data = gcp_data, - .iface_idx = iface_idx, + .intern_iface_idx = intern_iface_idx, + .extern_iface_idx = extern_iface_idx_cnt++, .n_fips_pending = 0, }; g_ptr_array_add(ifaces_arr, iface_data); } - gcp_data->n_ifaces_pending = ifaces_arr->len; _LOGI("found GCP interfaces: %u", ifaces_arr->len); + if (ifaces_arr->len == 0) { + _nmcs_provider_get_config_task_maybe_return( + get_config_data, + nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "no GCP interfaces found")); + return; + } + for (i = 0; i < ifaces_arr->len; ++i) { GCPIfaceData * data = ifaces_arr->pdata[i]; gs_free const char *uri = NULL; char sbuf[100]; - _LOGD("GCP interface[%" G_GSSIZE_FORMAT "]: retrieving configuration", data->iface_idx); + _LOGD("GCP interface[%" G_GSSIZE_FORMAT "]: retrieving configuration", + data->intern_iface_idx); - nm_sprintf_buf(sbuf, "%" G_GSSIZE_FORMAT "/mac", data->iface_idx); + nm_sprintf_buf(sbuf, "%" G_GSSIZE_FORMAT "/mac", data->intern_iface_idx); + get_config_data->n_pending++; nm_http_client_poll_get(NM_HTTP_CLIENT(source), (uri = _gcp_uri_interfaces(sbuf)), HTTP_TIMEOUT_MS, @@ -396,31 +416,21 @@ _get_net_ifaces_list_cb(GObject *source, GAsyncResult *result, gpointer user_dat HTTP_POLL_TIMEOUT_MS, HTTP_RATE_LIMIT_MS, NM_MAKE_STRV(NM_GCP_METADATA_HEADER), - g_task_get_cancellable(gcp_data->config_data->task), + get_config_data->intern_cancellable, NULL, NULL, _get_config_iface_cb, data); } - if (ifaces_arr->len == 0) { - error = nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "no GCP interfaces found"); - _get_config_maybe_task_return(gcp_data, g_steal_pointer(&error)); - } + get_config_data->extra_data = g_steal_pointer(&ifaces_arr); + get_config_data->extra_data_destroy = (GDestroyNotify) g_ptr_array_unref; } static void get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_data) { gs_free const char *uri = NULL; - GCPData * gcp_data; - - gcp_data = g_slice_new(GCPData); - *gcp_data = (GCPData){ - .config_data = get_config_data, - .n_ifaces_pending = 0, - .error = NULL, - }; nm_http_client_poll_get(nmcs_provider_get_http_client(provider), (uri = _gcp_uri_interfaces()), @@ -429,11 +439,11 @@ get_config(NMCSProvider *provider, NMCSProviderGetConfigTaskData *get_config_dat HTTP_POLL_TIMEOUT_MS, HTTP_RATE_LIMIT_MS, NM_MAKE_STRV(NM_GCP_METADATA_HEADER), - g_task_get_cancellable(gcp_data->config_data->task), + get_config_data->intern_cancellable, NULL, NULL, _get_net_ifaces_list_cb, - gcp_data); + get_config_data); } /*****************************************************************************/ |