[PATCH net] selftests: openvswitch: Test SET on later IPv6 fragments
flat view
WARM2d
From: Sahaj Chaudhari <hidden>
Date: 2026-10-09 09:05:54
Also in:
linux-kselftest
Subsystem:
kernel selftest framework, networking [general], openvswitch, the rest · Maintainers:
Shuah Khan, Shuah Khan, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Aaron Conole, Eelco Chaudron, Ilya Maximets, Linus Torvalds
Add regression coverage for OVS IPv6 SET actions on later IPv6 fragments. A later fragment has no transport header, so the test sends a crafted noninitial fragment through a source-address SET flow, checks that the flow counter advances, and looks for a set_ipv6_addr warning. This covers the later-fragment case handled by the upstream fix. Signed-off-by: Sahaj Chaudhari <redacted> --- tools/testing/selftests/net/openvswitch/Makefile | 2 +- tools/testing/selftests/net/openvswitch/config | 1 + .../selftests/net/openvswitch/openvswitch.sh | 43 +++++++++++++++++++ .../selftests/net/openvswitch/ovs-ipv6-frag.py | 48 ++++++++++++++++++++++ 4 files changed, 93 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/net/openvswitch/Makefile b/tools/testing/selftests/net/openvswitch/Makefile
index 3fd1da2ec07d5..b3260cd354419 100644
--- a/tools/testing/selftests/net/openvswitch/Makefile
+++ b/tools/testing/selftests/net/openvswitch/Makefile@@ -6,7 +6,7 @@ CFLAGS += -Wall -Wl,--no-as-needed -O2 -g -I$(top_srcdir)/usr/include $(KHDR_INC TEST_PROGS := openvswitch.sh -TEST_FILES := ovs-dpctl.py +TEST_FILES := ovs-dpctl.py ovs-ipv6-frag.py EXTRA_CLEAN := test_netlink_checks
diff --git a/tools/testing/selftests/net/openvswitch/config b/tools/testing/selftests/net/openvswitch/config
index a825e0b5c88e5..b062ebbce0f00 100644
--- a/tools/testing/selftests/net/openvswitch/config
+++ b/tools/testing/selftests/net/openvswitch/config@@ -3,6 +3,7 @@ CONFIG_INET_DIAG=y CONFIG_IP_SCTP=y CONFIG_IPV6=y CONFIG_NETFILTER=y +CONFIG_DEBUG_NET=y CONFIG_NET_IPGRE=m CONFIG_NET_IPGRE_DEMUX=m CONFIG_NF_CONNTRACK=m
diff --git a/tools/testing/selftests/net/openvswitch/openvswitch.sh b/tools/testing/selftests/net/openvswitch/openvswitch.sh
index a31f7fb6882dc..b9a4c4bf40672 100755
--- a/tools/testing/selftests/net/openvswitch/openvswitch.sh
+++ b/tools/testing/selftests/net/openvswitch/openvswitch.sh@@ -31,6 +31,7 @@ tests=" dec_ttl ttl: dec_ttl decrements IP TTL flow_set flow-set: Flow modify action_set set: SET action rewrites fields + ipv6_later_frag ipv6-frag: SET on a later IPv6 fragment trunc trunc: output truncation icmpv6 icmpv6: ICMPv6 echo type match sctp_connect_v4 sctp: SCTP flow key matching
@@ -66,6 +67,11 @@ ovs_wait() { return 1 } +ovs_flow_has_packets() { + python3 "$ovs_base/ovs-dpctl.py" dump-flows "$1" | + grep -Eq 'packets:[1-9][0-9]*,' +} + ovs_base=`pwd` sbxs= sbx_add () {
@@ -445,6 +451,43 @@ test_action_set() { return 0 } +test_ipv6_later_frag() { + local t="test_ipv6_later_frag" + local warning="WARNING:.*set_ipv6_addr" + local before after + + if ! dmesg >/dev/null 2>&1; then + info "dmesg unavailable - cannot check for kernel warning" + return $ksft_skip + fi + + before=$(dmesg | grep -c "$warning" || true) + if [ "$before" -ne 0 ]; then + info "set_ipv6_addr warning already present - skipping" + return $ksft_skip + fi + + sbx_add "$t" || return 1 + ovs_add_dp "$t" fragtest || return 1 + ovs_add_netns_and_veths "$t" fragtest client c0 c1 || return 1 + + ovs_add_flow "$t" fragtest \ + 'in_port(1),eth(),eth_type(0x86dd),ipv6(proto=44)' \ + 'set(ipv6(src=2001:db8::99,proto=44)),drop' || return 1 + + ip netns exec client python3 "$ovs_base/ovs-ipv6-frag.py" c1 || \ + return 1 + ovs_wait ovs_flow_has_packets fragtest || return 1 + + after=$(dmesg | grep -c "$warning" || true) + if [ "$after" -ne "$before" ]; then + info "set_ipv6_addr warning emitted for later IPv6 fragment" + return 1 + fi + + return 0 +} + # trunc test # - trunc(14): truncate to ETH_HLEN, strips IP payload, ping fails # - trunc(1) and trunc(13): kernel rejects below ETH_HLEN (EINVAL)
diff --git a/tools/testing/selftests/net/openvswitch/ovs-ipv6-frag.py b/tools/testing/selftests/net/openvswitch/ovs-ipv6-frag.py
new file mode 100644
index 0000000000000..869f9d6503ef4
--- /dev/null
+++ b/tools/testing/selftests/net/openvswitch/ovs-ipv6-frag.py@@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 + +import ipaddress +import socket +import struct +import sys + + +def main(): + if len(sys.argv) != 2: + print(f"Usage: {sys.argv[0]} INTERFACE", file=sys.stderr) + return 2 + + interface = sys.argv[1] + payload = bytes(range(8)) + # Offset 1 and M=1 make this a noninitial fragment. + fragment = struct.pack("!BBHI", socket.IPPROTO_TCP, 0, 0x0009, 1) + ipv6 = struct.pack( + "!IHBB16s16s", + 6 << 28, + len(fragment) + len(payload), + socket.IPPROTO_FRAGMENT, + 64, + ipaddress.IPv6Address("2001:db8::1").packed, + ipaddress.IPv6Address("2001:db8::2").packed, + ) + ethernet = struct.pack( + "!6s6sH", + b"\xff" * 6, + bytes.fromhex("020000000001"), + 0x86DD, + ) + packet = ethernet + ipv6 + fragment + payload + + with socket.socket( + socket.AF_PACKET, socket.SOCK_RAW, socket.htons(0x0003) + ) as sock: + sock.bind((interface, 0)) + sent = sock.send(packet) + + if sent != len(packet): + raise OSError(f"short packet send: {sent} of {len(packet)} bytes") + return 0 + + +if __name__ == "__main__": + sys.exit(main())