From d38cbfb3d1ec43d953f484b39fcc6c6128e7bf3b Mon Sep 17 00:00:00 2001 From: Tomas Bzatek Date: Tue, 10 Dec 2024 19:22:14 +0100 Subject: [PATCH] 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 --- 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 09e5eb12d..cf2c3c162 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 */