File 0102-initrd-VLAN-support-for-the-NBFT-parser.patch of Package NetworkManager

From ca72e693cf754613f533a6f5dd2703fbb606261f Mon Sep 17 00:00:00 2001
From: Tomas Bzatek <tbzatek@redhat.com>
Date: Tue, 10 Dec 2024 19:22:14 +0100
Subject: [PATCH 102/106] initrd: VLAN support for the NBFT parser

Creates additional connections for VLANs, which are in fact
separate HFI records in the NBFT table. Uses MAC address for
linking parent interface as the interface naming is defined
by an external service.

Signed-off-by: Tomas Bzatek <tbzatek@redhat.com>
---
 src/nm-initrd-generator/nmi-nbft-reader.c | 164 ++++++++++++++++------
 1 file changed, 122 insertions(+), 42 deletions(-)

diff --git a/src/nm-initrd-generator/nmi-nbft-reader.c b/src/nm-initrd-generator/nmi-nbft-reader.c
index 09e5eb1..cf2c3c1 100644
--- a/src/nm-initrd-generator/nmi-nbft-reader.c
+++ b/src/nm-initrd-generator/nmi-nbft-reader.c
@@ -61,45 +61,57 @@ load_libnvme(void)
     return handle;
 }
 
-static NMConnection *
-parse_hfi(struct nbft_info_hfi *hfi, int iface_idx, char **hostname)
+static char *
+format_conn_name(const char *table_name, struct nbft_info_hfi *hfi, gboolean is_vlan)
 {
-    gs_unref_object NMConnection         *connection;
-    NMSetting                            *s_connection;
-    NMSetting                            *s_wired;
-    gs_free char                         *hwaddr = NULL;
-    gs_free char                         *ifname = NULL;
-    gs_unref_object NMSetting            *s_ip4  = NULL;
-    gs_unref_object NMSetting            *s_ip6  = NULL;
-    nm_auto_unref_ip_address NMIPAddress *ipaddr = NULL;
-    gs_free_error GError                 *error  = NULL;
-    int                                   family = AF_UNSPEC;
-    NMIPAddr                              addr_bin;
+    if (is_vlan) {
+        nm_assert(hfi->tcp_info.vlan > 0);
+        return g_strdup_printf("%s connection HFI %d VLAN %d",
+                               table_name,
+                               hfi->index,
+                               hfi->tcp_info.vlan);
+    } else
+        return g_strdup_printf("%s connection HFI %d", table_name, hfi->index);
+}
 
-    /* Pre-checks */
-    if (!nm_inet_parse_bin_full(family, FALSE, hfi->tcp_info.ipaddr, &family, &addr_bin)) {
-        _LOGW(LOGD_CORE, "NBFT: Malformed IP address: '%s'", hfi->tcp_info.ipaddr);
-        return NULL;
+static NMConnection *
+find_conn_for_wired_mac(GPtrArray *a, const char *hwaddr)
+{
+    guint i;
+
+    for (i = 0; i < a->len; i++) {
+        NMConnection   *con = a->pdata[i];
+        NMSettingWired *s_wired;
+
+        if (!nm_connection_is_type(con, NM_SETTING_WIRED_SETTING_NAME))
+            continue;
+        s_wired = nm_connection_get_setting_wired(con);
+        if (!s_wired)
+            continue;
+        if (nm_streq(hwaddr, nm_setting_wired_get_mac_address(s_wired)))
+            return con;
     }
+    return NULL;
+}
 
-    ifname = g_strdup_printf("NBFT connection %d", iface_idx);
-    hwaddr = g_strdup_printf("%02x:%02x:%02x:%02x:%02x:%02x",
-                             hfi->tcp_info.mac_addr[0],
-                             hfi->tcp_info.mac_addr[1],
-                             hfi->tcp_info.mac_addr[2],
-                             hfi->tcp_info.mac_addr[3],
-                             hfi->tcp_info.mac_addr[4],
-                             hfi->tcp_info.mac_addr[5]);
+static NMConnection *
+create_wired_conn(struct nbft_info_hfi *hfi,
+                  const char           *conn_name,
+                  const char           *hwaddr,
+                  gboolean              is_vlan)
+{
+    NMConnection *connection;
+    NMSetting    *s_connection;
+    NMSetting    *s_wired;
 
-    /* Create new connection */
     connection = nm_simple_connection_new();
 
     s_connection = nm_setting_connection_new();
     g_object_set(s_connection,
                  NM_SETTING_CONNECTION_TYPE,
-                 NM_SETTING_WIRED_SETTING_NAME,
+                 is_vlan ? NM_SETTING_VLAN_SETTING_NAME : NM_SETTING_WIRED_SETTING_NAME,
                  NM_SETTING_CONNECTION_ID,
-                 ifname,
+                 conn_name,
                  NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY,
                  NMI_AUTOCONNECT_PRIORITY_FIRMWARE,
                  NULL);
@@ -110,7 +122,80 @@ parse_hfi(struct nbft_info_hfi *hfi, int iface_idx, char **hostname)
     g_object_set(s_wired, NM_SETTING_WIRED_MAC_ADDRESS, hwaddr, NULL);
     nm_connection_add_setting(connection, s_wired);
 
-    /* TODO: hfi->tcp_info.vlan */
+    return connection;
+}
+
+static void
+parse_hfi(GPtrArray *a, struct nbft_info_hfi *hfi, const char *table_name, char **hostname)
+{
+    gs_unref_object NMConnection         *connection = NULL;
+    NMConnection                         *parent_connection;
+    NMSetting                            *s_vlan;
+    gs_free char                         *hwaddr    = NULL;
+    gs_free char                         *conn_name = NULL;
+    gs_unref_object NMSetting            *s_ip4     = NULL;
+    gs_unref_object NMSetting            *s_ip6     = NULL;
+    nm_auto_unref_ip_address NMIPAddress *ipaddr    = NULL;
+    guint                                 prefix;
+    gs_free_error GError                 *error  = NULL;
+    int                                   family = AF_UNSPEC;
+    NMIPAddr                              addr_bin;
+
+    /* Pre-checks */
+    if (!nm_inet_parse_bin_full(family, FALSE, hfi->tcp_info.ipaddr, &family, &addr_bin)) {
+        _LOGW(LOGD_CORE, "NBFT: Malformed IP address: '%s'", hfi->tcp_info.ipaddr);
+        return;
+    }
+
+    /* MAC address */
+    hwaddr = g_strdup_printf("%02X:%02X:%02X:%02X:%02X:%02X",
+                             hfi->tcp_info.mac_addr[0],
+                             hfi->tcp_info.mac_addr[1],
+                             hfi->tcp_info.mac_addr[2],
+                             hfi->tcp_info.mac_addr[3],
+                             hfi->tcp_info.mac_addr[4],
+                             hfi->tcp_info.mac_addr[5]);
+
+    /* First check if we need VLANs */
+    if (hfi->tcp_info.vlan > 0) {
+        parent_connection = find_conn_for_wired_mac(a, hwaddr);
+        if (!parent_connection) {
+            /* Create new parent wired connection */
+            conn_name         = format_conn_name(table_name, hfi, FALSE);
+            parent_connection = create_wired_conn(hfi, conn_name, hwaddr, FALSE);
+
+            s_ip4 = nm_setting_ip4_config_new();
+            s_ip6 = nm_setting_ip6_config_new();
+            g_object_set(s_ip4,
+                         NM_SETTING_IP_CONFIG_METHOD,
+                         NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
+                         NULL);
+            g_object_set(s_ip6,
+                         NM_SETTING_IP_CONFIG_METHOD,
+                         NM_SETTING_IP6_CONFIG_METHOD_DISABLED,
+                         NULL);
+            nm_connection_add_setting(parent_connection, g_steal_pointer(&s_ip4));
+            nm_connection_add_setting(parent_connection, g_steal_pointer(&s_ip6));
+
+            if (!nm_connection_normalize(parent_connection, NULL, NULL, &error)) {
+                _LOGW(LOGD_CORE, "Generated an invalid connection: %s", error->message);
+                g_object_unref(parent_connection);
+                return;
+            }
+            g_ptr_array_add(a, parent_connection);
+        }
+
+        conn_name  = format_conn_name(table_name, hfi, TRUE);
+        connection = create_wired_conn(hfi, conn_name, hwaddr, TRUE);
+
+        s_vlan = nm_setting_vlan_new();
+        g_object_set(s_vlan, NM_SETTING_VLAN_ID, hfi->tcp_info.vlan, NULL);
+        nm_connection_add_setting(connection, s_vlan);
+    } else {
+        /* No VLANS */
+        conn_name  = format_conn_name(table_name, hfi, FALSE);
+        connection = create_wired_conn(hfi, conn_name, hwaddr, FALSE);
+    }
 
     /* IP addresses */
     s_ip4 = nm_setting_ip4_config_new();
@@ -149,7 +234,7 @@ parse_hfi(struct nbft_info_hfi *hfi, int iface_idx, char **hostname)
                       hfi->tcp_info.ipaddr,
                       hfi->tcp_info.subnet_mask_prefix,
                       error->message);
-                return NULL;
+                return;
             }
             nm_setting_ip_config_add_address(NM_SETTING_IP_CONFIG(s_ip4), ipaddr);
             if (is_valid_addr(AF_INET, hfi->tcp_info.gateway_ipaddr)) {
@@ -204,7 +289,7 @@ parse_hfi(struct nbft_info_hfi *hfi, int iface_idx, char **hostname)
                       hfi->tcp_info.ipaddr,
                       prefix,
                       error->message);
-                return NULL;
+                return;
             }
             nm_setting_ip_config_add_address(NM_SETTING_IP_CONFIG(s_ip6), ipaddr);
             if (is_valid_addr(AF_INET6, hfi->tcp_info.gateway_ipaddr)) {
@@ -246,9 +331,10 @@ parse_hfi(struct nbft_info_hfi *hfi, int iface_idx, char **hostname)
 
     if (!nm_connection_normalize(connection, NULL, NULL, &error)) {
         _LOGW(LOGD_CORE, "Generated an invalid connection: %s", error->message);
-        return NULL;
+        return;
     }
-    return g_steal_pointer(&connection);
+
+    g_ptr_array_add(a, g_steal_pointer(&connection));
 }
 
 NMConnection **
@@ -260,7 +346,6 @@ nmi_nbft_reader_parse(const char *sysfs_dir, char **hostname)
     GDir                             *dir;
     void                             *libnvme_handle = NULL;
     const char                       *entry_name;
-    int                               idx = 1;
 
     g_return_val_if_fail(sysfs_dir != NULL, NULL);
     path = g_build_filename(sysfs_dir, "firmware", "acpi", "tables", NULL);
@@ -293,9 +378,7 @@ nmi_nbft_reader_parse(const char *sysfs_dir, char **hostname)
             continue;
         }
 
-        for (hfi = nbft->hfi_list; hfi && *hfi; hfi++, idx++) {
-            NMConnection *connection;
-
+        for (hfi = nbft->hfi_list; hfi && *hfi; hfi++) {
             if (!nm_streq((*hfi)->transport, "tcp")) {
                 _LOGW(LOGD_CORE,
                       "NBFT table %s, HFI descriptor %d: unsupported transport type '%s'",
@@ -304,10 +387,7 @@ nmi_nbft_reader_parse(const char *sysfs_dir, char **hostname)
                       (*hfi)->transport);
                 continue;
             }
-
-            connection = parse_hfi(*hfi, idx, hostname);
-            if (connection)
-                g_ptr_array_add(a, connection);
+            parse_hfi(a, *hfi, entry_name, hostname);
         }
 
         _nvme_nbft_free(nbft);
@@ -316,7 +396,7 @@ nmi_nbft_reader_parse(const char *sysfs_dir, char **hostname)
     g_dir_close(dir);
     dlclose(libnvme_handle);
     g_ptr_array_add(a, NULL); /* trailing NULL-delimiter */
-    return (NMConnection **) g_ptr_array_free(a, FALSE);
+    return (NMConnection **) g_ptr_array_free(g_steal_pointer(&a), FALSE);
 }
 
 #else /* WITH_NBFT */
-- 
2.49.0

openSUSE Build Service is sponsored by