mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-16 17:57:38 -04:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Minor conflicts in net/mptcp/protocol.h and tools/testing/selftests/net/Makefile. In both cases code was added on both sides in the same place so just keep both. Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -20,6 +20,7 @@ TEST_PROGS += vrf-xfrm-tests.sh
|
||||
TEST_PROGS += rxtimestamp.sh
|
||||
TEST_PROGS += devlink_port_split.py
|
||||
TEST_PROGS += drop_monitor_tests.sh
|
||||
TEST_PROGS += vrf_route_leaking.sh
|
||||
TEST_PROGS_EXTENDED := in_netns.sh
|
||||
TEST_GEN_FILES = socket nettest
|
||||
TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy reuseport_addr_any
|
||||
|
||||
626
tools/testing/selftests/net/vrf_route_leaking.sh
Executable file
626
tools/testing/selftests/net/vrf_route_leaking.sh
Executable file
@@ -0,0 +1,626 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Copyright (c) 2019 David Ahern <dsahern@gmail.com>. All rights reserved.
|
||||
# Copyright (c) 2020 Michael Jeanson <mjeanson@efficios.com>. All rights reserved.
|
||||
#
|
||||
# Requires CONFIG_NET_VRF, CONFIG_VETH, CONFIG_BRIDGE and CONFIG_NET_NS.
|
||||
#
|
||||
#
|
||||
# Symmetric routing topology
|
||||
#
|
||||
# blue red
|
||||
# +----+ .253 +----+ .253 +----+
|
||||
# | h1 |-------------------| r1 |-------------------| h2 |
|
||||
# +----+ .1 +----+ .2 +----+
|
||||
# 172.16.1/24 172.16.2/24
|
||||
# 2001:db8:16:1/64 2001:db8:16:2/64
|
||||
#
|
||||
#
|
||||
# Route from h1 to h2 and back goes through r1, incoming vrf blue has a route
|
||||
# to the outgoing vrf red for the n2 network and red has a route back to n1.
|
||||
# The red VRF interface has a MTU of 1400.
|
||||
#
|
||||
# The first test sends a ping with a ttl of 1 from h1 to h2 and parses the
|
||||
# output of the command to check that a ttl expired error is received.
|
||||
#
|
||||
# The second test runs traceroute from h1 to h2 and parses the output to check
|
||||
# for a hop on r1.
|
||||
#
|
||||
# The third test sends a ping with a packet size of 1450 from h1 to h2 and
|
||||
# parses the output of the command to check that a fragmentation error is
|
||||
# received.
|
||||
#
|
||||
#
|
||||
# Asymmetric routing topology
|
||||
#
|
||||
# This topology represents a customer setup where the issue with icmp errors
|
||||
# and VRF route leaking was initialy reported. The MTU test isn't done here
|
||||
# because of the lack of a return route in the red VRF.
|
||||
#
|
||||
# blue red
|
||||
# .253 +----+ .253
|
||||
# +----| r1 |----+
|
||||
# | +----+ |
|
||||
# +----+ | | +----+
|
||||
# | h1 |--------------+ +--------------| h2 |
|
||||
# +----+ .1 | | .2 +----+
|
||||
# 172.16.1/24 | +----+ | 172.16.2/24
|
||||
# 2001:db8:16:1/64 +----| r2 |----+ 2001:db8:16:2/64
|
||||
# .254 +----+ .254
|
||||
#
|
||||
#
|
||||
# Route from h1 to h2 goes through r1, incoming vrf blue has a route to the
|
||||
# outgoing vrf red for the n2 network but red doesn't have a route back to n1.
|
||||
# Route from h2 to h1 goes through r2.
|
||||
#
|
||||
# The objective is to check that the incoming vrf routing table is selected
|
||||
# to send an ICMP error back to the source when the ttl of a packet reaches 1
|
||||
# while it is forwarded between different vrfs.
|
||||
|
||||
VERBOSE=0
|
||||
PAUSE_ON_FAIL=no
|
||||
DEFAULT_TTYPE=sym
|
||||
|
||||
H1_N1=172.16.1.0/24
|
||||
H1_N1_6=2001:db8:16:1::/64
|
||||
|
||||
H1_N1_IP=172.16.1.1
|
||||
R1_N1_IP=172.16.1.253
|
||||
R2_N1_IP=172.16.1.254
|
||||
|
||||
H1_N1_IP6=2001:db8:16:1::1
|
||||
R1_N1_IP6=2001:db8:16:1::253
|
||||
R2_N1_IP6=2001:db8:16:1::254
|
||||
|
||||
H2_N2=172.16.2.0/24
|
||||
H2_N2_6=2001:db8:16:2::/64
|
||||
|
||||
H2_N2_IP=172.16.2.2
|
||||
R1_N2_IP=172.16.2.253
|
||||
R2_N2_IP=172.16.2.254
|
||||
|
||||
H2_N2_IP6=2001:db8:16:2::2
|
||||
R1_N2_IP6=2001:db8:16:2::253
|
||||
R2_N2_IP6=2001:db8:16:2::254
|
||||
|
||||
################################################################################
|
||||
# helpers
|
||||
|
||||
log_section()
|
||||
{
|
||||
echo
|
||||
echo "###########################################################################"
|
||||
echo "$*"
|
||||
echo "###########################################################################"
|
||||
echo
|
||||
}
|
||||
|
||||
log_test()
|
||||
{
|
||||
local rc=$1
|
||||
local expected=$2
|
||||
local msg="$3"
|
||||
|
||||
if [ "${rc}" -eq "${expected}" ]; then
|
||||
printf "TEST: %-60s [ OK ]\n" "${msg}"
|
||||
nsuccess=$((nsuccess+1))
|
||||
else
|
||||
ret=1
|
||||
nfail=$((nfail+1))
|
||||
printf "TEST: %-60s [FAIL]\n" "${msg}"
|
||||
if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
|
||||
echo
|
||||
echo "hit enter to continue, 'q' to quit"
|
||||
read -r a
|
||||
[ "$a" = "q" ] && exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
run_cmd()
|
||||
{
|
||||
local cmd="$*"
|
||||
local out
|
||||
local rc
|
||||
|
||||
if [ "$VERBOSE" = "1" ]; then
|
||||
echo "COMMAND: $cmd"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
out=$(eval $cmd 2>&1)
|
||||
rc=$?
|
||||
if [ "$VERBOSE" = "1" ] && [ -n "$out" ]; then
|
||||
echo "$out"
|
||||
fi
|
||||
|
||||
[ "$VERBOSE" = "1" ] && echo
|
||||
|
||||
return $rc
|
||||
}
|
||||
|
||||
run_cmd_grep()
|
||||
{
|
||||
local grep_pattern="$1"
|
||||
shift
|
||||
local cmd="$*"
|
||||
local out
|
||||
local rc
|
||||
|
||||
if [ "$VERBOSE" = "1" ]; then
|
||||
echo "COMMAND: $cmd"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
out=$(eval $cmd 2>&1)
|
||||
if [ "$VERBOSE" = "1" ] && [ -n "$out" ]; then
|
||||
echo "$out"
|
||||
fi
|
||||
|
||||
echo "$out" | grep -q "$grep_pattern"
|
||||
rc=$?
|
||||
|
||||
[ "$VERBOSE" = "1" ] && echo
|
||||
|
||||
return $rc
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# setup and teardown
|
||||
|
||||
cleanup()
|
||||
{
|
||||
local ns
|
||||
|
||||
for ns in h1 h2 r1 r2; do
|
||||
ip netns del $ns 2>/dev/null
|
||||
done
|
||||
}
|
||||
|
||||
setup_vrf()
|
||||
{
|
||||
local ns=$1
|
||||
|
||||
ip -netns "${ns}" rule del pref 0
|
||||
ip -netns "${ns}" rule add pref 32765 from all lookup local
|
||||
ip -netns "${ns}" -6 rule del pref 0
|
||||
ip -netns "${ns}" -6 rule add pref 32765 from all lookup local
|
||||
}
|
||||
|
||||
create_vrf()
|
||||
{
|
||||
local ns=$1
|
||||
local vrf=$2
|
||||
local table=$3
|
||||
|
||||
ip -netns "${ns}" link add "${vrf}" type vrf table "${table}"
|
||||
ip -netns "${ns}" link set "${vrf}" up
|
||||
ip -netns "${ns}" route add vrf "${vrf}" unreachable default metric 8192
|
||||
ip -netns "${ns}" -6 route add vrf "${vrf}" unreachable default metric 8192
|
||||
|
||||
ip -netns "${ns}" addr add 127.0.0.1/8 dev "${vrf}"
|
||||
ip -netns "${ns}" -6 addr add ::1 dev "${vrf}" nodad
|
||||
}
|
||||
|
||||
setup_sym()
|
||||
{
|
||||
local ns
|
||||
|
||||
# make sure we are starting with a clean slate
|
||||
cleanup
|
||||
|
||||
#
|
||||
# create nodes as namespaces
|
||||
#
|
||||
for ns in h1 h2 r1; do
|
||||
ip netns add $ns
|
||||
ip -netns $ns link set lo up
|
||||
|
||||
case "${ns}" in
|
||||
h[12]) ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0
|
||||
ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1
|
||||
;;
|
||||
r1) ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1
|
||||
ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1
|
||||
esac
|
||||
done
|
||||
|
||||
#
|
||||
# create interconnects
|
||||
#
|
||||
ip -netns h1 link add eth0 type veth peer name r1h1
|
||||
ip -netns h1 link set r1h1 netns r1 name eth0 up
|
||||
|
||||
ip -netns h2 link add eth0 type veth peer name r1h2
|
||||
ip -netns h2 link set r1h2 netns r1 name eth1 up
|
||||
|
||||
#
|
||||
# h1
|
||||
#
|
||||
ip -netns h1 addr add dev eth0 ${H1_N1_IP}/24
|
||||
ip -netns h1 -6 addr add dev eth0 ${H1_N1_IP6}/64 nodad
|
||||
ip -netns h1 link set eth0 up
|
||||
|
||||
# h1 to h2 via r1
|
||||
ip -netns h1 route add ${H2_N2} via ${R1_N1_IP} dev eth0
|
||||
ip -netns h1 -6 route add ${H2_N2_6} via "${R1_N1_IP6}" dev eth0
|
||||
|
||||
#
|
||||
# h2
|
||||
#
|
||||
ip -netns h2 addr add dev eth0 ${H2_N2_IP}/24
|
||||
ip -netns h2 -6 addr add dev eth0 ${H2_N2_IP6}/64 nodad
|
||||
ip -netns h2 link set eth0 up
|
||||
|
||||
# h2 to h1 via r1
|
||||
ip -netns h2 route add default via ${R1_N2_IP} dev eth0
|
||||
ip -netns h2 -6 route add default via ${R1_N2_IP6} dev eth0
|
||||
|
||||
#
|
||||
# r1
|
||||
#
|
||||
setup_vrf r1
|
||||
create_vrf r1 blue 1101
|
||||
create_vrf r1 red 1102
|
||||
ip -netns r1 link set mtu 1400 dev eth1
|
||||
ip -netns r1 link set eth0 vrf blue up
|
||||
ip -netns r1 link set eth1 vrf red up
|
||||
ip -netns r1 addr add dev eth0 ${R1_N1_IP}/24
|
||||
ip -netns r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad
|
||||
ip -netns r1 addr add dev eth1 ${R1_N2_IP}/24
|
||||
ip -netns r1 -6 addr add dev eth1 ${R1_N2_IP6}/64 nodad
|
||||
|
||||
# Route leak from blue to red
|
||||
ip -netns r1 route add vrf blue ${H2_N2} dev red
|
||||
ip -netns r1 -6 route add vrf blue ${H2_N2_6} dev red
|
||||
|
||||
# Route leak from red to blue
|
||||
ip -netns r1 route add vrf red ${H1_N1} dev blue
|
||||
ip -netns r1 -6 route add vrf red ${H1_N1_6} dev blue
|
||||
|
||||
|
||||
# Wait for ip config to settle
|
||||
sleep 2
|
||||
}
|
||||
|
||||
setup_asym()
|
||||
{
|
||||
local ns
|
||||
|
||||
# make sure we are starting with a clean slate
|
||||
cleanup
|
||||
|
||||
#
|
||||
# create nodes as namespaces
|
||||
#
|
||||
for ns in h1 h2 r1 r2; do
|
||||
ip netns add $ns
|
||||
ip -netns $ns link set lo up
|
||||
|
||||
case "${ns}" in
|
||||
h[12]) ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0
|
||||
ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1
|
||||
;;
|
||||
r[12]) ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1
|
||||
ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1
|
||||
esac
|
||||
done
|
||||
|
||||
#
|
||||
# create interconnects
|
||||
#
|
||||
ip -netns h1 link add eth0 type veth peer name r1h1
|
||||
ip -netns h1 link set r1h1 netns r1 name eth0 up
|
||||
|
||||
ip -netns h1 link add eth1 type veth peer name r2h1
|
||||
ip -netns h1 link set r2h1 netns r2 name eth0 up
|
||||
|
||||
ip -netns h2 link add eth0 type veth peer name r1h2
|
||||
ip -netns h2 link set r1h2 netns r1 name eth1 up
|
||||
|
||||
ip -netns h2 link add eth1 type veth peer name r2h2
|
||||
ip -netns h2 link set r2h2 netns r2 name eth1 up
|
||||
|
||||
#
|
||||
# h1
|
||||
#
|
||||
ip -netns h1 link add br0 type bridge
|
||||
ip -netns h1 link set br0 up
|
||||
ip -netns h1 addr add dev br0 ${H1_N1_IP}/24
|
||||
ip -netns h1 -6 addr add dev br0 ${H1_N1_IP6}/64 nodad
|
||||
ip -netns h1 link set eth0 master br0 up
|
||||
ip -netns h1 link set eth1 master br0 up
|
||||
|
||||
# h1 to h2 via r1
|
||||
ip -netns h1 route add ${H2_N2} via ${R1_N1_IP} dev br0
|
||||
ip -netns h1 -6 route add ${H2_N2_6} via "${R1_N1_IP6}" dev br0
|
||||
|
||||
#
|
||||
# h2
|
||||
#
|
||||
ip -netns h2 link add br0 type bridge
|
||||
ip -netns h2 link set br0 up
|
||||
ip -netns h2 addr add dev br0 ${H2_N2_IP}/24
|
||||
ip -netns h2 -6 addr add dev br0 ${H2_N2_IP6}/64 nodad
|
||||
ip -netns h2 link set eth0 master br0 up
|
||||
ip -netns h2 link set eth1 master br0 up
|
||||
|
||||
# h2 to h1 via r2
|
||||
ip -netns h2 route add default via ${R2_N2_IP} dev br0
|
||||
ip -netns h2 -6 route add default via ${R2_N2_IP6} dev br0
|
||||
|
||||
#
|
||||
# r1
|
||||
#
|
||||
setup_vrf r1
|
||||
create_vrf r1 blue 1101
|
||||
create_vrf r1 red 1102
|
||||
ip -netns r1 link set mtu 1400 dev eth1
|
||||
ip -netns r1 link set eth0 vrf blue up
|
||||
ip -netns r1 link set eth1 vrf red up
|
||||
ip -netns r1 addr add dev eth0 ${R1_N1_IP}/24
|
||||
ip -netns r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad
|
||||
ip -netns r1 addr add dev eth1 ${R1_N2_IP}/24
|
||||
ip -netns r1 -6 addr add dev eth1 ${R1_N2_IP6}/64 nodad
|
||||
|
||||
# Route leak from blue to red
|
||||
ip -netns r1 route add vrf blue ${H2_N2} dev red
|
||||
ip -netns r1 -6 route add vrf blue ${H2_N2_6} dev red
|
||||
|
||||
# No route leak from red to blue
|
||||
|
||||
#
|
||||
# r2
|
||||
#
|
||||
ip -netns r2 addr add dev eth0 ${R2_N1_IP}/24
|
||||
ip -netns r2 -6 addr add dev eth0 ${R2_N1_IP6}/64 nodad
|
||||
ip -netns r2 addr add dev eth1 ${R2_N2_IP}/24
|
||||
ip -netns r2 -6 addr add dev eth1 ${R2_N2_IP6}/64 nodad
|
||||
|
||||
# Wait for ip config to settle
|
||||
sleep 2
|
||||
}
|
||||
|
||||
check_connectivity()
|
||||
{
|
||||
ip netns exec h1 ping -c1 -w1 ${H2_N2_IP} >/dev/null 2>&1
|
||||
log_test $? 0 "Basic IPv4 connectivity"
|
||||
return $?
|
||||
}
|
||||
|
||||
check_connectivity6()
|
||||
{
|
||||
ip netns exec h1 "${ping6}" -c1 -w1 ${H2_N2_IP6} >/dev/null 2>&1
|
||||
log_test $? 0 "Basic IPv6 connectivity"
|
||||
return $?
|
||||
}
|
||||
|
||||
check_traceroute()
|
||||
{
|
||||
if [ ! -x "$(command -v traceroute)" ]; then
|
||||
echo "SKIP: Could not run IPV4 test without traceroute"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_traceroute6()
|
||||
{
|
||||
if [ ! -x "$(command -v traceroute6)" ]; then
|
||||
echo "SKIP: Could not run IPV6 test without traceroute6"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
ipv4_traceroute()
|
||||
{
|
||||
local ttype="$1"
|
||||
|
||||
[ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
|
||||
|
||||
log_section "IPv4 ($ttype route): VRF ICMP error route lookup traceroute"
|
||||
|
||||
check_traceroute || return
|
||||
|
||||
setup_"$ttype"
|
||||
|
||||
check_connectivity || return
|
||||
|
||||
run_cmd_grep "${R1_N1_IP}" ip netns exec h1 traceroute ${H2_N2_IP}
|
||||
log_test $? 0 "Traceroute reports a hop on r1"
|
||||
}
|
||||
|
||||
ipv4_traceroute_asym()
|
||||
{
|
||||
ipv4_traceroute asym
|
||||
}
|
||||
|
||||
ipv6_traceroute()
|
||||
{
|
||||
local ttype="$1"
|
||||
|
||||
[ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
|
||||
|
||||
log_section "IPv6 ($ttype route): VRF ICMP error route lookup traceroute"
|
||||
|
||||
check_traceroute6 || return
|
||||
|
||||
setup_"$ttype"
|
||||
|
||||
check_connectivity6 || return
|
||||
|
||||
run_cmd_grep "${R1_N1_IP6}" ip netns exec h1 traceroute6 ${H2_N2_IP6}
|
||||
log_test $? 0 "Traceroute6 reports a hop on r1"
|
||||
}
|
||||
|
||||
ipv6_traceroute_asym()
|
||||
{
|
||||
ipv6_traceroute asym
|
||||
}
|
||||
|
||||
ipv4_ping_ttl()
|
||||
{
|
||||
local ttype="$1"
|
||||
|
||||
[ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
|
||||
|
||||
log_section "IPv4 ($ttype route): VRF ICMP ttl error route lookup ping"
|
||||
|
||||
setup_"$ttype"
|
||||
|
||||
check_connectivity || return
|
||||
|
||||
run_cmd_grep "Time to live exceeded" ip netns exec h1 ping -t1 -c1 -W2 ${H2_N2_IP}
|
||||
log_test $? 0 "Ping received ICMP ttl exceeded"
|
||||
}
|
||||
|
||||
ipv4_ping_ttl_asym()
|
||||
{
|
||||
ipv4_ping_ttl asym
|
||||
}
|
||||
|
||||
ipv4_ping_frag()
|
||||
{
|
||||
local ttype="$1"
|
||||
|
||||
[ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
|
||||
|
||||
log_section "IPv4 ($ttype route): VRF ICMP fragmentation error route lookup ping"
|
||||
|
||||
setup_"$ttype"
|
||||
|
||||
check_connectivity || return
|
||||
|
||||
run_cmd_grep "Frag needed" ip netns exec h1 ping -s 1450 -Mdo -c1 -W2 ${H2_N2_IP}
|
||||
log_test $? 0 "Ping received ICMP Frag needed"
|
||||
}
|
||||
|
||||
ipv4_ping_frag_asym()
|
||||
{
|
||||
ipv4_ping_frag asym
|
||||
}
|
||||
|
||||
ipv6_ping_ttl()
|
||||
{
|
||||
local ttype="$1"
|
||||
|
||||
[ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
|
||||
|
||||
log_section "IPv6 ($ttype route): VRF ICMP ttl error route lookup ping"
|
||||
|
||||
setup_"$ttype"
|
||||
|
||||
check_connectivity6 || return
|
||||
|
||||
run_cmd_grep "Time exceeded: Hop limit" ip netns exec h1 "${ping6}" -t1 -c1 -W2 ${H2_N2_IP6}
|
||||
log_test $? 0 "Ping received ICMP Hop limit"
|
||||
}
|
||||
|
||||
ipv6_ping_ttl_asym()
|
||||
{
|
||||
ipv6_ping_ttl asym
|
||||
}
|
||||
|
||||
ipv6_ping_frag()
|
||||
{
|
||||
local ttype="$1"
|
||||
|
||||
[ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
|
||||
|
||||
log_section "IPv6 ($ttype route): VRF ICMP fragmentation error route lookup ping"
|
||||
|
||||
setup_"$ttype"
|
||||
|
||||
check_connectivity6 || return
|
||||
|
||||
run_cmd_grep "Packet too big" ip netns exec h1 "${ping6}" -s 1450 -Mdo -c1 -W2 ${H2_N2_IP6}
|
||||
log_test $? 0 "Ping received ICMP Packet too big"
|
||||
}
|
||||
|
||||
ipv6_ping_frag_asym()
|
||||
{
|
||||
ipv6_ping_frag asym
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# usage
|
||||
|
||||
usage()
|
||||
{
|
||||
cat <<EOF
|
||||
usage: ${0##*/} OPTS
|
||||
|
||||
-4 Run IPv4 tests only
|
||||
-6 Run IPv6 tests only
|
||||
-t TEST Run only TEST
|
||||
-p Pause on fail
|
||||
-v verbose mode (show commands and output)
|
||||
EOF
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# main
|
||||
|
||||
# Some systems don't have a ping6 binary anymore
|
||||
command -v ping6 > /dev/null 2>&1 && ping6=$(command -v ping6) || ping6=$(command -v ping)
|
||||
|
||||
TESTS_IPV4="ipv4_ping_ttl ipv4_traceroute ipv4_ping_frag ipv4_ping_ttl_asym ipv4_traceroute_asym"
|
||||
TESTS_IPV6="ipv6_ping_ttl ipv6_traceroute ipv6_ping_frag ipv6_ping_ttl_asym ipv6_traceroute_asym"
|
||||
|
||||
ret=0
|
||||
nsuccess=0
|
||||
nfail=0
|
||||
|
||||
while getopts :46t:pvh o
|
||||
do
|
||||
case $o in
|
||||
4) TESTS=ipv4;;
|
||||
6) TESTS=ipv6;;
|
||||
t) TESTS=$OPTARG;;
|
||||
p) PAUSE_ON_FAIL=yes;;
|
||||
v) VERBOSE=1;;
|
||||
h) usage; exit 0;;
|
||||
*) usage; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
#
|
||||
# show user test config
|
||||
#
|
||||
if [ -z "$TESTS" ]; then
|
||||
TESTS="$TESTS_IPV4 $TESTS_IPV6"
|
||||
elif [ "$TESTS" = "ipv4" ]; then
|
||||
TESTS="$TESTS_IPV4"
|
||||
elif [ "$TESTS" = "ipv6" ]; then
|
||||
TESTS="$TESTS_IPV6"
|
||||
fi
|
||||
|
||||
for t in $TESTS
|
||||
do
|
||||
case $t in
|
||||
ipv4_ping_ttl|ping) ipv4_ping_ttl;;&
|
||||
ipv4_ping_ttl_asym|ping) ipv4_ping_ttl_asym;;&
|
||||
ipv4_traceroute|traceroute) ipv4_traceroute;;&
|
||||
ipv4_traceroute_asym|traceroute) ipv4_traceroute_asym;;&
|
||||
ipv4_ping_frag|ping) ipv4_ping_frag;;&
|
||||
|
||||
ipv6_ping_ttl|ping) ipv6_ping_ttl;;&
|
||||
ipv6_ping_ttl_asym|ping) ipv6_ping_ttl_asym;;&
|
||||
ipv6_traceroute|traceroute) ipv6_traceroute;;&
|
||||
ipv6_traceroute_asym|traceroute) ipv6_traceroute_asym;;&
|
||||
ipv6_ping_frag|ping) ipv6_ping_frag;;&
|
||||
|
||||
# setup namespaces and config, but do not run any tests
|
||||
setup_sym|setup) setup_sym; exit 0;;
|
||||
setup_asym) setup_asym; exit 0;;
|
||||
|
||||
help) echo "Test names: $TESTS"; exit 0;;
|
||||
esac
|
||||
done
|
||||
|
||||
cleanup
|
||||
|
||||
printf "\nTests passed: %3d\n" ${nsuccess}
|
||||
printf "Tests failed: %3d\n" ${nfail}
|
||||
|
||||
exit $ret
|
||||
@@ -17,9 +17,12 @@
|
||||
|
||||
struct options {
|
||||
bool count_packets;
|
||||
bool gso_enabled;
|
||||
int verbose;
|
||||
unsigned int queue_num;
|
||||
unsigned int timeout;
|
||||
uint32_t verdict;
|
||||
uint32_t delay_ms;
|
||||
};
|
||||
|
||||
static unsigned int queue_stats[5];
|
||||
@@ -27,7 +30,7 @@ static struct options opts;
|
||||
|
||||
static void help(const char *p)
|
||||
{
|
||||
printf("Usage: %s [-c|-v [-vv] ] [-t timeout] [-q queue_num]\n", p);
|
||||
printf("Usage: %s [-c|-v [-vv] ] [-t timeout] [-q queue_num] [-Qdst_queue ] [ -d ms_delay ] [-G]\n", p);
|
||||
}
|
||||
|
||||
static int parse_attr_cb(const struct nlattr *attr, void *data)
|
||||
@@ -162,7 +165,7 @@ nfq_build_cfg_params(char *buf, uint8_t mode, int range, int queue_num)
|
||||
}
|
||||
|
||||
static struct nlmsghdr *
|
||||
nfq_build_verdict(char *buf, int id, int queue_num, int verd)
|
||||
nfq_build_verdict(char *buf, int id, int queue_num, uint32_t verd)
|
||||
{
|
||||
struct nfqnl_msg_verdict_hdr vh = {
|
||||
.verdict = htonl(verd),
|
||||
@@ -189,9 +192,6 @@ static void print_stats(void)
|
||||
unsigned int last, total;
|
||||
int i;
|
||||
|
||||
if (!opts.count_packets)
|
||||
return;
|
||||
|
||||
total = 0;
|
||||
last = queue_stats[0];
|
||||
|
||||
@@ -234,7 +234,8 @@ struct mnl_socket *open_queue(void)
|
||||
|
||||
nlh = nfq_build_cfg_params(buf, NFQNL_COPY_PACKET, 0xFFFF, queue_num);
|
||||
|
||||
flags = NFQA_CFG_F_GSO | NFQA_CFG_F_UID_GID;
|
||||
flags = opts.gso_enabled ? NFQA_CFG_F_GSO : 0;
|
||||
flags |= NFQA_CFG_F_UID_GID;
|
||||
mnl_attr_put_u32(nlh, NFQA_CFG_FLAGS, htonl(flags));
|
||||
mnl_attr_put_u32(nlh, NFQA_CFG_MASK, htonl(flags));
|
||||
|
||||
@@ -255,6 +256,17 @@ struct mnl_socket *open_queue(void)
|
||||
return nl;
|
||||
}
|
||||
|
||||
static void sleep_ms(uint32_t delay)
|
||||
{
|
||||
struct timespec ts = { .tv_sec = delay / 1000 };
|
||||
|
||||
delay %= 1000;
|
||||
|
||||
ts.tv_nsec = delay * 1000llu * 1000llu;
|
||||
|
||||
nanosleep(&ts, NULL);
|
||||
}
|
||||
|
||||
static int mainloop(void)
|
||||
{
|
||||
unsigned int buflen = 64 * 1024 + MNL_SOCKET_BUFFER_SIZE;
|
||||
@@ -278,7 +290,7 @@ static int mainloop(void)
|
||||
|
||||
ret = mnl_socket_recvfrom(nl, buf, buflen);
|
||||
if (ret == -1) {
|
||||
if (errno == ENOBUFS)
|
||||
if (errno == ENOBUFS || errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (errno == EAGAIN) {
|
||||
@@ -298,7 +310,10 @@ static int mainloop(void)
|
||||
}
|
||||
|
||||
id = ret - MNL_CB_OK;
|
||||
nlh = nfq_build_verdict(buf, id, opts.queue_num, NF_ACCEPT);
|
||||
if (opts.delay_ms)
|
||||
sleep_ms(opts.delay_ms);
|
||||
|
||||
nlh = nfq_build_verdict(buf, id, opts.queue_num, opts.verdict);
|
||||
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
|
||||
perror("mnl_socket_sendto");
|
||||
exit(EXIT_FAILURE);
|
||||
@@ -314,7 +329,7 @@ static void parse_opts(int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
|
||||
while ((c = getopt(argc, argv, "chvt:q:")) != -1) {
|
||||
while ((c = getopt(argc, argv, "chvt:q:Q:d:G")) != -1) {
|
||||
switch (c) {
|
||||
case 'c':
|
||||
opts.count_packets = true;
|
||||
@@ -328,20 +343,48 @@ static void parse_opts(int argc, char **argv)
|
||||
if (opts.queue_num > 0xffff)
|
||||
opts.queue_num = 0;
|
||||
break;
|
||||
case 'Q':
|
||||
opts.verdict = atoi(optarg);
|
||||
if (opts.verdict > 0xffff) {
|
||||
fprintf(stderr, "Expected destination queue number\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
opts.verdict <<= 16;
|
||||
opts.verdict |= NF_QUEUE;
|
||||
break;
|
||||
case 'd':
|
||||
opts.delay_ms = atoi(optarg);
|
||||
if (opts.delay_ms == 0) {
|
||||
fprintf(stderr, "Expected nonzero delay (in milliseconds)\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
opts.timeout = atoi(optarg);
|
||||
break;
|
||||
case 'G':
|
||||
opts.gso_enabled = false;
|
||||
break;
|
||||
case 'v':
|
||||
opts.verbose++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.verdict != NF_ACCEPT && (opts.verdict >> 16 == opts.queue_num)) {
|
||||
fprintf(stderr, "Cannot use same destination and source queue\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
opts.verdict = NF_ACCEPT;
|
||||
opts.gso_enabled = true;
|
||||
|
||||
parse_opts(argc, argv);
|
||||
|
||||
ret = mainloop();
|
||||
|
||||
@@ -7,8 +7,7 @@ ksft_skip=4
|
||||
sfx=$(mktemp -u "XXXXXXXX")
|
||||
ns0="ns0-$sfx"
|
||||
|
||||
nft --version > /dev/null 2>&1
|
||||
if [ $? -ne 0 ];then
|
||||
if ! nft --version > /dev/null 2>&1; then
|
||||
echo "SKIP: Could not run test without nft tool"
|
||||
exit $ksft_skip
|
||||
fi
|
||||
@@ -24,6 +23,8 @@ ip -net "$ns0" addr add 127.0.0.1 dev lo
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
currentyear=$(date +%G)
|
||||
lastyear=$((currentyear-1))
|
||||
ip netns exec "$ns0" nft -f /dev/stdin <<EOF
|
||||
table inet filter {
|
||||
counter iifcount {}
|
||||
@@ -33,6 +34,9 @@ table inet filter {
|
||||
counter infproto4count {}
|
||||
counter il4protocounter {}
|
||||
counter imarkcounter {}
|
||||
counter icpu0counter {}
|
||||
counter ilastyearcounter {}
|
||||
counter icurrentyearcounter {}
|
||||
|
||||
counter oifcount {}
|
||||
counter oifnamecount {}
|
||||
@@ -54,6 +58,9 @@ table inet filter {
|
||||
meta nfproto ipv4 counter name "infproto4count"
|
||||
meta l4proto icmp counter name "il4protocounter"
|
||||
meta mark 42 counter name "imarkcounter"
|
||||
meta cpu 0 counter name "icpu0counter"
|
||||
meta time "$lastyear-01-01" - "$lastyear-12-31" counter name ilastyearcounter
|
||||
meta time "$currentyear-01-01" - "$currentyear-12-31" counter name icurrentyearcounter
|
||||
}
|
||||
|
||||
chain output {
|
||||
@@ -84,11 +91,10 @@ check_one_counter()
|
||||
local want="packets $2"
|
||||
local verbose="$3"
|
||||
|
||||
cnt=$(ip netns exec "$ns0" nft list counter inet filter $cname | grep -q "$want")
|
||||
if [ $? -ne 0 ];then
|
||||
if ! ip netns exec "$ns0" nft list counter inet filter $cname | grep -q "$want"; then
|
||||
echo "FAIL: $cname, want \"$want\", got"
|
||||
ret=1
|
||||
ip netns exec "$ns0" nft list counter inet filter $counter
|
||||
ip netns exec "$ns0" nft list counter inet filter $cname
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -100,8 +106,7 @@ check_lo_counters()
|
||||
|
||||
for counter in iifcount iifnamecount iifgroupcount iiftypecount infproto4count \
|
||||
oifcount oifnamecount oifgroupcount oiftypecount onfproto4count \
|
||||
il4protocounter \
|
||||
ol4protocounter \
|
||||
il4protocounter icurrentyearcounter ol4protocounter \
|
||||
; do
|
||||
check_one_counter "$counter" "$want" "$verbose"
|
||||
done
|
||||
@@ -116,9 +121,22 @@ check_one_counter oskuidcounter "1" true
|
||||
check_one_counter oskgidcounter "1" true
|
||||
check_one_counter imarkcounter "1" true
|
||||
check_one_counter omarkcounter "1" true
|
||||
check_one_counter ilastyearcounter "0" true
|
||||
|
||||
if [ $ret -eq 0 ];then
|
||||
echo "OK: nftables meta iif/oif counters at expected values"
|
||||
else
|
||||
exit $ret
|
||||
fi
|
||||
|
||||
#First CPU execution and counter
|
||||
taskset -p 01 $$ > /dev/null
|
||||
ip netns exec "$ns0" nft reset counters > /dev/null
|
||||
ip netns exec "$ns0" ping -q -c 1 127.0.0.1 > /dev/null
|
||||
check_one_counter icpu0counter "2" true
|
||||
|
||||
if [ $ret -eq 0 ];then
|
||||
echo "OK: nftables meta cpu counter at expected values"
|
||||
fi
|
||||
|
||||
exit $ret
|
||||
|
||||
@@ -12,6 +12,7 @@ sfx=$(mktemp -u "XXXXXXXX")
|
||||
ns1="ns1-$sfx"
|
||||
ns2="ns2-$sfx"
|
||||
nsrouter="nsrouter-$sfx"
|
||||
timeout=4
|
||||
|
||||
cleanup()
|
||||
{
|
||||
@@ -20,6 +21,7 @@ cleanup()
|
||||
ip netns del ${nsrouter}
|
||||
rm -f "$TMPFILE0"
|
||||
rm -f "$TMPFILE1"
|
||||
rm -f "$TMPFILE2" "$TMPFILE3"
|
||||
}
|
||||
|
||||
nft --version > /dev/null 2>&1
|
||||
@@ -42,6 +44,8 @@ fi
|
||||
|
||||
TMPFILE0=$(mktemp)
|
||||
TMPFILE1=$(mktemp)
|
||||
TMPFILE2=$(mktemp)
|
||||
TMPFILE3=$(mktemp)
|
||||
trap cleanup EXIT
|
||||
|
||||
ip netns add ${ns1}
|
||||
@@ -83,7 +87,7 @@ load_ruleset() {
|
||||
local name=$1
|
||||
local prio=$2
|
||||
|
||||
ip netns exec ${nsrouter} nft -f - <<EOF
|
||||
ip netns exec ${nsrouter} nft -f /dev/stdin <<EOF
|
||||
table inet $name {
|
||||
chain nfq {
|
||||
ip protocol icmp queue bypass
|
||||
@@ -118,7 +122,7 @@ EOF
|
||||
load_counter_ruleset() {
|
||||
local prio=$1
|
||||
|
||||
ip netns exec ${nsrouter} nft -f - <<EOF
|
||||
ip netns exec ${nsrouter} nft -f /dev/stdin <<EOF
|
||||
table inet countrules {
|
||||
chain pre {
|
||||
type filter hook prerouting priority $prio; policy accept;
|
||||
@@ -175,7 +179,7 @@ test_ping_router() {
|
||||
test_queue_blackhole() {
|
||||
local proto=$1
|
||||
|
||||
ip netns exec ${nsrouter} nft -f - <<EOF
|
||||
ip netns exec ${nsrouter} nft -f /dev/stdin <<EOF
|
||||
table $proto blackh {
|
||||
chain forward {
|
||||
type filter hook forward priority 0; policy accept;
|
||||
@@ -184,10 +188,10 @@ table $proto blackh {
|
||||
}
|
||||
EOF
|
||||
if [ $proto = "ip" ] ;then
|
||||
ip netns exec ${ns1} ping -c 1 -q 10.0.2.99 > /dev/null
|
||||
ip netns exec ${ns1} ping -W 2 -c 1 -q 10.0.2.99 > /dev/null
|
||||
lret=$?
|
||||
elif [ $proto = "ip6" ]; then
|
||||
ip netns exec ${ns1} ping -c 1 -q dead:2::99 > /dev/null
|
||||
ip netns exec ${ns1} ping -W 2 -c 1 -q dead:2::99 > /dev/null
|
||||
lret=$?
|
||||
else
|
||||
lret=111
|
||||
@@ -214,8 +218,8 @@ test_queue()
|
||||
local last=""
|
||||
|
||||
# spawn nf-queue listeners
|
||||
ip netns exec ${nsrouter} ./nf-queue -c -q 0 -t 3 > "$TMPFILE0" &
|
||||
ip netns exec ${nsrouter} ./nf-queue -c -q 1 -t 3 > "$TMPFILE1" &
|
||||
ip netns exec ${nsrouter} ./nf-queue -c -q 0 -t $timeout > "$TMPFILE0" &
|
||||
ip netns exec ${nsrouter} ./nf-queue -c -q 1 -t $timeout > "$TMPFILE1" &
|
||||
sleep 1
|
||||
test_ping
|
||||
ret=$?
|
||||
@@ -250,11 +254,11 @@ test_queue()
|
||||
|
||||
test_tcp_forward()
|
||||
{
|
||||
ip netns exec ${nsrouter} ./nf-queue -q 2 -t 10 &
|
||||
ip netns exec ${nsrouter} ./nf-queue -q 2 -t $timeout &
|
||||
local nfqpid=$!
|
||||
|
||||
tmpfile=$(mktemp) || exit 1
|
||||
dd conv=sparse status=none if=/dev/zero bs=1M count=100 of=$tmpfile
|
||||
dd conv=sparse status=none if=/dev/zero bs=1M count=200 of=$tmpfile
|
||||
ip netns exec ${ns2} nc -w 5 -l -p 12345 <"$tmpfile" >/dev/null &
|
||||
local rpid=$!
|
||||
|
||||
@@ -270,15 +274,13 @@ test_tcp_forward()
|
||||
|
||||
test_tcp_localhost()
|
||||
{
|
||||
tc -net "${nsrouter}" qdisc add dev lo root netem loss random 1%
|
||||
|
||||
tmpfile=$(mktemp) || exit 1
|
||||
|
||||
dd conv=sparse status=none if=/dev/zero bs=1M count=900 of=$tmpfile
|
||||
dd conv=sparse status=none if=/dev/zero bs=1M count=200 of=$tmpfile
|
||||
ip netns exec ${nsrouter} nc -w 5 -l -p 12345 <"$tmpfile" >/dev/null &
|
||||
local rpid=$!
|
||||
|
||||
ip netns exec ${nsrouter} ./nf-queue -q 3 -t 30 &
|
||||
ip netns exec ${nsrouter} ./nf-queue -q 3 -t $timeout &
|
||||
local nfqpid=$!
|
||||
|
||||
sleep 1
|
||||
@@ -287,6 +289,47 @@ test_tcp_localhost()
|
||||
|
||||
wait $rpid
|
||||
[ $? -eq 0 ] && echo "PASS: tcp via loopback"
|
||||
wait 2>/dev/null
|
||||
}
|
||||
|
||||
test_tcp_localhost_requeue()
|
||||
{
|
||||
ip netns exec ${nsrouter} nft -f /dev/stdin <<EOF
|
||||
flush ruleset
|
||||
table inet filter {
|
||||
chain output {
|
||||
type filter hook output priority 0; policy accept;
|
||||
tcp dport 12345 limit rate 1/second burst 1 packets counter queue num 0
|
||||
}
|
||||
chain post {
|
||||
type filter hook postrouting priority 0; policy accept;
|
||||
tcp dport 12345 limit rate 1/second burst 1 packets counter queue num 0
|
||||
}
|
||||
}
|
||||
EOF
|
||||
tmpfile=$(mktemp) || exit 1
|
||||
dd conv=sparse status=none if=/dev/zero bs=1M count=200 of=$tmpfile
|
||||
ip netns exec ${nsrouter} nc -w 5 -l -p 12345 <"$tmpfile" >/dev/null &
|
||||
local rpid=$!
|
||||
|
||||
ip netns exec ${nsrouter} ./nf-queue -c -q 1 -t $timeout > "$TMPFILE2" &
|
||||
|
||||
# nfqueue 1 will be called via output hook. But this time,
|
||||
# re-queue the packet to nfqueue program on queue 2.
|
||||
ip netns exec ${nsrouter} ./nf-queue -G -d 150 -c -q 0 -Q 1 -t $timeout > "$TMPFILE3" &
|
||||
|
||||
sleep 1
|
||||
ip netns exec ${nsrouter} nc -w 5 127.0.0.1 12345 <"$tmpfile" > /dev/null
|
||||
rm -f "$tmpfile"
|
||||
|
||||
wait
|
||||
|
||||
if ! diff -u "$TMPFILE2" "$TMPFILE3" ; then
|
||||
echo "FAIL: lost packets during requeue?!" 1>&2
|
||||
return
|
||||
fi
|
||||
|
||||
echo "PASS: tcp via loopback and re-queueing"
|
||||
}
|
||||
|
||||
ip netns exec ${nsrouter} sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
|
||||
@@ -328,5 +371,6 @@ test_queue 20
|
||||
|
||||
test_tcp_forward
|
||||
test_tcp_localhost
|
||||
test_tcp_localhost_requeue
|
||||
|
||||
exit $ret
|
||||
|
||||
Reference in New Issue
Block a user