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: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2025-07-17 07:44:30 -07:00
commit 9bb8a9f6ea
3 changed files with 120 additions and 21 deletions

View File

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

View File

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

View File

@ -3,27 +3,101 @@
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
fail() {
echo "ERROR: ${1:-unexpected return code} (ret: $_)" >&2
ret=1
echo "ERROR: ${1:-unexpected return code} (ret: $_)" >&2
ret=1
}
ip netns add ${NETNS}
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
ip netns exec ${NETNS} ethtool -K bond0 rx-vlan-filter off
ip netns exec ${NETNS} ip link add link bond_slave_1 name bond_slave_1.0 type vlan id 0
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"
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
ip netns exec ${NETNS} ethtool -K bond0 rx-vlan-filter off
ip netns exec ${NETNS} ip link add link bond_slave_1 name bond_slave_1.0 type vlan id 0
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