Commit b02e3c4c authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'macsec-add-support-for-vlan-filtering-in-offload-mode'

Cosmin Ratiu says:

====================
macsec: Add support for VLAN filtering in offload mode

This short series adds support for VLANs in MACsec devices when offload
mode is enabled. This allows VLAN netdevs on top of MACsec netdevs to
function, which accidentally used to be the case in the past, but was
broken. This series adds back proper support.

As part of this, the existing nsim-only MACsec offload tests were
translated to Python so they can run against real HW and new
traffic-based tests were added for VLAN filter propagation, since
there's currently no uAPI to check VLAN filters.
====================

Link: https://patch.msgid.link/20260408115240.1636047-1-cratiu@nvidia.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents eb216e42 a363b1c8
Loading
Loading
Loading
Loading
+63 −8
Original line number Diff line number Diff line
@@ -2584,7 +2584,9 @@ static void macsec_inherit_tso_max(struct net_device *dev)
		netif_inherit_tso_max(dev, macsec->real_dev);
}

static int macsec_update_offload(struct net_device *dev, enum macsec_offload offload)
static int macsec_update_offload(struct net_device *dev,
				 enum macsec_offload offload,
				 struct netlink_ext_ack *extack)
{
	enum macsec_offload prev_offload;
	const struct macsec_ops *ops;
@@ -2616,14 +2618,35 @@ static int macsec_update_offload(struct net_device *dev, enum macsec_offload off
	if (!ops)
		return -EOPNOTSUPP;

	macsec->offload = offload;

	ctx.secy = &macsec->secy;
	ret = offload == MACSEC_OFFLOAD_OFF ? macsec_offload(ops->mdo_del_secy, &ctx)
					    : macsec_offload(ops->mdo_add_secy, &ctx);
	if (ret) {
		macsec->offload = prev_offload;
	if (ret)
		return ret;

	/* Remove VLAN filters when disabling offload. */
	if (offload == MACSEC_OFFLOAD_OFF) {
		vlan_drop_rx_ctag_filter_info(dev);
		vlan_drop_rx_stag_filter_info(dev);
	}
	macsec->offload = offload;
	/* Add VLAN filters when enabling offload. */
	if (prev_offload == MACSEC_OFFLOAD_OFF) {
		ret = vlan_get_rx_ctag_filter_info(dev);
		if (ret) {
			NL_SET_ERR_MSG_FMT(extack,
					   "adding ctag VLAN filters failed, err %d",
					   ret);
			goto rollback_offload;
		}
		ret = vlan_get_rx_stag_filter_info(dev);
		if (ret) {
			NL_SET_ERR_MSG_FMT(extack,
					   "adding stag VLAN filters failed, err %d",
					   ret);
			vlan_drop_rx_ctag_filter_info(dev);
			goto rollback_offload;
		}
	}

	macsec_set_head_tail_room(dev);
@@ -2633,6 +2656,12 @@ static int macsec_update_offload(struct net_device *dev, enum macsec_offload off

	netdev_update_features(dev);

	return 0;

rollback_offload:
	macsec->offload = prev_offload;
	macsec_offload(ops->mdo_del_secy, &ctx);

	return ret;
}

@@ -2673,7 +2702,7 @@ static int macsec_upd_offload(struct sk_buff *skb, struct genl_info *info)
	offload = nla_get_u8(tb_offload[MACSEC_OFFLOAD_ATTR_TYPE]);

	if (macsec->offload != offload)
		ret = macsec_update_offload(dev, offload);
		ret = macsec_update_offload(dev, offload, info->extack);
out:
	rtnl_unlock();
	return ret;
@@ -3486,7 +3515,8 @@ static netdev_tx_t macsec_start_xmit(struct sk_buff *skb,
}

#define MACSEC_FEATURES \
	(NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST)
	(NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
	 NETIF_F_HW_VLAN_STAG_FILTER | NETIF_F_HW_VLAN_CTAG_FILTER)

#define MACSEC_OFFLOAD_FEATURES \
	(MACSEC_FEATURES | NETIF_F_GSO_SOFTWARE | NETIF_F_SOFT_FEATURES | \
@@ -3707,6 +3737,29 @@ static int macsec_set_mac_address(struct net_device *dev, void *p)
	return err;
}

static int macsec_vlan_rx_add_vid(struct net_device *dev,
				  __be16 proto, u16 vid)
{
	struct macsec_dev *macsec = netdev_priv(dev);

	if (!macsec_is_offloaded(macsec))
		return 0;

	return vlan_vid_add(macsec->real_dev, proto, vid);
}

static int macsec_vlan_rx_kill_vid(struct net_device *dev,
				   __be16 proto, u16 vid)
{
	struct macsec_dev *macsec = netdev_priv(dev);

	if (!macsec_is_offloaded(macsec))
		return 0;

	vlan_vid_del(macsec->real_dev, proto, vid);
	return 0;
}

static int macsec_change_mtu(struct net_device *dev, int new_mtu)
{
	struct macsec_dev *macsec = macsec_priv(dev);
@@ -3748,6 +3801,8 @@ static const struct net_device_ops macsec_netdev_ops = {
	.ndo_set_rx_mode	= macsec_dev_set_rx_mode,
	.ndo_change_rx_flags	= macsec_dev_change_rx_flags,
	.ndo_set_mac_address	= macsec_set_mac_address,
	.ndo_vlan_rx_add_vid	= macsec_vlan_rx_add_vid,
	.ndo_vlan_rx_kill_vid	= macsec_vlan_rx_kill_vid,
	.ndo_start_xmit		= macsec_start_xmit,
	.ndo_get_stats64	= macsec_get_stats64,
	.ndo_get_iflink		= macsec_get_iflink,
@@ -3912,7 +3967,7 @@ static int macsec_changelink(struct net_device *dev, struct nlattr *tb[],
		offload = nla_get_u8(data[IFLA_MACSEC_OFFLOAD]);
		if (macsec->offload != offload) {
			macsec_offload_state_change = true;
			ret = macsec_update_offload(dev, offload);
			ret = macsec_update_offload(dev, offload, extack);
			if (ret)
				goto cleanup;
		}
+63 −2
Original line number Diff line number Diff line
@@ -605,6 +605,36 @@ static int nsim_stop(struct net_device *dev)
	return 0;
}

static int nsim_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid)
{
	struct netdevsim *ns = netdev_priv(dev);

	if (vid >= VLAN_N_VID)
		return -EINVAL;

	if (proto == htons(ETH_P_8021Q))
		WARN_ON_ONCE(test_and_set_bit(vid, ns->vlan.ctag));
	else if (proto == htons(ETH_P_8021AD))
		WARN_ON_ONCE(test_and_set_bit(vid, ns->vlan.stag));

	return 0;
}

static int nsim_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
{
	struct netdevsim *ns = netdev_priv(dev);

	if (vid >= VLAN_N_VID)
		return -EINVAL;

	if (proto == htons(ETH_P_8021Q))
		WARN_ON_ONCE(!test_and_clear_bit(vid, ns->vlan.ctag));
	else if (proto == htons(ETH_P_8021AD))
		WARN_ON_ONCE(!test_and_clear_bit(vid, ns->vlan.stag));

	return 0;
}

static int nsim_shaper_set(struct net_shaper_binding *binding,
			   const struct net_shaper *shaper,
			   struct netlink_ext_ack *extack)
@@ -662,6 +692,8 @@ static const struct net_device_ops nsim_netdev_ops = {
	.ndo_bpf		= nsim_bpf,
	.ndo_open		= nsim_open,
	.ndo_stop		= nsim_stop,
	.ndo_vlan_rx_add_vid	= nsim_vlan_rx_add_vid,
	.ndo_vlan_rx_kill_vid	= nsim_vlan_rx_kill_vid,
	.net_shaper_ops		= &nsim_shaper_ops,
};

@@ -673,6 +705,8 @@ static const struct net_device_ops nsim_vf_netdev_ops = {
	.ndo_change_mtu		= nsim_change_mtu,
	.ndo_setup_tc		= nsim_setup_tc,
	.ndo_set_features	= nsim_set_features,
	.ndo_vlan_rx_add_vid	= nsim_vlan_rx_add_vid,
	.ndo_vlan_rx_kill_vid	= nsim_vlan_rx_kill_vid,
};

/* We don't have true per-queue stats, yet, so do some random fakery here.
@@ -970,6 +1004,20 @@ static const struct file_operations nsim_pp_hold_fops = {
	.owner = THIS_MODULE,
};

static int nsim_vlan_show(struct seq_file *s, void *data)
{
	struct netdevsim *ns = s->private;
	int vid;

	for_each_set_bit(vid, ns->vlan.ctag, VLAN_N_VID)
		seq_printf(s, "ctag %d\n", vid);
	for_each_set_bit(vid, ns->vlan.stag, VLAN_N_VID)
		seq_printf(s, "stag %d\n", vid);

	return 0;
}
DEFINE_SHOW_ATTRIBUTE(nsim_vlan);

static void nsim_setup(struct net_device *dev)
{
	ether_setup(dev);
@@ -982,14 +1030,18 @@ static void nsim_setup(struct net_device *dev)
			 NETIF_F_FRAGLIST |
			 NETIF_F_HW_CSUM |
			 NETIF_F_LRO |
			 NETIF_F_TSO;
			 NETIF_F_TSO |
			 NETIF_F_HW_VLAN_CTAG_FILTER |
			 NETIF_F_HW_VLAN_STAG_FILTER;
	dev->hw_features |= NETIF_F_HW_TC |
			    NETIF_F_SG |
			    NETIF_F_FRAGLIST |
			    NETIF_F_HW_CSUM |
			    NETIF_F_LRO |
			    NETIF_F_TSO |
			    NETIF_F_LOOPBACK;
			    NETIF_F_LOOPBACK |
			    NETIF_F_HW_VLAN_CTAG_FILTER |
			    NETIF_F_HW_VLAN_STAG_FILTER;
	dev->pcpu_stat_type = NETDEV_PCPU_STAT_DSTATS;
	dev->max_mtu = ETH_MAX_MTU;
	dev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_HW_OFFLOAD;
@@ -1156,6 +1208,8 @@ struct netdevsim *nsim_create(struct nsim_dev *nsim_dev,
	ns->qr_dfs = debugfs_create_file("queue_reset", 0200,
					 nsim_dev_port->ddir, ns,
					 &nsim_qreset_fops);
	ns->vlan_dfs = debugfs_create_file("vlan", 0400, nsim_dev_port->ddir,
					   ns, &nsim_vlan_fops);
	return ns;

err_free_netdev:
@@ -1167,7 +1221,9 @@ void nsim_destroy(struct netdevsim *ns)
{
	struct net_device *dev = ns->netdev;
	struct netdevsim *peer;
	u16 vid;

	debugfs_remove(ns->vlan_dfs);
	debugfs_remove(ns->qr_dfs);
	debugfs_remove(ns->pp_dfs);

@@ -1193,6 +1249,11 @@ void nsim_destroy(struct netdevsim *ns)
	if (nsim_dev_port_is_pf(ns->nsim_dev_port))
		nsim_exit_netdevsim(ns);

	for_each_set_bit(vid, ns->vlan.ctag, VLAN_N_VID)
		WARN_ON_ONCE(1);
	for_each_set_bit(vid, ns->vlan.stag, VLAN_N_VID)
		WARN_ON_ONCE(1);

	/* Put this intentionally late to exercise the orphaning path */
	if (ns->page) {
		page_pool_put_full_page(pp_page_to_nmdesc(ns->page)->pp,
+8 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/ethtool.h>
#include <linux/ethtool_netlink.h>
#include <linux/kernel.h>
#include <linux/if_vlan.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include <linux/ptp_mock.h>
@@ -75,6 +76,11 @@ struct nsim_macsec {
	u8 nsim_secy_count;
};

struct nsim_vlan {
	DECLARE_BITMAP(ctag, VLAN_N_VID);
	DECLARE_BITMAP(stag, VLAN_N_VID);
};

struct nsim_ethtool_pauseparam {
	bool rx;
	bool tx;
@@ -135,6 +141,7 @@ struct netdevsim {
	bool bpf_map_accept;
	struct nsim_ipsec ipsec;
	struct nsim_macsec macsec;
	struct nsim_vlan vlan;
	struct {
		u32 inject_error;
		u32 __ports[2][NSIM_UDP_TUNNEL_N_PORTS];
@@ -146,6 +153,7 @@ struct netdevsim {
	struct page *page;
	struct dentry *pp_dfs;
	struct dentry *qr_dfs;
	struct dentry *vlan_dfs;

	struct nsim_ethtool ethtool;
	struct netdevsim __rcu *peer;
+1 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@ TEST_GEN_FILES := \
TEST_PROGS := \
	gro.py \
	hds.py \
	macsec.py \
	napi_id.py \
	napi_threaded.py \
	netpoll_basic.py \
+2 −0
Original line number Diff line number Diff line
@@ -3,8 +3,10 @@ CONFIG_DEBUG_INFO_BTF=y
CONFIG_DEBUG_INFO_BTF_MODULES=n
CONFIG_INET_PSP=y
CONFIG_IPV6=y
CONFIG_MACSEC=m
CONFIG_NETCONSOLE=m
CONFIG_NETCONSOLE_DYNAMIC=y
CONFIG_NETCONSOLE_EXTENDED_LOG=y
CONFIG_NETDEVSIM=m
CONFIG_VLAN_8021Q=m
CONFIG_XDP_SOCKETS=y
Loading