Commit 9bb8a9f6 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'net-vlan-fix-vlan-0-refcount-imbalance-of-toggling-filtering-during-runtime'

Dong Chenchen says:

====================
net: vlan: fix VLAN 0 refcount imbalance of toggling filtering during runtime

Fix VLAN 0 refcount imbalance of toggling filtering during runtime.
====================

Link: https://patch.msgid.link/20250716034504.2285203-1-dongchenchen2@huawei.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents afb5bef5 e0f3b3e5
Loading
Loading
Loading
Loading
+33 −9
Original line number Diff line number Diff line
@@ -357,6 +357,35 @@ static int __vlan_device_event(struct net_device *dev, unsigned long event)
	return err;
}

static void vlan_vid0_add(struct net_device *dev)
{
	struct vlan_info *vlan_info;
	int err;

	if (!(dev->features & NETIF_F_HW_VLAN_CTAG_FILTER))
		return;

	pr_info("adding VLAN 0 to HW filter on device %s\n", dev->name);

	err = vlan_vid_add(dev, htons(ETH_P_8021Q), 0);
	if (err)
		return;

	vlan_info = rtnl_dereference(dev->vlan_info);
	vlan_info->auto_vid0 = true;
}

static void vlan_vid0_del(struct net_device *dev)
{
	struct vlan_info *vlan_info = rtnl_dereference(dev->vlan_info);

	if (!vlan_info || !vlan_info->auto_vid0)
		return;

	vlan_info->auto_vid0 = false;
	vlan_vid_del(dev, htons(ETH_P_8021Q), 0);
}

static int vlan_device_event(struct notifier_block *unused, unsigned long event,
			     void *ptr)
{
@@ -378,15 +407,10 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
			return notifier_from_errno(err);
	}

	if ((event == NETDEV_UP) &&
	    (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) {
		pr_info("adding VLAN 0 to HW filter on device %s\n",
			dev->name);
		vlan_vid_add(dev, htons(ETH_P_8021Q), 0);
	}
	if (event == NETDEV_DOWN &&
	    (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER))
		vlan_vid_del(dev, htons(ETH_P_8021Q), 0);
	if (event == NETDEV_UP)
		vlan_vid0_add(dev);
	else if (event == NETDEV_DOWN)
		vlan_vid0_del(dev);

	vlan_info = rtnl_dereference(dev->vlan_info);
	if (!vlan_info)
+1 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ struct vlan_info {
	struct vlan_group	grp;
	struct list_head	vid_list;
	unsigned int		nr_vids;
	bool			auto_vid0;
	struct rcu_head		rcu;
};

+86 −12
Original line number Diff line number Diff line
@@ -3,10 +3,22 @@

readonly NETNS="ns-$(mktemp -u XXXXXX)"

ALL_TESTS="
	test_vlan_filter_check
	test_vlan0_del_crash_01
	test_vlan0_del_crash_02
	test_vlan0_del_crash_03
	test_vid0_memleak
"

ret=0

setup() {
	ip netns add ${NETNS}
}

cleanup() {
	ip netns del $NETNS
	ip netns del $NETNS 2>/dev/null
}

trap cleanup EXIT
@@ -16,7 +28,16 @@ fail() {
	ret=1
}

ip netns add ${NETNS}
tests_run()
{
	local current_test
	for current_test in ${TESTS:-$ALL_TESTS}; do
		$current_test
	done
}

test_vlan_filter_check() {
	setup
	ip netns exec ${NETNS} ip link add bond0 type bond mode 0
	ip netns exec ${NETNS} ip link add bond_slave_1 type veth peer veth2
	ip netns exec ${NETNS} ip link set bond_slave_1 master bond0
@@ -25,5 +46,58 @@ ip netns exec ${NETNS} ip link add link bond_slave_1 name bond_slave_1.0 type vl
	ip netns exec ${NETNS} ip link add link bond0 name bond0.0 type vlan id 0
	ip netns exec ${NETNS} ip link set bond_slave_1 nomaster
	ip netns exec ${NETNS} ip link del veth2 || fail "Please check vlan HW filter function"
	cleanup
}

#enable vlan_filter feature of real_dev with vlan0 during running time
test_vlan0_del_crash_01() {
	setup
	ip netns exec ${NETNS} ip link add bond0 type bond mode 0
	ip netns exec ${NETNS} ip link add link bond0 name vlan0 type vlan id 0 protocol 802.1q
	ip netns exec ${NETNS} ethtool -K bond0 rx-vlan-filter off
	ip netns exec ${NETNS} ifconfig bond0 up
	ip netns exec ${NETNS} ethtool -K bond0 rx-vlan-filter on
	ip netns exec ${NETNS} ifconfig bond0 down
	ip netns exec ${NETNS} ifconfig bond0 up
	ip netns exec ${NETNS} ip link del vlan0 || fail "Please check vlan HW filter function"
	cleanup
}

#enable vlan_filter feature and add vlan0 for real_dev during running time
test_vlan0_del_crash_02() {
	setup
	ip netns exec ${NETNS} ip link add bond0 type bond mode 0
	ip netns exec ${NETNS} ethtool -K bond0 rx-vlan-filter off
	ip netns exec ${NETNS} ifconfig bond0 up
	ip netns exec ${NETNS} ethtool -K bond0 rx-vlan-filter on
	ip netns exec ${NETNS} ip link add link bond0 name vlan0 type vlan id 0 protocol 802.1q
	ip netns exec ${NETNS} ifconfig bond0 down
	ip netns exec ${NETNS} ifconfig bond0 up
	ip netns exec ${NETNS} ip link del vlan0 || fail "Please check vlan HW filter function"
	cleanup
}

#enable vlan_filter feature of real_dev during running time
#test kernel_bug of vlan unregister
test_vlan0_del_crash_03() {
	setup
	ip netns exec ${NETNS} ip link add bond0 type bond mode 0
	ip netns exec ${NETNS} ip link add link bond0 name vlan0 type vlan id 0 protocol 802.1q
	ip netns exec ${NETNS} ethtool -K bond0 rx-vlan-filter off
	ip netns exec ${NETNS} ifconfig bond0 up
	ip netns exec ${NETNS} ethtool -K bond0 rx-vlan-filter on
	ip netns exec ${NETNS} ifconfig bond0 down
	ip netns exec ${NETNS} ip link del vlan0 || fail "Please check vlan HW filter function"
	cleanup
}

test_vid0_memleak() {
	setup
	ip netns exec ${NETNS} ip link add bond0 up type bond mode 0
	ip netns exec ${NETNS} ethtool -K bond0 rx-vlan-filter off
	ip netns exec ${NETNS} ip link del dev bond0 || fail "Please check vlan HW filter function"
	cleanup
}

tests_run
exit $ret