diff --git a/src/nm-cloud-setup/nmcs-provider-oci.c b/src/nm-cloud-setup/nmcs-provider-oci.c index b0b0edf9a..17cd997ef 100644 --- a/src/nm-cloud-setup/nmcs-provider-oci.c +++ b/src/nm-cloud-setup/nmcs-provider-oci.c @@ -92,6 +92,9 @@ _get_config_done_cb(GObject *source, GAsyncResult *result, gpointer user_data) gs_unref_bytes GBytes *response = NULL; gs_free_error GError *error = NULL; nm_auto_decref_json json_t *vnics = NULL; + gboolean is_baremetal; + gs_unref_ptrarray GPtrArray *phys_nic_macs = NULL; + GHashTableIter h_iter; size_t i; nm_http_client_poll_req_finish(NM_HTTP_CLIENT(source), result, NULL, &response, &error); @@ -112,12 +115,24 @@ _get_config_done_cb(GObject *source, GAsyncResult *result, gpointer user_data) goto out; } + if (json_array_size(vnics) > 0) { + is_baremetal = NULL != json_object_get(json_array_get(vnics, 0), "nicIndex"); + _LOGI("get-config: detected %s instance", is_baremetal ? "baremetal" : "VM"); + } else { + is_baremetal = FALSE; + _LOGI("get-config: empty VNICs metadata, cannot detect instance type"); + } + + if (is_baremetal) + phys_nic_macs = g_ptr_array_sized_new(16); + for (i = 0; i < json_array_size(vnics); i++) { json_t *vnic, *field; const char *vnic_id = "", *val; gs_free char *mac = NULL; in_addr_t addr; int prefix; + json_int_t nic_index = -1, vlan_tag = -1; vnic = json_array_get(vnics, i); if (!json_is_object(vnic)) { @@ -130,12 +145,28 @@ _get_config_done_cb(GObject *source, GAsyncResult *result, gpointer user_data) field = json_object_get(vnic, "macAddr"); val = field && json_is_string(field) ? json_string_value(field) : NULL; - if (!val) { + mac = val ? nmcs_utils_hwaddr_normalize(val, json_string_length(field)) : NULL; + if (!mac) { _VNIC_WARN("missing or invalid 'macAddr', ignoring VNIC"); continue; } - mac = nmcs_utils_hwaddr_normalize(val, json_string_length(field)); + if (is_baremetal) { + field = json_object_get(vnic, "nicIndex"); + nic_index = field && json_is_integer(field) ? json_integer_value(field) : -1; + if (nic_index < 0 || nic_index >= 1024) { /* 1024 = random limit to prevent abuse*/ + _VNIC_WARN("missing or invalid 'nicIndex', ignoring VNIC"); + continue; + } + + field = json_object_get(vnic, "vlanTag"); + vlan_tag = field && json_is_integer(field) ? json_integer_value(field) : -1; + if (vlan_tag < 0) { + _VNIC_WARN("missing or invalid 'vlanTag', ignoring VNIC"); + continue; + } + } + config_iface_data = nmcs_provider_get_config_iface_data_create(get_config_data, FALSE, mac); config_iface_data->iface_idx = i; @@ -168,6 +199,48 @@ _get_config_done_cb(GObject *source, GAsyncResult *result, gpointer user_data) } else { _VNIC_WARN("missing or invalid 'subnetCidrBlock'"); } + + if (is_baremetal) { + gboolean is_phys_nic = vlan_tag == 0; + + /* In baremetal instances, configure VNICs' VLAN (physical NICs don't need it) */ + if (is_phys_nic) { + config_iface_data->priv.oci.vlan_tag = 0; + config_iface_data->priv.oci.parent_hwaddr = NULL; + if (nic_index >= phys_nic_macs->len) + g_ptr_array_set_size(phys_nic_macs, + NM_MAX((guint) (nic_index + 1), phys_nic_macs->len * 2)); + phys_nic_macs->pdata[nic_index] = (gpointer) config_iface_data->hwaddr; + } else { + /* We might not have all the physical NICs' MACs yet, save nicIndex for later */ + config_iface_data->priv.oci.parent_hwaddr = GINT_TO_POINTER((int) nic_index); + config_iface_data->priv.oci.vlan_tag = vlan_tag; + } + } + } + + if (is_baremetal) { + g_hash_table_iter_init(&h_iter, get_config_data->result_dict); + + /* Now that all the metadata is processed we should have all the physical NICs' MACs */ + while (g_hash_table_iter_next(&h_iter, NULL, (gpointer *) &config_iface_data)) { + bool is_phys_nic = config_iface_data->priv.oci.vlan_tag == 0; + int nic_index = GPOINTER_TO_INT(config_iface_data->priv.oci.parent_hwaddr); + + if (is_phys_nic) + continue; + + if (nic_index >= phys_nic_macs->len || phys_nic_macs->pdata[nic_index] == NULL) { + _LOGW("get-config: physical NIC for nicIndex=%d not found, ignoring VNIC " + "(VNIC macAddr=%s)", + nic_index, + config_iface_data->hwaddr); + g_hash_table_iter_remove(&h_iter); + continue; + } + + config_iface_data->priv.oci.parent_hwaddr = g_strdup(phys_nic_macs->pdata[nic_index]); + } } out: diff --git a/src/nm-cloud-setup/nmcs-provider.c b/src/nm-cloud-setup/nmcs-provider.c index 0f06c4e22..251749ba7 100644 --- a/src/nm-cloud-setup/nmcs-provider.c +++ b/src/nm-cloud-setup/nmcs-provider.c @@ -188,6 +188,7 @@ nmcs_provider_get_config_iface_data_create(NMCSProviderGetConfigTaskData *get_co iface_data = g_slice_new(NMCSProviderGetConfigIfaceData); *iface_data = (NMCSProviderGetConfigIfaceData) { + .provider = g_object_ref(get_config_data->self), .get_config_data = get_config_data, .hwaddr = g_strdup(hwaddr), .iface_idx = -1, @@ -203,6 +204,11 @@ nmcs_provider_get_config_iface_data_create(NMCSProviderGetConfigTaskData *get_co iface_data->priv.aliyun = (typeof(iface_data->priv.aliyun)) { .has_primary_ip_address = FALSE, }; + } else if (G_OBJECT_TYPE(get_config_data->self) == nmcs_provider_oci_get_type()) { + iface_data->priv.oci = (typeof(iface_data->priv.oci)) { + .vlan_tag = 0, + .parent_hwaddr = NULL, + }; } /* the has does not own the key (iface_datta->hwaddr), the lifetime of the @@ -220,6 +226,9 @@ _iface_data_free(gpointer data) g_free(iface_data->ipv4s_arr); nm_g_ptr_array_unref(iface_data->iproutes); g_free((char *) iface_data->hwaddr); + if (G_OBJECT_TYPE(iface_data->provider) == nmcs_provider_oci_get_type()) + g_free((char *) iface_data->priv.oci.parent_hwaddr); + g_clear_object(&iface_data->provider); nm_g_slice_free(iface_data); } diff --git a/src/nm-cloud-setup/nmcs-provider.h b/src/nm-cloud-setup/nmcs-provider.h index 98e50ea37..95a591c65 100644 --- a/src/nm-cloud-setup/nmcs-provider.h +++ b/src/nm-cloud-setup/nmcs-provider.h @@ -17,6 +17,8 @@ typedef struct { * dictionary. */ const char *hwaddr; + struct _NMCSProvider *provider; + struct _NMCSProviderGetConfigTaskData *get_config_data; in_addr_t *ipv4s_arr; @@ -51,6 +53,10 @@ typedef struct { bool has_primary_ip_address : 1; bool ipv4s_arr_ordered : 1; } aliyun; + struct { + guint32 vlan_tag; /* 0 if no VLAN is needed */ + const char *parent_hwaddr; + } oci; } priv; } NMCSProviderGetConfigIfaceData;