diff --git a/src/core/settings/plugins/etcnet-alt/nms-etcnet-alt-reader.c b/src/core/settings/plugins/etcnet-alt/nms-etcnet-alt-reader.c --- a/src/core/settings/plugins/etcnet-alt/nms-etcnet-alt-reader.c +++ b/src/core/settings/plugins/etcnet-alt/nms-etcnet-alt-reader.c @@ -1159,6 +1159,91 @@ error: return NULL; } +static NMSetting * +make_vlan_setting(options_file_t *options, GError **error) +{ + NMSettingVlan *s_vlan = NULL; + char * host = NULL; + char * vid = NULL; + long int vlan_id; + + g_return_val_if_fail(options != NULL, NULL); + + host = options_get_value(options, "HOST"); + if (!host || !host[0]) { + PLUGIN_SET_ERROR_LITERAL(error, "Missing VLAN HOST option"); + goto done; + } + + vid = options_get_value(options, "VID"); + if (!vid || !get_int(vid, &vlan_id) || vlan_id < 0 || vlan_id > 4094) { + PLUGIN_SET_ERROR(error, "Invalid VLAN VID '%s'", vid ? vid : ""); + goto done; + } + + s_vlan = NM_SETTING_VLAN(nm_setting_vlan_new()); + g_object_set(s_vlan, + NM_SETTING_VLAN_PARENT, + host, + NM_SETTING_VLAN_ID, + (guint32) vlan_id, + NULL); + +done: + g_free(host); + g_free(vid); + return NM_SETTING(s_vlan); +} + +static NMConnection * +read_vlan_connection(const char * iface_path, + options_file_t *options, + GError ** error) +{ + NMConnection *connection = NULL; + NMSetting * con_setting = NULL; + NMSetting * vlan_setting = NULL; + NMSetting * wired_setting = NULL; + + g_return_val_if_fail(iface_path != NULL, NULL); + g_return_val_if_fail(options != NULL, NULL); + + connection = nm_simple_connection_new(); + if (!connection) { + PLUGIN_SET_ERROR(error, "Failed to allocate new connection for %s.", iface_path); + return NULL; + } + + con_setting = make_connection_setting(iface_path, + options, + NM_SETTING_VLAN_SETTING_NAME, + NULL); + if (!con_setting) { + PLUGIN_SET_ERROR_LITERAL(error, "Failed to create connection setting."); + goto error; + } + nm_connection_add_setting(connection, con_setting); + + vlan_setting = make_vlan_setting(options, error); + if (!vlan_setting) + goto error; + nm_connection_add_setting(connection, vlan_setting); + + wired_setting = make_wired_setting(iface_path, error); + if (!wired_setting) + goto error; + nm_connection_add_setting(connection, wired_setting); + + if (!nm_connection_verify(connection, error)) + goto error; + + return connection; + +error: + g_object_unref(connection); + return NULL; +} + static char * get_supplicant_config_value(GHashTable *wsconf, const char *key, gboolean to_lower) { @@ -1604,8 +1707,8 @@ read_wireless_connection(const char * iface_path, return connection; } -/* Only NM_DEVICE_TYPE_WIFI and NM_DEVICE_TYPE_ETHERNET are - * recognized */ +/* Only NM_DEVICE_TYPE_WIFI, NM_DEVICE_TYPE_ETHERNET and + * NM_DEVICE_TYPE_VLAN are recognized */ static NMDeviceType get_device_type(options_file_t *options, const char *iface_name) { @@ -1626,6 +1729,8 @@ get_device_type(options_file_t *options, const char *iface_name) dev_type = options_true_value(options, "CONFIG_WIRELESS", FALSE) ? NM_DEVICE_TYPE_WIFI : NM_DEVICE_TYPE_ETHERNET; } + } else if (!g_ascii_strcasecmp("vlan", options->type)) { + dev_type = NM_DEVICE_TYPE_VLAN; } return dev_type; @@ -1697,6 +1802,9 @@ read_connection(const char * iface_path, connection = read_wireless_connection(iface_path, options, wsconf, error); break; + case NM_DEVICE_TYPE_VLAN: + connection = read_vlan_connection(iface_path, options, error); + break; default: PLUGIN_SET_ERROR(error, "Connection for %s : Unknown device type", diff --git a/src/core/settings/plugins/etcnet-alt/tests/ifaces-config/ens19.100/ipv4address b/src/core/settings/plugins/etcnet-alt/tests/ifaces-config/ens19.100/ipv4address new file mode 100644 --- /dev/null +++ b/src/core/settings/plugins/etcnet-alt/tests/ifaces-config/ens19.100/ipv4address @@ -0,0 +1 @@ +192.168.0.1/24 diff --git a/src/core/settings/plugins/etcnet-alt/tests/ifaces-config/ens19.100/options b/src/core/settings/plugins/etcnet-alt/tests/ifaces-config/ens19.100/options new file mode 100644 index 0000000000..1111111111 --- /dev/null +++ b/src/core/settings/plugins/etcnet-alt/tests/ifaces-config/ens19.100/options @@ -0,0 +1,12 @@ +TYPE=vlan +HOST=ens19 +VID=100 +ONBOOT=yes +CONFIG_WIRELESS=no +CONFIG_IPV4=yes +CONFIG_IPV6=no +BOOTPROTO=static +SYSTEMD_BOOTPROTO=static +DISABLED=yes +NM_CONTROLLED=yes +SYSTEMD_CONTROLLED=no diff --git a/src/core/settings/plugins/etcnet-alt/tests/ifaces-config/ens19.200/options b/src/core/settings/plugins/etcnet-alt/tests/ifaces-config/ens19.200/options new file mode 100644 --- /dev/null +++ b/src/core/settings/plugins/etcnet-alt/tests/ifaces-config/ens19.200/options @@ -0,0 +1,8 @@ +TYPE=vlan +HOST=ens19 +VID=200 +ONBOOT=yes +CONFIG_IPV4=no +CONFIG_IPV6=no +NM_CONTROLLED=yes +SYSTEMD_CONTROLLED=no diff --git a/src/core/settings/plugins/etcnet-alt/tests/test-etcnet-alt.c b/src/core/settings/plugins/etcnet-alt/tests/test-etcnet-alt.c --- a/src/core/settings/plugins/etcnet-alt/tests/test-etcnet-alt.c +++ b/src/core/settings/plugins/etcnet-alt/tests/test-etcnet-alt.c @@ -28,6 +28,8 @@ #define TEST_CONFIG_WIRELESS_DHCP TEST_CONFIGS_DIR "/ifaces-config/wl" #define TEST_CONFIG_IPV6 TEST_CONFIGS_DIR "/ifaces-config/ipv6" #define TEST_CONFIG_BRIDGE TEST_CONFIGS_DIR "/ifaces-config/bridge" +#define TEST_CONFIG_VLAN_STATIC TEST_CONFIGS_DIR "/ifaces-config/ens19.100" +#define TEST_CONFIG_VLAN_L2 TEST_CONFIGS_DIR "/ifaces-config/ens19.200" static void verify_setting_connection(NMSettingConnection *s_con, const char *expected_id, @@ -1475,6 +1476,99 @@ test_read_bridge_ignored(void) test_read_bridge(TEST_CONFIG_BRIDGE, NULL, TRUE, TRUE, "System bridge"); } +static void +test_read_vlan(const char * iface_path, + const char * expected_id, + const char * expected_iface_name, + guint32 expected_vid, + const char * expected_ipv4_method, + guint32 expected_num_ipv4addr, + const test_ip_address_t *expected_ipv4addresses) +{ + NMConnection * connection; + NMSettingConnection *s_con; + NMSettingVlan * s_vlan; + NMSettingIPConfig * s_ip4; + NMSettingIPConfig * s_ip6; + GError * error = NULL; + gboolean ignored = TRUE; + + connection = read_connection(iface_path, NULL, &ignored, &error); + + g_assert_false(ignored); + g_assert_no_error(error); + g_assert(connection); + nmtst_assert_connection_verifies(connection); + + s_con = nm_connection_get_setting_connection(connection); + verify_setting_connection(s_con, expected_id, TRUE); + g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), + ==, + NM_SETTING_VLAN_SETTING_NAME); + g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, expected_iface_name); + + s_vlan = nm_connection_get_setting_vlan(connection); + g_assert(s_vlan); + g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, "ens19"); + g_assert_cmpuint(nm_setting_vlan_get_id(s_vlan), ==, expected_vid); + + s_ip4 = nm_connection_get_setting_ip4_config(connection); + verify_setting_ip(s_ip4, + expected_id, + expected_ipv4_method, + expected_num_ipv4addr, + expected_ipv4addresses, + NULL, + 0, + NULL, + 0, + NULL, + 0, + NULL); + + s_ip6 = nm_connection_get_setting_ip6_config(connection); + verify_setting_ip(s_ip6, + expected_id, + NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + 0, + NULL, + NULL, + 0, + NULL, + 0, + NULL, + 0, + NULL); + + g_object_unref(connection); +} + +static void +test_read_vlan_static(void) +{ + const test_ip_address_t addresses[1] = {{"192.168.0.1", 24}}; + + test_read_vlan(TEST_CONFIG_VLAN_STATIC, + "System ens19.100", + "ens19.100", + 100, + NM_SETTING_IP4_CONFIG_METHOD_MANUAL, + 1, + addresses); +} + +static void +test_read_vlan_l2(void) +{ + test_read_vlan(TEST_CONFIG_VLAN_L2, + "System ens19.200", + "ens19.200", + 200, + NM_SETTING_IP4_CONFIG_METHOD_DISABLED, + 0, + NULL); +} + static void test_read_eth_dhcp_no_type(void) { @@ -1533,6 +1610,9 @@ main(int argc, char **argv) g_test_add_func(TPATH "test_read_bridge_ignored", test_read_bridge_ignored); + g_test_add_func(TPATH "test_read_vlan_static", test_read_vlan_static); + g_test_add_func(TPATH "test_read_vlan_l2", test_read_vlan_l2); + g_test_add_func(TPATH "test_read_eth_dhcp_no_type", test_read_eth_dhcp_no_type); return g_test_run();