diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c index 206d46e7f9b..c586b513e00 100644 --- a/sys/net/if_vlan.c +++ b/sys/net/if_vlan.c @@ -1702,10 +1702,20 @@ vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t vid, ifv->ifv_proto = proto; if (ifv->ifv_vid != vid) { + int oldvid = ifv->ifv_vid; + /* Re-hash */ vlan_remhash(trunk, ifv); ifv->ifv_vid = vid; error = vlan_inshash(trunk, ifv); + if (error) { + int ret __diagused; + + ifv->ifv_vid = oldvid; + /* Re-insert back where we found it. */ + ret = vlan_inshash(trunk, ifv); + MPASS(ret == 0); + } } /* Will unlock */ goto done; diff --git a/tests/sys/net/if_vlan.sh b/tests/sys/net/if_vlan.sh index 458e3cc36bc..41dac6222cb 100755 --- a/tests/sys/net/if_vlan.sh +++ b/tests/sys/net/if_vlan.sh @@ -297,6 +297,42 @@ bpf_pcp_cleanup() vnet_cleanup } +atf_test_case "conflict_id" "cleanup" +conflict_id_head() +{ + atf_set descr 'Test conflicting VLAN IDs, PR #279195' + atf_set require.user root +} + +conflict_id_body() +{ + vnet_init + + epair=$(vnet_mkepair) + + vnet_mkjail alcatraz ${epair}b + vlan_a=$(jexec alcatraz ifconfig vlan create) + vlan_b=$(jexec alcatraz ifconfig vlan create) + + jexec alcatraz ifconfig ${vlan_a} vlan 100 vlandev ${epair}b + jexec alcatraz ifconfig ${vlan_b} vlan 101 vlandev ${epair}b + + atf_check -s exit:1 -o ignore -e ignore \ + jexec alcatraz ifconfig ${vlan_a} vlan 101 + + atf_check -s exit:0 -o match:"vlan: 100" \ + jexec alcatraz ifconfig ${vlan_a} + + atf_check -s exit:0 -o ignore -e ignore \ + jexec alcatraz ifconfig ${vlan_a} vlan 100 +} + +conflict_id_cleanup() +{ + vnet_cleanup + +} + atf_init_test_cases() { atf_add_test_case "basic" @@ -306,4 +342,5 @@ atf_init_test_cases() atf_add_test_case "qinq_dot" atf_add_test_case "qinq_setflags" atf_add_test_case "bpf_pcp" + atf_add_test_case "conflict_id" }