Beniamino Galvani 2020-11-24 11:42:07 +01:00
commit fcb436ea8e
5 changed files with 339 additions and 37 deletions

View file

@ -1776,6 +1776,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)
@ -1814,6 +1825,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);

View file

@ -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);

View file

@ -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>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>: */
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) {

View file

@ -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:

View file

@ -383,7 +383,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;
@ -418,6 +418,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);
@ -481,7 +482,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");
@ -504,6 +505,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
@ -1106,6 +1119,228 @@ test_team (void)
g_assert_cmpint (nm_setting_connection_get_multi_connect (s_con), ==, NM_CONNECTION_MULTI_CONNECT_SINGLE);
}
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)
{
@ -1718,6 +1953,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);