1#!/bin/bash 2# 3# This tests nf_queue: 4# 1. can process packets from all hooks 5# 2. support running nfqueue from more than one base chain 6# 7# shellcheck disable=SC2162,SC2317 8 9source lib.sh 10ret=0 11timeout=5 12 13SCTP_TEST_TIMEOUT=60 14STRESS_TEST_TIMEOUT=30 15 16cleanup() 17{ 18 ip netns pids "$ns1" | xargs kill 2>/dev/null 19 ip netns pids "$ns2" | xargs kill 2>/dev/null 20 ip netns pids "$nsrouter" | xargs kill 2>/dev/null 21 22 cleanup_all_ns 23 24 rm -f "$TMPINPUT" 25 rm -f "$TMPFILE0" 26 rm -f "$TMPFILE1" 27 rm -f "$TMPFILE2" "$TMPFILE3" 28} 29 30checktool "nft --version" "test without nft tool" 31checktool "socat -h" "run test without socat" 32 33modprobe -q sctp 34 35trap cleanup EXIT 36 37setup_ns ns1 ns2 ns3 nsrouter 38 39TMPFILE0=$(mktemp) 40TMPFILE1=$(mktemp) 41TMPFILE2=$(mktemp) 42TMPFILE3=$(mktemp) 43 44TMPINPUT=$(mktemp) 45COUNT=200 46[ "$KSFT_MACHINE_SLOW" = "yes" ] && COUNT=$((COUNT/8)) 47dd conv=sparse status=none if=/dev/zero bs=1M count=$COUNT of="$TMPINPUT" 48 49if ! ip link add veth0 netns "$nsrouter" type veth peer name eth0 netns "$ns1" > /dev/null 2>&1; then 50 echo "SKIP: No virtual ethernet pair device support in kernel" 51 exit $ksft_skip 52fi 53ip link add veth1 netns "$nsrouter" type veth peer name eth0 netns "$ns2" 54ip link add veth2 netns "$nsrouter" type veth peer name eth0 netns "$ns3" 55 56ip -net "$nsrouter" link set veth0 up 57ip -net "$nsrouter" addr add 10.0.1.1/24 dev veth0 58ip -net "$nsrouter" addr add dead:1::1/64 dev veth0 nodad 59 60ip -net "$nsrouter" link set veth1 up 61ip -net "$nsrouter" addr add 10.0.2.1/24 dev veth1 62ip -net "$nsrouter" addr add dead:2::1/64 dev veth1 nodad 63 64ip -net "$nsrouter" link set veth2 up 65ip -net "$nsrouter" addr add 10.0.3.1/24 dev veth2 66ip -net "$nsrouter" addr add dead:3::1/64 dev veth2 nodad 67 68ip -net "$ns1" link set eth0 up 69ip -net "$ns2" link set eth0 up 70ip -net "$ns3" link set eth0 up 71 72ip -net "$ns1" addr add 10.0.1.99/24 dev eth0 73ip -net "$ns1" addr add dead:1::99/64 dev eth0 nodad 74ip -net "$ns1" route add default via 10.0.1.1 75ip -net "$ns1" route add default via dead:1::1 76 77ip -net "$ns2" addr add 10.0.2.99/24 dev eth0 78ip -net "$ns2" addr add dead:2::99/64 dev eth0 nodad 79ip -net "$ns2" route add default via 10.0.2.1 80ip -net "$ns2" route add default via dead:2::1 81 82ip -net "$ns3" addr add 10.0.3.99/24 dev eth0 83ip -net "$ns3" addr add dead:3::99/64 dev eth0 nodad 84ip -net "$ns3" route add default via 10.0.3.1 85ip -net "$ns3" route add default via dead:3::1 86 87load_ruleset() { 88 local family=$1 89 local name=$2 90 local prio=$3 91 92ip netns exec "$nsrouter" nft -f /dev/stdin <<EOF 93table $family $name { 94 chain nfq { 95 ip protocol icmp queue bypass 96 icmpv6 type { "echo-request", "echo-reply" } queue num 1 bypass 97 } 98 chain pre { 99 type filter hook prerouting priority $prio; policy accept; 100 jump nfq 101 } 102 chain input { 103 type filter hook input priority $prio; policy accept; 104 jump nfq 105 } 106 chain forward { 107 type filter hook forward priority $prio; policy accept; 108 tcp dport 12345 queue num 2 109 jump nfq 110 } 111 chain output { 112 type filter hook output priority $prio; policy accept; 113 tcp dport 12345 queue num 3 114 tcp sport 23456 queue num 3 115 jump nfq 116 } 117 chain post { 118 type filter hook postrouting priority $prio; policy accept; 119 jump nfq 120 } 121} 122EOF 123} 124 125load_counter_ruleset() { 126 local prio=$1 127 128ip netns exec "$nsrouter" nft -f /dev/stdin <<EOF 129table inet countrules { 130 chain pre { 131 type filter hook prerouting priority $prio; policy accept; 132 counter 133 } 134 chain input { 135 type filter hook input priority $prio; policy accept; 136 counter 137 } 138 chain forward { 139 type filter hook forward priority $prio; policy accept; 140 counter 141 } 142 chain output { 143 type filter hook output priority $prio; policy accept; 144 counter 145 } 146 chain post { 147 type filter hook postrouting priority $prio; policy accept; 148 counter 149 } 150} 151EOF 152} 153 154test_ping() { 155 if ! ip netns exec "$ns1" ping -c 1 -q 10.0.2.99 > /dev/null; then 156 return 1 157 fi 158 159 if ! ip netns exec "$ns1" ping -c 1 -q dead:2::99 > /dev/null; then 160 return 2 161 fi 162 163 return 0 164} 165 166test_ping_router() { 167 if ! ip netns exec "$ns1" ping -c 1 -q 10.0.2.1 > /dev/null; then 168 return 3 169 fi 170 171 if ! ip netns exec "$ns1" ping -c 1 -q dead:2::1 > /dev/null; then 172 return 4 173 fi 174 175 return 0 176} 177 178test_queue_blackhole() { 179 local proto=$1 180 181ip netns exec "$nsrouter" nft -f /dev/stdin <<EOF 182table $proto blackh { 183 chain forward { 184 type filter hook forward priority 0; policy accept; 185 queue num 600 186 } 187} 188EOF 189 if [ "$proto" = "ip" ] ;then 190 ip netns exec "$ns1" ping -W 2 -c 1 -q 10.0.2.99 > /dev/null 191 lret=$? 192 elif [ "$proto" = "ip6" ]; then 193 ip netns exec "$ns1" ping -W 2 -c 1 -q dead:2::99 > /dev/null 194 lret=$? 195 else 196 lret=111 197 fi 198 199 # queue without bypass keyword should drop traffic if no listener exists. 200 if [ "$lret" -eq 0 ];then 201 echo "FAIL: $proto expected failure, got $lret" 1>&2 202 exit 1 203 fi 204 205 if ! ip netns exec "$nsrouter" nft delete table "$proto" blackh; then 206 echo "FAIL: $proto: Could not delete blackh table" 207 exit 1 208 fi 209 210 echo "PASS: $proto: statement with no listener results in packet drop" 211} 212 213nf_queue_wait() 214{ 215 local procfile="/proc/self/net/netfilter/nfnetlink_queue" 216 local netns id 217 218 netns="$1" 219 id="$2" 220 221 # if this file doesn't exist, nfnetlink_module isn't loaded. 222 # rather than loading it ourselves, wait for kernel module autoload 223 # completion, nfnetlink should do so automatically because nf_queue 224 # helper program, spawned in the background, asked for this functionality. 225 test -f "$procfile" && 226 ip netns exec "$netns" cat "$procfile" | grep -q "^ *$id " 227} 228 229test_queue() 230{ 231 local expected="$1" 232 local family="$2" 233 local last="" 234 235 # spawn nf_queue listeners 236 ip netns exec "$nsrouter" ./nf_queue -c -q 0 -t $timeout > "$TMPFILE0" & 237 ip netns exec "$nsrouter" ./nf_queue -c -q 1 -t $timeout > "$TMPFILE1" & 238 239 busywait "$BUSYWAIT_TIMEOUT" nf_queue_wait "$nsrouter" 0 240 busywait "$BUSYWAIT_TIMEOUT" nf_queue_wait "$nsrouter" 1 241 242 if ! test_ping;then 243 echo "FAIL: netns routing/connectivity with active listener on queues 0 and 1: $ret" 1>&2 244 exit $ret 245 fi 246 247 if ! test_ping_router;then 248 echo "FAIL: netns router unreachable listener on queue 0 and 1: $ret" 1>&2 249 exit $ret 250 fi 251 252 wait 253 ret=$? 254 255 for file in $TMPFILE0 $TMPFILE1; do 256 last=$(tail -n1 "$file") 257 if [ x"$last" != x"$expected packets total" ]; then 258 echo "FAIL: Expected $expected packets total, but got $last" 1>&2 259 ip netns exec "$nsrouter" nft list ruleset 260 echo -n "$TMPFILE0: ";cat "$TMPFILE0" 261 echo -n "$TMPFILE1: ";cat "$TMPFILE1" 262 exit 1 263 fi 264 done 265 266 echo "PASS: Expected and received $last ($family)" 267} 268 269listener_ready() 270{ 271 ss -N "$1" -lnt -o "sport = :12345" | grep -q 12345 272} 273 274test_tcp_forward() 275{ 276 ip netns exec "$nsrouter" ./nf_queue -q 2 & 277 local nfqpid=$! 278 279 timeout 5 ip netns exec "$ns2" socat -u TCP-LISTEN:12345 STDOUT >/dev/null & 280 local rpid=$! 281 282 busywait "$BUSYWAIT_TIMEOUT" listener_ready "$ns2" 283 busywait "$BUSYWAIT_TIMEOUT" nf_queue_wait "$nsrouter" 2 284 285 local tthen=$(date +%s) 286 287 ip netns exec "$ns1" socat -u STDIN TCP:10.0.2.99:12345 <"$TMPINPUT" >/dev/null 288 289 wait_and_check_retval "$rpid" "tcp and nfqueue in forward chain" "$tthen" 290 kill "$nfqpid" 291} 292 293test_tcp_localhost() 294{ 295 timeout 5 ip netns exec "$nsrouter" socat -u TCP-LISTEN:12345 STDOUT >/dev/null & 296 local rpid=$! 297 298 ip netns exec "$nsrouter" ./nf_queue -q 3 & 299 local nfqpid=$! 300 local tthen=$(date +%s) 301 302 busywait "$BUSYWAIT_TIMEOUT" listener_ready "$nsrouter" 303 busywait "$BUSYWAIT_TIMEOUT" nf_queue_wait "$nsrouter" 3 304 305 ip netns exec "$nsrouter" socat -u STDIN TCP:127.0.0.1:12345 <"$TMPINPUT" >/dev/null 306 307 wait_and_check_retval "$rpid" "tcp via loopback" "$tthen" 308 kill "$nfqpid" 309} 310 311test_tcp_localhost_connectclose() 312{ 313 ip netns exec "$nsrouter" ./nf_queue -q 3 & 314 local nfqpid=$! 315 316 busywait "$BUSYWAIT_TIMEOUT" nf_queue_wait "$nsrouter" 3 317 318 timeout 10 ip netns exec "$nsrouter" ./connect_close -p 23456 -t 3 319 320 kill "$nfqpid" 321 wait && echo "PASS: tcp via loopback with connect/close" 322} 323 324test_tcp_localhost_requeue() 325{ 326ip netns exec "$nsrouter" nft -f /dev/stdin <<EOF 327flush ruleset 328table inet filter { 329 chain output { 330 type filter hook output priority 0; policy accept; 331 tcp dport 12345 limit rate 1/second burst 1 packets counter queue num 0 332 } 333 chain post { 334 type filter hook postrouting priority 0; policy accept; 335 tcp dport 12345 limit rate 1/second burst 1 packets counter queue num 0 336 } 337} 338EOF 339 timeout 5 ip netns exec "$nsrouter" socat -u TCP-LISTEN:12345 STDOUT >/dev/null & 340 local rpid=$! 341 342 ip netns exec "$nsrouter" ./nf_queue -c -q 1 -t "$timeout" > "$TMPFILE2" & 343 344 # nfqueue 1 will be called via output hook. But this time, 345 # re-queue the packet to nfqueue program on queue 2. 346 ip netns exec "$nsrouter" ./nf_queue -G -d 150 -c -q 0 -Q 1 -t "$timeout" > "$TMPFILE3" & 347 348 busywait "$BUSYWAIT_TIMEOUT" listener_ready "$nsrouter" 349 ip netns exec "$nsrouter" socat -u STDIN TCP:127.0.0.1:12345 <"$TMPINPUT" > /dev/null 350 351 wait 352 353 if ! diff -u "$TMPFILE2" "$TMPFILE3" ; then 354 echo "FAIL: lost packets during requeue?!" 1>&2 355 return 356 fi 357 358 echo "PASS: tcp via loopback and re-queueing" 359} 360 361test_icmp_vrf() { 362 if ! ip -net "$ns1" link add tvrf type vrf table 9876;then 363 echo "SKIP: Could not add vrf device" 364 return 365 fi 366 367 ip -net "$ns1" li set eth0 master tvrf 368 ip -net "$ns1" li set tvrf up 369 370 ip -net "$ns1" route add 10.0.2.0/24 via 10.0.1.1 dev eth0 table 9876 371ip netns exec "$ns1" nft -f /dev/stdin <<EOF 372flush ruleset 373table inet filter { 374 chain output { 375 type filter hook output priority 0; policy accept; 376 meta oifname "tvrf" icmp type echo-request counter queue num 1 377 meta oifname "eth0" icmp type echo-request counter queue num 1 378 } 379 chain post { 380 type filter hook postrouting priority 0; policy accept; 381 meta oifname "tvrf" icmp type echo-request counter queue num 1 382 meta oifname "eth0" icmp type echo-request counter queue num 1 383 } 384} 385EOF 386 ip netns exec "$ns1" ./nf_queue -q 1 & 387 local nfqpid=$! 388 389 busywait "$BUSYWAIT_TIMEOUT" nf_queue_wait "$ns1" 1 390 391 ip netns exec "$ns1" ip vrf exec tvrf ping -c 1 10.0.2.99 > /dev/null 392 393 for n in output post; do 394 for d in tvrf eth0; do 395 if ! ip netns exec "$ns1" nft list chain inet filter "$n" | grep -q "oifname \"$d\" icmp type echo-request counter packets 1"; then 396 kill "$nfqpid" 397 echo "FAIL: chain $n: icmp packet counter mismatch for device $d" 1>&2 398 ip netns exec "$ns1" nft list ruleset 399 ret=1 400 return 401 fi 402 done 403 done 404 405 kill "$nfqpid" 406 echo "PASS: icmp+nfqueue via vrf" 407 ip -net "$ns1" link del tvrf 408 ip netns exec "$ns1" nft flush ruleset 409} 410 411sctp_listener_ready() 412{ 413 ss -S -N "$1" -ln -o "sport = :12345" | grep -q 12345 414} 415 416check_output_files() 417{ 418 local f1="$1" 419 local f2="$2" 420 local err="$3" 421 422 if ! cmp "$f1" "$f2" ; then 423 echo "FAIL: $err: input and output file differ" 1>&2 424 echo -n " Input file" 1>&2 425 ls -l "$f1" 1>&2 426 echo -n "Output file" 1>&2 427 ls -l "$f2" 1>&2 428 ret=1 429 fi 430} 431 432wait_and_check_retval() 433{ 434 local rpid="$1" 435 local msg="$2" 436 local tthen="$3" 437 local tnow=$(date +%s) 438 439 if wait "$rpid";then 440 echo -n "PASS: " 441 else 442 echo -n "FAIL: " 443 ret=1 444 fi 445 446 printf "%s (duration: %ds)\n" "$msg" $((tnow-tthen)) 447} 448 449test_sctp_forward() 450{ 451 ip netns exec "$nsrouter" nft -f /dev/stdin <<EOF 452flush ruleset 453table inet sctpq { 454 chain forward { 455 type filter hook forward priority 0; policy accept; 456 sctp dport 12345 queue num 10 457 } 458} 459EOF 460 timeout "$SCTP_TEST_TIMEOUT" ip netns exec "$ns2" socat -u SCTP-LISTEN:12345 STDOUT > "$TMPFILE1" & 461 local rpid=$! 462 463 busywait "$BUSYWAIT_TIMEOUT" sctp_listener_ready "$ns2" 464 465 ip netns exec "$nsrouter" ./nf_queue -q 10 -G & 466 local nfqpid=$! 467 local tthen=$(date +%s) 468 469 ip netns exec "$ns1" socat -u STDIN SCTP:10.0.2.99:12345 <"$TMPINPUT" >/dev/null 470 471 if ! ip netns exec "$nsrouter" nft delete table inet sctpq; then 472 echo "FAIL: Could not delete sctpq table" 473 exit 1 474 fi 475 476 wait_and_check_retval "$rpid" "sctp and nfqueue in forward chain" "$tthen" 477 kill "$nfqpid" 478 479 check_output_files "$TMPINPUT" "$TMPFILE1" "sctp forward" 480} 481 482test_sctp_output() 483{ 484 ip netns exec "$ns1" nft -f /dev/stdin <<EOF 485table inet sctpq { 486 chain output { 487 type filter hook output priority 0; policy accept; 488 sctp dport 12345 queue num 11 489 } 490} 491EOF 492 # reduce test file size, software segmentation causes sk wmem increase. 493 dd conv=sparse status=none if=/dev/zero bs=1M count=$((COUNT/2)) of="$TMPINPUT" 494 495 timeout "$SCTP_TEST_TIMEOUT" ip netns exec "$ns2" socat -u SCTP-LISTEN:12345 STDOUT > "$TMPFILE1" & 496 local rpid=$! 497 498 busywait "$BUSYWAIT_TIMEOUT" sctp_listener_ready "$ns2" 499 500 ip netns exec "$ns1" ./nf_queue -q 11 & 501 local nfqpid=$! 502 local tthen=$(date +%s) 503 504 ip netns exec "$ns1" socat -u STDIN SCTP:10.0.2.99:12345 <"$TMPINPUT" >/dev/null 505 506 if ! ip netns exec "$ns1" nft delete table inet sctpq; then 507 echo "FAIL: Could not delete sctpq table" 508 exit 1 509 fi 510 511 # must wait before checking completeness of output file. 512 wait_and_check_retval "$rpid" "sctp and nfqueue in output chain with GSO" "$tthen" 513 kill "$nfqpid" 514 515 check_output_files "$TMPINPUT" "$TMPFILE1" "sctp output" 516} 517 518udp_listener_ready() 519{ 520 ss -S -N "$1" -uln -o "sport = :$2" | grep -q "$2" 521} 522 523output_files_written() 524{ 525 test -s "$1" && test -s "$2" 526} 527 528test_udp_nat_race() 529{ 530 ip netns exec "$nsrouter" nft -f /dev/stdin <<EOF 531flush ruleset 532table inet udpq { 533 chain prerouting { 534 type nat hook prerouting priority dstnat - 5; policy accept; 535 ip daddr 10.6.6.6 udp dport 12345 counter dnat to numgen inc mod 2 map { 0 : 10.0.2.99, 1 : 10.0.3.99 } 536 } 537 chain postrouting { 538 type filter hook postrouting priority srcnat - 5; policy accept; 539 udp dport 12345 counter queue num 12 540 } 541} 542EOF 543 :> "$TMPFILE1" 544 :> "$TMPFILE2" 545 546 timeout 10 ip netns exec "$ns2" socat UDP-LISTEN:12345,fork,pf=ipv4 OPEN:"$TMPFILE1",trunc & 547 local rpid1=$! 548 549 timeout 10 ip netns exec "$ns3" socat UDP-LISTEN:12345,fork,pf=ipv4 OPEN:"$TMPFILE2",trunc & 550 local rpid2=$! 551 552 ip netns exec "$nsrouter" ./nf_queue -q 12 -d 1000 & 553 local nfqpid=$! 554 555 busywait "$BUSYWAIT_TIMEOUT" udp_listener_ready "$ns2" 12345 556 busywait "$BUSYWAIT_TIMEOUT" udp_listener_ready "$ns3" 12345 557 busywait "$BUSYWAIT_TIMEOUT" nf_queue_wait "$nsrouter" 12 558 559 # Send two packets, one should end up in ns1, other in ns2. 560 # This is because nfqueue will delay packet for long enough so that 561 # second packet will not find existing conntrack entry. 562 echo "Packet 1" | ip netns exec "$ns1" socat -u STDIN UDP-DATAGRAM:10.6.6.6:12345,bind=0.0.0.0:55221 563 echo "Packet 2" | ip netns exec "$ns1" socat -u STDIN UDP-DATAGRAM:10.6.6.6:12345,bind=0.0.0.0:55221 564 565 busywait 10000 output_files_written "$TMPFILE1" "$TMPFILE2" 566 567 kill "$nfqpid" "$rpid1" "$rpid2" 568 569 if ! ip netns exec "$nsrouter" bash -c 'conntrack -L -p udp --dport 12345 2>/dev/null | wc -l | grep -q "^1"'; then 570 echo "FAIL: Expected One udp conntrack entry" 571 ip netns exec "$nsrouter" conntrack -L -p udp --dport 12345 572 ret=1 573 fi 574 575 if ! ip netns exec "$nsrouter" nft delete table inet udpq; then 576 echo "FAIL: Could not delete udpq table" 577 ret=1 578 return 579 fi 580 581 NUMLINES1=$(wc -l < "$TMPFILE1") 582 NUMLINES2=$(wc -l < "$TMPFILE2") 583 584 if [ "$NUMLINES1" -ne 1 ] || [ "$NUMLINES2" -ne 1 ]; then 585 ret=1 586 echo "FAIL: uneven udp packet distribution: $NUMLINES1 $NUMLINES2" 587 echo -n "$TMPFILE1: ";cat "$TMPFILE1" 588 echo -n "$TMPFILE2: ";cat "$TMPFILE2" 589 return 590 fi 591 592 echo "PASS: both udp receivers got one packet each" 593} 594 595# Make sure UDPGRO aggregated packets don't lose 596# their skb->nfct entry when nfqueue passes the 597# skb to userspace with software gso segmentation on. 598test_udp_gro_ct() 599{ 600 local errprefix="FAIL: test_udp_gro_ct:" 601 local timeout=5 602 603 ip netns exec "$nsrouter" conntrack -F 2>/dev/null 604 605 ip netns exec "$nsrouter" nft -f /dev/stdin <<EOF 606flush ruleset 607table inet udpq { 608 # Number of packets/bytes queued to userspace 609 counter toqueue { } 610 # Number of packets/bytes reinjected from userspace with 'ct new' intact 611 counter fromqueue { } 612 # These two counters should be identical and not 0. 613 614 chain prerouting { 615 type filter hook prerouting priority -300; policy accept; 616 617 # userspace sends small packets, if < 1000, UDPGRO did 618 # not kick in, but test needs a 'new' conntrack with udpgro skb. 619 meta iifname veth0 meta l4proto udp meta length > 1000 accept 620 621 # don't pick up non-gso packets and don't queue them to 622 # userspace. 623 notrack 624 } 625 626 chain postrouting { 627 type filter hook postrouting priority 0; policy accept; 628 629 # Only queue unconfirmed fraglist gro skbs to userspace. 630 udp dport 12346 ct status ! confirmed counter name "toqueue" mark set 1 queue num 1 631 } 632 633 chain validate { 634 type filter hook postrouting priority 1; policy accept; 635 # ... and only count those that were reinjected with the 636 # skb->nfct intact. 637 mark 1 counter name "fromqueue" 638 } 639} 640EOF 641 timeout "$timeout" ip netns exec "$ns2" socat UDP-LISTEN:12346,fork,pf=ipv4 OPEN:"$TMPFILE1",trunc & 642 local rpid=$! 643 644 ip netns exec "$nsrouter" nice -n -19 ./nf_queue -G -c -q 1 -o -t 2 > "$TMPFILE2" & 645 local nfqpid=$! 646 647 ip netns exec "$nsrouter" ethtool -K "veth0" rx-udp-gro-forwarding on rx-gro-list on generic-receive-offload on 648 649 busywait "$BUSYWAIT_TIMEOUT" udp_listener_ready "$ns2" 12346 650 busywait "$BUSYWAIT_TIMEOUT" nf_queue_wait "$nsrouter" 1 651 652 local bs=512 653 local count=$(((32 * 1024 * 1024) / bs)) 654 655 local nprocs=$(nproc) 656 [ $nprocs -gt 1 ] && nprocs=$((nprocs - 1)) 657 658 dd if=/dev/zero bs="$bs" count="$count" 2>/dev/null | for i in $(seq 1 $nprocs); do 659 timeout "$timeout" nice -n 19 ip netns exec "$ns1" \ 660 socat -u -b 512 STDIN UDP-DATAGRAM:10.0.2.99:12346,reuseport,bind=0.0.0.0:55221 & 661 done 662 663 busywait 10000 test -s "$TMPFILE1" 664 665 kill "$rpid" 666 667 wait 668 669 local p 670 local b 671 local pqueued 672 local bqueued 673 674 c=$(ip netns exec "$nsrouter" nft list counter inet udpq "toqueue" | grep packets) 675 read p pqueued b bqueued <<EOF 676$c 677EOF 678 local preinject 679 local breinject 680 c=$(ip netns exec "$nsrouter" nft list counter inet udpq "fromqueue" | grep packets) 681 read p preinject b breinject <<EOF 682$c 683EOF 684 ip netns exec "$nsrouter" ethtool -K "veth0" rx-udp-gro-forwarding off 685 ip netns exec "$nsrouter" ethtool -K "veth1" rx-udp-gro-forwarding off 686 687 if [ "$pqueued" -eq 0 ];then 688 # happens when gro did not build at least on aggregate 689 echo "SKIP: No packets were queued" 690 return 691 fi 692 693 local saw_ct_entry=0 694 if ip netns exec "$nsrouter" bash -c 'conntrack -L -p udp --dport 12346 2>/dev/null | wc -l | grep -q "^1"'; then 695 saw_ct_entry=1 696 else 697 echo "$errprefix Expected udp conntrack entry" 698 ip netns exec "$nsrouter" conntrack -L 699 ret=1 700 fi 701 702 if [ "$pqueued" -ge "$preinject" ] ;then 703 echo "$errprefix Expected software segmentation to occur, had $pqueued and $preinject" 704 ret=1 705 return 706 fi 707 708 # sw segmentation adds extra udp and ip headers. 709 local breinject_expect=$((preinject * (512 + 20 + 8))) 710 711 if [ "$breinject" -eq "$breinject_expect" ]; then 712 if [ "$saw_ct_entry" -eq 1 ];then 713 echo "PASS: fraglist gro skb passed with conntrack entry" 714 else 715 echo "$errprefix fraglist gro skb passed without conntrack entry" 716 ret=1 717 fi 718 else 719 echo "$errprefix Counter mismatch, conntrack entry dropped by nfqueue? Queued: $pqueued, $bqueued. Post-queue: $preinject, $breinject. Expected $breinject_expect" 720 ret=1 721 fi 722 723 if ! ip netns exec "$nsrouter" nft delete table inet udpq; then 724 echo "$errprefix: Could not delete udpq table" 725 ret=1 726 fi 727} 728 729check_tainted() 730{ 731 local msg="$1" 732 733 if [ "$tainted_then" -ne 0 ];then 734 return 735 fi 736 737 read tainted_now < /proc/sys/kernel/tainted 738 if [ "$tainted_now" -eq 0 ];then 739 echo "PASS: $msg" 740 else 741 echo "TAINT: $msg" 742 dmesg 743 ret=1 744 fi 745} 746 747test_queue_stress() 748{ 749 read tainted_then < /proc/sys/kernel/tainted 750 local i 751 752 ip netns exec "$nsrouter" nft -f /dev/stdin <<EOF 753flush ruleset 754table inet t { 755 chain forward { 756 type filter hook forward priority 0; policy accept; 757 758 queue flags bypass to numgen random mod 8 759 } 760} 761EOF 762 timeout "$STRESS_TEST_TIMEOUT" ip netns exec "$ns2" \ 763 socat -u UDP-LISTEN:12345,fork,pf=ipv4 STDOUT > /dev/null & 764 765 timeout "$STRESS_TEST_TIMEOUT" ip netns exec "$ns3" \ 766 socat -u UDP-LISTEN:12345,fork,pf=ipv4 STDOUT > /dev/null & 767 768 for i in $(seq 0 7); do 769 ip netns exec "$nsrouter" timeout "$STRESS_TEST_TIMEOUT" \ 770 ./nf_queue -q $i -t 2 -O -b > /dev/null & 771 done 772 773 ip netns exec "$ns1" timeout "$STRESS_TEST_TIMEOUT" \ 774 ping -q -f 10.0.2.99 > /dev/null 2>&1 & 775 ip netns exec "$ns1" timeout "$STRESS_TEST_TIMEOUT" \ 776 ping -q -f 10.0.3.99 > /dev/null 2>&1 & 777 ip netns exec "$ns1" timeout "$STRESS_TEST_TIMEOUT" \ 778 ping -q -f "dead:2::99" > /dev/null 2>&1 & 779 ip netns exec "$ns1" timeout "$STRESS_TEST_TIMEOUT" \ 780 ping -q -f "dead:3::99" > /dev/null 2>&1 & 781 782 busywait "$BUSYWAIT_TIMEOUT" udp_listener_ready "$ns2" 12345 783 busywait "$BUSYWAIT_TIMEOUT" udp_listener_ready "$ns3" 12345 784 785 for i in $(seq 1 4);do 786 ip netns exec "$ns1" timeout "$STRESS_TEST_TIMEOUT" \ 787 socat -u STDIN UDP-DATAGRAM:10.0.2.99:12345 < /dev/zero > /dev/null & 788 ip netns exec "$ns1" timeout "$STRESS_TEST_TIMEOUT" \ 789 socat -u STDIN UDP-DATAGRAM:10.0.3.99:12345 < /dev/zero > /dev/null & 790 done 791 792 wait 793 794 check_tainted "concurrent queueing" 795} 796 797test_queue_removal() 798{ 799 read tainted_then < /proc/sys/kernel/tainted 800 801 ip netns exec "$ns1" nft -f - <<EOF 802flush ruleset 803table ip filter { 804 chain output { 805 type filter hook output priority 0; policy accept; 806 ip protocol icmp queue num 0 807 } 808} 809EOF 810 ip netns exec "$ns1" ./nf_queue -q 0 -d 30000 & 811 local nfqpid=$! 812 813 busywait "$BUSYWAIT_TIMEOUT" nf_queue_wait "$ns1" 0 814 815 ip netns exec "$ns1" ping -w 2 -f -c 10 127.0.0.1 -q >/dev/null 816 kill $nfqpid 817 818 ip netns exec "$ns1" nft flush ruleset 819 820 check_tainted "queue program exiting while packets queued" 821} 822 823test_queue_bridge() 824{ 825 ip -net "$nsrouter" addr flush dev veth0 826 ip -net "$nsrouter" addr flush dev veth1 827 828 ip -net "$nsrouter" link add br0 type bridge 829 ip -net "$nsrouter" link set veth0 master br0 830 ip -net "$nsrouter" link set veth1 master br0 831 832 ip -net "$nsrouter" link set br0 up 833 834 ip -net "$nsrouter" addr add 10.0.2.1/16 dev br0 835 ip -net "$nsrouter" addr add dead:2::1/64 dev br0 nodad 836 837 ip -net "$ns1" addr flush dev eth0 838 ip -net "$ns2" addr flush dev eth0 839 840 ip -net "$ns1" addr add 10.0.1.1/16 dev eth0 841 ip -net "$ns1" addr add dead:2::2/64 dev eth0 nodad 842 843 ip -net "$ns2" addr add 10.0.2.99/16 dev eth0 844 ip -net "$ns2" addr add dead:2::99/64 dev eth0 nodad 845 846 ip netns exec "$nsrouter" nft flush ruleset 847 848 ip netns exec "$nsrouter" sysctl net.ipv6.conf.all.forwarding=0 > /dev/null 849 ip netns exec "$nsrouter" sysctl net.ipv4.conf.veth0.forwarding=0 > /dev/null 850 ip netns exec "$nsrouter" sysctl net.ipv4.conf.veth1.forwarding=0 > /dev/null 851 852 if ! test_ping;then 853 echo "FAIL: netns bridge connectivity" 1>&2 854 exit $ret 855 fi 856 857 load_ruleset "bridge" "filter" 10 858 test_queue 10 "bridge" 859 860 load_ruleset "bridge" "filter2" 20 861 test_queue 20 "bridge" 862} 863 864ip netns exec "$nsrouter" sysctl net.ipv6.conf.all.forwarding=1 > /dev/null 865ip netns exec "$nsrouter" sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null 866ip netns exec "$nsrouter" sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null 867ip netns exec "$nsrouter" sysctl net.ipv4.conf.veth2.forwarding=1 > /dev/null 868 869load_ruleset "inet" "filter" 0 870 871if test_ping; then 872 # queue bypass works (rules were skipped, no listener) 873 echo "PASS: ${ns1} can reach ${ns2}" 874else 875 echo "FAIL: ${ns1} cannot reach ${ns2}: $ret" 1>&2 876 exit $ret 877fi 878 879test_queue_blackhole ip 880test_queue_blackhole ip6 881 882# dummy ruleset to add base chains between the 883# queueing rules. We don't want the second reinject 884# to re-execute the old hooks. 885load_counter_ruleset 10 886 887# we are hooking all: prerouting/input/forward/output/postrouting. 888# we ping ${ns2} from ${ns1} via ${nsrouter} using ipv4 and ipv6, so: 889# 1x icmp prerouting,forward,postrouting -> 3 queue events (6 incl. reply). 890# 1x icmp prerouting,input,output postrouting -> 4 queue events incl. reply. 891# so we expect that userspace program receives 10 packets. 892test_queue 10 "inet" 893 894# same. We queue to a second program as well. 895load_ruleset "inet" "filter2" 20 896test_queue 20 "inet" 897ip netns exec "$ns1" nft flush ruleset 898 899test_tcp_forward 900test_tcp_localhost 901test_tcp_localhost_connectclose 902test_tcp_localhost_requeue 903test_sctp_forward 904test_sctp_output 905test_udp_nat_race 906test_udp_gro_ct 907test_queue_stress 908 909# should be last, adds vrf device in ns1 and changes routes 910test_icmp_vrf 911test_queue_removal 912 913# turns router into a bridge 914test_queue_bridge 915 916exit $ret 917