From bd24e0b27461d25956593cc4ff76d01539316656 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 2 Dec 2022 10:47:14 +0100 Subject: [PATCH] platform: support VLAN protocol Add support for the "protocol" attribute of VLAN links. --- src/core/devices/nm-device-vlan.c | 8 +++- src/core/platform/tests/test-common.c | 44 +++++++++++++++++++++ src/core/platform/tests/test-common.h | 5 +++ src/core/platform/tests/test-link.c | 55 +++++++++++++++++++++----- src/libnm-platform/nm-linux-platform.c | 7 ++++ src/libnm-platform/nm-platform.c | 17 +++++++- src/libnm-platform/nm-platform.h | 29 ++++---------- 7 files changed, 131 insertions(+), 34 deletions(-) diff --git a/src/core/devices/nm-device-vlan.c b/src/core/devices/nm-device-vlan.c index faaa62f53c..627a2cceec 100644 --- a/src/core/devices/nm-device-vlan.c +++ b/src/core/devices/nm-device-vlan.c @@ -8,6 +8,7 @@ #include "nm-device-vlan.h" #include +#include #include "nm-manager.h" #include "nm-utils.h" @@ -230,8 +231,11 @@ create_and_realize(NMDevice *device, r = nm_platform_link_vlan_add(nm_device_get_platform(device), iface, parent_ifindex, - vlan_id, - nm_setting_vlan_get_flags(s_vlan), + &((NMPlatformLnkVlan){ + .id = vlan_id, + .flags = nm_setting_vlan_get_flags(s_vlan), + .protocol = ETH_P_8021Q, + }), out_plink); if (r < 0) { g_set_error(error, diff --git a/src/core/platform/tests/test-common.c b/src/core/platform/tests/test-common.c index 5c0484d914..7116bcf35d 100644 --- a/src/core/platform/tests/test-common.c +++ b/src/core/platform/tests/test-common.c @@ -2073,6 +2073,50 @@ nmtstp_link_tun_add(NMPlatform *platform, return pllink; } +const NMPlatformLink * +nmtstp_link_vlan_add(NMPlatform *platform, + int external_command, + const char *name, + int parent, + const NMPlatformLnkVlan *lnk) +{ + const NMPlatformLink *pllink = NULL; + gboolean success; + + g_assert(nm_utils_ifname_valid_kernel(name, NULL)); + + external_command = nmtstp_run_command_check_external(external_command); + + _init_platform(&platform, external_command); + + if (external_command) { + const char *dev; + + dev = nm_platform_link_get_name(platform, parent); + g_assert(dev); + g_assert(NM_IN_SET(lnk->protocol, ETH_P_8021Q, ETH_P_8021AD)); + + success = !nmtstp_run_command( + "ip link add name %s link %s type vlan id %hu protocol %s%s%s%s%s", + name, + dev, + lnk->id, + lnk->protocol == ETH_P_8021Q ? "802.1Q" : "802.1ad", + !(lnk->flags & _NM_VLAN_FLAG_REORDER_HEADERS) ? " reorder_hdr off" : "", + (lnk->flags & _NM_VLAN_FLAG_GVRP) ? " gvrp on" : "", + (lnk->flags & _NM_VLAN_FLAG_MVRP) ? " mvrp on" : "", + (lnk->flags & _NM_VLAN_FLAG_LOOSE_BINDING) ? " loose_binding on" : ""); + if (success) + pllink = nmtstp_assert_wait_for_link(platform, name, NM_LINK_TYPE_VLAN, 100); + } else + success = + NMTST_NM_ERR_SUCCESS(nm_platform_link_vlan_add(platform, name, parent, lnk, &pllink)); + + _assert_pllink(platform, success, pllink, name, NM_LINK_TYPE_VLAN); + + return pllink; +} + const NMPlatformLink * nmtstp_link_vrf_add(NMPlatform *platform, int external_command, diff --git a/src/core/platform/tests/test-common.h b/src/core/platform/tests/test-common.h index cd5b8e8638..c18d0bde62 100644 --- a/src/core/platform/tests/test-common.h +++ b/src/core/platform/tests/test-common.h @@ -499,6 +499,11 @@ const NMPlatformLink *nmtstp_link_tun_add(NMPlatform *platform, const char *name, const NMPlatformLnkTun *lnk, int *out_fd); +const NMPlatformLink *nmtstp_link_vlan_add(NMPlatform *platform, + int external_command, + const char *name, + int parent, + const NMPlatformLnkVlan *lnk); const NMPlatformLink *nmtstp_link_vrf_add(NMPlatform *platform, int external_command, const char *name, diff --git a/src/core/platform/tests/test-link.c b/src/core/platform/tests/test-link.c index e92b3965d4..57b074a068 100644 --- a/src/core/platform/tests/test-link.c +++ b/src/core/platform/tests/test-link.c @@ -161,8 +161,14 @@ software_add(NMLinkType link_type, const char *name) accept_signals(parent_changed, 1, 2); free_signal(parent_changed); - return NMTST_NM_ERR_SUCCESS( - nm_platform_link_vlan_add(NM_PLATFORM_GET, name, parent_ifindex, VLAN_ID, 0, NULL)); + return NMTST_NM_ERR_SUCCESS(nm_platform_link_vlan_add(NM_PLATFORM_GET, + name, + parent_ifindex, + &((NMPlatformLnkVlan){ + .id = VLAN_ID, + .protocol = ETH_P_8021Q, + }), + NULL)); } } default: @@ -1296,7 +1302,7 @@ test_software_detect(gconstpointer user_data) lnk_bridge.ageing_time = 2200; lnk_bridge.stp_state = TRUE; lnk_bridge.priority = 22; - lnk_bridge.vlan_protocol = 0x8100; + lnk_bridge.vlan_protocol = ETH_P_8021Q; lnk_bridge.vlan_stats_enabled = nmtstp_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_BR_VLAN_STATS_ENABLED) ? TRUE @@ -1571,10 +1577,28 @@ test_software_detect(gconstpointer user_data) break; } case NM_LINK_TYPE_VLAN: - nmtstp_run_command_check("ip link add name %s link %s type vlan id 1242", - DEVICE_NAME, - PARENT_NAME); + { + NMPlatformLnkVlan lnk_vlan = {}; + + switch (test_data->test_mode) { + case 0: + lnk_vlan.id = 1242; + lnk_vlan.protocol = ETH_P_8021Q; + lnk_vlan.flags = _NM_VLAN_FLAG_REORDER_HEADERS; + break; + case 1: + lnk_vlan.id = 4094; + lnk_vlan.protocol = ETH_P_8021AD; + lnk_vlan.flags = _NM_VLAN_FLAG_GVRP | _NM_VLAN_FLAG_MVRP; + break; + default: + nm_assert_not_reached(); + } + + if (!nmtstp_link_vlan_add(NULL, ext, DEVICE_NAME, ifindex_parent, &lnk_vlan)) + g_error("Failed adding VLAN interface"); break; + } case NM_LINK_TYPE_VRF: { NMPlatformLnkVrf lnk_vrf = {}; @@ -1727,7 +1751,7 @@ test_software_detect(gconstpointer user_data) g_assert_cmpint(plnk->ageing_time, ==, lnk_bridge_norm->ageing_time); g_assert_cmpint(plnk->stp_state, ==, TRUE); g_assert_cmpint(plnk->priority, ==, 22); - g_assert_cmpint(plnk->vlan_protocol, ==, 0x8100); + g_assert_cmpint(plnk->vlan_protocol, ==, ETH_P_8021Q); g_assert_cmpint(plnk->vlan_stats_enabled, ==, lnk_bridge_norm->vlan_stats_enabled); g_assert_cmpint(plnk->group_fwd_mask, ==, 8); g_assert_cmpint(plnk->mcast_snooping, ==, TRUE); @@ -1910,7 +1934,19 @@ test_software_detect(gconstpointer user_data) const NMPlatformLnkVlan *plnk = &lnk->lnk_vlan; g_assert(plnk == nm_platform_link_get_lnk_vlan(NM_PLATFORM_GET, ifindex, NULL)); - g_assert_cmpint(plnk->id, ==, 1242); + + switch (test_data->test_mode) { + case 0: + g_assert_cmpint(plnk->id, ==, 1242); + g_assert_cmpint(plnk->protocol, ==, ETH_P_8021Q); + g_assert_cmpint(plnk->flags, ==, _NM_VLAN_FLAG_REORDER_HEADERS); + break; + case 1: + g_assert_cmpint(plnk->id, ==, 4094); + g_assert_cmpint(plnk->protocol, ==, ETH_P_8021AD); + g_assert_cmpint(plnk->flags, ==, _NM_VLAN_FLAG_GVRP | _NM_VLAN_FLAG_MVRP); + break; + } break; } case NM_LINK_TYPE_VRF: @@ -3823,7 +3859,8 @@ _nmtstp_setup_tests(void) test_software_detect_add("/link/software/detect/macvtap", NM_LINK_TYPE_MACVTAP, 0); test_software_detect_add("/link/software/detect/sit", NM_LINK_TYPE_SIT, 0); test_software_detect_add("/link/software/detect/tun", NM_LINK_TYPE_TUN, 0); - test_software_detect_add("/link/software/detect/vlan", NM_LINK_TYPE_VLAN, 0); + test_software_detect_add("/link/software/detect/vlan/0", NM_LINK_TYPE_VLAN, 0); + test_software_detect_add("/link/software/detect/vlan/1", NM_LINK_TYPE_VLAN, 1); test_software_detect_add("/link/software/detect/vrf", NM_LINK_TYPE_VRF, 0); test_software_detect_add("/link/software/detect/vxlan/0", NM_LINK_TYPE_VXLAN, 0); test_software_detect_add("/link/software/detect/vxlan/1", NM_LINK_TYPE_VXLAN, 1); diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 9bdc62872d..d452e262fd 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -2255,6 +2255,11 @@ _parse_lnk_vlan(const char *kind, struct nlattr *info_data) obj = nmp_object_new(NMP_OBJECT_TYPE_LNK_VLAN, NULL); obj->lnk_vlan.id = nla_get_u16(tb[IFLA_VLAN_ID]); + if (tb[IFLA_VLAN_PROTOCOL]) + obj->lnk_vlan.protocol = ntohs(nla_get_u16(tb[IFLA_VLAN_PROTOCOL])); + else + obj->lnk_vlan.protocol = ETH_P_8021Q; + if (tb[IFLA_VLAN_FLAGS]) { struct ifla_vlan_flags flags; @@ -4658,11 +4663,13 @@ _nl_msg_new_link_set_linkinfo(struct nl_msg *msg, NMLinkType link_type, gconstpo const NMPlatformLnkVlan *props = extra_data; nm_assert(extra_data); + nm_assert(props->protocol != 0); if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) goto nla_put_failure; NLA_PUT_U16(msg, IFLA_VLAN_ID, props->id); + NLA_PUT_U16(msg, IFLA_VLAN_PROTOCOL, htons(props->protocol)); { struct ifla_vlan_flags flags = { diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index 5b970686d7..4688269d2c 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -6470,13 +6470,27 @@ const char * nm_platform_lnk_vlan_to_string(const NMPlatformLnkVlan *lnk, char *buf, gsize len) { char *b; + char protocol[32]; if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len)) return buf; b = buf; + switch (lnk->protocol) { + case ETH_P_8021AD: + nm_sprintf_buf(protocol, "802.1ad"); + break; + case ETH_P_8021Q: + nm_sprintf_buf(protocol, "802.1Q"); + break; + default: + nm_sprintf_buf(protocol, "0x%04hx", lnk->protocol); + break; + } + nm_strbuf_append(&b, &len, "vlan %u", lnk->id); + nm_strbuf_append(&b, &len, " protocol %s", protocol); if (lnk->flags) nm_strbuf_append(&b, &len, " flags 0x%x", lnk->flags); return buf; @@ -8146,7 +8160,7 @@ nm_platform_lnk_tun_cmp(const NMPlatformLnkTun *a, const NMPlatformLnkTun *b) void nm_platform_lnk_vlan_hash_update(const NMPlatformLnkVlan *obj, NMHashState *h) { - nm_hash_update_vals(h, obj->id, obj->flags); + nm_hash_update_vals(h, obj->id, obj->protocol, obj->flags); } int @@ -8154,6 +8168,7 @@ nm_platform_lnk_vlan_cmp(const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b) { NM_CMP_SELF(a, b); NM_CMP_FIELD(a, b, id); + NM_CMP_FIELD(a, b, protocol); NM_CMP_FIELD(a, b, flags); return 0; } diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index 22e6c12e3b..dceb3e6be5 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -862,8 +862,8 @@ typedef struct { } _nm_alignas(NMPlatformObject) NMPlatformLnkTun; typedef struct { - /* rtnl_link_vlan_get_id(), IFLA_VLAN_ID */ guint16 id; + guint16 protocol; _NMVlanFlags flags; } _nm_alignas(NMPlatformObject) NMPlatformLnkVlan; @@ -1660,28 +1660,13 @@ nm_platform_link_sit_add(NMPlatform *self, } static inline int -nm_platform_link_vlan_add(NMPlatform *self, - const char *name, - int parent, - int vlanid, - guint32 vlanflags, - const NMPlatformLink **out_link) +nm_platform_link_vlan_add(NMPlatform *self, + const char *name, + int parent, + const NMPlatformLnkVlan *props, + const NMPlatformLink **out_link) { - g_return_val_if_fail(parent >= 0, -NME_BUG); - g_return_val_if_fail(vlanid >= 0, -NME_BUG); - - return nm_platform_link_add(self, - NM_LINK_TYPE_VLAN, - name, - parent, - NULL, - 0, - 0, - &((NMPlatformLnkVlan){ - .id = vlanid, - .flags = vlanflags, - }), - out_link); + return nm_platform_link_add(self, NM_LINK_TYPE_VLAN, name, parent, NULL, 0, 0, props, out_link); } static inline int