]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
selftests: openvswitch: add pop_vlan test
authorMinxi Hou <houminxi@gmail.com>
Tue, 12 May 2026 07:08:41 +0000 (15:08 +0800)
committerJakub Kicinski <kuba@kernel.org>
Fri, 15 May 2026 00:10:02 +0000 (17:10 -0700)
Add test_pop_vlan() to verify OVS kernel datapath pop_vlan action
correctly strips 802.1Q VLAN tags from frames.

Test structure:
- Baseline: untagged forwarding validates basic connectivity.
- Negative: forward without pop_vlan, tagged frame is invisible
  to ns2 (no VLAN sub-interface), ping fails.
- Positive: pop_vlan strips tag on forward path, push_vlan
  restores tag on return path, ping succeeds.

Use static ARP entries to avoid VLAN-tagged ARP complexity.
Rely on ping success/failure for verification -- no tcpdump or
pcap files needed.

Signed-off-by: Minxi Hou <houminxi@gmail.com>
Reviewed-by: Aaron Conole <aconole@redhat.com>
Link: https://patch.msgid.link/20260512070841.1183581-3-houminxi@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
tools/testing/selftests/net/openvswitch/openvswitch.sh

index 3cdd953f681324e0f4b6865fdeed41e47f438dcf..8cd5b3d894abd14ea6e58f386b60da5f5a6f4597 100755 (executable)
@@ -28,6 +28,7 @@ tests="
        tunnel_metadata                         ovs: test extraction of tunnel metadata
        tunnel_refcount                         ovs: test tunnel vport reference cleanup
        drop_reason                             drop: test drop reasons are emitted
+       pop_vlan                                vlan: POP_VLAN action strips tag
        psample                                 psample: Sampling packets with psample"
 
 info() {
@@ -864,6 +865,83 @@ test_tunnel_refcount() {
                ovs_wait dev_removed dp-${tun_type} || return 1
                ovs_wait dev_removed ovs-${tun_type}0 || return 1
        done
+
+       return 0
+}
+
+test_pop_vlan() {
+       local sbx="test_pop_vlan"
+       sbx_add "$sbx" || return $?
+       ovs_add_dp "$sbx" vlandp || return 1
+
+       ovs_add_netns_and_veths "$sbx" vlandp \
+               ns1 veth1 ns1veth 192.0.2.1/24 || return 1
+       ovs_add_netns_and_veths "$sbx" vlandp \
+               ns2 veth2 ns2veth 192.0.2.2/24 || return 1
+
+       # Baseline: untagged bidirectional forwarding
+       ovs_add_flow "$sbx" vlandp \
+               'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
+       ovs_add_flow "$sbx" vlandp \
+               'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
+       ovs_add_flow "$sbx" vlandp \
+               'in_port(1),eth(),eth_type(0x0800),ipv4()' '2' || return 1
+       ovs_add_flow "$sbx" vlandp \
+               'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1
+       ovs_sbx "$sbx" ip netns exec ns1 ping -c 3 -W 2 \
+               192.0.2.2 || return 1
+
+       # VLAN topology: ns1 uses VLAN sub-interface, ns2 is plain
+       ip -n ns1 link add link ns1veth name ns1veth.10 \
+               type vlan id 10 || return 1
+       on_exit "ip -n ns1 link del ns1veth.10 2>/dev/null"
+       ip -n ns1 addr add 198.51.100.1/24 dev ns1veth.10 || return 1
+       ip -n ns1 link set ns1veth.10 up || return 1
+       ip -n ns2 addr add 198.51.100.2/24 dev ns2veth || return 1
+
+       ovs_del_flows "$sbx" vlandp
+
+       # Static ARP: avoids VLAN-tagged ARP complexity
+       local ns1veth10mac ns2mac
+       ns1veth10mac=$(ip -n ns1 link show ns1veth.10 \
+               | awk '/link\/ether/ {print $2}')
+       [ -z "$ns1veth10mac" ] && \
+               { info "failed to get ns1veth10mac"; return 1; }
+       ns2mac=$(ip -n ns2 link show ns2veth \
+               | awk '/link\/ether/ {print $2}')
+       [ -z "$ns2mac" ] && \
+               { info "failed to get ns2mac"; return 1; }
+       ip -n ns1 neigh replace 198.51.100.2 lladdr "$ns2mac" \
+               dev ns1veth.10 nud permanent || return 1
+       ip -n ns2 neigh replace 198.51.100.1 \
+               lladdr "$ns1veth10mac" \
+               dev ns2veth nud permanent || return 1
+
+       local vlan_match='in_port(1),eth(),eth_type(0x8100),'
+       vlan_match+='vlan(vid=10),'
+       vlan_match+='encap(eth_type(0x0800),'
+       vlan_match+='ipv4(src=198.51.100.1,proto=1),icmp())'
+
+       # Negative: forward without pop_vlan -- tagged frame
+       # is invisible to ns2 (no VLAN sub-interface), ping fails
+       ovs_add_flow "$sbx" vlandp "$vlan_match" '2' || return 1
+       ovs_sbx "$sbx" ip netns exec ns1 ping -I ns1veth.10 \
+               -c 3 -W 1 198.51.100.2 >/dev/null 2>&1 \
+               && { info "FAIL: ping should fail without pop_vlan"
+                    return 1; }
+
+       ovs_del_flows "$sbx" vlandp
+
+       # Positive: pop_vlan strips tag on forward path,
+       # push_vlan restores tag on return path -- ping succeeds
+       ovs_add_flow "$sbx" vlandp \
+               "$vlan_match" 'pop_vlan,2' || return 1
+       ovs_add_flow "$sbx" vlandp \
+               'in_port(2),eth(),eth_type(0x0800),ipv4()' \
+               'push_vlan(vid=10,pcp=0,tpid=0x8100),1' || return 1
+       ovs_sbx "$sbx" ip netns exec ns1 ping -I ns1veth.10 \
+               -c 3 -W 2 198.51.100.2 || return 1
+
        return 0
 }