summary refs log tree commit diff
path: root/src/nm-cloud-setup/nmcs-provider-oci.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-cloud-setup/nmcs-provider-oci.c')
-rw-r--r--src/nm-cloud-setup/nmcs-provider-oci.c77
1 files changed, 75 insertions, 2 deletions
diff --git a/src/nm-cloud-setup/nmcs-provider-oci.c b/src/nm-cloud-setup/nmcs-provider-oci.c
index b0b0edf9..17cd997e 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: