platform: support VLAN protocol

Add support for the "protocol" attribute of VLAN links.
This commit is contained in:
Beniamino Galvani 2022-12-02 10:47:14 +01:00
parent 8febb15bfe
commit bd24e0b274
7 changed files with 131 additions and 34 deletions

View file

@ -8,6 +8,7 @@
#include "nm-device-vlan.h"
#include <sys/socket.h>
#include <linux/if_ether.h>
#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,

View file

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

View file

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

View file

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

View file

@ -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 = {

View file

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

View file

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