From fb43f2aa0bae0be6681eef8098b54efc989ecb9b Mon Sep 17 00:00:00 2001 From: Packit Service Date: Apr 07 2021 22:22:23 +0000 Subject: Apply patch 1021-initrd-vlan-fixes-rh1903695-rh1903698.patch patch_name: 1021-initrd-vlan-fixes-rh1903695-rh1903698.patch present_in_specfile: true location_in_specfile: 23 --- diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index b17c8d1..f33949e 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -1771,6 +1771,17 @@ GSource *nm_utils_g_main_context_create_integrate_source (GMainContext *internal /*****************************************************************************/ +static inline GPtrArray * +nm_strv_ptrarray_ensure (GPtrArray **p_arr) +{ + nm_assert (p_arr); + + if (G_UNLIKELY (!*p_arr)) + *p_arr = g_ptr_array_new_with_free_func (g_free); + + return *p_arr; +} + static inline void nm_strv_ptrarray_add_string_take (GPtrArray *cmd, char *str) @@ -1809,6 +1820,22 @@ nm_strv_ptrarray_take_gstring (GPtrArray *cmd, FALSE)); } +static inline gssize +nm_strv_ptrarray_find_first (const GPtrArray *strv, + const char *str) +{ + if (!strv) + return -1; + return nm_utils_strv_find_first ((char **) strv->pdata, strv->len, str); +} + +static inline gboolean +nm_strv_ptrarray_contains (const GPtrArray *strv, + const char *str) +{ + return nm_strv_ptrarray_find_first (strv, str) >= 0; +} + /*****************************************************************************/ int nm_utils_getpagesize (void); diff --git a/src/initrd/nm-initrd-generator.h b/src/initrd/nm-initrd-generator.h index 8e17f04..e7647ed 100644 --- a/src/initrd/nm-initrd-generator.h +++ b/src/initrd/nm-initrd-generator.h @@ -11,17 +11,23 @@ #define NMI_WAIT_DEVICE_TIMEOUT_MS 60000 -static inline gboolean -guess_ip_address_family (const char *str) +static inline int +get_ip_address_family (const char *str, gboolean with_prefix) { - if (str == NULL) - return AF_UNSPEC; - else if (strchr (str, '.')) - return AF_INET; - else if (strchr (str, ':')) - return AF_INET6; - else + int addr_family; + + if (!str) return AF_UNSPEC; + + if (with_prefix) { + if (nm_utils_parse_inaddr_prefix_bin (AF_UNSPEC, str, &addr_family, NULL, NULL)) + return addr_family; + } else { + if (nm_utils_parse_inaddr_bin (AF_UNSPEC, str, &addr_family, NULL)) + return addr_family; + } + + return AF_UNSPEC; } GHashTable *nmi_ibft_read (const char *sysfs_dir); diff --git a/src/initrd/nmi-cmdline-reader.c b/src/initrd/nmi-cmdline-reader.c index 257ba3d..f94cc7d 100644 --- a/src/initrd/nmi-cmdline-reader.c +++ b/src/initrd/nmi-cmdline-reader.c @@ -21,6 +21,8 @@ typedef struct { GHashTable *hash; GPtrArray *array; + GPtrArray *vlan_parents; + GHashTable *explicit_ip_connections; NMConnection *bootdev_connection; /* connection for bootdev=$ifname */ NMConnection *default_connection; /* connection not bound to any ifname */ char *hostname; @@ -38,7 +40,9 @@ reader_new (void) reader = g_slice_new (Reader); *reader = (Reader) { - .hash = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_object_unref), + .hash = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_object_unref), + .explicit_ip_connections = g_hash_table_new_full (nm_direct_hash, NULL, g_object_unref, NULL), + .vlan_parents = g_ptr_array_new_with_free_func (g_free), .array = g_ptr_array_new (), }; @@ -51,6 +55,8 @@ reader_destroy (Reader *reader, gboolean free_hash) gs_unref_hashtable GHashTable *hash = NULL; g_ptr_array_unref (reader->array); + g_ptr_array_unref (reader->vlan_parents); + g_hash_table_unref (reader->explicit_ip_connections); hash = g_steal_pointer (&reader->hash); nm_clear_g_free (&reader->hostname); nm_clear_g_free (&reader->dhcp4_vci); @@ -385,7 +391,7 @@ reader_parse_ip (Reader *reader, const char *sysfs_dir, char *argument) /* ip={dhcp|on|any|dhcp6|auto6|ibft} */ kind = tmp; } else { - client_ip_family = guess_ip_address_family (tmp); + client_ip_family = get_ip_address_family (tmp, TRUE); if (client_ip_family != AF_UNSPEC) { /* :[]:::: */ client_ip = tmp; @@ -411,11 +417,11 @@ reader_parse_ip (Reader *reader, const char *sysfs_dir, char *argument) kind = get_word (&argument, ':'); tmp = get_word (&argument, ':'); - dns_addr_family[0] = guess_ip_address_family (tmp); + dns_addr_family[0] = get_ip_address_family (tmp, FALSE); if (dns_addr_family[0] != AF_UNSPEC) { dns[0] = tmp; dns[1] = get_word (&argument, ':'); - dns_addr_family[1] = guess_ip_address_family (dns[1]); + dns_addr_family[1] = get_ip_address_family (dns[1], FALSE); if (*argument) _LOGW (LOGD_CORE, "Ignoring extra: '%s'.", argument); } else { @@ -436,6 +442,8 @@ reader_parse_ip (Reader *reader, const char *sysfs_dir, char *argument) else connection = reader_get_default_connection (reader); + g_hash_table_add (reader->explicit_ip_connections, g_object_ref (connection)); + s_ip4 = nm_connection_get_setting_ip4_config (connection); s_ip6 = nm_connection_get_setting_ip6_config (connection); @@ -475,9 +483,8 @@ reader_parse_ip (Reader *reader, const char *sysfs_dir, char *argument) _LOGW (LOGD_CORE, "Invalid address '%s': %s", client_ip, error->message); g_clear_error (&error); } - } else { - _LOGW (LOGD_CORE, "Unrecognized address: %s", client_ip); - } + } else + nm_assert_not_reached (); if (address) { switch (client_ip_family) { @@ -496,7 +503,7 @@ reader_parse_ip (Reader *reader, const char *sysfs_dir, char *argument) nm_setting_ip_config_add_address (s_ip6, address); break; default: - _LOGW (LOGD_CORE, "Unknown address family: %s", client_ip); + nm_assert_not_reached (); break; } nm_ip_address_unref (address); @@ -579,22 +586,16 @@ reader_parse_ip (Reader *reader, const char *sysfs_dir, char *argument) _LOGW (LOGD_CORE, "Ignoring peer: %s (not implemented)\n", peer); if (gateway_ip && *gateway_ip) { - int addr_family = guess_ip_address_family (gateway_ip); - - if (nm_utils_ipaddr_is_valid (addr_family, gateway_ip)) { - switch (addr_family) { - case AF_INET: - g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway_ip, NULL); - break; - case AF_INET6: - g_object_set (s_ip6, NM_SETTING_IP_CONFIG_GATEWAY, gateway_ip, NULL); - break; - default: - _LOGW (LOGD_CORE, "Unknown address family: %s", gateway_ip); - break; - } - } else { + switch (get_ip_address_family (gateway_ip, FALSE)) { + case AF_INET: + g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway_ip, NULL); + break; + case AF_INET6: + g_object_set (s_ip6, NM_SETTING_IP_CONFIG_GATEWAY, gateway_ip, NULL); + break; + default: _LOGW (LOGD_CORE, "Invalid gateway: %s", gateway_ip); + break; } } @@ -796,6 +797,9 @@ reader_parse_vlan (Reader *reader, char *argument) if (argument && *argument) _LOGW (LOGD_CORE, "Ignoring extra: '%s'.", argument); + + if (!nm_strv_ptrarray_contains (reader->vlan_parents, phy)) + g_ptr_array_add (reader->vlan_parents, g_strdup (phy)); } static void @@ -893,7 +897,7 @@ reader_add_nameservers (Reader *reader, GPtrArray *nameservers) for (i = 0; i < nameservers->len; i++) { ns = nameservers->pdata[i]; - addr_family = guess_ip_address_family (ns); + addr_family = get_ip_address_family (ns, FALSE); if (addr_family == AF_UNSPEC) { _LOGW (LOGD_CORE, "Unknown address family: %s", ns); continue; @@ -1038,6 +1042,33 @@ nmi_cmdline_reader_parse (const char *sysfs_dir, const char *const*argv, char ** } } + for (i = 0; i < reader->vlan_parents->len; i++) { + NMConnection *connection; + NMSettingIPConfig *s_ip; + + /* Disable IP configuration for parent connections of VLANs, + * unless those interfaces were explicitly configured otherwise. */ + + connection = reader_get_connection (reader, reader->vlan_parents->pdata[i], NULL, TRUE); + if (!g_hash_table_contains (reader->explicit_ip_connections, connection)) { + s_ip = nm_connection_get_setting_ip4_config (connection); + if (s_ip) { + g_object_set (s_ip, + NM_SETTING_IP_CONFIG_METHOD, + NM_SETTING_IP4_CONFIG_METHOD_DISABLED, + NULL); + } + + s_ip = nm_connection_get_setting_ip6_config (connection); + if (s_ip) { + g_object_set (s_ip, + NM_SETTING_IP_CONFIG_METHOD, + NM_SETTING_IP6_CONFIG_METHOD_DISABLED, + NULL); + } + } + } + if (ignore_bootif) nm_clear_g_free (&bootif_val); if (bootif_val) { diff --git a/src/initrd/nmi-ibft-reader.c b/src/initrd/nmi-ibft-reader.c index fe6f643..bdb99e6 100644 --- a/src/initrd/nmi-ibft-reader.c +++ b/src/initrd/nmi-ibft-reader.c @@ -162,9 +162,9 @@ ip_setting_add_from_block (GHashTable *nic, NULL); } - family = guess_ip_address_family (s_ipaddr); + family = get_ip_address_family (s_ipaddr, FALSE); if (family == AF_UNSPEC) - family = guess_ip_address_family (s_gateway); + family = get_ip_address_family (s_gateway, FALSE); switch (family) { case AF_INET: diff --git a/src/initrd/tests/test-cmdline-reader.c b/src/initrd/tests/test-cmdline-reader.c index d696602..b9d2acf 100644 --- a/src/initrd/tests/test-cmdline-reader.c +++ b/src/initrd/tests/test-cmdline-reader.c @@ -340,7 +340,7 @@ static void test_multiple_merge (void) { gs_unref_hashtable GHashTable *connections = NULL; - const char *const*ARGV = NM_MAKE_STRV ("ip=192.0.2.2:::::eth0", + const char *const*ARGV = NM_MAKE_STRV ("ip=192.0.2.2/16:::::eth0", "ip=[2001:db8::2]:::56::eth0"); NMConnection *connection; NMSettingConnection *s_con; @@ -375,6 +375,7 @@ test_multiple_merge (void) ip_addr = nm_setting_ip_config_get_address (s_ip4, 0); g_assert (ip_addr); g_assert_cmpstr (nm_ip_address_get_address (ip_addr), ==, "192.0.2.2"); + g_assert_cmpint (nm_ip_address_get_prefix (ip_addr), ==, 16); s_ip6 = nm_connection_get_setting_ip6_config (connection); g_assert (s_ip6); @@ -438,7 +439,7 @@ test_bootdev (void) connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV, &hostname); g_assert (connections); - g_assert_cmpint (g_hash_table_size (connections), ==, 2); + g_assert_cmpint (g_hash_table_size (connections), ==, 3); g_assert_cmpstr (hostname, ==, NULL); connection = g_hash_table_lookup (connections, "ens3"); @@ -461,6 +462,18 @@ test_bootdev (void) g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_VLAN_SETTING_NAME); g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "vlan2"); g_assert_cmpstr (nm_setting_connection_get_interface_name (s_con), ==, "vlan2"); + + connection = g_hash_table_lookup (connections, "ens5"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), + ==, + NM_SETTING_WIRED_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "ens5"); + g_assert_cmpstr (nm_setting_connection_get_interface_name (s_con), ==, "ens5"); } static void @@ -1064,6 +1077,228 @@ test_team (void) } static void +test_vlan (void) +{ + const char *const *ARGV0 = NM_MAKE_STRV ("ip=eth0.100:dhcp", "vlan=eth0.100:eth0"); + const char *const *ARGV1 = NM_MAKE_STRV ("vlan=eth0.100:eth0", "ip=eth0.100:dhcp"); + const char *const *ARGV[] = {ARGV0, ARGV1}; + guint i; + + for (i = 0; i < G_N_ELEMENTS (ARGV); i++) { + gs_unref_hashtable GHashTable *connections = NULL; + NMConnection *connection; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + NMSettingVlan *s_vlan; + gs_free char *hostname = NULL; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV[i], &hostname); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 2); + g_assert_cmpstr (hostname, ==, NULL); + + /* VLAN eth0.100 */ + connection = g_hash_table_lookup (connections, "eth0.100"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_connection_type(connection), + ==, + NM_SETTING_VLAN_SETTING_NAME); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "eth0.100"); + + s_vlan = nm_connection_get_setting_vlan (connection); + g_assert (s_vlan); + g_assert_cmpstr (nm_setting_vlan_get_parent (s_vlan), ==, "eth0"); + g_assert_cmpint (nm_setting_vlan_get_id (s_vlan), ==, 100); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), + ==, + NM_SETTING_IP4_CONFIG_METHOD_AUTO); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), + ==, + NM_SETTING_IP6_CONFIG_METHOD_AUTO); + + /* Ethernet eth0 */ + connection = g_hash_table_lookup (connections, "eth0"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_connection_type (connection), + ==, + NM_SETTING_WIRED_SETTING_NAME); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "eth0"); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), + ==, + NM_SETTING_IP4_CONFIG_METHOD_DISABLED); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), + ==, + NM_SETTING_IP6_CONFIG_METHOD_DISABLED); + } +} + +static void +test_vlan_with_dhcp_on_parent (void) +{ + const char *const *ARGV0 = NM_MAKE_STRV ("vlan=eth0.100:eth0", "ip=eth0:dhcp"); + const char *const *ARGV1 = NM_MAKE_STRV ("ip=eth0:dhcp", "vlan=eth0.100:eth0"); + const char *const *ARGV[] = {ARGV0, ARGV1}; + guint i; + + for (i = 0; i < G_N_ELEMENTS (ARGV); i++) { + gs_unref_hashtable GHashTable *connections = NULL; + NMConnection *connection; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + NMSettingVlan *s_vlan; + gs_free char *hostname = NULL; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV[i], &hostname); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 2); + g_assert_cmpstr (hostname, ==, NULL); + + /* VLAN eth0.100 */ + connection = g_hash_table_lookup (connections, "eth0.100"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_connection_type (connection), + ==, + NM_SETTING_VLAN_SETTING_NAME); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "eth0.100"); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), + ==, + NM_SETTING_IP4_CONFIG_METHOD_AUTO); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), + ==, + NM_SETTING_IP6_CONFIG_METHOD_AUTO); + + s_vlan = nm_connection_get_setting_vlan (connection); + g_assert (s_vlan); + g_assert_cmpstr (nm_setting_vlan_get_parent (s_vlan), ==, "eth0"); + g_assert_cmpint (nm_setting_vlan_get_id (s_vlan), ==, 100); + + /* Ethernet eth0 */ + connection = g_hash_table_lookup (connections, "eth0"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_connection_type (connection), + ==, + NM_SETTING_WIRED_SETTING_NAME); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "eth0"); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), + ==, + NM_SETTING_IP4_CONFIG_METHOD_AUTO); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), + ==, + NM_SETTING_IP6_CONFIG_METHOD_AUTO); + } +} + +static void +test_vlan_over_bond (void) +{ + const char *const *ARGV0 = NM_MAKE_STRV ("ip=1.2.3.4:::24::vlan1:none", + "bond=bond2:ens3,ens4:mode=active-backup", + "vlan=vlan1:bond2"); + const char *const *ARGV1 = NM_MAKE_STRV ("vlan=vlan1:bond2", + "ip=1.2.3.4:::24::vlan1:none", + "bond=bond2:ens3,ens4:mode=active-backup"); + const char *const *ARGV2 = NM_MAKE_STRV ("bond=bond2:ens3,ens4:mode=active-backup", + "ip=1.2.3.4:::24::vlan1:none", + "vlan=vlan1:bond2"); + const char *const *ARGV[] = {ARGV0, ARGV1, ARGV2}; + guint i; + + for (i = 0; i < G_N_ELEMENTS (ARGV); i++) { + gs_unref_hashtable GHashTable *connections = NULL; + NMConnection *connection; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + NMSettingVlan *s_vlan; + gs_free char *hostname = NULL; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV[i], &hostname); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 4); + g_assert_cmpstr (hostname, ==, NULL); + + /* VLAN vlan1 */ + connection = g_hash_table_lookup (connections, "vlan1"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_connection_type (connection), + ==, + NM_SETTING_VLAN_SETTING_NAME); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "vlan1"); + + s_ip4 = nm_connection_get_setting_ip4_config(connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), + ==, + NM_SETTING_IP4_CONFIG_METHOD_MANUAL); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), + ==, + NM_SETTING_IP6_CONFIG_METHOD_DISABLED); + s_vlan = nm_connection_get_setting_vlan (connection); + g_assert (s_vlan); + g_assert_cmpstr(nm_setting_vlan_get_parent (s_vlan), ==, "bond2"); + g_assert_cmpint(nm_setting_vlan_get_id (s_vlan), ==, 1); + + /* Bond bond2 */ + connection = g_hash_table_lookup (connections, "bond2"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_connection_type (connection), + ==, + NM_SETTING_BOND_SETTING_NAME); + g_assert_cmpstr(nm_connection_get_id (connection), ==, "bond2"); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), + ==, + NM_SETTING_IP4_CONFIG_METHOD_DISABLED); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), + ==, + NM_SETTING_IP6_CONFIG_METHOD_DISABLED); + + /* Ethernet ens3 and ens4 */ + connection = g_hash_table_lookup (connections, "ens3"); + g_assert (connection); + connection = g_hash_table_lookup (connections, "ens4"); + g_assert (connection); + } +} + +static void test_ibft_ip_dev (void) { const char *const*ARGV = NM_MAKE_STRV ("ip=eth0:ibft"); @@ -1674,6 +1909,9 @@ int main (int argc, char **argv) g_test_add_func ("/initrd/cmdline/bond/ip", test_bond_ip); g_test_add_func ("/initrd/cmdline/bond/default", test_bond_default); g_test_add_func ("/initrd/cmdline/team", test_team); + g_test_add_func ("/initrd/cmdline/vlan", test_vlan); + g_test_add_func ("/initrd/cmdline/vlan/dhcp-on-parent", test_vlan_with_dhcp_on_parent); + g_test_add_func ("/initrd/cmdline/vlan/over-bond", test_vlan_over_bond); g_test_add_func ("/initrd/cmdline/bridge", test_bridge); g_test_add_func ("/initrd/cmdline/bridge/default", test_bridge_default); g_test_add_func ("/initrd/cmdline/bridge/ip", test_bridge_ip);