summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-04-23 16:50:42 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-04-23 16:50:42 -0700
commite728258debd553c95d2e70f9cd97c9fde27c7130 (patch)
tree18ef97c80f9923717f5cf6bdab44d77607ca0f4b /tools
parente8df5a0c0d041588e7f02781822d637d226cdbe8 (diff)
parent5e6391da4539c35422c0df1d1d2d9a9bb97cd736 (diff)
Merge tag 'net-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Pull networking fixes from Jakub Kicinski: "Including fixes from Netfilter. Steady stream of fixes. Last two weeks feel comparable to the two weeks before the merge window. Lots of AI-aided bug discovery. A newer big source is Sashiko/Gemini (Roman Gushchin's system), which points out issues in existing code during patch review (maybe 25% of fixes here likely originating from Sashiko). Nice thing is these are often fixed by the respective maintainers, not drive-bys. Current release - new code bugs: - kconfig: MDIO_PIC64HPSC should depend on ARCH_MICROCHIP Previous releases - regressions: - add async ndo_set_rx_mode and switch drivers which we promised to be called under the per-netdev mutex to it - dsa: remove duplicate netdev_lock_ops() for conduit ethtool ops - hv_sock: report EOF instead of -EIO for FIN - vsock/virtio: fix MSG_PEEK calculation on bytes to copy Previous releases - always broken: - ipv6: fix possible UAF in icmpv6_rcv() - icmp: validate reply type before using icmp_pointers - af_unix: drop all SCM attributes for SOCKMAP - netfilter: fix a number of bugs in the osf (OS fingerprinting) - eth: intel: fix timestamp interrupt configuration for E825C Misc: - bunch of data-race annotations" * tag 'net-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (148 commits) rxrpc: Fix error handling in rxgk_extract_token() rxrpc: Fix re-decryption of RESPONSE packets rxrpc: Fix rxrpc_input_call_event() to only unshare DATA packets rxrpc: Fix missing validation of ticket length in non-XDR key preparsing rxgk: Fix potential integer overflow in length check rxrpc: Fix conn-level packet handling to unshare RESPONSE packets rxrpc: Fix potential UAF after skb_unshare() failure rxrpc: Fix rxkad crypto unalignment handling rxrpc: Fix memory leaks in rxkad_verify_response() net: rds: fix MR cleanup on copy error m68k: mvme147: Make me the maintainer net: txgbe: fix firmware version check selftests/bpf: check epoll readiness during reuseport migration tcp: call sk_data_ready() after listener migration vhost_net: fix sleeping with preempt-disabled in vhost_net_busy_poll() ipv6: Cap TLV scan in ip6_tnl_parse_tlv_enc_lim tipc: fix double-free in tipc_buf_append() llc: Return -EINPROGRESS from llc_ui_connect() ipv4: icmp: validate reply type before using icmp_pointers selftests/net: packetdrill: cover RFC 5961 5.2 challenge ACK on both edges ...
Diffstat (limited to 'tools')
-rw-r--r--tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c49
-rw-r--r--tools/testing/selftests/drivers/net/bonding/lag_lib.sh17
-rwxr-xr-xtools/testing/selftests/drivers/net/team/dev_addr_lists.sh2
-rw-r--r--tools/testing/selftests/net/config1
-rwxr-xr-xtools/testing/selftests/net/fib_nexthops.sh22
-rwxr-xr-xtools/testing/selftests/net/mptcp/diag.sh28
-rw-r--r--tools/testing/selftests/net/ovpn/common.sh355
-rw-r--r--tools/testing/selftests/net/ovpn/config3
-rwxr-xr-xtools/testing/selftests/net/ovpn/test-chachapoly.sh2
-rwxr-xr-xtools/testing/selftests/net/ovpn/test-close-socket-tcp.sh2
-rwxr-xr-xtools/testing/selftests/net/ovpn/test-close-socket.sh90
-rwxr-xr-xtools/testing/selftests/net/ovpn/test-float.sh2
-rwxr-xr-xtools/testing/selftests/net/ovpn/test-mark.sh237
-rwxr-xr-xtools/testing/selftests/net/ovpn/test-symmetric-id-float.sh4
-rwxr-xr-xtools/testing/selftests/net/ovpn/test-symmetric-id-tcp.sh4
-rwxr-xr-xtools/testing/selftests/net/ovpn/test-symmetric-id.sh2
-rwxr-xr-xtools/testing/selftests/net/ovpn/test-tcp.sh2
-rwxr-xr-xtools/testing/selftests/net/ovpn/test.sh449
-rw-r--r--tools/testing/selftests/net/packetdrill/tcp_rfc5961_ack-out-of-window.pkt48
-rw-r--r--tools/testing/selftests/net/packetdrill/tcp_ts_recent_invalid_ack.pkt4
-rwxr-xr-xtools/testing/selftests/net/rtnetlink.sh44
-rw-r--r--tools/testing/selftests/net/tcp_ao/config1
-rw-r--r--tools/testing/vsock/util.c15
-rw-r--r--tools/testing/vsock/vsock_test.c50
24 files changed, 1048 insertions, 385 deletions
diff --git a/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c b/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c
index 653b0a20fab9..c62907732c19 100644
--- a/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c
+++ b/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c
@@ -7,24 +7,29 @@
* 3. call listen() for 1 server socket. (migration target)
* 4. update a map to migrate all child sockets
* to the last server socket (migrate_map[cookie] = 4)
- * 5. call shutdown() for first 4 server sockets
+ * 5. for TCP_ESTABLISHED and TCP_SYN_RECV cases, verify via epoll
+ * that the last server socket is not ready before migration.
+ * 6. call shutdown() for first 4 server sockets
* and migrate the requests in the accept queue
* to the last server socket.
- * 6. call listen() for the second server socket.
- * 7. call shutdown() for the last server
+ * 7. for TCP_ESTABLISHED and TCP_SYN_RECV cases, verify via epoll
+ * that the last server socket is ready after migration.
+ * 8. call listen() for the second server socket.
+ * 9. call shutdown() for the last server
* and migrate the requests in the accept queue
* to the second server socket.
- * 8. call listen() for the last server.
- * 9. call shutdown() for the second server
+ * 10. call listen() for the last server.
+ * 11. call shutdown() for the second server
* and migrate the requests in the accept queue
* to the last server socket.
- * 10. call accept() for the last server socket.
+ * 12. call accept() for the last server socket.
*
* Author: Kuniyuki Iwashima <kuniyu@amazon.co.jp>
*/
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
+#include <sys/epoll.h>
#include "test_progs.h"
#include "test_migrate_reuseport.skel.h"
@@ -350,21 +355,51 @@ static int update_maps(struct migrate_reuseport_test_case *test_case,
static int migrate_dance(struct migrate_reuseport_test_case *test_case)
{
+ struct epoll_event ev = {
+ .events = EPOLLIN,
+ };
+ int epoll = -1, nfds;
int i, err;
+ if (test_case->state != BPF_TCP_NEW_SYN_RECV) {
+ epoll = epoll_create1(0);
+ if (!ASSERT_NEQ(epoll, -1, "epoll_create1"))
+ return -1;
+
+ ev.data.fd = test_case->servers[MIGRATED_TO];
+ if (!ASSERT_OK(epoll_ctl(epoll, EPOLL_CTL_ADD,
+ test_case->servers[MIGRATED_TO], &ev),
+ "epoll_ctl"))
+ goto close_epoll;
+
+ nfds = epoll_wait(epoll, &ev, 1, 0);
+ if (!ASSERT_EQ(nfds, 0, "epoll_wait 1"))
+ goto close_epoll;
+ }
+
/* Migrate TCP_ESTABLISHED and TCP_SYN_RECV requests
* to the last listener based on eBPF.
*/
for (i = 0; i < MIGRATED_TO; i++) {
err = shutdown(test_case->servers[i], SHUT_RDWR);
if (!ASSERT_OK(err, "shutdown"))
- return -1;
+ goto close_epoll;
}
/* No dance for TCP_NEW_SYN_RECV to migrate based on eBPF */
if (test_case->state == BPF_TCP_NEW_SYN_RECV)
return 0;
+ nfds = epoll_wait(epoll, &ev, 1, 0);
+ if (!ASSERT_EQ(nfds, 1, "epoll_wait 2")) {
+close_epoll:
+ if (epoll >= 0)
+ close(epoll);
+ return -1;
+ }
+
+ close(epoll);
+
/* Note that we use the second listener instead of the
* first one here.
*
diff --git a/tools/testing/selftests/drivers/net/bonding/lag_lib.sh b/tools/testing/selftests/drivers/net/bonding/lag_lib.sh
index bf9bcd1b5ec0..f2e43b6c4c81 100644
--- a/tools/testing/selftests/drivers/net/bonding/lag_lib.sh
+++ b/tools/testing/selftests/drivers/net/bonding/lag_lib.sh
@@ -23,20 +23,9 @@ test_LAG_cleanup()
ip link set dev dummy2 master "$name"
elif [ "$driver" = "team" ]; then
name="team0"
- teamd -d -c '
- {
- "device": "'"$name"'",
- "runner": {
- "name": "'"$mode"'"
- },
- "ports": {
- "dummy1":
- {},
- "dummy2":
- {}
- }
- }
- '
+ ip link add "$name" type team
+ ip link set dev dummy1 master "$name"
+ ip link set dev dummy2 master "$name"
ip link set dev "$name" up
else
check_err 1
diff --git a/tools/testing/selftests/drivers/net/team/dev_addr_lists.sh b/tools/testing/selftests/drivers/net/team/dev_addr_lists.sh
index b1ec7755b783..26469f3be022 100755
--- a/tools/testing/selftests/drivers/net/team/dev_addr_lists.sh
+++ b/tools/testing/selftests/drivers/net/team/dev_addr_lists.sh
@@ -42,8 +42,6 @@ team_cleanup()
}
-require_command teamd
-
trap cleanup EXIT
tests_run
diff --git a/tools/testing/selftests/net/config b/tools/testing/selftests/net/config
index 2a390cae41bf..94d722770420 100644
--- a/tools/testing/selftests/net/config
+++ b/tools/testing/selftests/net/config
@@ -101,6 +101,7 @@ CONFIG_NET_SCH_HTB=m
CONFIG_NET_SCH_INGRESS=m
CONFIG_NET_SCH_NETEM=y
CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_TEAM=y
CONFIG_NET_VRF=y
CONFIG_NF_CONNTRACK=m
CONFIG_NF_CONNTRACK_OVS=y
diff --git a/tools/testing/selftests/net/fib_nexthops.sh b/tools/testing/selftests/net/fib_nexthops.sh
index 6eb7f95e70e1..ac868a731694 100755
--- a/tools/testing/selftests/net/fib_nexthops.sh
+++ b/tools/testing/selftests/net/fib_nexthops.sh
@@ -1209,6 +1209,28 @@ ipv6_fcnal_runtime()
run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 124"
log_test $? 0 "IPv6 route using a group after replacing v4 gateways"
+ # Replacing an IPv6 nexthop with an IPv4 nexthop should update has_v4
+ # for all groups using it, preventing IPv6 routes from referencing the
+ # group after the replace.
+ run_cmd "$IP nexthop add id 89 via 2001:db8:91::2 dev veth1"
+ run_cmd "$IP nexthop add id 125 group 89"
+ run_cmd "$IP nexthop replace id 89 via 172.16.1.1 dev veth1"
+ run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 125"
+ log_test $? 2 "IPv6 route can not use group after v6 nexthop replaced by v4"
+
+ # Same scenario but with a blackhole nexthop: the group has no IPv6
+ # routes yet when the replace happens, so fib6_check_nh_list returns
+ # early without checking. has_v4 must still be updated to block
+ # subsequent IPv6 route additions.
+ run_cmd "$IP nexthop flush >/dev/null 2>&1"
+ run_cmd "$IP -6 nexthop add id 90 blackhole"
+ run_cmd "$IP nexthop add id 125 group 90"
+ run_cmd "$IP nexthop replace id 90 blackhole"
+ run_cmd "$IP -6 ro add 2001:db8:101::1/128 nhid 125"
+ log_test $? 2 "IPv6 route reject v6 blackhole replaced by v4 blackhole"
+ run_cmd "ip netns exec $me ping -6 2001:db8:101::1 -c1 -w$PING_TIMEOUT"
+ log_test $? 2 "Ping unreachable after rejected route"
+
$IP nexthop flush >/dev/null 2>&1
#
diff --git a/tools/testing/selftests/net/mptcp/diag.sh b/tools/testing/selftests/net/mptcp/diag.sh
index d847ff1737c3..27cbda68144e 100755
--- a/tools/testing/selftests/net/mptcp/diag.sh
+++ b/tools/testing/selftests/net/mptcp/diag.sh
@@ -322,6 +322,33 @@ wait_connected()
done
}
+chk_sndbuf()
+{
+ local server_sndbuf client_sndbuf msg
+ local port=${1}
+
+ msg="....chk sndbuf server/client"
+ server_sndbuf=$(ss -N "${ns}" -inmHM "sport" "${port}" | \
+ sed -n 's/.*tb\([0-9]\+\).*/\1/p')
+ client_sndbuf=$(ss -N "${ns}" -inmHM "dport" "${port}" | \
+ sed -n 's/.*tb\([0-9]\+\).*/\1/p')
+
+ mptcp_lib_print_title "${msg}"
+ if [ -z "${server_sndbuf}" ] || [ -z "${client_sndbuf}" ]; then
+ mptcp_lib_pr_fail "sndbuf S=${server_sndbuf} C=${client_sndbuf}"
+ mptcp_lib_result_fail "${msg}"
+ ret=${KSFT_FAIL}
+ elif [ "${server_sndbuf}" != "${client_sndbuf}" ]; then
+ mptcp_lib_pr_fail "sndbuf S=${server_sndbuf} != C=${client_sndbuf}"
+ mptcp_lib_result_fail "${msg}"
+ ret=${KSFT_FAIL}
+ else
+ mptcp_lib_pr_ok
+ mptcp_lib_result_pass "${msg}"
+ fi
+}
+
+
trap cleanup EXIT
mptcp_lib_ns_init ns
@@ -341,6 +368,7 @@ echo "b" | \
127.0.0.1 >/dev/null &
wait_connected $ns 10000
chk_msk_nr 2 "after MPC handshake"
+chk_sndbuf 10000
chk_last_time_info 10000
chk_msk_remote_key_nr 2 "....chk remote_key"
chk_msk_fallback_nr 0 "....chk no fallback"
diff --git a/tools/testing/selftests/net/ovpn/common.sh b/tools/testing/selftests/net/ovpn/common.sh
index 4c08f756e63a..2d844eb3aa6e 100644
--- a/tools/testing/selftests/net/ovpn/common.sh
+++ b/tools/testing/selftests/net/ovpn/common.sh
@@ -4,62 +4,181 @@
#
# Author: Antonio Quartulli <antonio@openvpn.net>
-UDP_PEERS_FILE=${UDP_PEERS_FILE:-udp_peers.txt}
-TCP_PEERS_FILE=${TCP_PEERS_FILE:-tcp_peers.txt}
-OVPN_CLI=${OVPN_CLI:-./ovpn-cli}
-YNL_CLI=${YNL_CLI:-../../../../net/ynl/pyynl/cli.py}
-ALG=${ALG:-aes}
-PROTO=${PROTO:-UDP}
-FLOAT=${FLOAT:-0}
-SYMMETRIC_ID=${SYMMETRIC_ID:-0}
-
-export ID_OFFSET=$(( 9 * (SYMMETRIC_ID == 0) ))
-
-JQ_FILTER='map(select(.msg.peer | has("remote-ipv6") | not)) |
+OVPN_COMMON_DIR=$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")
+source "$OVPN_COMMON_DIR/../../kselftest/ktap_helpers.sh"
+
+OVPN_UDP_PEERS_FILE=${OVPN_UDP_PEERS_FILE:-udp_peers.txt}
+OVPN_TCP_PEERS_FILE=${OVPN_TCP_PEERS_FILE:-tcp_peers.txt}
+OVPN_CLI=${OVPN_CLI:-${OVPN_COMMON_DIR}/ovpn-cli}
+OVPN_YNL=${OVPN_YNL:-${OVPN_COMMON_DIR}/../../../../net/ynl/pyynl/cli.py}
+OVPN_ALG=${OVPN_ALG:-aes}
+OVPN_PROTO=${OVPN_PROTO:-UDP}
+OVPN_FLOAT=${OVPN_FLOAT:-0}
+OVPN_SYMMETRIC_ID=${OVPN_SYMMETRIC_ID:-0}
+OVPN_VERBOSE=${OVPN_VERBOSE:-0}
+
+export OVPN_ID_OFFSET=$(( 9 * (OVPN_SYMMETRIC_ID == 0) ))
+
+OVPN_JQ_FILTER='map(if type == "array" then .[] else . end) |
+ map(select(.msg.peer | has("remote-ipv6") | not)) |
map(del(.msg.ifindex)) | sort_by(.msg.peer.id)[]'
-LAN_IP="11.11.11.11"
+OVPN_LAN_IP="11.11.11.11"
+
+declare -A OVPN_TMP_JSONS=()
+declare -A OVPN_LISTENER_PIDS=()
+OVPN_CURRENT_STAGE=""
+
+ovpn_is_verbose() {
+ [[ "${OVPN_VERBOSE}" == "1" ]]
+}
+
+ovpn_log() {
+ ovpn_is_verbose || return 0
+ printf '%s\n' "$*"
+}
+
+ovpn_print_cmd_output() {
+ local output_file="$1"
+ local line
+
+ [[ -s "${output_file}" ]] || return 0
+
+ while IFS= read -r line; do
+ ovpn_log "${line}"
+ done < "${output_file}"
+}
+
+ovpn_cmd_run() {
+ local mode="$1"
+ local label="$2"
+ local output_file
+ local rc
+ local ret=0
+
+ shift 2
+
+ output_file=$(mktemp)
+ if "$@" >"${output_file}" 2>&1; then
+ rc=0
+ else
+ rc=$?
+ fi
+
+ case "${mode}" in
+ ok)
+ if [[ "${rc}" -ne 0 ]]; then
+ cat "${output_file}"
+ printf '%s\n' \
+ "${label}: command failed with rc=${rc}: $*"
+ ret="${rc}"
+ fi
+ ;;
+ mayfail)
+ ;;
+ fail)
+ [[ "${rc}" -eq 0 ]] && ret=1
+ ;;
+ esac
+
+ if ovpn_is_verbose && [[ "${rc}" -eq 0 || "${mode}" != "ok" ]]; then
+ ovpn_print_cmd_output "${output_file}"
+ fi
+
+ rm -f "${output_file}"
+ return "${ret}"
+}
+
+ovpn_cmd_ok() {
+ ovpn_cmd_run ok "$@"
+}
+
+ovpn_cmd_mayfail() {
+ ovpn_cmd_run mayfail "$@"
+}
+
+ovpn_cmd_fail() {
+ ovpn_cmd_run fail "$@"
+}
-declare -A tmp_jsons=()
-declare -A listener_pids=()
+ovpn_run_bg() {
+ local pid_var="$1"
-create_ns() {
- ip netns add peer${1}
+ shift
+ if ovpn_is_verbose; then
+ "$@" &
+ else
+ "$@" >/dev/null 2>&1 &
+ fi
+
+ printf -v "${pid_var}" '%s' "$!"
+}
+
+ovpn_run_stage() {
+ local label="$1"
+
+ shift
+ OVPN_CURRENT_STAGE="${label}"
+ "$@"
+ OVPN_CURRENT_STAGE=""
+ ktap_test_pass "${label}"
}
-setup_ns() {
+ovpn_stage_err() {
+ # ERR trap is global under set -eE: only report failures that happen
+ # while ovpn_run_stage() is actively executing a stage body.
+ if [[ -n "${OVPN_CURRENT_STAGE}" ]]; then
+ ktap_test_fail "${OVPN_CURRENT_STAGE}"
+ OVPN_CURRENT_STAGE=""
+ fi
+}
+
+ovpn_create_ns() {
+ ip netns add "ovpn_peer${1}"
+}
+
+ovpn_setup_ns() {
+ local peer="ovpn_peer${1}"
+ local server_ns="ovpn_peer0"
+ local peer_ns
MODE="P2P"
if [ ${1} -eq 0 ]; then
MODE="MP"
- for p in $(seq 1 ${NUM_PEERS}); do
- ip link add veth${p} netns peer0 type veth peer name veth${p} netns peer${p}
+ for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+ peer_ns="ovpn_peer${p}"
+ ip link add veth${p} netns "${server_ns}" type veth \
+ peer name veth${p} netns "${peer_ns}"
- ip -n peer0 addr add 10.10.${p}.1/24 dev veth${p}
- ip -n peer0 addr add fd00:0:0:${p}::1/64 dev veth${p}
- ip -n peer0 link set veth${p} up
+ ip -n "${server_ns}" addr add 10.10.${p}.1/24 dev \
+ veth${p}
+ ip -n "${server_ns}" addr add fd00:0:0:${p}::1/64 dev \
+ veth${p}
+ ip -n "${server_ns}" link set veth${p} up
- ip -n peer${p} addr add 10.10.${p}.2/24 dev veth${p}
- ip -n peer${p} addr add fd00:0:0:${p}::2/64 dev veth${p}
- ip -n peer${p} link set veth${p} up
+ ip -n "${peer_ns}" addr add 10.10.${p}.2/24 dev veth${p}
+ ip -n "${peer_ns}" addr add fd00:0:0:${p}::2/64 dev \
+ veth${p}
+ ip -n "${peer_ns}" link set veth${p} up
done
fi
- ip netns exec peer${1} ${OVPN_CLI} new_iface tun${1} $MODE
- ip -n peer${1} addr add ${2} dev tun${1}
+ ip netns exec "${peer}" ${OVPN_CLI} new_iface tun${1} $MODE
+ ip -n "${peer}" addr add ${2} dev tun${1}
# add a secondary IP to peer 1, to test a LAN behind a client
- if [ ${1} -eq 1 -a -n "${LAN_IP}" ]; then
- ip -n peer${1} addr add ${LAN_IP} dev tun${1}
- ip -n peer0 route add ${LAN_IP} via $(echo ${2} |sed -e s'!/.*!!') dev tun0
+ if [ ${1} -eq 1 -a -n "${OVPN_LAN_IP}" ]; then
+ ip -n "${peer}" addr add ${OVPN_LAN_IP} dev tun${1}
+ ip -n "${server_ns}" route add ${OVPN_LAN_IP} via \
+ $(echo ${2} |sed -e s'!/.*!!') dev tun0
fi
if [ -n "${3}" ]; then
- ip -n peer${1} link set mtu ${3} dev tun${1}
+ ip -n "${peer}" link set mtu ${3} dev tun${1}
fi
- ip -n peer${1} link set tun${1} up
+ ip -n "${peer}" link set tun${1} up
}
-build_capture_filter() {
+ovpn_build_capture_filter() {
# match the first four bytes of the openvpn data payload
- if [ "${PROTO}" == "UDP" ]; then
+ if [ "${OVPN_PROTO}" == "UDP" ]; then
# For UDP, libpcap transport indexing only works for IPv4, so
# use an explicit IPv4 or IPv6 expression based on the peer
# address. The IPv6 branch assumes there are no extension
@@ -76,108 +195,170 @@ build_capture_filter() {
fi
}
-setup_listener() {
+ovpn_setup_listener() {
+ local peer="$1"
+ local file
+ local peer_ns="ovpn_peer${peer}"
+
file=$(mktemp)
- PYTHONUNBUFFERED=1 ip netns exec peer${p} ${YNL_CLI} --family ovpn \
- --subscribe peers --output-json --duration 40 > ${file} &
- listener_pids[$1]=$!
- tmp_jsons[$1]="${file}"
+ PYTHONUNBUFFERED=1 ip netns exec "${peer_ns}" "${OVPN_YNL}" --family \
+ ovpn --subscribe peers --output-json > "${file}" \
+ 2>/dev/null &
+ OVPN_LISTENER_PIDS["${peer}"]=$!
+ OVPN_TMP_JSONS["${peer}"]="${file}"
}
-add_peer() {
+ovpn_add_peer() {
labels=("ASYMM" "SYMM")
- M_ID=${labels[SYMMETRIC_ID]}
+ local peer_ns
+ local server_ns="ovpn_peer0"
+ M_ID=${labels[OVPN_SYMMETRIC_ID]}
- if [ "${PROTO}" == "UDP" ]; then
+ if [ "${OVPN_PROTO}" == "UDP" ]; then
if [ ${1} -eq 0 ]; then
- ip netns exec peer0 ${OVPN_CLI} new_multi_peer tun0 1 \
- ${M_ID} ${UDP_PEERS_FILE}
+ ip netns exec "${server_ns}" ${OVPN_CLI} \
+ new_multi_peer tun0 1 ${M_ID} \
+ ${OVPN_UDP_PEERS_FILE}
- for p in $(seq 1 ${NUM_PEERS}); do
- ip netns exec peer0 ${OVPN_CLI} new_key tun0 ${p} 1 0 ${ALG} 0 \
+ for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+ ip netns exec "${server_ns}" ${OVPN_CLI} \
+ new_key tun0 ${p} 1 0 ${OVPN_ALG} 0 \
data64.key
done
else
- if [ "${SYMMETRIC_ID}" -eq 1 ]; then
+ peer_ns="ovpn_peer${1}"
+ if [ "${OVPN_SYMMETRIC_ID}" -eq 1 ]; then
PEER_ID=${1}
TX_ID="none"
else
PEER_ID=$(awk "NR == ${1} {print \$2}" \
- ${UDP_PEERS_FILE})
+ ${OVPN_UDP_PEERS_FILE})
TX_ID=${1}
fi
- RADDR=$(awk "NR == ${1} {print \$3}" ${UDP_PEERS_FILE})
- RPORT=$(awk "NR == ${1} {print \$4}" ${UDP_PEERS_FILE})
- LPORT=$(awk "NR == ${1} {print \$6}" ${UDP_PEERS_FILE})
- ip netns exec peer${1} ${OVPN_CLI} new_peer tun${1} \
- ${PEER_ID} ${TX_ID} ${LPORT} ${RADDR} ${RPORT}
- ip netns exec peer${1} ${OVPN_CLI} new_key tun${1} \
- ${PEER_ID} 1 0 ${ALG} 1 data64.key
+ RADDR=$(awk "NR == ${1} {print \$3}" \
+ ${OVPN_UDP_PEERS_FILE})
+ RPORT=$(awk "NR == ${1} {print \$4}" \
+ ${OVPN_UDP_PEERS_FILE})
+ LPORT=$(awk "NR == ${1} {print \$6}" \
+ ${OVPN_UDP_PEERS_FILE})
+ ip netns exec "${peer_ns}" ${OVPN_CLI} new_peer \
+ tun${1} ${PEER_ID} ${TX_ID} ${LPORT} ${RADDR} \
+ ${RPORT}
+ ip netns exec "${peer_ns}" ${OVPN_CLI} new_key tun${1} \
+ ${PEER_ID} 1 0 ${OVPN_ALG} 1 data64.key
fi
else
if [ ${1} -eq 0 ]; then
- (ip netns exec peer0 ${OVPN_CLI} listen tun0 1 ${M_ID} \
- ${TCP_PEERS_FILE} && {
- for p in $(seq 1 ${NUM_PEERS}); do
- ip netns exec peer0 ${OVPN_CLI} new_key tun0 ${p} 1 0 \
- ${ALG} 0 data64.key
+ (ip netns exec "${server_ns}" ${OVPN_CLI} listen tun0 \
+ 1 ${M_ID} ${OVPN_TCP_PEERS_FILE} && {
+ for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+ ip netns exec "${server_ns}" \
+ ${OVPN_CLI} new_key tun0 ${p} \
+ 1 0 ${OVPN_ALG} 0 data64.key
done
}) &
sleep 5
else
- if [ "${SYMMETRIC_ID}" -eq 1 ]; then
+ peer_ns="ovpn_peer${1}"
+ if [ "${OVPN_SYMMETRIC_ID}" -eq 1 ]; then
PEER_ID=${1}
TX_ID="none"
else
PEER_ID=$(awk "NR == ${1} {print \$2}" \
- ${TCP_PEERS_FILE})
+ ${OVPN_TCP_PEERS_FILE})
TX_ID=${1}
fi
- ip netns exec peer${1} ${OVPN_CLI} connect tun${1} \
+ ip netns exec "${peer_ns}" ${OVPN_CLI} connect tun${1} \
${PEER_ID} ${TX_ID} 10.10.${1}.1 1 data64.key
fi
fi
}
-compare_ntfs() {
- if [ ${#tmp_jsons[@]} -gt 0 ]; then
+ovpn_compare_ntfs() {
+ local diff_rc=0
+ local diff_file
+
+ if [ ${#OVPN_TMP_JSONS[@]} -gt 0 ]; then
suffix=""
- [ "${SYMMETRIC_ID}" -eq 1 ] && suffix="${suffix}-symm"
- [ "$FLOAT" == 1 ] && suffix="${suffix}-float"
+ [ "${OVPN_SYMMETRIC_ID}" -eq 1 ] && suffix="${suffix}-symm"
+ [ "$OVPN_FLOAT" == 1 ] && suffix="${suffix}-float"
expected="json/peer${1}${suffix}.json"
- received="${tmp_jsons[$1]}"
+ received="${OVPN_TMP_JSONS[$1]}"
+ diff_file=$(mktemp)
- kill -TERM ${listener_pids[$1]} || true
- wait ${listener_pids[$1]} || true
+ ovpn_stop_listener "${1}" 1
printf "Checking notifications for peer ${1}... "
- if diff <(jq -s "${JQ_FILTER}" ${expected}) \
- <(jq -s "${JQ_FILTER}" ${received}); then
+ if diff <(jq -s "${OVPN_JQ_FILTER}" ${expected}) \
+ <(jq -s "${OVPN_JQ_FILTER}" ${received}) \
+ >"${diff_file}" 2>&1; then
echo "OK"
+ else
+ diff_rc=$?
+ echo "failed"
+ cat "${diff_file}"
fi
- rm -f ${received} || true
+ rm -f "${diff_file}" || true
+ rm -f "${received}" || true
+ unset "OVPN_TMP_JSONS[$1]"
fi
+
+ return "${diff_rc}"
}
-cleanup() {
+ovpn_stop_listener() {
+ local peer="$1"
+ local keep_json="${2:-0}"
+ local pid="${OVPN_LISTENER_PIDS[$peer]:-}"
+ local json="${OVPN_TMP_JSONS[$peer]:-}"
+
+ if [[ -n "${pid}" ]]; then
+ kill -TERM "${pid}" 2>/dev/null || true
+ wait "${pid}" 2>/dev/null || true
+ unset "OVPN_LISTENER_PIDS[$peer]"
+ fi
+
+ if [[ -n "${json}" && "${keep_json}" -eq 0 ]]; then
+ rm -f "${json}" || true
+ unset "OVPN_TMP_JSONS[$peer]"
+ fi
+}
+
+ovpn_cleanup_peer_ns() {
+ local peer="$1"
+ local peer_id="${peer#ovpn_peer}"
+
+ ip -n "${peer}" link set tun${peer_id} down 2>/dev/null || true
+ ip netns exec "${peer}" ${OVPN_CLI} del_iface tun${peer_id} \
+ 1>/dev/null 2>&1 || true
+ ip netns del "${peer}" 2>/dev/null || true
+}
+
+ovpn_cleanup() {
+ local peer
+
# some ovpn-cli processes sleep in background so they need manual poking
- killall $(basename ${OVPN_CLI}) 2>/dev/null || true
+ killall "$(basename "${OVPN_CLI}")" 2>/dev/null || true
- # netns peer0 is deleted without erasing ifaces first
- for p in $(seq 1 10); do
- ip -n peer${p} link set tun${p} down 2>/dev/null || true
- ip netns exec peer${p} ${OVPN_CLI} del_iface tun${p} 2>/dev/null || true
+ for peer in "${!OVPN_LISTENER_PIDS[@]}"; do
+ ovpn_stop_listener "${peer}" 2>/dev/null
done
+
for p in $(seq 1 10); do
- ip -n peer0 link del veth${p} 2>/dev/null || true
- done
- for p in $(seq 0 10); do
- ip netns del peer${p} 2>/dev/null || true
+ ip -n ovpn_peer0 link del veth${p} 2>/dev/null || true
done
+
+ # remove from ovpn's netns pool
+ while IFS= read -r peer; do
+ [[ -n "${peer}" ]] || continue
+ ovpn_cleanup_peer_ns "${peer}" 2>/dev/null
+ done < <(ip netns list 2>/dev/null | awk '/^ovpn_/ {print $1}')
}
-if [ "${PROTO}" == "UDP" ]; then
- NUM_PEERS=${NUM_PEERS:-$(wc -l ${UDP_PEERS_FILE} | awk '{print $1}')}
+if [ "${OVPN_PROTO}" == "UDP" ]; then
+ OVPN_NUM_PEERS=${OVPN_NUM_PEERS:-$(wc -l ${OVPN_UDP_PEERS_FILE} | \
+ awk '{print $1}')}
else
- NUM_PEERS=${NUM_PEERS:-$(wc -l ${TCP_PEERS_FILE} | awk '{print $1}')}
+ OVPN_NUM_PEERS=${OVPN_NUM_PEERS:-$(wc -l ${OVPN_TCP_PEERS_FILE} | \
+ awk '{print $1}')}
fi
diff --git a/tools/testing/selftests/net/ovpn/config b/tools/testing/selftests/net/ovpn/config
index 42699740936d..d6cf033d555e 100644
--- a/tools/testing/selftests/net/ovpn/config
+++ b/tools/testing/selftests/net/ovpn/config
@@ -5,6 +5,9 @@ CONFIG_CRYPTO_GCM=y
CONFIG_DST_CACHE=y
CONFIG_INET=y
CONFIG_NET=y
+CONFIG_NETFILTER=y
CONFIG_NET_UDP_TUNNEL=y
+CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=y
CONFIG_OVPN=m
CONFIG_STREAM_PARSER=y
diff --git a/tools/testing/selftests/net/ovpn/test-chachapoly.sh b/tools/testing/selftests/net/ovpn/test-chachapoly.sh
index 32504079a2b8..cd3d94355d58 100755
--- a/tools/testing/selftests/net/ovpn/test-chachapoly.sh
+++ b/tools/testing/selftests/net/ovpn/test-chachapoly.sh
@@ -4,6 +4,6 @@
#
# Author: Antonio Quartulli <antonio@openvpn.net>
-ALG="chachapoly"
+OVPN_ALG="chachapoly"
source test.sh
diff --git a/tools/testing/selftests/net/ovpn/test-close-socket-tcp.sh b/tools/testing/selftests/net/ovpn/test-close-socket-tcp.sh
index 093d44772ffd..392d269bada5 100755
--- a/tools/testing/selftests/net/ovpn/test-close-socket-tcp.sh
+++ b/tools/testing/selftests/net/ovpn/test-close-socket-tcp.sh
@@ -4,6 +4,6 @@
#
# Author: Antonio Quartulli <antonio@openvpn.net>
-PROTO="TCP"
+OVPN_PROTO="TCP"
source test-close-socket.sh
diff --git a/tools/testing/selftests/net/ovpn/test-close-socket.sh b/tools/testing/selftests/net/ovpn/test-close-socket.sh
index 0d09df14fe8e..af1532b4d2da 100755
--- a/tools/testing/selftests/net/ovpn/test-close-socket.sh
+++ b/tools/testing/selftests/net/ovpn/test-close-socket.sh
@@ -5,41 +5,81 @@
# Author: Antonio Quartulli <antonio@openvpn.net>
#set -x
-set -e
+set -eE
source ./common.sh
-cleanup
+ovpn_test_finished=0
-modprobe -q ovpn || true
+ovpn_test_exit() {
+ ovpn_cleanup
+ modprobe -r ovpn || true
+
+ if [ "${ovpn_test_finished}" -eq 0 ]; then
+ ktap_print_totals
+ fi
+}
+
+ovpn_prepare_network() {
+ local p
+ local peer_ns
+
+ for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+ ovpn_cmd_ok "create namespace peer${p}" ovpn_create_ns "${p}"
+ done
-for p in $(seq 0 ${NUM_PEERS}); do
- create_ns ${p}
-done
+ for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+ ovpn_cmd_ok "configure peer${p} namespace" ovpn_setup_ns \
+ "${p}" 5.5.5.$((p + 1))/24
+ done
-for p in $(seq 0 ${NUM_PEERS}); do
- setup_ns ${p} 5.5.5.$((${p} + 1))/24
-done
+ for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+ ovpn_cmd_ok "register peer${p} in overlay" ovpn_add_peer "${p}"
+ done
-for p in $(seq 0 ${NUM_PEERS}); do
- add_peer ${p}
-done
+ for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+ peer_ns="ovpn_peer${p}"
+ ovpn_cmd_ok "set peer0 timeout for peer ${p}" \
+ ip netns exec ovpn_peer0 ${OVPN_CLI} set_peer tun0 \
+ ${p} 60 120
+ ovpn_cmd_ok "set peer${p} timeout for peer ${p}" \
+ ip netns exec "${peer_ns}" ${OVPN_CLI} set_peer \
+ tun${p} $((p + OVPN_ID_OFFSET)) 60 120
+ done
+}
-for p in $(seq 1 ${NUM_PEERS}); do
- ip netns exec peer0 ${OVPN_CLI} set_peer tun0 ${p} 60 120
- ip netns exec peer${p} ${OVPN_CLI} set_peer tun${p} $((${p}+9)) 60 120
-done
+ovpn_run_ping_traffic() {
+ local p
-sleep 1
+ for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+ ovpn_cmd_ok "send ping traffic to peer ${p}" \
+ ip netns exec ovpn_peer0 ping -qfc 500 -w 3 \
+ 5.5.5.$((p + 1))
+ done
+}
-for p in $(seq 1 ${NUM_PEERS}); do
- ip netns exec peer0 ping -qfc 500 -w 3 5.5.5.$((${p} + 1))
-done
+ovpn_run_iperf() {
+ local iperf_pid
-ip netns exec peer0 iperf3 -1 -s &
-sleep 1
-ip netns exec peer1 iperf3 -Z -t 3 -c 5.5.5.1
+ ovpn_run_bg iperf_pid ip netns exec ovpn_peer0 iperf3 -1 -s
+ sleep 1
+ ovpn_cmd_ok "run iperf throughput flow" \
+ ip netns exec ovpn_peer1 iperf3 -Z -t 3 -c 5.5.5.1
+ wait "${iperf_pid}" || return 1
+}
+
+trap ovpn_test_exit EXIT
+trap ovpn_stage_err ERR
+
+ktap_print_header
+ktap_set_plan 3
+
+ovpn_cleanup
+modprobe -q ovpn || true
-cleanup
+ovpn_run_stage "setup network topology" ovpn_prepare_network
+ovpn_run_stage "run ping traffic" ovpn_run_ping_traffic
+ovpn_run_stage "run iperf throughput" ovpn_run_iperf
-modprobe -r ovpn || true
+ovpn_test_finished=1
+ktap_finished
diff --git a/tools/testing/selftests/net/ovpn/test-float.sh b/tools/testing/selftests/net/ovpn/test-float.sh
index ba5d725e18b0..91f8e113718e 100755
--- a/tools/testing/selftests/net/ovpn/test-float.sh
+++ b/tools/testing/selftests/net/ovpn/test-float.sh
@@ -4,6 +4,6 @@
#
# Author: Antonio Quartulli <antonio@openvpn.net>
-FLOAT="1"
+OVPN_FLOAT="1"
source test.sh
diff --git a/tools/testing/selftests/net/ovpn/test-mark.sh b/tools/testing/selftests/net/ovpn/test-mark.sh
index 8534428ed3eb..5a8f47554286 100755
--- a/tools/testing/selftests/net/ovpn/test-mark.sh
+++ b/tools/testing/selftests/net/ovpn/test-mark.sh
@@ -6,91 +6,166 @@
# Antonio Quartulli <antonio@openvpn.net>
#set -x
-set -e
+set -eE
MARK=1056
+MARK_DROP_COUNTER=0
source ./common.sh
-cleanup
-
+ovpn_test_finished=0
+
+ovpn_test_exit() {
+ ovpn_cleanup
+ modprobe -r ovpn || true
+
+ if [ "${ovpn_test_finished}" -eq 0 ]; then
+ ktap_print_totals
+ fi
+}
+
+ovpn_mark_prepare_network() {
+ local p
+ local peer_ns
+
+ for p in $(seq 0 "${OVPN_NUM_PEERS}"); do
+ ovpn_cmd_ok "create namespace peer${p}" ovpn_create_ns "${p}"
+ done
+
+ for p in $(seq 0 3); do
+ ovpn_cmd_ok "configure peer${p} namespace" ovpn_setup_ns \
+ "${p}" 5.5.5.$((p + 1))/24
+ done
+
+ ovpn_cmd_ok "create server-side multi-peer with fwmark" \
+ ip netns exec ovpn_peer0 "${OVPN_CLI}" new_multi_peer tun0 1 \
+ ASYMM "${OVPN_UDP_PEERS_FILE}" "${MARK}"
+ for p in $(seq 1 3); do
+ ovpn_cmd_ok "install server key for peer ${p}" \
+ ip netns exec ovpn_peer0 "${OVPN_CLI}" new_key tun0 \
+ "${p}" 1 0 "${OVPN_ALG}" 0 data64.key
+ done
+
+ for p in $(seq 1 3); do
+ ovpn_cmd_ok "register peer${p} in overlay" ovpn_add_peer "${p}"
+ done
+
+ for p in $(seq 1 3); do
+ peer_ns="ovpn_peer${p}"
+ ovpn_cmd_ok "set peer0 timeout for peer ${p}" \
+ ip netns exec ovpn_peer0 "${OVPN_CLI}" set_peer tun0 \
+ "${p}" 60 120
+ ovpn_cmd_ok "set peer${p} timeout for peer ${p}" \
+ ip netns exec "${peer_ns}" "${OVPN_CLI}" set_peer \
+ tun"${p}" $((p + OVPN_ID_OFFSET)) 60 120
+ done
+}
+
+ovpn_mark_run_baseline_traffic() {
+ local p
+
+ for p in $(seq 1 3); do
+ ovpn_cmd_ok "send baseline traffic to peer ${p}" \
+ ip netns exec ovpn_peer0 ping -qfc 500 -w 3 \
+ 5.5.5.$((p + 1))
+ done
+}
+
+ovpn_mark_add_drop_rule() {
+ ovpn_log "Adding an nftables drop rule based on mark value ${MARK}"
+
+ ovpn_cmd_ok "flush nft ruleset" ip netns exec ovpn_peer0 nft flush \
+ ruleset
+ ovpn_cmd_ok "create nft filter table" ip netns exec ovpn_peer0 nft \
+ "add table inet filter"
+ ovpn_cmd_ok "create nft filter output chain" \
+ ip netns exec ovpn_peer0 nft "add chain inet filter output { \
+ type filter hook output priority 0; policy accept; }"
+ ovpn_cmd_ok "add nft drop rule for mark ${MARK}" \
+ ip netns exec ovpn_peer0 nft add rule inet filter output \
+ meta mark == "${MARK}" \
+ counter drop
+
+ MARK_DROP_COUNTER=$(ip netns exec ovpn_peer0 nft list chain inet \
+ filter output | sed -n 's/.*packets \([0-9]*\).*/\1/p')
+ if [ -z "${MARK_DROP_COUNTER}" ]; then
+ printf '%s\n' "unable to read nft drop counter"
+ return 1
+ fi
+}
+
+ovpn_mark_verify_drop_traffic() {
+ local p
+ local ping_output
+ local lost_packets
+ local total_count
+
+ for p in $(seq 1 3); do
+ if ping_output=$(ip netns exec ovpn_peer0 ping -qfc 500 -w 1 \
+ 5.5.5.$((p + 1)) 2>&1); then
+ printf '%s\n' "expected ping to peer ${p} to fail \
+ after nft drop rule"
+ return 1
+ fi
+ ovpn_log "${ping_output}"
+ lost_packets=$(echo "${ping_output}" | \
+ awk '/packets transmitted/ { print $1 }')
+ if [ -z "${lost_packets}" ]; then
+ printf '%s\n' "unable to parse lost packets for peer \
+ ${p}"
+ return 1
+ fi
+ MARK_DROP_COUNTER=$((MARK_DROP_COUNTER + lost_packets))
+ done
+
+ total_count=$(ip netns exec ovpn_peer0 nft list chain inet filter \
+ output | sed -n 's/.*packets \([0-9]*\).*/\1/p')
+ if [ -z "${total_count}" ]; then
+ printf '%s\n' "unable to read final nft drop counter"
+ return 1
+ fi
+ if [ "${MARK_DROP_COUNTER}" -ne "${total_count}" ]; then
+ printf '%s\n' "expected ${MARK_DROP_COUNTER} drops, got \
+ ${total_count}"
+ return 1
+ fi
+}
+
+ovpn_mark_remove_drop_rule() {
+ ovpn_log "Removing the drop rule"
+
+ ovpn_cmd_ok "flush nft ruleset" ip netns exec ovpn_peer0 nft flush \
+ ruleset
+}
+
+ovpn_mark_verify_traffic_recovery() {
+ local p
+
+ sleep 1
+ for p in $(seq 1 3); do
+ ovpn_cmd_ok "send recovery traffic to peer ${p}" \
+ ip netns exec ovpn_peer0 ping -qfc 500 -w 3 \
+ 5.5.5.$((p + 1))
+ done
+}
+
+trap ovpn_test_exit EXIT
+trap ovpn_stage_err ERR
+
+ktap_print_header
+ktap_set_plan 6
+
+ovpn_cleanup
modprobe -q ovpn || true
-for p in $(seq 0 "${NUM_PEERS}"); do
- create_ns "${p}"
-done
-
-for p in $(seq 0 3); do
- setup_ns "${p}" 5.5.5.$((p + 1))/24
-done
-
-# add peer0 with mark
-ip netns exec peer0 "${OVPN_CLI}" new_multi_peer tun0 1 ASYMM \
- "${UDP_PEERS_FILE}" \
- ${MARK}
-for p in $(seq 1 3); do
- ip netns exec peer0 "${OVPN_CLI}" new_key tun0 "${p}" 1 0 "${ALG}" 0 \
- data64.key
-done
-
-for p in $(seq 1 3); do
- add_peer "${p}"
-done
-
-for p in $(seq 1 3); do
- ip netns exec peer0 "${OVPN_CLI}" set_peer tun0 "${p}" 60 120
- ip netns exec peer"${p}" "${OVPN_CLI}" set_peer tun"${p}" \
- $((p + 9)) 60 120
-done
-
-sleep 1
-
-for p in $(seq 1 3); do
- ip netns exec peer0 ping -qfc 500 -w 3 5.5.5.$((p + 1))
-done
-
-echo "Adding an nftables drop rule based on mark value ${MARK}"
-ip netns exec peer0 nft flush ruleset
-ip netns exec peer0 nft 'add table inet filter'
-ip netns exec peer0 nft 'add chain inet filter output {
- type filter hook output priority 0;
- policy accept;
-}'
-ip netns exec peer0 nft add rule inet filter output \
- meta mark == ${MARK} \
- counter drop
-
-DROP_COUNTER=$(ip netns exec peer0 nft list chain inet filter output \
- | sed -n 's/.*packets \([0-9]*\).*/\1/p')
-sleep 1
-
-# ping should fail
-for p in $(seq 1 3); do
- PING_OUTPUT=$(ip netns exec peer0 ping \
- -qfc 500 -w 1 5.5.5.$((p + 1)) 2>&1) && exit 1
- echo "${PING_OUTPUT}"
- LOST_PACKETS=$(echo "$PING_OUTPUT" \
- | awk '/packets transmitted/ { print $1 }')
- # increment the drop counter by the amount of lost packets
- DROP_COUNTER=$((DROP_COUNTER + LOST_PACKETS))
-done
-
-# check if the final nft counter matches our counter
-TOTAL_COUNT=$(ip netns exec peer0 nft list chain inet filter output \
- | sed -n 's/.*packets \([0-9]*\).*/\1/p')
-if [ "${DROP_COUNTER}" -ne "${TOTAL_COUNT}" ]; then
- echo "Expected ${TOTAL_COUNT} drops, got ${DROP_COUNTER}"
- exit 1
-fi
-
-echo "Removing the drop rule"
-ip netns exec peer0 nft flush ruleset
-sleep 1
-
-for p in $(seq 1 3); do
- ip netns exec peer0 ping -qfc 500 -w 3 5.5.5.$((p + 1))
-done
-
-cleanup
-
-modprobe -r ovpn || true
+ovpn_run_stage "setup marked network topology" ovpn_mark_prepare_network
+ovpn_run_stage "run baseline traffic" ovpn_mark_run_baseline_traffic
+ovpn_run_stage "install nft mark drop rule" ovpn_mark_add_drop_rule
+ovpn_run_stage "drop marked traffic and count packets" \
+ ovpn_mark_verify_drop_traffic
+ovpn_run_stage "remove nft drop rule" ovpn_mark_remove_drop_rule
+ovpn_run_stage "traffic recovers after drop removal" \
+ ovpn_mark_verify_traffic_recovery
+
+ovpn_test_finished=1
+ktap_finished
diff --git a/tools/testing/selftests/net/ovpn/test-symmetric-id-float.sh b/tools/testing/selftests/net/ovpn/test-symmetric-id-float.sh
index b3711a81b463..75296fe72c39 100755
--- a/tools/testing/selftests/net/ovpn/test-symmetric-id-float.sh
+++ b/tools/testing/selftests/net/ovpn/test-symmetric-id-float.sh
@@ -5,7 +5,7 @@
# Author: Ralf Lici <ralf@mandelbit.com>
# Antonio Quartulli <antonio@openvpn.net>
-SYMMETRIC_ID="1"
-FLOAT="1"
+OVPN_SYMMETRIC_ID="1"
+OVPN_FLOAT="1"
source test.sh
diff --git a/tools/testing/selftests/net/ovpn/test-symmetric-id-tcp.sh b/tools/testing/selftests/net/ovpn/test-symmetric-id-tcp.sh
index 188cafb67b2f..680a465c49d2 100755
--- a/tools/testing/selftests/net/ovpn/test-symmetric-id-tcp.sh
+++ b/tools/testing/selftests/net/ovpn/test-symmetric-id-tcp.sh
@@ -5,7 +5,7 @@
# Author: Ralf Lici <ralf@mandelbit.com>
# Antonio Quartulli <antonio@openvpn.net>
-PROTO="TCP"
-SYMMETRIC_ID=1
+OVPN_PROTO="TCP"
+OVPN_SYMMETRIC_ID=1
source test.sh
diff --git a/tools/testing/selftests/net/ovpn/test-symmetric-id.sh b/tools/testing/selftests/net/ovpn/test-symmetric-id.sh
index 35b119c72e4f..a2e2808959d9 100755
--- a/tools/testing/selftests/net/ovpn/test-symmetric-id.sh
+++ b/tools/testing/selftests/net/ovpn/test-symmetric-id.sh
@@ -5,6 +5,6 @@
# Author: Ralf Lici <ralf@mandelbit.com>
# Antonio Quartulli <antonio@openvpn.net>
-SYMMETRIC_ID="1"
+OVPN_SYMMETRIC_ID="1"
source test.sh
diff --git a/tools/testing/selftests/net/ovpn/test-tcp.sh b/tools/testing/selftests/net/ovpn/test-tcp.sh
index ba3f1f315a34..27cc6e7b98bc 100755
--- a/tools/testing/selftests/net/ovpn/test-tcp.sh
+++ b/tools/testing/selftests/net/ovpn/test-tcp.sh
@@ -4,6 +4,6 @@
#
# Author: Antonio Quartulli <antonio@openvpn.net>
-PROTO="TCP"
+OVPN_PROTO="TCP"
source test.sh
diff --git a/tools/testing/selftests/net/ovpn/test.sh b/tools/testing/selftests/net/ovpn/test.sh
index b60e94a4094e..b50dbe45a4d0 100755
--- a/tools/testing/selftests/net/ovpn/test.sh
+++ b/tools/testing/selftests/net/ovpn/test.sh
@@ -5,161 +5,316 @@
# Author: Antonio Quartulli <antonio@openvpn.net>
#set -x
-set -e
+set -eE
source ./common.sh
-cleanup
+ovpn_test_finished=0
-modprobe -q ovpn || true
+ovpn_test_exit() {
+ ovpn_cleanup
+ modprobe -r ovpn || true
+
+ if [ "${ovpn_test_finished}" -eq 0 ]; then
+ ktap_print_totals
+ fi
+}
+
+ovpn_prepare_network() {
+ local p
+ local peer_ns
+
+ for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+ ovpn_cmd_ok "create namespace peer${p}" ovpn_create_ns "${p}"
+ done
+
+ for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+ ovpn_cmd_ok "start notification listener peer${p}" \
+ ovpn_setup_listener "${p}"
+ # starting all YNL listeners back-to-back can intermittently
+ # stall their startup so serialize launches a bit
+ sleep 0.5
+ done
+
+ for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+ ovpn_cmd_ok "configure peer${p} namespace" ovpn_setup_ns \
+ "${p}" 5.5.5.$((p + 1))/24 "${MTU}"
+ done
+
+ for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+ ovpn_cmd_ok "register peer${p} in overlay" ovpn_add_peer "${p}"
+ done
+
+ for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+ peer_ns="ovpn_peer${p}"
+ ovpn_cmd_ok "set peer0 timeout for peer ${p}" \
+ ip netns exec ovpn_peer0 ${OVPN_CLI} set_peer tun0 \
+ ${p} 60 120
+ ovpn_cmd_ok "set peer${p} timeout for peer ${p}" \
+ ip netns exec "${peer_ns}" ${OVPN_CLI} set_peer \
+ tun${p} $((p + OVPN_ID_OFFSET)) 60 120
+ done
+}
+
+ovpn_run_basic_traffic() {
+ local p
+ local header1
+ local header2
+ local peer_ns
+ local raddr
+ local tcpdump_pid1
+ local tcpdump_pid2
+ local tcpdump_timeout="1.5s"
+
+ for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+ # The first part of the data packet header consists of:
+ # - TCP only: 2 bytes for the packet length
+ # - 5 bits for opcode ("9" for DATA_V2)
+ # - 3 bits for key-id ("0" at this point)
+ # - 12 bytes for peer-id:
+ # - with asymmetric ID: "${p}" one way and "${p} + 9" the
+ # other way
+ # - with symmetric ID: "${p}" both ways
+ header1=$(printf "0x4800000%x" ${p})
+ header2=$(printf "0x4800000%x" $((p + OVPN_ID_OFFSET)))
+ raddr=""
+ if [ "${OVPN_PROTO}" == "UDP" ]; then
+ raddr=$(awk "NR == ${p} {print \$3}" \
+ "${OVPN_UDP_PEERS_FILE}")
+ fi
+ peer_ns="ovpn_peer${p}"
+
+ timeout ${tcpdump_timeout} ip netns exec "${peer_ns}" \
+ tcpdump --immediate-mode -p -ni veth${p} -c 1 \
+ "$(ovpn_build_capture_filter "${header1}" "${raddr}")" \
+ >/dev/null 2>&1 &
+ tcpdump_pid1=$!
+ timeout ${tcpdump_timeout} ip netns exec "${peer_ns}" \
+ tcpdump --immediate-mode -p -ni veth${p} -c 1 \
+ "$(ovpn_build_capture_filter "${header2}" "${raddr}")" \
+ >/dev/null 2>&1 &
+ tcpdump_pid2=$!
+
+ sleep 0.3
+ ovpn_cmd_ok "send baseline traffic to peer ${p}" \
+ ip netns exec ovpn_peer0 \
+ ping -qfc 500 -w 3 5.5.5.$((p + 1))
+ ovpn_cmd_ok "send large-payload traffic to peer ${p}" \
+ ip netns exec ovpn_peer0 \
+ ping -qfc 500 -s 3000 -w 3 5.5.5.$((p + 1))
+
+ wait "${tcpdump_pid1}" || return 1
+ wait "${tcpdump_pid2}" || return 1
+ done
+}
+
+ovpn_run_lan_traffic() {
+ ovpn_cmd_ok "ping LAN behind peer1" \
+ ip netns exec ovpn_peer0 ping -qfc 500 -w 3 "${OVPN_LAN_IP}"
+}
+
+ovpn_run_float_mode() {
+ local p
+ local peer_ns
+
+ for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+ peer_ns="ovpn_peer${p}"
+ ovpn_cmd_ok "float: remove old transport address on peer${p}" \
+ ip -n "${peer_ns}" addr del 10.10.${p}.2/24 dev veth${p}
+ ovpn_cmd_ok "float: add new transport address on peer${p}" \
+ ip -n "${peer_ns}" addr add 10.10.${p}.3/24 dev veth${p}
+ done
+ for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+ peer_ns="ovpn_peer${p}"
+ ovpn_cmd_ok "ping tunnel after float peer ${p}" \
+ ip netns exec "${peer_ns}" ping -qfc 500 -w 3 5.5.5.1
+ done
+}
+
+ovpn_run_iperf() {
+ local iperf_pid
+
+ ovpn_run_bg iperf_pid ip netns exec ovpn_peer0 iperf3 -1 -s
+ sleep 1
+
+ ovpn_cmd_ok "run iperf throughput flow" \
+ ip netns exec ovpn_peer1 iperf3 -Z -t 3 -c 5.5.5.1
+ wait "${iperf_pid}" || return 1
+}
+
+ovpn_run_key_rollover() {
+ local p
+ local peer_ns
+
+ ovpn_log "Adding secondary key and then swap:"
+
+ for p in $(seq 1 ${OVPN_NUM_PEERS}); do
+ peer_ns="ovpn_peer${p}"
+ ovpn_cmd_ok "add secondary key on peer0 for peer ${p}" \
+ ip netns exec ovpn_peer0 ${OVPN_CLI} new_key tun0 \
+ ${p} 2 1 ${OVPN_ALG} 0 data64.key
+ ovpn_cmd_ok "add secondary key on peer${p} for peer ${p}" \
+ ip netns exec "${peer_ns}" ${OVPN_CLI} new_key tun${p} \
+ $((p + OVPN_ID_OFFSET)) 2 1 ${OVPN_ALG} 1 \
+ data64.key
+ ovpn_cmd_ok "swap keys on peer${p}" \
+ ip netns exec "${peer_ns}" ${OVPN_CLI} swap_keys \
+ tun${p} $((p + OVPN_ID_OFFSET))
+ done
+}
-for p in $(seq 0 ${NUM_PEERS}); do
- create_ns ${p}
-done
-
-for p in $(seq 0 ${NUM_PEERS}); do
- setup_listener ${p}
-done
-
-for p in $(seq 0 ${NUM_PEERS}); do
- setup_ns ${p} 5.5.5.$((${p} + 1))/24 ${MTU}
-done
-
-for p in $(seq 0 ${NUM_PEERS}); do
- add_peer ${p}
-done
-
-for p in $(seq 1 ${NUM_PEERS}); do
- ip netns exec peer0 ${OVPN_CLI} set_peer tun0 ${p} 60 120
- ip netns exec peer${p} ${OVPN_CLI} set_peer tun${p} \
- $((${p}+ID_OFFSET)) 60 120
-done
-
-sleep 1
-
-TCPDUMP_TIMEOUT="1.5s"
-for p in $(seq 1 ${NUM_PEERS}); do
- # The first part of the data packet header consists of:
- # - TCP only: 2 bytes for the packet length
- # - 5 bits for opcode ("9" for DATA_V2)
- # - 3 bits for key-id ("0" at this point)
- # - 12 bytes for peer-id:
- # - with asymmetric ID: "${p}" one way and "${p} + 9" the other way
- # - with symmetric ID: "${p}" both ways
- HEADER1=$(printf "0x4800000%x" ${p})
- HEADER2=$(printf "0x4800000%x" $((${p} + ID_OFFSET)))
- RADDR=""
- if [ "${PROTO}" == "UDP" ]; then
- RADDR=$(awk "NR == ${p} {print \$3}" ${UDP_PEERS_FILE})
+ovpn_run_queries() {
+ ovpn_log "Querying all peers:"
+
+ ovpn_cmd_ok "query all peers from peer0" \
+ ip netns exec ovpn_peer0 ${OVPN_CLI} get_peer tun0
+ ovpn_cmd_ok "query all peers from peer1" \
+ ip netns exec ovpn_peer1 ${OVPN_CLI} get_peer tun1
+
+ ovpn_log "Querying peer 1:"
+
+ ovpn_cmd_ok "query peer 1 from peer0" \
+ ip netns exec ovpn_peer0 ${OVPN_CLI} get_peer tun0 1
+}
+
+ovpn_query_peer_missing() {
+ ovpn_log "Querying non-existent peer 20:"
+
+ ovpn_cmd_fail "query missing peer 20 on peer0" \
+ ip netns exec ovpn_peer0 ${OVPN_CLI} get_peer tun0 20
+}
+
+ovpn_run_peer_cleanup() {
+ local p
+ local peer_ns
+
+ ovpn_log "Deleting peer 1:"
+
+ ovpn_cmd_ok "delete peer1 on peer0" \
+ ip netns exec ovpn_peer0 ${OVPN_CLI} del_peer tun0 1
+ ovpn_cmd_ok "delete peer1 on peer1" \
+ ip netns exec ovpn_peer1 ${OVPN_CLI} del_peer tun1 \
+ $((1 + OVPN_ID_OFFSET))
+
+ ovpn_log "Querying keys:"
+
+ for p in $(seq 2 ${OVPN_NUM_PEERS}); do
+ peer_ns="ovpn_peer${p}"
+ ovpn_cmd_ok "query peer${p} key 1" \
+ ip netns exec "${peer_ns}" ${OVPN_CLI} get_key tun${p} \
+ $((p + OVPN_ID_OFFSET)) 1
+ ovpn_cmd_ok "query peer${p} key 2" \
+ ip netns exec "${peer_ns}" ${OVPN_CLI} get_key tun${p} \
+ $((p + OVPN_ID_OFFSET)) 2
+ done
+}
+
+ovpn_run_traffic_delete_peer() {
+ local ping_pid
+
+ ovpn_log "Deleting peer while sending traffic:"
+
+ ovpn_run_bg ping_pid ip netns exec ovpn_peer2 ping -qf -w 4 5.5.5.1
+ sleep 2
+ ovpn_cmd_ok "delete peer0 peer 2" \
+ ip netns exec ovpn_peer0 ${OVPN_CLI} del_peer tun0 2
+
+ if [ "${OVPN_PROTO}" == "TCP" ]; then
+ # In TCP mode this command is expected to fail for both peers.
+ ovpn_cmd_mayfail "delete peer2 peer 2 (TCP non-fatal)" \
+ ip netns exec ovpn_peer2 ${OVPN_CLI} del_peer tun2 \
+ $((2 + OVPN_ID_OFFSET))
+ else
+ ovpn_cmd_ok "delete peer2 peer 2" ip netns exec ovpn_peer2 \
+ ${OVPN_CLI} del_peer tun2 $((2 + OVPN_ID_OFFSET))
fi
- timeout ${TCPDUMP_TIMEOUT} ip netns exec peer${p} \
- tcpdump --immediate-mode -p -ni veth${p} -c 1 \
- "$(build_capture_filter "${HEADER1}" "${RADDR}")" \
- >/dev/null 2>&1 &
- TCPDUMP_PID1=$!
- timeout ${TCPDUMP_TIMEOUT} ip netns exec peer${p} \
- tcpdump --immediate-mode -p -ni veth${p} -c 1 \
- "$(build_capture_filter "${HEADER2}" "${RADDR}")" \
- >/dev/null 2>&1 &
- TCPDUMP_PID2=$!
-
- sleep 0.3
- ip netns exec peer0 ping -qfc 500 -w 3 5.5.5.$((${p} + 1))
- ip netns exec peer0 ping -qfc 500 -s 3000 -w 3 5.5.5.$((${p} + 1))
-
- wait ${TCPDUMP_PID1}
- wait ${TCPDUMP_PID2}
-done
-
-# ping LAN behind client 1
-ip netns exec peer0 ping -qfc 500 -w 3 ${LAN_IP}
-
-if [ "$FLOAT" == "1" ]; then
- # make clients float..
- for p in $(seq 1 ${NUM_PEERS}); do
- ip -n peer${p} addr del 10.10.${p}.2/24 dev veth${p}
- ip -n peer${p} addr add 10.10.${p}.3/24 dev veth${p}
+ wait "${ping_pid}" || true
+}
+
+ovpn_run_key_cleanup() {
+ local p
+ local peer_ns
+
+ ovpn_log "Deleting keys:"
+
+ for p in $(seq 3 ${OVPN_NUM_PEERS}); do
+ peer_ns="ovpn_peer${p}"
+ ovpn_cmd_ok "delete key 1 for peer${p}" \
+ ip netns exec "${peer_ns}" ${OVPN_CLI} del_key tun${p} \
+ $((p + OVPN_ID_OFFSET)) 1
+ ovpn_cmd_ok "delete key 2 for peer${p}" \
+ ip netns exec "${peer_ns}" ${OVPN_CLI} del_key tun${p} \
+ $((p + OVPN_ID_OFFSET)) 2
+ done
+}
+
+ovpn_run_timeouts() {
+ local p
+ local peer_ns
+
+ ovpn_log "Setting timeout to 3s MP:"
+
+ for p in $(seq 3 ${OVPN_NUM_PEERS}); do
+ # Non-fatal: this may fail in some protocol modes.
+ ovpn_cmd_mayfail "set peer0 timeout for peer ${p} (non-fatal)" \
+ ip netns exec ovpn_peer0 ${OVPN_CLI} set_peer tun0 \
+ ${p} 3 3
+ peer_ns="ovpn_peer${p}"
+ ovpn_cmd_ok "disable timeout on peer${p} while peer0 adjusts \
+ state" ip netns exec "${peer_ns}" ${OVPN_CLI} set_peer \
+ tun${p} $((p + OVPN_ID_OFFSET)) 0 0
+ done
+ # wait for peers to timeout
+ sleep 5
+
+ ovpn_log "Setting timeout to 3s P2P:"
+
+ for p in $(seq 3 ${OVPN_NUM_PEERS}); do
+ peer_ns="ovpn_peer${p}"
+ ovpn_cmd_ok "set peer${p} P2P timeout" \
+ ip netns exec "${peer_ns}" ${OVPN_CLI} set_peer \
+ tun${p} $((p + OVPN_ID_OFFSET)) 3 3
done
- for p in $(seq 1 ${NUM_PEERS}); do
- ip netns exec peer${p} ping -qfc 500 -w 3 5.5.5.1
+ sleep 5
+}
+
+ovpn_run_notifications() {
+ local p
+
+ for p in $(seq 0 ${OVPN_NUM_PEERS}); do
+ ovpn_cmd_ok "validate listener output for peer ${p}" \
+ ovpn_compare_ntfs "${p}"
done
+}
+
+trap ovpn_test_exit EXIT
+trap ovpn_stage_err ERR
+
+ktap_print_header
+if [ "${OVPN_FLOAT}" == "1" ]; then
+ ktap_set_plan 13
+else
+ ktap_set_plan 12
fi
-ip netns exec peer0 iperf3 -1 -s &
-sleep 1
-ip netns exec peer1 iperf3 -Z -t 3 -c 5.5.5.1
-
-echo "Adding secondary key and then swap:"
-for p in $(seq 1 ${NUM_PEERS}); do
- ip netns exec peer0 ${OVPN_CLI} new_key tun0 ${p} 2 1 ${ALG} 0 \
- data64.key
- ip netns exec peer${p} ${OVPN_CLI} new_key tun${p} \
- $((${p} + ID_OFFSET)) 2 1 ${ALG} 1 data64.key
- ip netns exec peer${p} ${OVPN_CLI} swap_keys tun${p} \
- $((${p} + ID_OFFSET))
-done
-
-sleep 1
-
-echo "Querying all peers:"
-ip netns exec peer0 ${OVPN_CLI} get_peer tun0
-ip netns exec peer1 ${OVPN_CLI} get_peer tun1
-
-echo "Querying peer 1:"
-ip netns exec peer0 ${OVPN_CLI} get_peer tun0 1
-
-echo "Querying non-existent peer 20:"
-ip netns exec peer0 ${OVPN_CLI} get_peer tun0 20 || true
-
-echo "Deleting peer 1:"
-ip netns exec peer0 ${OVPN_CLI} del_peer tun0 1
-ip netns exec peer1 ${OVPN_CLI} del_peer tun1 $((1 + ID_OFFSET))
-
-echo "Querying keys:"
-for p in $(seq 2 ${NUM_PEERS}); do
- ip netns exec peer${p} ${OVPN_CLI} get_key tun${p} \
- $((${p} + ID_OFFSET)) 1
- ip netns exec peer${p} ${OVPN_CLI} get_key tun${p} \
- $((${p} + ID_OFFSET)) 2
-done
-
-echo "Deleting peer while sending traffic:"
-(ip netns exec peer2 ping -qf -w 4 5.5.5.1)&
-sleep 2
-ip netns exec peer0 ${OVPN_CLI} del_peer tun0 2
-# following command fails in TCP mode
-# (both ends get conn reset when one peer disconnects)
-ip netns exec peer2 ${OVPN_CLI} del_peer tun2 $((2 + ID_OFFSET)) || true
-
-echo "Deleting keys:"
-for p in $(seq 3 ${NUM_PEERS}); do
- ip netns exec peer${p} ${OVPN_CLI} del_key tun${p} \
- $((${p} + ID_OFFSET)) 1
- ip netns exec peer${p} ${OVPN_CLI} del_key tun${p} \
- $((${p} + ID_OFFSET)) 2
-done
-
-echo "Setting timeout to 3s MP:"
-for p in $(seq 3 ${NUM_PEERS}); do
- ip netns exec peer0 ${OVPN_CLI} set_peer tun0 ${p} 3 3 || true
- ip netns exec peer${p} ${OVPN_CLI} set_peer tun${p} \
- $((${p} + ID_OFFSET)) 0 0
-done
-# wait for peers to timeout
-sleep 5
-
-echo "Setting timeout to 3s P2P:"
-for p in $(seq 3 ${NUM_PEERS}); do
- ip netns exec peer${p} ${OVPN_CLI} set_peer tun${p} \
- $((${p} + ID_OFFSET)) 3 3
-done
-sleep 5
-
-for p in $(seq 0 ${NUM_PEERS}); do
- compare_ntfs ${p}
-done
-
-cleanup
-
-modprobe -r ovpn || true
+ovpn_cleanup
+modprobe -q ovpn || true
+
+ovpn_run_stage "setup network topology" ovpn_prepare_network
+ovpn_run_stage "run baseline data traffic" ovpn_run_basic_traffic
+ovpn_run_stage "run LAN traffic behind peer1" ovpn_run_lan_traffic
+[ "${OVPN_FLOAT}" == "1" ] && ovpn_run_stage "run floating peer checks" \
+ ovpn_run_float_mode
+ovpn_run_stage "run iperf throughput" ovpn_run_iperf
+ovpn_run_stage "run key rollout" ovpn_run_key_rollover
+ovpn_run_stage "query peers" ovpn_run_queries
+ovpn_run_stage "query missing peer fails" ovpn_query_peer_missing
+ovpn_run_stage "peer lifecycle and key queries" ovpn_run_peer_cleanup
+ovpn_run_stage "delete peer while traffic" ovpn_run_traffic_delete_peer
+ovpn_run_stage "delete stale keys" ovpn_run_key_cleanup
+ovpn_run_stage "check timeout behavior" ovpn_run_timeouts
+ovpn_run_stage "validate notification output" ovpn_run_notifications
+
+ovpn_test_finished=1
+ktap_finished
diff --git a/tools/testing/selftests/net/packetdrill/tcp_rfc5961_ack-out-of-window.pkt b/tools/testing/selftests/net/packetdrill/tcp_rfc5961_ack-out-of-window.pkt
new file mode 100644
index 000000000000..2776b8728085
--- /dev/null
+++ b/tools/testing/selftests/net/packetdrill/tcp_rfc5961_ack-out-of-window.pkt
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// RFC 5961 Section 5.2 / RFC 793 Section 3.9: an incoming segment's
+// ACK value must lie in [SND.UNA - MAX.SND.WND, SND.NXT]; otherwise
+// the receiver MUST discard the segment and send a challenge ACK
+// back. Exercise both edges of that window in a single connection.
+
+`./defaults.sh
+sysctl -q net.ipv4.tcp_invalid_ratelimit=0
+`
+
+ 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+ +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+ +0 bind(3, ..., ...) = 0
+ +0 listen(3, 1) = 0
+
+// Three-way handshake. Peer advertises rwnd = 1000 (no wscale), so
+// MAX.SND.WND is tracked as 1000.
+ +0 < S 0:0(0) win 1000 <mss 1000,sackOK,nop,nop,nop,wscale 0>
+ +0 > S. 0:0(0) ack 1 <...>
++.1 < . 1:1(0) ack 1 win 1000
+ +0 accept(3, ..., ...) = 4
+
+// ---- Upper edge: SEG.ACK > SND.NXT --------------------------------
+// Server has sent nothing yet, so SND.UNA = SND.NXT = 1.
+// Peer sends a pure ACK with SEG.ACK = 2, beyond SND.NXT.
+ +0 < . 1:1(0) ack 2 win 1000
+// Expect a challenge ACK: <SEQ = SND.NXT = 1, ACK = RCV.NXT = 1>.
+ +0 > . 1:1(0) ack 1
+
+// Advance SND.UNA past MAX.SND.WND so that the lower edge becomes
+// reachable. Issue two 1-MSS writes so each skb is exactly one MSS
+// and PSH is set by tcp_push() at the end of each sendmsg, keeping
+// the setup independent of the TSO / tcp_fragment split path.
+ +0 write(4, ..., 1000) = 1000
+ +0 > P. 1:1001(1000) ack 1
++.01 < . 1:1(0) ack 1001 win 1000
+ +0 write(4, ..., 1000) = 1000
+ +0 > P. 1001:2001(1000) ack 1
++.01 < . 1:1(0) ack 2001 win 1000
+// Now SND.UNA = SND.NXT = 2001, MAX.SND.WND = 1000, bytes_acked = 2000.
+
+// ---- Lower edge: SEG.ACK < SND.UNA - MAX.SND.WND ------------------
+// SND.UNA - MAX.SND.WND = 2001 - 1000 = 1001, so SEG.ACK = 1000 falls
+// below the acceptable range.
+ +0 < . 1:1(0) ack 1000 win 1000
+// Expect a challenge ACK: <SEQ = SND.NXT = 2001, ACK = RCV.NXT = 1>.
+ +0 > . 2001:2001(0) ack 1
diff --git a/tools/testing/selftests/net/packetdrill/tcp_ts_recent_invalid_ack.pkt b/tools/testing/selftests/net/packetdrill/tcp_ts_recent_invalid_ack.pkt
index 174ce9a1bfc0..ee6baf7c36cf 100644
--- a/tools/testing/selftests/net/packetdrill/tcp_ts_recent_invalid_ack.pkt
+++ b/tools/testing/selftests/net/packetdrill/tcp_ts_recent_invalid_ack.pkt
@@ -19,7 +19,9 @@
// bad packet with high tsval (its ACK sequence is above our sndnxt)
+0 < F. 1:1(0) ack 9999 win 20000 <nop,nop,TS val 200000 ecr 100>
-
+// Challenge ACK for SEG.ACK > SND.NXT (RFC 5961 5.2 / RFC 793 3.9).
+// ecr=200 (not 200000) proves ts_recent was not updated from the bad packet.
+ +0 > . 1:1(0) ack 1 <nop,nop,TS val 200 ecr 200>
+0 < . 1:1001(1000) ack 1 win 20000 <nop,nop,TS val 201 ecr 100>
+0 > . 1:1(0) ack 1001 <nop,nop,TS val 200 ecr 201>
diff --git a/tools/testing/selftests/net/rtnetlink.sh b/tools/testing/selftests/net/rtnetlink.sh
index 5a5ff88321d5..c499953d4885 100755
--- a/tools/testing/selftests/net/rtnetlink.sh
+++ b/tools/testing/selftests/net/rtnetlink.sh
@@ -23,6 +23,7 @@ ALL_TESTS="
kci_test_encap
kci_test_macsec
kci_test_macsec_vlan
+ kci_test_team_bridge_macvlan
kci_test_ipsec
kci_test_ipsec_offload
kci_test_fdb_get
@@ -636,6 +637,49 @@ kci_test_macsec_vlan()
end_test "PASS: macsec_vlan"
}
+# Test ndo_change_rx_flags call from dev_uc_add under addr_list_lock spinlock.
+# When we are flipping the promisc, make sure it runs on the work queue.
+#
+# https://lore.kernel.org/netdev/20260214033859.43857-1-jiayuan.chen@linux.dev/
+# With (more conventional) macvlan instead of macsec.
+# macvlan -> bridge -> team -> dummy
+kci_test_team_bridge_macvlan()
+{
+ local vlan="test_macv1"
+ local bridge="test_br1"
+ local team="test_team1"
+ local dummy="test_dummy1"
+ local ret=0
+
+ run_cmd ip link add $team type team
+ if [ $ret -ne 0 ]; then
+ end_test "SKIP: team_bridge_macvlan: can't add team interface"
+ return $ksft_skip
+ fi
+
+ run_cmd ip link add $dummy type dummy
+ run_cmd ip link set $dummy master $team
+ run_cmd ip link set $team up
+ run_cmd ip link add $bridge type bridge vlan_filtering 1
+ run_cmd ip link set $bridge up
+ run_cmd ip link set $team master $bridge
+ run_cmd ip link add link $bridge name $vlan \
+ address 00:aa:bb:cc:dd:ee type macvlan mode bridge
+ run_cmd ip link set $vlan up
+
+ run_cmd ip link del $vlan
+ run_cmd ip link del $bridge
+ run_cmd ip link del $team
+ run_cmd ip link del $dummy
+
+ if [ $ret -ne 0 ]; then
+ end_test "FAIL: team_bridge_macvlan"
+ return 1
+ fi
+
+ end_test "PASS: team_bridge_macvlan"
+}
+
#-------------------------------------------------------------------
# Example commands
# ip x s add proto esp src 14.0.0.52 dst 14.0.0.70 \
diff --git a/tools/testing/selftests/net/tcp_ao/config b/tools/testing/selftests/net/tcp_ao/config
index 971cb6fa2d63..f22148512365 100644
--- a/tools/testing/selftests/net/tcp_ao/config
+++ b/tools/testing/selftests/net/tcp_ao/config
@@ -1,3 +1,4 @@
+CONFIG_CRYPTO_CMAC=y
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_RMD160=y
CONFIG_CRYPTO_SHA1=y
diff --git a/tools/testing/vsock/util.c b/tools/testing/vsock/util.c
index 1fe1338c79cd..fe316b02a590 100644
--- a/tools/testing/vsock/util.c
+++ b/tools/testing/vsock/util.c
@@ -381,8 +381,14 @@ void send_buf(int fd, const void *buf, size_t len, int flags,
}
}
+#define RECV_PEEK_RETRY_USEC (10 * 1000)
+
/* Receive bytes in a buffer and check the return value.
*
+ * When MSG_PEEK is set, recv() is retried until it returns at least
+ * expected_ret bytes. The function returns on error, EOF, or timeout
+ * as usual.
+ *
* expected_ret:
* <0 Negative errno (for testing errors)
* 0 End-of-file
@@ -403,6 +409,15 @@ void recv_buf(int fd, void *buf, size_t len, int flags, ssize_t expected_ret)
if (ret <= 0)
break;
+ if (flags & MSG_PEEK) {
+ if (ret >= expected_ret) {
+ nread = ret;
+ break;
+ }
+ timeout_usleep(RECV_PEEK_RETRY_USEC);
+ continue;
+ }
+
nread += ret;
} while (nread < len);
timeout_end();
diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c
index 5bd20ccd9335..76be0e4a7f0e 100644
--- a/tools/testing/vsock/vsock_test.c
+++ b/tools/testing/vsock/vsock_test.c
@@ -346,6 +346,38 @@ static void test_stream_msg_peek_server(const struct test_opts *opts)
return test_msg_peek_server(opts, false);
}
+static void test_stream_peek_after_recv_server(const struct test_opts *opts)
+{
+ unsigned char buf_normal[MSG_PEEK_BUF_LEN];
+ unsigned char buf_peek[MSG_PEEK_BUF_LEN];
+ int fd;
+
+ fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
+ if (fd < 0) {
+ perror("accept");
+ exit(EXIT_FAILURE);
+ }
+
+ control_writeln("SRVREADY");
+
+ /* Partial recv to advance offset within the skb */
+ recv_buf(fd, buf_normal, 1, 0, 1);
+
+ /* Peek with a buffer larger than the remaining data */
+ recv_buf(fd, buf_peek, sizeof(buf_peek), MSG_PEEK, sizeof(buf_peek) - 1);
+
+ /* Consume the remaining data */
+ recv_buf(fd, buf_normal, sizeof(buf_normal) - 1, 0, sizeof(buf_normal) - 1);
+
+ /* Compare full peek and normal read. */
+ if (memcmp(buf_peek, buf_normal, sizeof(buf_peek) - 1)) {
+ fprintf(stderr, "Full peek data mismatch\n");
+ exit(EXIT_FAILURE);
+ }
+
+ close(fd);
+}
+
#define SOCK_BUF_SIZE (2 * 1024 * 1024)
#define SOCK_BUF_SIZE_SMALL (64 * 1024)
#define MAX_MSG_PAGES 4
@@ -1500,18 +1532,7 @@ static void test_stream_credit_update_test(const struct test_opts *opts,
}
/* Wait until there will be 128KB of data in rx queue. */
- while (1) {
- ssize_t res;
-
- res = recv(fd, buf, buf_size, MSG_PEEK);
- if (res == buf_size)
- break;
-
- if (res <= 0) {
- fprintf(stderr, "unexpected 'recv()' return: %zi\n", res);
- exit(EXIT_FAILURE);
- }
- }
+ recv_buf(fd, buf, buf_size, MSG_PEEK, buf_size);
/* There is 128KB of data in the socket's rx queue, dequeue first
* 64KB, credit update is sent if 'low_rx_bytes_test' == true.
@@ -2520,6 +2541,11 @@ static struct test_case test_cases[] = {
.run_client = test_stream_tx_credit_bounds_client,
.run_server = test_stream_tx_credit_bounds_server,
},
+ {
+ .name = "SOCK_STREAM MSG_PEEK after partial recv",
+ .run_client = test_stream_msg_peek_client,
+ .run_server = test_stream_peek_after_recv_server,
+ },
{},
};