cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fib_tests.sh (60175B)


      1#!/bin/bash
      2# SPDX-License-Identifier: GPL-2.0
      3
      4# This test is for checking IPv4 and IPv6 FIB behavior in response to
      5# different events.
      6
      7ret=0
      8# Kselftest framework requirement - SKIP code is 4.
      9ksft_skip=4
     10
     11# all tests in this script. Can be overridden with -t option
     12TESTS="unregister down carrier nexthop suppress ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric ipv6_route_metrics ipv4_route_metrics ipv4_route_v6_gw rp_filter ipv4_del_addr ipv4_mangle ipv6_mangle ipv4_bcast_neigh"
     13
     14VERBOSE=0
     15PAUSE_ON_FAIL=no
     16PAUSE=no
     17IP="ip -netns ns1"
     18NS_EXEC="ip netns exec ns1"
     19
     20which ping6 > /dev/null 2>&1 && ping6=$(which ping6) || ping6=$(which ping)
     21
     22log_test()
     23{
     24	local rc=$1
     25	local expected=$2
     26	local msg="$3"
     27
     28	if [ ${rc} -eq ${expected} ]; then
     29		printf "    TEST: %-60s  [ OK ]\n" "${msg}"
     30		nsuccess=$((nsuccess+1))
     31	else
     32		ret=1
     33		nfail=$((nfail+1))
     34		printf "    TEST: %-60s  [FAIL]\n" "${msg}"
     35		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
     36		echo
     37			echo "hit enter to continue, 'q' to quit"
     38			read a
     39			[ "$a" = "q" ] && exit 1
     40		fi
     41	fi
     42
     43	if [ "${PAUSE}" = "yes" ]; then
     44		echo
     45		echo "hit enter to continue, 'q' to quit"
     46		read a
     47		[ "$a" = "q" ] && exit 1
     48	fi
     49}
     50
     51setup()
     52{
     53	set -e
     54	ip netns add ns1
     55	ip netns set ns1 auto
     56	$IP link set dev lo up
     57	ip netns exec ns1 sysctl -qw net.ipv4.ip_forward=1
     58	ip netns exec ns1 sysctl -qw net.ipv6.conf.all.forwarding=1
     59
     60	$IP link add dummy0 type dummy
     61	$IP link set dev dummy0 up
     62	$IP address add 198.51.100.1/24 dev dummy0
     63	$IP -6 address add 2001:db8:1::1/64 dev dummy0
     64	set +e
     65
     66}
     67
     68cleanup()
     69{
     70	$IP link del dev dummy0 &> /dev/null
     71	ip netns del ns1
     72	ip netns del ns2 &> /dev/null
     73}
     74
     75get_linklocal()
     76{
     77	local dev=$1
     78	local addr
     79
     80	addr=$($IP -6 -br addr show dev ${dev} | \
     81	awk '{
     82		for (i = 3; i <= NF; ++i) {
     83			if ($i ~ /^fe80/)
     84				print $i
     85		}
     86	}'
     87	)
     88	addr=${addr/\/*}
     89
     90	[ -z "$addr" ] && return 1
     91
     92	echo $addr
     93
     94	return 0
     95}
     96
     97fib_unreg_unicast_test()
     98{
     99	echo
    100	echo "Single path route test"
    101
    102	setup
    103
    104	echo "    Start point"
    105	$IP route get fibmatch 198.51.100.2 &> /dev/null
    106	log_test $? 0 "IPv4 fibmatch"
    107	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
    108	log_test $? 0 "IPv6 fibmatch"
    109
    110	set -e
    111	$IP link del dev dummy0
    112	set +e
    113
    114	echo "    Nexthop device deleted"
    115	$IP route get fibmatch 198.51.100.2 &> /dev/null
    116	log_test $? 2 "IPv4 fibmatch - no route"
    117	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
    118	log_test $? 2 "IPv6 fibmatch - no route"
    119
    120	cleanup
    121}
    122
    123fib_unreg_multipath_test()
    124{
    125
    126	echo
    127	echo "Multipath route test"
    128
    129	setup
    130
    131	set -e
    132	$IP link add dummy1 type dummy
    133	$IP link set dev dummy1 up
    134	$IP address add 192.0.2.1/24 dev dummy1
    135	$IP -6 address add 2001:db8:2::1/64 dev dummy1
    136
    137	$IP route add 203.0.113.0/24 \
    138		nexthop via 198.51.100.2 dev dummy0 \
    139		nexthop via 192.0.2.2 dev dummy1
    140	$IP -6 route add 2001:db8:3::/64 \
    141		nexthop via 2001:db8:1::2 dev dummy0 \
    142		nexthop via 2001:db8:2::2 dev dummy1
    143	set +e
    144
    145	echo "    Start point"
    146	$IP route get fibmatch 203.0.113.1 &> /dev/null
    147	log_test $? 0 "IPv4 fibmatch"
    148	$IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
    149	log_test $? 0 "IPv6 fibmatch"
    150
    151	set -e
    152	$IP link del dev dummy0
    153	set +e
    154
    155	echo "    One nexthop device deleted"
    156	$IP route get fibmatch 203.0.113.1 &> /dev/null
    157	log_test $? 2 "IPv4 - multipath route removed on delete"
    158
    159	$IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
    160	# In IPv6 we do not flush the entire multipath route.
    161	log_test $? 0 "IPv6 - multipath down to single path"
    162
    163	set -e
    164	$IP link del dev dummy1
    165	set +e
    166
    167	echo "    Second nexthop device deleted"
    168	$IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
    169	log_test $? 2 "IPv6 - no route"
    170
    171	cleanup
    172}
    173
    174fib_unreg_test()
    175{
    176	fib_unreg_unicast_test
    177	fib_unreg_multipath_test
    178}
    179
    180fib_down_unicast_test()
    181{
    182	echo
    183	echo "Single path, admin down"
    184
    185	setup
    186
    187	echo "    Start point"
    188	$IP route get fibmatch 198.51.100.2 &> /dev/null
    189	log_test $? 0 "IPv4 fibmatch"
    190	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
    191	log_test $? 0 "IPv6 fibmatch"
    192
    193	set -e
    194	$IP link set dev dummy0 down
    195	set +e
    196
    197	echo "    Route deleted on down"
    198	$IP route get fibmatch 198.51.100.2 &> /dev/null
    199	log_test $? 2 "IPv4 fibmatch"
    200	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
    201	log_test $? 2 "IPv6 fibmatch"
    202
    203	cleanup
    204}
    205
    206fib_down_multipath_test_do()
    207{
    208	local down_dev=$1
    209	local up_dev=$2
    210
    211	$IP route get fibmatch 203.0.113.1 \
    212		oif $down_dev &> /dev/null
    213	log_test $? 2 "IPv4 fibmatch on down device"
    214	$IP -6 route get fibmatch 2001:db8:3::1 \
    215		oif $down_dev &> /dev/null
    216	log_test $? 2 "IPv6 fibmatch on down device"
    217
    218	$IP route get fibmatch 203.0.113.1 \
    219		oif $up_dev &> /dev/null
    220	log_test $? 0 "IPv4 fibmatch on up device"
    221	$IP -6 route get fibmatch 2001:db8:3::1 \
    222		oif $up_dev &> /dev/null
    223	log_test $? 0 "IPv6 fibmatch on up device"
    224
    225	$IP route get fibmatch 203.0.113.1 | \
    226		grep $down_dev | grep -q "dead linkdown"
    227	log_test $? 0 "IPv4 flags on down device"
    228	$IP -6 route get fibmatch 2001:db8:3::1 | \
    229		grep $down_dev | grep -q "dead linkdown"
    230	log_test $? 0 "IPv6 flags on down device"
    231
    232	$IP route get fibmatch 203.0.113.1 | \
    233		grep $up_dev | grep -q "dead linkdown"
    234	log_test $? 1 "IPv4 flags on up device"
    235	$IP -6 route get fibmatch 2001:db8:3::1 | \
    236		grep $up_dev | grep -q "dead linkdown"
    237	log_test $? 1 "IPv6 flags on up device"
    238}
    239
    240fib_down_multipath_test()
    241{
    242	echo
    243	echo "Admin down multipath"
    244
    245	setup
    246
    247	set -e
    248	$IP link add dummy1 type dummy
    249	$IP link set dev dummy1 up
    250
    251	$IP address add 192.0.2.1/24 dev dummy1
    252	$IP -6 address add 2001:db8:2::1/64 dev dummy1
    253
    254	$IP route add 203.0.113.0/24 \
    255		nexthop via 198.51.100.2 dev dummy0 \
    256		nexthop via 192.0.2.2 dev dummy1
    257	$IP -6 route add 2001:db8:3::/64 \
    258		nexthop via 2001:db8:1::2 dev dummy0 \
    259		nexthop via 2001:db8:2::2 dev dummy1
    260	set +e
    261
    262	echo "    Verify start point"
    263	$IP route get fibmatch 203.0.113.1 &> /dev/null
    264	log_test $? 0 "IPv4 fibmatch"
    265
    266	$IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
    267	log_test $? 0 "IPv6 fibmatch"
    268
    269	set -e
    270	$IP link set dev dummy0 down
    271	set +e
    272
    273	echo "    One device down, one up"
    274	fib_down_multipath_test_do "dummy0" "dummy1"
    275
    276	set -e
    277	$IP link set dev dummy0 up
    278	$IP link set dev dummy1 down
    279	set +e
    280
    281	echo "    Other device down and up"
    282	fib_down_multipath_test_do "dummy1" "dummy0"
    283
    284	set -e
    285	$IP link set dev dummy0 down
    286	set +e
    287
    288	echo "    Both devices down"
    289	$IP route get fibmatch 203.0.113.1 &> /dev/null
    290	log_test $? 2 "IPv4 fibmatch"
    291	$IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
    292	log_test $? 2 "IPv6 fibmatch"
    293
    294	$IP link del dev dummy1
    295	cleanup
    296}
    297
    298fib_down_test()
    299{
    300	fib_down_unicast_test
    301	fib_down_multipath_test
    302}
    303
    304# Local routes should not be affected when carrier changes.
    305fib_carrier_local_test()
    306{
    307	echo
    308	echo "Local carrier tests - single path"
    309
    310	setup
    311
    312	set -e
    313	$IP link set dev dummy0 carrier on
    314	set +e
    315
    316	echo "    Start point"
    317	$IP route get fibmatch 198.51.100.1 &> /dev/null
    318	log_test $? 0 "IPv4 fibmatch"
    319	$IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null
    320	log_test $? 0 "IPv6 fibmatch"
    321
    322	$IP route get fibmatch 198.51.100.1 | \
    323		grep -q "linkdown"
    324	log_test $? 1 "IPv4 - no linkdown flag"
    325	$IP -6 route get fibmatch 2001:db8:1::1 | \
    326		grep -q "linkdown"
    327	log_test $? 1 "IPv6 - no linkdown flag"
    328
    329	set -e
    330	$IP link set dev dummy0 carrier off
    331	sleep 1
    332	set +e
    333
    334	echo "    Carrier off on nexthop"
    335	$IP route get fibmatch 198.51.100.1 &> /dev/null
    336	log_test $? 0 "IPv4 fibmatch"
    337	$IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null
    338	log_test $? 0 "IPv6 fibmatch"
    339
    340	$IP route get fibmatch 198.51.100.1 | \
    341		grep -q "linkdown"
    342	log_test $? 1 "IPv4 - linkdown flag set"
    343	$IP -6 route get fibmatch 2001:db8:1::1 | \
    344		grep -q "linkdown"
    345	log_test $? 1 "IPv6 - linkdown flag set"
    346
    347	set -e
    348	$IP address add 192.0.2.1/24 dev dummy0
    349	$IP -6 address add 2001:db8:2::1/64 dev dummy0
    350	set +e
    351
    352	echo "    Route to local address with carrier down"
    353	$IP route get fibmatch 192.0.2.1 &> /dev/null
    354	log_test $? 0 "IPv4 fibmatch"
    355	$IP -6 route get fibmatch 2001:db8:2::1 &> /dev/null
    356	log_test $? 0 "IPv6 fibmatch"
    357
    358	$IP route get fibmatch 192.0.2.1 | \
    359		grep -q "linkdown"
    360	log_test $? 1 "IPv4 linkdown flag set"
    361	$IP -6 route get fibmatch 2001:db8:2::1 | \
    362		grep -q "linkdown"
    363	log_test $? 1 "IPv6 linkdown flag set"
    364
    365	cleanup
    366}
    367
    368fib_carrier_unicast_test()
    369{
    370	ret=0
    371
    372	echo
    373	echo "Single path route carrier test"
    374
    375	setup
    376
    377	set -e
    378	$IP link set dev dummy0 carrier on
    379	set +e
    380
    381	echo "    Start point"
    382	$IP route get fibmatch 198.51.100.2 &> /dev/null
    383	log_test $? 0 "IPv4 fibmatch"
    384	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
    385	log_test $? 0 "IPv6 fibmatch"
    386
    387	$IP route get fibmatch 198.51.100.2 | \
    388		grep -q "linkdown"
    389	log_test $? 1 "IPv4 no linkdown flag"
    390	$IP -6 route get fibmatch 2001:db8:1::2 | \
    391		grep -q "linkdown"
    392	log_test $? 1 "IPv6 no linkdown flag"
    393
    394	set -e
    395	$IP link set dev dummy0 carrier off
    396	sleep 1
    397	set +e
    398
    399	echo "    Carrier down"
    400	$IP route get fibmatch 198.51.100.2 &> /dev/null
    401	log_test $? 0 "IPv4 fibmatch"
    402	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
    403	log_test $? 0 "IPv6 fibmatch"
    404
    405	$IP route get fibmatch 198.51.100.2 | \
    406		grep -q "linkdown"
    407	log_test $? 0 "IPv4 linkdown flag set"
    408	$IP -6 route get fibmatch 2001:db8:1::2 | \
    409		grep -q "linkdown"
    410	log_test $? 0 "IPv6 linkdown flag set"
    411
    412	set -e
    413	$IP address add 192.0.2.1/24 dev dummy0
    414	$IP -6 address add 2001:db8:2::1/64 dev dummy0
    415	set +e
    416
    417	echo "    Second address added with carrier down"
    418	$IP route get fibmatch 192.0.2.2 &> /dev/null
    419	log_test $? 0 "IPv4 fibmatch"
    420	$IP -6 route get fibmatch 2001:db8:2::2 &> /dev/null
    421	log_test $? 0 "IPv6 fibmatch"
    422
    423	$IP route get fibmatch 192.0.2.2 | \
    424		grep -q "linkdown"
    425	log_test $? 0 "IPv4 linkdown flag set"
    426	$IP -6 route get fibmatch 2001:db8:2::2 | \
    427		grep -q "linkdown"
    428	log_test $? 0 "IPv6 linkdown flag set"
    429
    430	cleanup
    431}
    432
    433fib_carrier_test()
    434{
    435	fib_carrier_local_test
    436	fib_carrier_unicast_test
    437}
    438
    439fib_rp_filter_test()
    440{
    441	echo
    442	echo "IPv4 rp_filter tests"
    443
    444	setup
    445
    446	set -e
    447	ip netns add ns2
    448	ip netns set ns2 auto
    449
    450	ip -netns ns2 link set dev lo up
    451
    452	$IP link add name veth1 type veth peer name veth2
    453	$IP link set dev veth2 netns ns2
    454	$IP address add 192.0.2.1/24 dev veth1
    455	ip -netns ns2 address add 192.0.2.1/24 dev veth2
    456	$IP link set dev veth1 up
    457	ip -netns ns2 link set dev veth2 up
    458
    459	$IP link set dev lo address 52:54:00:6a:c7:5e
    460	$IP link set dev veth1 address 52:54:00:6a:c7:5e
    461	ip -netns ns2 link set dev lo address 52:54:00:6a:c7:5e
    462	ip -netns ns2 link set dev veth2 address 52:54:00:6a:c7:5e
    463
    464	# 1. (ns2) redirect lo's egress to veth2's egress
    465	ip netns exec ns2 tc qdisc add dev lo parent root handle 1: fq_codel
    466	ip netns exec ns2 tc filter add dev lo parent 1: protocol arp basic \
    467		action mirred egress redirect dev veth2
    468	ip netns exec ns2 tc filter add dev lo parent 1: protocol ip basic \
    469		action mirred egress redirect dev veth2
    470
    471	# 2. (ns1) redirect veth1's ingress to lo's ingress
    472	$NS_EXEC tc qdisc add dev veth1 ingress
    473	$NS_EXEC tc filter add dev veth1 ingress protocol arp basic \
    474		action mirred ingress redirect dev lo
    475	$NS_EXEC tc filter add dev veth1 ingress protocol ip basic \
    476		action mirred ingress redirect dev lo
    477
    478	# 3. (ns1) redirect lo's egress to veth1's egress
    479	$NS_EXEC tc qdisc add dev lo parent root handle 1: fq_codel
    480	$NS_EXEC tc filter add dev lo parent 1: protocol arp basic \
    481		action mirred egress redirect dev veth1
    482	$NS_EXEC tc filter add dev lo parent 1: protocol ip basic \
    483		action mirred egress redirect dev veth1
    484
    485	# 4. (ns2) redirect veth2's ingress to lo's ingress
    486	ip netns exec ns2 tc qdisc add dev veth2 ingress
    487	ip netns exec ns2 tc filter add dev veth2 ingress protocol arp basic \
    488		action mirred ingress redirect dev lo
    489	ip netns exec ns2 tc filter add dev veth2 ingress protocol ip basic \
    490		action mirred ingress redirect dev lo
    491
    492	$NS_EXEC sysctl -qw net.ipv4.conf.all.rp_filter=1
    493	$NS_EXEC sysctl -qw net.ipv4.conf.all.accept_local=1
    494	$NS_EXEC sysctl -qw net.ipv4.conf.all.route_localnet=1
    495	ip netns exec ns2 sysctl -qw net.ipv4.conf.all.rp_filter=1
    496	ip netns exec ns2 sysctl -qw net.ipv4.conf.all.accept_local=1
    497	ip netns exec ns2 sysctl -qw net.ipv4.conf.all.route_localnet=1
    498	set +e
    499
    500	run_cmd "ip netns exec ns2 ping -w1 -c1 192.0.2.1"
    501	log_test $? 0 "rp_filter passes local packets"
    502
    503	run_cmd "ip netns exec ns2 ping -w1 -c1 127.0.0.1"
    504	log_test $? 0 "rp_filter passes loopback packets"
    505
    506	cleanup
    507}
    508
    509################################################################################
    510# Tests on nexthop spec
    511
    512# run 'ip route add' with given spec
    513add_rt()
    514{
    515	local desc="$1"
    516	local erc=$2
    517	local vrf=$3
    518	local pfx=$4
    519	local gw=$5
    520	local dev=$6
    521	local cmd out rc
    522
    523	[ "$vrf" = "-" ] && vrf="default"
    524	[ -n "$gw" ] && gw="via $gw"
    525	[ -n "$dev" ] && dev="dev $dev"
    526
    527	cmd="$IP route add vrf $vrf $pfx $gw $dev"
    528	if [ "$VERBOSE" = "1" ]; then
    529		printf "\n    COMMAND: $cmd\n"
    530	fi
    531
    532	out=$(eval $cmd 2>&1)
    533	rc=$?
    534	if [ "$VERBOSE" = "1" -a -n "$out" ]; then
    535		echo "    $out"
    536	fi
    537	log_test $rc $erc "$desc"
    538}
    539
    540fib4_nexthop()
    541{
    542	echo
    543	echo "IPv4 nexthop tests"
    544
    545	echo "<<< write me >>>"
    546}
    547
    548fib6_nexthop()
    549{
    550	local lldummy=$(get_linklocal dummy0)
    551	local llv1=$(get_linklocal dummy0)
    552
    553	if [ -z "$lldummy" ]; then
    554		echo "Failed to get linklocal address for dummy0"
    555		return 1
    556	fi
    557	if [ -z "$llv1" ]; then
    558		echo "Failed to get linklocal address for veth1"
    559		return 1
    560	fi
    561
    562	echo
    563	echo "IPv6 nexthop tests"
    564
    565	add_rt "Directly connected nexthop, unicast address" 0 \
    566		- 2001:db8:101::/64 2001:db8:1::2
    567	add_rt "Directly connected nexthop, unicast address with device" 0 \
    568		- 2001:db8:102::/64 2001:db8:1::2 "dummy0"
    569	add_rt "Gateway is linklocal address" 0 \
    570		- 2001:db8:103::1/64 $llv1 "veth0"
    571
    572	# fails because LL address requires a device
    573	add_rt "Gateway is linklocal address, no device" 2 \
    574		- 2001:db8:104::1/64 $llv1
    575
    576	# local address can not be a gateway
    577	add_rt "Gateway can not be local unicast address" 2 \
    578		- 2001:db8:105::/64 2001:db8:1::1
    579	add_rt "Gateway can not be local unicast address, with device" 2 \
    580		- 2001:db8:106::/64 2001:db8:1::1 "dummy0"
    581	add_rt "Gateway can not be a local linklocal address" 2 \
    582		- 2001:db8:107::1/64 $lldummy "dummy0"
    583
    584	# VRF tests
    585	add_rt "Gateway can be local address in a VRF" 0 \
    586		- 2001:db8:108::/64 2001:db8:51::2
    587	add_rt "Gateway can be local address in a VRF, with device" 0 \
    588		- 2001:db8:109::/64 2001:db8:51::2 "veth0"
    589	add_rt "Gateway can be local linklocal address in a VRF" 0 \
    590		- 2001:db8:110::1/64 $llv1 "veth0"
    591
    592	add_rt "Redirect to VRF lookup" 0 \
    593		- 2001:db8:111::/64 "" "red"
    594
    595	add_rt "VRF route, gateway can be local address in default VRF" 0 \
    596		red 2001:db8:112::/64 2001:db8:51::1
    597
    598	# local address in same VRF fails
    599	add_rt "VRF route, gateway can not be a local address" 2 \
    600		red 2001:db8:113::1/64 2001:db8:2::1
    601	add_rt "VRF route, gateway can not be a local addr with device" 2 \
    602		red 2001:db8:114::1/64 2001:db8:2::1 "dummy1"
    603}
    604
    605# Default VRF:
    606#   dummy0 - 198.51.100.1/24 2001:db8:1::1/64
    607#   veth0  - 192.0.2.1/24    2001:db8:51::1/64
    608#
    609# VRF red:
    610#   dummy1 - 192.168.2.1/24 2001:db8:2::1/64
    611#   veth1  - 192.0.2.2/24   2001:db8:51::2/64
    612#
    613#  [ dummy0   veth0 ]--[ veth1   dummy1 ]
    614
    615fib_nexthop_test()
    616{
    617	setup
    618
    619	set -e
    620
    621	$IP -4 rule add pref 32765 table local
    622	$IP -4 rule del pref 0
    623	$IP -6 rule add pref 32765 table local
    624	$IP -6 rule del pref 0
    625
    626	$IP link add red type vrf table 1
    627	$IP link set red up
    628	$IP -4 route add vrf red unreachable default metric 4278198272
    629	$IP -6 route add vrf red unreachable default metric 4278198272
    630
    631	$IP link add veth0 type veth peer name veth1
    632	$IP link set dev veth0 up
    633	$IP address add 192.0.2.1/24 dev veth0
    634	$IP -6 address add 2001:db8:51::1/64 dev veth0
    635
    636	$IP link set dev veth1 vrf red up
    637	$IP address add 192.0.2.2/24 dev veth1
    638	$IP -6 address add 2001:db8:51::2/64 dev veth1
    639
    640	$IP link add dummy1 type dummy
    641	$IP link set dev dummy1 vrf red up
    642	$IP address add 192.168.2.1/24 dev dummy1
    643	$IP -6 address add 2001:db8:2::1/64 dev dummy1
    644	set +e
    645
    646	sleep 1
    647	fib4_nexthop
    648	fib6_nexthop
    649
    650	(
    651	$IP link del dev dummy1
    652	$IP link del veth0
    653	$IP link del red
    654	) 2>/dev/null
    655	cleanup
    656}
    657
    658fib_suppress_test()
    659{
    660	echo
    661	echo "FIB rule with suppress_prefixlength"
    662	setup
    663
    664	$IP link add dummy1 type dummy
    665	$IP link set dummy1 up
    666	$IP -6 route add default dev dummy1
    667	$IP -6 rule add table main suppress_prefixlength 0
    668	ping -f -c 1000 -W 1 1234::1 >/dev/null 2>&1
    669	$IP -6 rule del table main suppress_prefixlength 0
    670	$IP link del dummy1
    671
    672	# If we got here without crashing, we're good.
    673	log_test 0 0 "FIB rule suppress test"
    674
    675	cleanup
    676}
    677
    678################################################################################
    679# Tests on route add and replace
    680
    681run_cmd()
    682{
    683	local cmd="$1"
    684	local out
    685	local stderr="2>/dev/null"
    686
    687	if [ "$VERBOSE" = "1" ]; then
    688		printf "    COMMAND: $cmd\n"
    689		stderr=
    690	fi
    691
    692	out=$(eval $cmd $stderr)
    693	rc=$?
    694	if [ "$VERBOSE" = "1" -a -n "$out" ]; then
    695		echo "    $out"
    696	fi
    697
    698	[ "$VERBOSE" = "1" ] && echo
    699
    700	return $rc
    701}
    702
    703check_expected()
    704{
    705	local out="$1"
    706	local expected="$2"
    707	local rc=0
    708
    709	[ "${out}" = "${expected}" ] && return 0
    710
    711	if [ -z "${out}" ]; then
    712		if [ "$VERBOSE" = "1" ]; then
    713			printf "\nNo route entry found\n"
    714			printf "Expected:\n"
    715			printf "    ${expected}\n"
    716		fi
    717		return 1
    718	fi
    719
    720	# tricky way to convert output to 1-line without ip's
    721	# messy '\'; this drops all extra white space
    722	out=$(echo ${out})
    723	if [ "${out}" != "${expected}" ]; then
    724		rc=1
    725		if [ "${VERBOSE}" = "1" ]; then
    726			printf "    Unexpected route entry. Have:\n"
    727			printf "        ${out}\n"
    728			printf "    Expected:\n"
    729			printf "        ${expected}\n\n"
    730		fi
    731	fi
    732
    733	return $rc
    734}
    735
    736# add route for a prefix, flushing any existing routes first
    737# expected to be the first step of a test
    738add_route6()
    739{
    740	local pfx="$1"
    741	local nh="$2"
    742	local out
    743
    744	if [ "$VERBOSE" = "1" ]; then
    745		echo
    746		echo "    ##################################################"
    747		echo
    748	fi
    749
    750	run_cmd "$IP -6 ro flush ${pfx}"
    751	[ $? -ne 0 ] && exit 1
    752
    753	out=$($IP -6 ro ls match ${pfx})
    754	if [ -n "$out" ]; then
    755		echo "Failed to flush routes for prefix used for tests."
    756		exit 1
    757	fi
    758
    759	run_cmd "$IP -6 ro add ${pfx} ${nh}"
    760	if [ $? -ne 0 ]; then
    761		echo "Failed to add initial route for test."
    762		exit 1
    763	fi
    764}
    765
    766# add initial route - used in replace route tests
    767add_initial_route6()
    768{
    769	add_route6 "2001:db8:104::/64" "$1"
    770}
    771
    772check_route6()
    773{
    774	local pfx
    775	local expected="$1"
    776	local out
    777	local rc=0
    778
    779	set -- $expected
    780	pfx=$1
    781
    782	out=$($IP -6 ro ls match ${pfx} | sed -e 's/ pref medium//')
    783	check_expected "${out}" "${expected}"
    784}
    785
    786route_cleanup()
    787{
    788	$IP li del red 2>/dev/null
    789	$IP li del dummy1 2>/dev/null
    790	$IP li del veth1 2>/dev/null
    791	$IP li del veth3 2>/dev/null
    792
    793	cleanup &> /dev/null
    794}
    795
    796route_setup()
    797{
    798	route_cleanup
    799	setup
    800
    801	[ "${VERBOSE}" = "1" ] && set -x
    802	set -e
    803
    804	ip netns add ns2
    805	ip netns set ns2 auto
    806	ip -netns ns2 link set dev lo up
    807	ip netns exec ns2 sysctl -qw net.ipv4.ip_forward=1
    808	ip netns exec ns2 sysctl -qw net.ipv6.conf.all.forwarding=1
    809
    810	$IP li add veth1 type veth peer name veth2
    811	$IP li add veth3 type veth peer name veth4
    812
    813	$IP li set veth1 up
    814	$IP li set veth3 up
    815	$IP li set veth2 netns ns2 up
    816	$IP li set veth4 netns ns2 up
    817	ip -netns ns2 li add dummy1 type dummy
    818	ip -netns ns2 li set dummy1 up
    819
    820	$IP -6 addr add 2001:db8:101::1/64 dev veth1 nodad
    821	$IP -6 addr add 2001:db8:103::1/64 dev veth3 nodad
    822	$IP addr add 172.16.101.1/24 dev veth1
    823	$IP addr add 172.16.103.1/24 dev veth3
    824
    825	ip -netns ns2 -6 addr add 2001:db8:101::2/64 dev veth2 nodad
    826	ip -netns ns2 -6 addr add 2001:db8:103::2/64 dev veth4 nodad
    827	ip -netns ns2 -6 addr add 2001:db8:104::1/64 dev dummy1 nodad
    828
    829	ip -netns ns2 addr add 172.16.101.2/24 dev veth2
    830	ip -netns ns2 addr add 172.16.103.2/24 dev veth4
    831	ip -netns ns2 addr add 172.16.104.1/24 dev dummy1
    832
    833	set +e
    834}
    835
    836# assumption is that basic add of a single path route works
    837# otherwise just adding an address on an interface is broken
    838ipv6_rt_add()
    839{
    840	local rc
    841
    842	echo
    843	echo "IPv6 route add / append tests"
    844
    845	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
    846	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
    847	run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2"
    848	log_test $? 2 "Attempt to add duplicate route - gw"
    849
    850	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
    851	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
    852	run_cmd "$IP -6 ro add 2001:db8:104::/64 dev veth3"
    853	log_test $? 2 "Attempt to add duplicate route - dev only"
    854
    855	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
    856	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
    857	run_cmd "$IP -6 ro add unreachable 2001:db8:104::/64"
    858	log_test $? 2 "Attempt to add duplicate route - reject route"
    859
    860	# route append with same prefix adds a new route
    861	# - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
    862	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
    863	run_cmd "$IP -6 ro append 2001:db8:104::/64 via 2001:db8:103::2"
    864	check_route6 "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
    865	log_test $? 0 "Append nexthop to existing route - gw"
    866
    867	# insert mpath directly
    868	add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
    869	check_route6  "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
    870	log_test $? 0 "Add multipath route"
    871
    872	add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
    873	run_cmd "$IP -6 ro add 2001:db8:104::/64 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
    874	log_test $? 2 "Attempt to add duplicate multipath route"
    875
    876	# insert of a second route without append but different metric
    877	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
    878	run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2 metric 512"
    879	rc=$?
    880	if [ $rc -eq 0 ]; then
    881		run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::3 metric 256"
    882		rc=$?
    883	fi
    884	log_test $rc 0 "Route add with different metrics"
    885
    886	run_cmd "$IP -6 ro del 2001:db8:104::/64 metric 512"
    887	rc=$?
    888	if [ $rc -eq 0 ]; then
    889		check_route6 "2001:db8:104::/64 via 2001:db8:103::3 dev veth3 metric 256 2001:db8:104::/64 via 2001:db8:101::2 dev veth1 metric 1024"
    890		rc=$?
    891	fi
    892	log_test $rc 0 "Route delete with metric"
    893}
    894
    895ipv6_rt_replace_single()
    896{
    897	# single path with single path
    898	#
    899	add_initial_route6 "via 2001:db8:101::2"
    900	run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:103::2"
    901	check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
    902	log_test $? 0 "Single path with single path"
    903
    904	# single path with multipath
    905	#
    906	add_initial_route6 "nexthop via 2001:db8:101::2"
    907	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::2"
    908	check_route6 "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::3 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
    909	log_test $? 0 "Single path with multipath"
    910
    911	# single path with single path using MULTIPATH attribute
    912	#
    913	add_initial_route6 "via 2001:db8:101::2"
    914	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:103::2"
    915	check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
    916	log_test $? 0 "Single path with single path via multipath attribute"
    917
    918	# route replace fails - invalid nexthop
    919	add_initial_route6 "via 2001:db8:101::2"
    920	run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:104::2"
    921	if [ $? -eq 0 ]; then
    922		# previous command is expected to fail so if it returns 0
    923		# that means the test failed.
    924		log_test 0 1 "Invalid nexthop"
    925	else
    926		check_route6 "2001:db8:104::/64 via 2001:db8:101::2 dev veth1 metric 1024"
    927		log_test $? 0 "Invalid nexthop"
    928	fi
    929
    930	# replace non-existent route
    931	# - note use of change versus replace since ip adds NLM_F_CREATE
    932	#   for replace
    933	add_initial_route6 "via 2001:db8:101::2"
    934	run_cmd "$IP -6 ro change 2001:db8:105::/64 via 2001:db8:101::2"
    935	log_test $? 2 "Single path - replace of non-existent route"
    936}
    937
    938ipv6_rt_replace_mpath()
    939{
    940	# multipath with multipath
    941	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
    942	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
    943	check_route6  "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::3 dev veth1 weight 1 nexthop via 2001:db8:103::3 dev veth3 weight 1"
    944	log_test $? 0 "Multipath with multipath"
    945
    946	# multipath with single
    947	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
    948	run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:101::3"
    949	check_route6  "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
    950	log_test $? 0 "Multipath with single path"
    951
    952	# multipath with single
    953	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
    954	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3"
    955	check_route6 "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
    956	log_test $? 0 "Multipath with single path via multipath attribute"
    957
    958	# multipath with dev-only
    959	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
    960	run_cmd "$IP -6 ro replace 2001:db8:104::/64 dev veth1"
    961	check_route6 "2001:db8:104::/64 dev veth1 metric 1024"
    962	log_test $? 0 "Multipath with dev-only"
    963
    964	# route replace fails - invalid nexthop 1
    965	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
    966	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:111::3 nexthop via 2001:db8:103::3"
    967	check_route6  "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
    968	log_test $? 0 "Multipath - invalid first nexthop"
    969
    970	# route replace fails - invalid nexthop 2
    971	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
    972	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:113::3"
    973	check_route6  "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
    974	log_test $? 0 "Multipath - invalid second nexthop"
    975
    976	# multipath non-existent route
    977	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
    978	run_cmd "$IP -6 ro change 2001:db8:105::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
    979	log_test $? 2 "Multipath - replace of non-existent route"
    980}
    981
    982ipv6_rt_replace()
    983{
    984	echo
    985	echo "IPv6 route replace tests"
    986
    987	ipv6_rt_replace_single
    988	ipv6_rt_replace_mpath
    989}
    990
    991ipv6_rt_dsfield()
    992{
    993	echo
    994	echo "IPv6 route with dsfield tests"
    995
    996	run_cmd "$IP -6 route flush 2001:db8:102::/64"
    997
    998	# IPv6 doesn't support routing based on dsfield
    999	run_cmd "$IP -6 route add 2001:db8:102::/64 dsfield 0x04 via 2001:db8:101::2"
   1000	log_test $? 2 "Reject route with dsfield"
   1001}
   1002
   1003ipv6_route_test()
   1004{
   1005	route_setup
   1006
   1007	ipv6_rt_add
   1008	ipv6_rt_replace
   1009	ipv6_rt_dsfield
   1010
   1011	route_cleanup
   1012}
   1013
   1014ip_addr_metric_check()
   1015{
   1016	ip addr help 2>&1 | grep -q metric
   1017	if [ $? -ne 0 ]; then
   1018		echo "iproute2 command does not support metric for addresses. Skipping test"
   1019		return 1
   1020	fi
   1021
   1022	return 0
   1023}
   1024
   1025ipv6_addr_metric_test()
   1026{
   1027	local rc
   1028
   1029	echo
   1030	echo "IPv6 prefix route tests"
   1031
   1032	ip_addr_metric_check || return 1
   1033
   1034	setup
   1035
   1036	set -e
   1037	$IP li add dummy1 type dummy
   1038	$IP li add dummy2 type dummy
   1039	$IP li set dummy1 up
   1040	$IP li set dummy2 up
   1041
   1042	# default entry is metric 256
   1043	run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64"
   1044	run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64"
   1045	set +e
   1046
   1047	check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 256 2001:db8:104::/64 dev dummy2 proto kernel metric 256"
   1048	log_test $? 0 "Default metric"
   1049
   1050	set -e
   1051	run_cmd "$IP -6 addr flush dev dummy1"
   1052	run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64 metric 257"
   1053	set +e
   1054
   1055	check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 256 2001:db8:104::/64 dev dummy1 proto kernel metric 257"
   1056	log_test $? 0 "User specified metric on first device"
   1057
   1058	set -e
   1059	run_cmd "$IP -6 addr flush dev dummy2"
   1060	run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64 metric 258"
   1061	set +e
   1062
   1063	check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 257 2001:db8:104::/64 dev dummy2 proto kernel metric 258"
   1064	log_test $? 0 "User specified metric on second device"
   1065
   1066	run_cmd "$IP -6 addr del dev dummy1 2001:db8:104::1/64 metric 257"
   1067	rc=$?
   1068	if [ $rc -eq 0 ]; then
   1069		check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 258"
   1070		rc=$?
   1071	fi
   1072	log_test $rc 0 "Delete of address on first device"
   1073
   1074	run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::2/64 metric 259"
   1075	rc=$?
   1076	if [ $rc -eq 0 ]; then
   1077		check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
   1078		rc=$?
   1079	fi
   1080	log_test $rc 0 "Modify metric of address"
   1081
   1082	# verify prefix route removed on down
   1083	run_cmd "ip netns exec ns1 sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1"
   1084	run_cmd "$IP li set dev dummy2 down"
   1085	rc=$?
   1086	if [ $rc -eq 0 ]; then
   1087		out=$($IP -6 ro ls match 2001:db8:104::/64)
   1088		check_expected "${out}" ""
   1089		rc=$?
   1090	fi
   1091	log_test $rc 0 "Prefix route removed on link down"
   1092
   1093	# verify prefix route re-inserted with assigned metric
   1094	run_cmd "$IP li set dev dummy2 up"
   1095	rc=$?
   1096	if [ $rc -eq 0 ]; then
   1097		check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
   1098		rc=$?
   1099	fi
   1100	log_test $rc 0 "Prefix route with metric on link up"
   1101
   1102	# verify peer metric added correctly
   1103	set -e
   1104	run_cmd "$IP -6 addr flush dev dummy2"
   1105	run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::1 peer 2001:db8:104::2 metric 260"
   1106	set +e
   1107
   1108	check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 260"
   1109	log_test $? 0 "Set metric with peer route on local side"
   1110	check_route6 "2001:db8:104::2 dev dummy2 proto kernel metric 260"
   1111	log_test $? 0 "Set metric with peer route on peer side"
   1112
   1113	set -e
   1114	run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::1 peer 2001:db8:104::3 metric 261"
   1115	set +e
   1116
   1117	check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 261"
   1118	log_test $? 0 "Modify metric and peer address on local side"
   1119	check_route6 "2001:db8:104::3 dev dummy2 proto kernel metric 261"
   1120	log_test $? 0 "Modify metric and peer address on peer side"
   1121
   1122	$IP li del dummy1
   1123	$IP li del dummy2
   1124	cleanup
   1125}
   1126
   1127ipv6_route_metrics_test()
   1128{
   1129	local rc
   1130
   1131	echo
   1132	echo "IPv6 routes with metrics"
   1133
   1134	route_setup
   1135
   1136	#
   1137	# single path with metrics
   1138	#
   1139	run_cmd "$IP -6 ro add 2001:db8:111::/64 via 2001:db8:101::2 mtu 1400"
   1140	rc=$?
   1141	if [ $rc -eq 0 ]; then
   1142		check_route6  "2001:db8:111::/64 via 2001:db8:101::2 dev veth1 metric 1024 mtu 1400"
   1143		rc=$?
   1144	fi
   1145	log_test $rc 0 "Single path route with mtu metric"
   1146
   1147
   1148	#
   1149	# multipath via separate routes with metrics
   1150	#
   1151	run_cmd "$IP -6 ro add 2001:db8:112::/64 via 2001:db8:101::2 mtu 1400"
   1152	run_cmd "$IP -6 ro append 2001:db8:112::/64 via 2001:db8:103::2"
   1153	rc=$?
   1154	if [ $rc -eq 0 ]; then
   1155		check_route6 "2001:db8:112::/64 metric 1024 mtu 1400 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
   1156		rc=$?
   1157	fi
   1158	log_test $rc 0 "Multipath route via 2 single routes with mtu metric on first"
   1159
   1160	# second route is coalesced to first to make a multipath route.
   1161	# MTU of the second path is hidden from display!
   1162	run_cmd "$IP -6 ro add 2001:db8:113::/64 via 2001:db8:101::2"
   1163	run_cmd "$IP -6 ro append 2001:db8:113::/64 via 2001:db8:103::2 mtu 1400"
   1164	rc=$?
   1165	if [ $rc -eq 0 ]; then
   1166		check_route6 "2001:db8:113::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
   1167		rc=$?
   1168	fi
   1169	log_test $rc 0 "Multipath route via 2 single routes with mtu metric on 2nd"
   1170
   1171	run_cmd "$IP -6 ro del 2001:db8:113::/64 via 2001:db8:101::2"
   1172	if [ $? -eq 0 ]; then
   1173		check_route6 "2001:db8:113::/64 via 2001:db8:103::2 dev veth3 metric 1024 mtu 1400"
   1174		log_test $? 0 "    MTU of second leg"
   1175	fi
   1176
   1177	#
   1178	# multipath with metrics
   1179	#
   1180	run_cmd "$IP -6 ro add 2001:db8:115::/64 mtu 1400 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
   1181	rc=$?
   1182	if [ $rc -eq 0 ]; then
   1183		check_route6  "2001:db8:115::/64 metric 1024 mtu 1400 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
   1184		rc=$?
   1185	fi
   1186	log_test $rc 0 "Multipath route with mtu metric"
   1187
   1188	$IP -6 ro add 2001:db8:104::/64 via 2001:db8:101::2 mtu 1300
   1189	run_cmd "ip netns exec ns1 ${ping6} -w1 -c1 -s 1500 2001:db8:104::1"
   1190	log_test $? 0 "Using route with mtu metric"
   1191
   1192	run_cmd "$IP -6 ro add 2001:db8:114::/64 via  2001:db8:101::2  congctl lock foo"
   1193	log_test $? 2 "Invalid metric (fails metric_convert)"
   1194
   1195	route_cleanup
   1196}
   1197
   1198# add route for a prefix, flushing any existing routes first
   1199# expected to be the first step of a test
   1200add_route()
   1201{
   1202	local pfx="$1"
   1203	local nh="$2"
   1204	local out
   1205
   1206	if [ "$VERBOSE" = "1" ]; then
   1207		echo
   1208		echo "    ##################################################"
   1209		echo
   1210	fi
   1211
   1212	run_cmd "$IP ro flush ${pfx}"
   1213	[ $? -ne 0 ] && exit 1
   1214
   1215	out=$($IP ro ls match ${pfx})
   1216	if [ -n "$out" ]; then
   1217		echo "Failed to flush routes for prefix used for tests."
   1218		exit 1
   1219	fi
   1220
   1221	run_cmd "$IP ro add ${pfx} ${nh}"
   1222	if [ $? -ne 0 ]; then
   1223		echo "Failed to add initial route for test."
   1224		exit 1
   1225	fi
   1226}
   1227
   1228# add initial route - used in replace route tests
   1229add_initial_route()
   1230{
   1231	add_route "172.16.104.0/24" "$1"
   1232}
   1233
   1234check_route()
   1235{
   1236	local pfx
   1237	local expected="$1"
   1238	local out
   1239
   1240	set -- $expected
   1241	pfx=$1
   1242	[ "${pfx}" = "unreachable" ] && pfx=$2
   1243
   1244	out=$($IP ro ls match ${pfx})
   1245	check_expected "${out}" "${expected}"
   1246}
   1247
   1248# assumption is that basic add of a single path route works
   1249# otherwise just adding an address on an interface is broken
   1250ipv4_rt_add()
   1251{
   1252	local rc
   1253
   1254	echo
   1255	echo "IPv4 route add / append tests"
   1256
   1257	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
   1258	add_route "172.16.104.0/24" "via 172.16.101.2"
   1259	run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2"
   1260	log_test $? 2 "Attempt to add duplicate route - gw"
   1261
   1262	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
   1263	add_route "172.16.104.0/24" "via 172.16.101.2"
   1264	run_cmd "$IP ro add 172.16.104.0/24 dev veth3"
   1265	log_test $? 2 "Attempt to add duplicate route - dev only"
   1266
   1267	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
   1268	add_route "172.16.104.0/24" "via 172.16.101.2"
   1269	run_cmd "$IP ro add unreachable 172.16.104.0/24"
   1270	log_test $? 2 "Attempt to add duplicate route - reject route"
   1271
   1272	# iproute2 prepend only sets NLM_F_CREATE
   1273	# - adds a new route; does NOT convert existing route to ECMP
   1274	add_route "172.16.104.0/24" "via 172.16.101.2"
   1275	run_cmd "$IP ro prepend 172.16.104.0/24 via 172.16.103.2"
   1276	check_route "172.16.104.0/24 via 172.16.103.2 dev veth3 172.16.104.0/24 via 172.16.101.2 dev veth1"
   1277	log_test $? 0 "Add new nexthop for existing prefix"
   1278
   1279	# route append with same prefix adds a new route
   1280	# - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
   1281	add_route "172.16.104.0/24" "via 172.16.101.2"
   1282	run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
   1283	check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 via 172.16.103.2 dev veth3"
   1284	log_test $? 0 "Append nexthop to existing route - gw"
   1285
   1286	add_route "172.16.104.0/24" "via 172.16.101.2"
   1287	run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
   1288	check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 dev veth3 scope link"
   1289	log_test $? 0 "Append nexthop to existing route - dev only"
   1290
   1291	add_route "172.16.104.0/24" "via 172.16.101.2"
   1292	run_cmd "$IP ro append unreachable 172.16.104.0/24"
   1293	check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 unreachable 172.16.104.0/24"
   1294	log_test $? 0 "Append nexthop to existing route - reject route"
   1295
   1296	run_cmd "$IP ro flush 172.16.104.0/24"
   1297	run_cmd "$IP ro add unreachable 172.16.104.0/24"
   1298	run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
   1299	check_route "unreachable 172.16.104.0/24 172.16.104.0/24 via 172.16.103.2 dev veth3"
   1300	log_test $? 0 "Append nexthop to existing reject route - gw"
   1301
   1302	run_cmd "$IP ro flush 172.16.104.0/24"
   1303	run_cmd "$IP ro add unreachable 172.16.104.0/24"
   1304	run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
   1305	check_route "unreachable 172.16.104.0/24 172.16.104.0/24 dev veth3 scope link"
   1306	log_test $? 0 "Append nexthop to existing reject route - dev only"
   1307
   1308	# insert mpath directly
   1309	add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
   1310	check_route  "172.16.104.0/24 nexthop via 172.16.101.2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
   1311	log_test $? 0 "add multipath route"
   1312
   1313	add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
   1314	run_cmd "$IP ro add 172.16.104.0/24 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
   1315	log_test $? 2 "Attempt to add duplicate multipath route"
   1316
   1317	# insert of a second route without append but different metric
   1318	add_route "172.16.104.0/24" "via 172.16.101.2"
   1319	run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2 metric 512"
   1320	rc=$?
   1321	if [ $rc -eq 0 ]; then
   1322		run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.3 metric 256"
   1323		rc=$?
   1324	fi
   1325	log_test $rc 0 "Route add with different metrics"
   1326
   1327	run_cmd "$IP ro del 172.16.104.0/24 metric 512"
   1328	rc=$?
   1329	if [ $rc -eq 0 ]; then
   1330		check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 via 172.16.103.3 dev veth3 metric 256"
   1331		rc=$?
   1332	fi
   1333	log_test $rc 0 "Route delete with metric"
   1334}
   1335
   1336ipv4_rt_replace_single()
   1337{
   1338	# single path with single path
   1339	#
   1340	add_initial_route "via 172.16.101.2"
   1341	run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.103.2"
   1342	check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
   1343	log_test $? 0 "Single path with single path"
   1344
   1345	# single path with multipath
   1346	#
   1347	add_initial_route "nexthop via 172.16.101.2"
   1348	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.2"
   1349	check_route "172.16.104.0/24 nexthop via 172.16.101.3 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
   1350	log_test $? 0 "Single path with multipath"
   1351
   1352	# single path with reject
   1353	#
   1354	add_initial_route "nexthop via 172.16.101.2"
   1355	run_cmd "$IP ro replace unreachable 172.16.104.0/24"
   1356	check_route "unreachable 172.16.104.0/24"
   1357	log_test $? 0 "Single path with reject route"
   1358
   1359	# single path with single path using MULTIPATH attribute
   1360	#
   1361	add_initial_route "via 172.16.101.2"
   1362	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.103.2"
   1363	check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
   1364	log_test $? 0 "Single path with single path via multipath attribute"
   1365
   1366	# route replace fails - invalid nexthop
   1367	add_initial_route "via 172.16.101.2"
   1368	run_cmd "$IP ro replace 172.16.104.0/24 via 2001:db8:104::2"
   1369	if [ $? -eq 0 ]; then
   1370		# previous command is expected to fail so if it returns 0
   1371		# that means the test failed.
   1372		log_test 0 1 "Invalid nexthop"
   1373	else
   1374		check_route "172.16.104.0/24 via 172.16.101.2 dev veth1"
   1375		log_test $? 0 "Invalid nexthop"
   1376	fi
   1377
   1378	# replace non-existent route
   1379	# - note use of change versus replace since ip adds NLM_F_CREATE
   1380	#   for replace
   1381	add_initial_route "via 172.16.101.2"
   1382	run_cmd "$IP ro change 172.16.105.0/24 via 172.16.101.2"
   1383	log_test $? 2 "Single path - replace of non-existent route"
   1384}
   1385
   1386ipv4_rt_replace_mpath()
   1387{
   1388	# multipath with multipath
   1389	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
   1390	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
   1391	check_route  "172.16.104.0/24 nexthop via 172.16.101.3 dev veth1 weight 1 nexthop via 172.16.103.3 dev veth3 weight 1"
   1392	log_test $? 0 "Multipath with multipath"
   1393
   1394	# multipath with single
   1395	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
   1396	run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.101.3"
   1397	check_route  "172.16.104.0/24 via 172.16.101.3 dev veth1"
   1398	log_test $? 0 "Multipath with single path"
   1399
   1400	# multipath with single
   1401	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
   1402	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3"
   1403	check_route "172.16.104.0/24 via 172.16.101.3 dev veth1"
   1404	log_test $? 0 "Multipath with single path via multipath attribute"
   1405
   1406	# multipath with reject
   1407	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
   1408	run_cmd "$IP ro replace unreachable 172.16.104.0/24"
   1409	check_route "unreachable 172.16.104.0/24"
   1410	log_test $? 0 "Multipath with reject route"
   1411
   1412	# route replace fails - invalid nexthop 1
   1413	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
   1414	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.111.3 nexthop via 172.16.103.3"
   1415	check_route  "172.16.104.0/24 nexthop via 172.16.101.2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
   1416	log_test $? 0 "Multipath - invalid first nexthop"
   1417
   1418	# route replace fails - invalid nexthop 2
   1419	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
   1420	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.113.3"
   1421	check_route  "172.16.104.0/24 nexthop via 172.16.101.2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
   1422	log_test $? 0 "Multipath - invalid second nexthop"
   1423
   1424	# multipath non-existent route
   1425	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
   1426	run_cmd "$IP ro change 172.16.105.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
   1427	log_test $? 2 "Multipath - replace of non-existent route"
   1428}
   1429
   1430ipv4_rt_replace()
   1431{
   1432	echo
   1433	echo "IPv4 route replace tests"
   1434
   1435	ipv4_rt_replace_single
   1436	ipv4_rt_replace_mpath
   1437}
   1438
   1439# checks that cached input route on VRF port is deleted
   1440# when VRF is deleted
   1441ipv4_local_rt_cache()
   1442{
   1443	run_cmd "ip addr add 10.0.0.1/32 dev lo"
   1444	run_cmd "ip netns add test-ns"
   1445	run_cmd "ip link add veth-outside type veth peer name veth-inside"
   1446	run_cmd "ip link add vrf-100 type vrf table 1100"
   1447	run_cmd "ip link set veth-outside master vrf-100"
   1448	run_cmd "ip link set veth-inside netns test-ns"
   1449	run_cmd "ip link set veth-outside up"
   1450	run_cmd "ip link set vrf-100 up"
   1451	run_cmd "ip route add 10.1.1.1/32 dev veth-outside table 1100"
   1452	run_cmd "ip netns exec test-ns ip link set veth-inside up"
   1453	run_cmd "ip netns exec test-ns ip addr add 10.1.1.1/32 dev veth-inside"
   1454	run_cmd "ip netns exec test-ns ip route add 10.0.0.1/32 dev veth-inside"
   1455	run_cmd "ip netns exec test-ns ip route add default via 10.0.0.1"
   1456	run_cmd "ip netns exec test-ns ping 10.0.0.1 -c 1 -i 1"
   1457	run_cmd "ip link delete vrf-100"
   1458
   1459	# if we do not hang test is a success
   1460	log_test $? 0 "Cached route removed from VRF port device"
   1461}
   1462
   1463ipv4_rt_dsfield()
   1464{
   1465	echo
   1466	echo "IPv4 route with dsfield tests"
   1467
   1468	run_cmd "$IP route flush 172.16.102.0/24"
   1469
   1470	# New routes should reject dsfield options that interfere with ECN
   1471	run_cmd "$IP route add 172.16.102.0/24 dsfield 0x01 via 172.16.101.2"
   1472	log_test $? 2 "Reject route with dsfield 0x01"
   1473
   1474	run_cmd "$IP route add 172.16.102.0/24 dsfield 0x02 via 172.16.101.2"
   1475	log_test $? 2 "Reject route with dsfield 0x02"
   1476
   1477	run_cmd "$IP route add 172.16.102.0/24 dsfield 0x03 via 172.16.101.2"
   1478	log_test $? 2 "Reject route with dsfield 0x03"
   1479
   1480	# A generic route that doesn't take DSCP into account
   1481	run_cmd "$IP route add 172.16.102.0/24 via 172.16.101.2"
   1482
   1483	# A more specific route for DSCP 0x10
   1484	run_cmd "$IP route add 172.16.102.0/24 dsfield 0x10 via 172.16.103.2"
   1485
   1486	# DSCP 0x10 should match the specific route, no matter the ECN bits
   1487	$IP route get fibmatch 172.16.102.1 dsfield 0x10 | \
   1488		grep -q "via 172.16.103.2"
   1489	log_test $? 0 "IPv4 route with DSCP and ECN:Not-ECT"
   1490
   1491	$IP route get fibmatch 172.16.102.1 dsfield 0x11 | \
   1492		grep -q "via 172.16.103.2"
   1493	log_test $? 0 "IPv4 route with DSCP and ECN:ECT(1)"
   1494
   1495	$IP route get fibmatch 172.16.102.1 dsfield 0x12 | \
   1496		grep -q "via 172.16.103.2"
   1497	log_test $? 0 "IPv4 route with DSCP and ECN:ECT(0)"
   1498
   1499	$IP route get fibmatch 172.16.102.1 dsfield 0x13 | \
   1500		grep -q "via 172.16.103.2"
   1501	log_test $? 0 "IPv4 route with DSCP and ECN:CE"
   1502
   1503	# Unknown DSCP should match the generic route, no matter the ECN bits
   1504	$IP route get fibmatch 172.16.102.1 dsfield 0x14 | \
   1505		grep -q "via 172.16.101.2"
   1506	log_test $? 0 "IPv4 route with unknown DSCP and ECN:Not-ECT"
   1507
   1508	$IP route get fibmatch 172.16.102.1 dsfield 0x15 | \
   1509		grep -q "via 172.16.101.2"
   1510	log_test $? 0 "IPv4 route with unknown DSCP and ECN:ECT(1)"
   1511
   1512	$IP route get fibmatch 172.16.102.1 dsfield 0x16 | \
   1513		grep -q "via 172.16.101.2"
   1514	log_test $? 0 "IPv4 route with unknown DSCP and ECN:ECT(0)"
   1515
   1516	$IP route get fibmatch 172.16.102.1 dsfield 0x17 | \
   1517		grep -q "via 172.16.101.2"
   1518	log_test $? 0 "IPv4 route with unknown DSCP and ECN:CE"
   1519
   1520	# Null DSCP should match the generic route, no matter the ECN bits
   1521	$IP route get fibmatch 172.16.102.1 dsfield 0x00 | \
   1522		grep -q "via 172.16.101.2"
   1523	log_test $? 0 "IPv4 route with no DSCP and ECN:Not-ECT"
   1524
   1525	$IP route get fibmatch 172.16.102.1 dsfield 0x01 | \
   1526		grep -q "via 172.16.101.2"
   1527	log_test $? 0 "IPv4 route with no DSCP and ECN:ECT(1)"
   1528
   1529	$IP route get fibmatch 172.16.102.1 dsfield 0x02 | \
   1530		grep -q "via 172.16.101.2"
   1531	log_test $? 0 "IPv4 route with no DSCP and ECN:ECT(0)"
   1532
   1533	$IP route get fibmatch 172.16.102.1 dsfield 0x03 | \
   1534		grep -q "via 172.16.101.2"
   1535	log_test $? 0 "IPv4 route with no DSCP and ECN:CE"
   1536}
   1537
   1538ipv4_route_test()
   1539{
   1540	route_setup
   1541
   1542	ipv4_rt_add
   1543	ipv4_rt_replace
   1544	ipv4_local_rt_cache
   1545	ipv4_rt_dsfield
   1546
   1547	route_cleanup
   1548}
   1549
   1550ipv4_addr_metric_test()
   1551{
   1552	local rc
   1553
   1554	echo
   1555	echo "IPv4 prefix route tests"
   1556
   1557	ip_addr_metric_check || return 1
   1558
   1559	setup
   1560
   1561	set -e
   1562	$IP li add dummy1 type dummy
   1563	$IP li add dummy2 type dummy
   1564	$IP li set dummy1 up
   1565	$IP li set dummy2 up
   1566
   1567	# default entry is metric 256
   1568	run_cmd "$IP addr add dev dummy1 172.16.104.1/24"
   1569	run_cmd "$IP addr add dev dummy2 172.16.104.2/24"
   1570	set +e
   1571
   1572	check_route "172.16.104.0/24 dev dummy1 proto kernel scope link src 172.16.104.1 172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2"
   1573	log_test $? 0 "Default metric"
   1574
   1575	set -e
   1576	run_cmd "$IP addr flush dev dummy1"
   1577	run_cmd "$IP addr add dev dummy1 172.16.104.1/24 metric 257"
   1578	set +e
   1579
   1580	check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 172.16.104.0/24 dev dummy1 proto kernel scope link src 172.16.104.1 metric 257"
   1581	log_test $? 0 "User specified metric on first device"
   1582
   1583	set -e
   1584	run_cmd "$IP addr flush dev dummy2"
   1585	run_cmd "$IP addr add dev dummy2 172.16.104.2/24 metric 258"
   1586	set +e
   1587
   1588	check_route "172.16.104.0/24 dev dummy1 proto kernel scope link src 172.16.104.1 metric 257 172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 258"
   1589	log_test $? 0 "User specified metric on second device"
   1590
   1591	run_cmd "$IP addr del dev dummy1 172.16.104.1/24 metric 257"
   1592	rc=$?
   1593	if [ $rc -eq 0 ]; then
   1594		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 258"
   1595		rc=$?
   1596	fi
   1597	log_test $rc 0 "Delete of address on first device"
   1598
   1599	run_cmd "$IP addr change dev dummy2 172.16.104.2/24 metric 259"
   1600	rc=$?
   1601	if [ $rc -eq 0 ]; then
   1602		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
   1603		rc=$?
   1604	fi
   1605	log_test $rc 0 "Modify metric of address"
   1606
   1607	# verify prefix route removed on down
   1608	run_cmd "$IP li set dev dummy2 down"
   1609	rc=$?
   1610	if [ $rc -eq 0 ]; then
   1611		out=$($IP ro ls match 172.16.104.0/24)
   1612		check_expected "${out}" ""
   1613		rc=$?
   1614	fi
   1615	log_test $rc 0 "Prefix route removed on link down"
   1616
   1617	# verify prefix route re-inserted with assigned metric
   1618	run_cmd "$IP li set dev dummy2 up"
   1619	rc=$?
   1620	if [ $rc -eq 0 ]; then
   1621		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
   1622		rc=$?
   1623	fi
   1624	log_test $rc 0 "Prefix route with metric on link up"
   1625
   1626	# explicitly check for metric changes on edge scenarios
   1627	run_cmd "$IP addr flush dev dummy2"
   1628	run_cmd "$IP addr add dev dummy2 172.16.104.0/24 metric 259"
   1629	run_cmd "$IP addr change dev dummy2 172.16.104.0/24 metric 260"
   1630	rc=$?
   1631	if [ $rc -eq 0 ]; then
   1632		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.0 metric 260"
   1633		rc=$?
   1634	fi
   1635	log_test $rc 0 "Modify metric of .0/24 address"
   1636
   1637	run_cmd "$IP addr flush dev dummy2"
   1638	run_cmd "$IP addr add dev dummy2 172.16.104.1/32 peer 172.16.104.2 metric 260"
   1639	rc=$?
   1640	if [ $rc -eq 0 ]; then
   1641		check_route "172.16.104.2 dev dummy2 proto kernel scope link src 172.16.104.1 metric 260"
   1642		rc=$?
   1643	fi
   1644	log_test $rc 0 "Set metric of address with peer route"
   1645
   1646	run_cmd "$IP addr change dev dummy2 172.16.104.1/32 peer 172.16.104.3 metric 261"
   1647	rc=$?
   1648	if [ $rc -eq 0 ]; then
   1649		check_route "172.16.104.3 dev dummy2 proto kernel scope link src 172.16.104.1 metric 261"
   1650		rc=$?
   1651	fi
   1652	log_test $rc 0 "Modify metric and peer address for peer route"
   1653
   1654	$IP li del dummy1
   1655	$IP li del dummy2
   1656	cleanup
   1657}
   1658
   1659ipv4_route_metrics_test()
   1660{
   1661	local rc
   1662
   1663	echo
   1664	echo "IPv4 route add / append tests"
   1665
   1666	route_setup
   1667
   1668	run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 mtu 1400"
   1669	rc=$?
   1670	if [ $rc -eq 0 ]; then
   1671		check_route "172.16.111.0/24 via 172.16.101.2 dev veth1 mtu 1400"
   1672		rc=$?
   1673	fi
   1674	log_test $rc 0 "Single path route with mtu metric"
   1675
   1676
   1677	run_cmd "$IP ro add 172.16.112.0/24 mtu 1400 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
   1678	rc=$?
   1679	if [ $rc -eq 0 ]; then
   1680		check_route "172.16.112.0/24 mtu 1400 nexthop via 172.16.101.2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
   1681		rc=$?
   1682	fi
   1683	log_test $rc 0 "Multipath route with mtu metric"
   1684
   1685	$IP ro add 172.16.104.0/24 via 172.16.101.2 mtu 1300
   1686	run_cmd "ip netns exec ns1 ping -w1 -c1 -s 1500 172.16.104.1"
   1687	log_test $? 0 "Using route with mtu metric"
   1688
   1689	run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 congctl lock foo"
   1690	log_test $? 2 "Invalid metric (fails metric_convert)"
   1691
   1692	route_cleanup
   1693}
   1694
   1695ipv4_del_addr_test()
   1696{
   1697	echo
   1698	echo "IPv4 delete address route tests"
   1699
   1700	setup
   1701
   1702	set -e
   1703	$IP li add dummy1 type dummy
   1704	$IP li set dummy1 up
   1705	$IP li add dummy2 type dummy
   1706	$IP li set dummy2 up
   1707	$IP li add red type vrf table 1111
   1708	$IP li set red up
   1709	$IP ro add vrf red unreachable default
   1710	$IP li set dummy2 vrf red
   1711
   1712	$IP addr add dev dummy1 172.16.104.1/24
   1713	$IP addr add dev dummy1 172.16.104.11/24
   1714	$IP addr add dev dummy2 172.16.104.1/24
   1715	$IP addr add dev dummy2 172.16.104.11/24
   1716	$IP route add 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
   1717	$IP route add vrf red 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
   1718	set +e
   1719
   1720	# removing address from device in vrf should only remove route from vrf table
   1721	$IP addr del dev dummy2 172.16.104.11/24
   1722	$IP ro ls vrf red | grep -q 172.16.105.0/24
   1723	log_test $? 1 "Route removed from VRF when source address deleted"
   1724
   1725	$IP ro ls | grep -q 172.16.105.0/24
   1726	log_test $? 0 "Route in default VRF not removed"
   1727
   1728	$IP addr add dev dummy2 172.16.104.11/24
   1729	$IP route add vrf red 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
   1730
   1731	$IP addr del dev dummy1 172.16.104.11/24
   1732	$IP ro ls | grep -q 172.16.105.0/24
   1733	log_test $? 1 "Route removed in default VRF when source address deleted"
   1734
   1735	$IP ro ls vrf red | grep -q 172.16.105.0/24
   1736	log_test $? 0 "Route in VRF is not removed by address delete"
   1737
   1738	$IP li del dummy1
   1739	$IP li del dummy2
   1740	cleanup
   1741}
   1742
   1743
   1744ipv4_route_v6_gw_test()
   1745{
   1746	local rc
   1747
   1748	echo
   1749	echo "IPv4 route with IPv6 gateway tests"
   1750
   1751	route_setup
   1752	sleep 2
   1753
   1754	#
   1755	# single path route
   1756	#
   1757	run_cmd "$IP ro add 172.16.104.0/24 via inet6 2001:db8:101::2"
   1758	rc=$?
   1759	log_test $rc 0 "Single path route with IPv6 gateway"
   1760	if [ $rc -eq 0 ]; then
   1761		check_route "172.16.104.0/24 via inet6 2001:db8:101::2 dev veth1"
   1762	fi
   1763
   1764	run_cmd "ip netns exec ns1 ping -w1 -c1 172.16.104.1"
   1765	log_test $rc 0 "Single path route with IPv6 gateway - ping"
   1766
   1767	run_cmd "$IP ro del 172.16.104.0/24 via inet6 2001:db8:101::2"
   1768	rc=$?
   1769	log_test $rc 0 "Single path route delete"
   1770	if [ $rc -eq 0 ]; then
   1771		check_route "172.16.112.0/24"
   1772	fi
   1773
   1774	#
   1775	# multipath - v6 then v4
   1776	#
   1777	run_cmd "$IP ro add 172.16.104.0/24 nexthop via inet6 2001:db8:101::2 dev veth1 nexthop via 172.16.103.2 dev veth3"
   1778	rc=$?
   1779	log_test $rc 0 "Multipath route add - v6 nexthop then v4"
   1780	if [ $rc -eq 0 ]; then
   1781		check_route "172.16.104.0/24 nexthop via inet6 2001:db8:101::2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
   1782	fi
   1783
   1784	run_cmd "$IP ro del 172.16.104.0/24 nexthop via 172.16.103.2 dev veth3 nexthop via inet6 2001:db8:101::2 dev veth1"
   1785	log_test $? 2 "    Multipath route delete - nexthops in wrong order"
   1786
   1787	run_cmd "$IP ro del 172.16.104.0/24 nexthop via inet6 2001:db8:101::2 dev veth1 nexthop via 172.16.103.2 dev veth3"
   1788	log_test $? 0 "    Multipath route delete exact match"
   1789
   1790	#
   1791	# multipath - v4 then v6
   1792	#
   1793	run_cmd "$IP ro add 172.16.104.0/24 nexthop via 172.16.103.2 dev veth3 nexthop via inet6 2001:db8:101::2 dev veth1"
   1794	rc=$?
   1795	log_test $rc 0 "Multipath route add - v4 nexthop then v6"
   1796	if [ $rc -eq 0 ]; then
   1797		check_route "172.16.104.0/24 nexthop via 172.16.103.2 dev veth3 weight 1 nexthop via inet6 2001:db8:101::2 dev veth1 weight 1"
   1798	fi
   1799
   1800	run_cmd "$IP ro del 172.16.104.0/24 nexthop via inet6 2001:db8:101::2 dev veth1 nexthop via 172.16.103.2 dev veth3"
   1801	log_test $? 2 "    Multipath route delete - nexthops in wrong order"
   1802
   1803	run_cmd "$IP ro del 172.16.104.0/24 nexthop via 172.16.103.2 dev veth3 nexthop via inet6 2001:db8:101::2 dev veth1"
   1804	log_test $? 0 "    Multipath route delete exact match"
   1805
   1806	route_cleanup
   1807}
   1808
   1809socat_check()
   1810{
   1811	if [ ! -x "$(command -v socat)" ]; then
   1812		echo "socat command not found. Skipping test"
   1813		return 1
   1814	fi
   1815
   1816	return 0
   1817}
   1818
   1819iptables_check()
   1820{
   1821	iptables -t mangle -L OUTPUT &> /dev/null
   1822	if [ $? -ne 0 ]; then
   1823		echo "iptables configuration not supported. Skipping test"
   1824		return 1
   1825	fi
   1826
   1827	return 0
   1828}
   1829
   1830ip6tables_check()
   1831{
   1832	ip6tables -t mangle -L OUTPUT &> /dev/null
   1833	if [ $? -ne 0 ]; then
   1834		echo "ip6tables configuration not supported. Skipping test"
   1835		return 1
   1836	fi
   1837
   1838	return 0
   1839}
   1840
   1841ipv4_mangle_test()
   1842{
   1843	local rc
   1844
   1845	echo
   1846	echo "IPv4 mangling tests"
   1847
   1848	socat_check || return 1
   1849	iptables_check || return 1
   1850
   1851	route_setup
   1852	sleep 2
   1853
   1854	local tmp_file=$(mktemp)
   1855	ip netns exec ns2 socat UDP4-LISTEN:54321,fork $tmp_file &
   1856
   1857	# Add a FIB rule and a route that will direct our connection to the
   1858	# listening server.
   1859	$IP rule add pref 100 ipproto udp sport 12345 dport 54321 table 123
   1860	$IP route add table 123 172.16.101.0/24 dev veth1
   1861
   1862	# Add an unreachable route to the main table that will block our
   1863	# connection in case the FIB rule is not hit.
   1864	$IP route add unreachable 172.16.101.2/32
   1865
   1866	run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
   1867	log_test $? 0 "    Connection with correct parameters"
   1868
   1869	run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=11111"
   1870	log_test $? 1 "    Connection with incorrect parameters"
   1871
   1872	# Add a mangling rule and make sure connection is still successful.
   1873	$NS_EXEC iptables -t mangle -A OUTPUT -j MARK --set-mark 1
   1874
   1875	run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
   1876	log_test $? 0 "    Connection with correct parameters - mangling"
   1877
   1878	# Delete the mangling rule and make sure connection is still
   1879	# successful.
   1880	$NS_EXEC iptables -t mangle -D OUTPUT -j MARK --set-mark 1
   1881
   1882	run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
   1883	log_test $? 0 "    Connection with correct parameters - no mangling"
   1884
   1885	# Verify connections were indeed successful on server side.
   1886	[[ $(cat $tmp_file | wc -l) -eq 3 ]]
   1887	log_test $? 0 "    Connection check - server side"
   1888
   1889	$IP route del unreachable 172.16.101.2/32
   1890	$IP route del table 123 172.16.101.0/24 dev veth1
   1891	$IP rule del pref 100
   1892
   1893	{ kill %% && wait %%; } 2>/dev/null
   1894	rm $tmp_file
   1895
   1896	route_cleanup
   1897}
   1898
   1899ipv6_mangle_test()
   1900{
   1901	local rc
   1902
   1903	echo
   1904	echo "IPv6 mangling tests"
   1905
   1906	socat_check || return 1
   1907	ip6tables_check || return 1
   1908
   1909	route_setup
   1910	sleep 2
   1911
   1912	local tmp_file=$(mktemp)
   1913	ip netns exec ns2 socat UDP6-LISTEN:54321,fork $tmp_file &
   1914
   1915	# Add a FIB rule and a route that will direct our connection to the
   1916	# listening server.
   1917	$IP -6 rule add pref 100 ipproto udp sport 12345 dport 54321 table 123
   1918	$IP -6 route add table 123 2001:db8:101::/64 dev veth1
   1919
   1920	# Add an unreachable route to the main table that will block our
   1921	# connection in case the FIB rule is not hit.
   1922	$IP -6 route add unreachable 2001:db8:101::2/128
   1923
   1924	run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
   1925	log_test $? 0 "    Connection with correct parameters"
   1926
   1927	run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=11111"
   1928	log_test $? 1 "    Connection with incorrect parameters"
   1929
   1930	# Add a mangling rule and make sure connection is still successful.
   1931	$NS_EXEC ip6tables -t mangle -A OUTPUT -j MARK --set-mark 1
   1932
   1933	run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
   1934	log_test $? 0 "    Connection with correct parameters - mangling"
   1935
   1936	# Delete the mangling rule and make sure connection is still
   1937	# successful.
   1938	$NS_EXEC ip6tables -t mangle -D OUTPUT -j MARK --set-mark 1
   1939
   1940	run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
   1941	log_test $? 0 "    Connection with correct parameters - no mangling"
   1942
   1943	# Verify connections were indeed successful on server side.
   1944	[[ $(cat $tmp_file | wc -l) -eq 3 ]]
   1945	log_test $? 0 "    Connection check - server side"
   1946
   1947	$IP -6 route del unreachable 2001:db8:101::2/128
   1948	$IP -6 route del table 123 2001:db8:101::/64 dev veth1
   1949	$IP -6 rule del pref 100
   1950
   1951	{ kill %% && wait %%; } 2>/dev/null
   1952	rm $tmp_file
   1953
   1954	route_cleanup
   1955}
   1956
   1957ip_neigh_get_check()
   1958{
   1959	ip neigh help 2>&1 | grep -q 'ip neigh get'
   1960	if [ $? -ne 0 ]; then
   1961		echo "iproute2 command does not support neigh get. Skipping test"
   1962		return 1
   1963	fi
   1964
   1965	return 0
   1966}
   1967
   1968ipv4_bcast_neigh_test()
   1969{
   1970	local rc
   1971
   1972	echo
   1973	echo "IPv4 broadcast neighbour tests"
   1974
   1975	ip_neigh_get_check || return 1
   1976
   1977	setup
   1978
   1979	set -e
   1980	run_cmd "$IP neigh add 192.0.2.111 lladdr 00:11:22:33:44:55 nud perm dev dummy0"
   1981	run_cmd "$IP neigh add 192.0.2.255 lladdr 00:11:22:33:44:55 nud perm dev dummy0"
   1982
   1983	run_cmd "$IP neigh get 192.0.2.111 dev dummy0"
   1984	run_cmd "$IP neigh get 192.0.2.255 dev dummy0"
   1985
   1986	run_cmd "$IP address add 192.0.2.1/24 broadcast 192.0.2.111 dev dummy0"
   1987
   1988	run_cmd "$IP neigh add 203.0.113.111 nud failed dev dummy0"
   1989	run_cmd "$IP neigh add 203.0.113.255 nud failed dev dummy0"
   1990
   1991	run_cmd "$IP neigh get 203.0.113.111 dev dummy0"
   1992	run_cmd "$IP neigh get 203.0.113.255 dev dummy0"
   1993
   1994	run_cmd "$IP address add 203.0.113.1/24 broadcast 203.0.113.111 dev dummy0"
   1995	set +e
   1996
   1997	run_cmd "$IP neigh get 192.0.2.111 dev dummy0"
   1998	log_test $? 0 "Resolved neighbour for broadcast address"
   1999
   2000	run_cmd "$IP neigh get 192.0.2.255 dev dummy0"
   2001	log_test $? 0 "Resolved neighbour for network broadcast address"
   2002
   2003	run_cmd "$IP neigh get 203.0.113.111 dev dummy0"
   2004	log_test $? 2 "Unresolved neighbour for broadcast address"
   2005
   2006	run_cmd "$IP neigh get 203.0.113.255 dev dummy0"
   2007	log_test $? 2 "Unresolved neighbour for network broadcast address"
   2008
   2009	cleanup
   2010}
   2011
   2012################################################################################
   2013# usage
   2014
   2015usage()
   2016{
   2017	cat <<EOF
   2018usage: ${0##*/} OPTS
   2019
   2020        -t <test>   Test(s) to run (default: all)
   2021                    (options: $TESTS)
   2022        -p          Pause on fail
   2023        -P          Pause after each test before cleanup
   2024        -v          verbose mode (show commands and output)
   2025EOF
   2026}
   2027
   2028################################################################################
   2029# main
   2030
   2031while getopts :t:pPhv o
   2032do
   2033	case $o in
   2034		t) TESTS=$OPTARG;;
   2035		p) PAUSE_ON_FAIL=yes;;
   2036		P) PAUSE=yes;;
   2037		v) VERBOSE=$(($VERBOSE + 1));;
   2038		h) usage; exit 0;;
   2039		*) usage; exit 1;;
   2040	esac
   2041done
   2042
   2043PEER_CMD="ip netns exec ${PEER_NS}"
   2044
   2045# make sure we don't pause twice
   2046[ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
   2047
   2048if [ "$(id -u)" -ne 0 ];then
   2049	echo "SKIP: Need root privileges"
   2050	exit $ksft_skip;
   2051fi
   2052
   2053if [ ! -x "$(command -v ip)" ]; then
   2054	echo "SKIP: Could not run test without ip tool"
   2055	exit $ksft_skip
   2056fi
   2057
   2058ip route help 2>&1 | grep -q fibmatch
   2059if [ $? -ne 0 ]; then
   2060	echo "SKIP: iproute2 too old, missing fibmatch"
   2061	exit $ksft_skip
   2062fi
   2063
   2064# start clean
   2065cleanup &> /dev/null
   2066
   2067for t in $TESTS
   2068do
   2069	case $t in
   2070	fib_unreg_test|unregister)	fib_unreg_test;;
   2071	fib_down_test|down)		fib_down_test;;
   2072	fib_carrier_test|carrier)	fib_carrier_test;;
   2073	fib_rp_filter_test|rp_filter)	fib_rp_filter_test;;
   2074	fib_nexthop_test|nexthop)	fib_nexthop_test;;
   2075	fib_suppress_test|suppress)	fib_suppress_test;;
   2076	ipv6_route_test|ipv6_rt)	ipv6_route_test;;
   2077	ipv4_route_test|ipv4_rt)	ipv4_route_test;;
   2078	ipv6_addr_metric)		ipv6_addr_metric_test;;
   2079	ipv4_addr_metric)		ipv4_addr_metric_test;;
   2080	ipv4_del_addr)			ipv4_del_addr_test;;
   2081	ipv6_route_metrics)		ipv6_route_metrics_test;;
   2082	ipv4_route_metrics)		ipv4_route_metrics_test;;
   2083	ipv4_route_v6_gw)		ipv4_route_v6_gw_test;;
   2084	ipv4_mangle)			ipv4_mangle_test;;
   2085	ipv6_mangle)			ipv6_mangle_test;;
   2086	ipv4_bcast_neigh)		ipv4_bcast_neigh_test;;
   2087
   2088	help) echo "Test names: $TESTS"; exit 0;;
   2089	esac
   2090done
   2091
   2092if [ "$TESTS" != "none" ]; then
   2093	printf "\nTests passed: %3d\n" ${nsuccess}
   2094	printf "Tests failed: %3d\n"   ${nfail}
   2095fi
   2096
   2097exit $ret