1#!/usr/bin/env atf-sh 2#- 3# SPDX-License-Identifier: BSD-2-Clause 4# 5# Copyright (c) 2020 Alexander V. Chernikov 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# 1. Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# 2. Redistributions in binary form must reproduce the above copyright 13# notice, this list of conditions and the following disclaimer in the 14# documentation and/or other materials provided with the distribution. 15# 16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26# SUCH DAMAGE. 27# 28# 29 30. $(atf_get_srcdir)/../common/vnet.subr 31 32atf_test_case "output_tcp_setup_success" "cleanup" 33output_tcp_setup_success_head() 34{ 35 36 atf_set descr 'Test valid IPv4 TCP output' 37 atf_set require.user root 38} 39 40output_tcp_setup_success_body() 41{ 42 43 vnet_init 44 45 net_src="192.0.2." 46 net_dst="192.0.2." 47 ip_src="${net_src}1" 48 ip_dst="${net_dst}2" 49 plen=24 50 text="testtesttst" 51 port=4242 52 53 script_name=`dirname $0`/../common/net_receiver.py 54 script_name=`realpath ${script_name}` 55 jname="v4t-output_tcp_setup_success" 56 57 epair=$(vnet_mkepair) 58 59 vnet_mkjail ${jname}a ${epair}a 60 jexec ${jname}a ifconfig ${epair}a up 61 jexec ${jname}a ifconfig ${epair}a inet ${ip_src}/${plen} 62 63 vnet_mkjail ${jname}b ${epair}b 64 jexec ${jname}b ifconfig ${epair}b up 65 66 jexec ${jname}b ifconfig ${epair}b inet ${ip_dst}/${plen} 67 68 # run listener 69 args="--family inet --ports ${port} --match_str ${text}" 70 echo jexec ${jname}b ${script_name} ${args} 71 jexec ${jname}b ${script_name} --test_name "test_listen_tcp" ${args} & 72 cmd_pid=$! 73 74 # wait for the script init 75 counter=0 76 while [ `jexec ${jname}b sockstat -4qlp ${port} | wc -l` != "1" ]; do 77 sleep 0.01 78 counter=$((counter+1)) 79 if [ ${counter} -ge 50 ]; then break; fi 80 done 81 if [ `jexec ${jname}b sockstat -4qlp ${port} | wc -l` != "1" ]; then 82 echo "App setup failed" 83 exit 1 84 fi 85 86 # run sender 87 echo -n "${text}" | jexec ${jname}a nc -N ${ip_dst} ${port} 88 exit_code=$? 89 if [ $exit_code -ne 0 ]; then atf_fail "sender exit code $exit_code" ; fi 90 91 wait ${cmd_pid} 92 exit_code=$? 93 if [ $exit_code -ne 0 ]; then atf_fail "receiver exit code $exit_code" ; fi 94} 95 96output_tcp_setup_success_cleanup() 97{ 98 vnet_cleanup 99} 100 101 102atf_test_case "output_udp_setup_success" "cleanup" 103output_udp_setup_success_head() 104{ 105 106 atf_set descr 'Test valid IPv4 UDP output' 107 atf_set require.user root 108} 109 110output_udp_setup_success_body() 111{ 112 113 vnet_init 114 115 net_src="192.0.2." 116 net_dst="192.0.2." 117 ip_src="${net_src}1" 118 ip_dst="${net_dst}2" 119 plen=24 120 text="testtesttst" 121 port=4242 122 123 script_name=`dirname $0`/../common/net_receiver.py 124 script_name=`realpath ${script_name}` 125 jname="v4t-output_udp_setup_success" 126 127 epair=$(vnet_mkepair) 128 129 vnet_mkjail ${jname}a ${epair}a 130 jexec ${jname}a ifconfig ${epair}a up 131 jexec ${jname}a ifconfig ${epair}a inet ${ip_src}/${plen} 132 133 vnet_mkjail ${jname}b ${epair}b 134 jexec ${jname}b ifconfig ${epair}b up 135 jexec ${jname}b ifconfig ${epair}b inet ${ip_dst}/${plen} 136 137 # run listener 138 args="--family inet --ports ${port} --match_str ${text}" 139 echo jexec ${jname}b ${script_name} ${args} 140 jexec ${jname}b ${script_name} --test_name "test_listen_udp" ${args} & 141 cmd_pid=$! 142 143 # wait for the script init 144 counter=0 145 while [ `jexec ${jname}b sockstat -4qlp ${port} | wc -l` != "1" ]; do 146 sleep 0.1 147 counterc=$((counter+1)) 148 if [ ${counter} -ge 50 ]; then break; fi 149 done 150 if [ `jexec ${jname}b sockstat -4qlp ${port} | wc -l` != "1" ]; then 151 echo "App setup failed" 152 exit 1 153 fi 154 155 # run sender 156 # TODO: switch from nc to some alternative to avoid 1-second delay 157 echo -n "${text}" | jexec ${jname}a nc -uNw1 ${ip_dst} ${port} 158 exit_code=$? 159 if [ $exit_code -ne 0 ]; then atf_fail "sender exit code $exit_code" ; fi 160 161 wait ${cmd_pid} 162 exit_code=$? 163 if [ $exit_code -ne 0 ]; then atf_fail "receiver exit code $exit_code" ; fi 164} 165 166output_udp_setup_success_cleanup() 167{ 168 vnet_cleanup 169} 170 171atf_test_case "output_raw_success" "cleanup" 172output_raw_success_head() 173{ 174 175 atf_set descr 'Test valid IPv4 raw output' 176 atf_set require.user root 177} 178 179output_raw_success_body() 180{ 181 182 vnet_init 183 184 net_src="192.0.2." 185 net_dst="192.0.2." 186 ip_src="${net_src}1" 187 ip_dst="${net_dst}2" 188 plen=24 189 190 script_name=`dirname $0`/../common/net_receiver.py 191 script_name=`realpath ${script_name}` 192 jname="v4t-output_raw_success" 193 194 epair=$(vnet_mkepair) 195 196 vnet_mkjail ${jname}a ${epair}a 197 jexec ${jname}a ifconfig ${epair}a up 198 jexec ${jname}a ifconfig ${epair}a inet ${ip_src}/${plen} 199 200 vnet_mkjail ${jname}b ${epair}b 201 jexec ${jname}b ifconfig ${epair}b up 202 203 jexec ${jname}b ifconfig ${epair}b inet ${ip_dst}/${plen} 204 205 atf_check -o match:'1 packets transmitted, 1 packets received' jexec ${jname}a ping -nc1 ${ip_dst} 206} 207 208output_raw_success_cleanup() 209{ 210 vnet_cleanup 211} 212 213# Multipath tests are done the following way: 214# epair0 215# jailA lo < > lo jailB 216# epair1 217# jailA has 2 routes towards /24 prefix on jailB loopback, via 2 epairs 218# jailB has 1 route towards /24 prefix on jailA loopback, via epair0 219# 220# jailA initiates connections/sends packets towards IPs on jailB loopback. 221# Script then compares amount of packets sent via epair0 and epair1 222 223mpath_check() 224{ 225 if [ `sysctl -iW net.route.multipath | wc -l` != "1" ]; then 226 atf_skip "This test requires ROUTE_MPATH enabled" 227 fi 228} 229 230mpath_enable() 231{ 232 jexec $1 sysctl net.route.multipath=1 233 if [ $? != 0 ]; then 234 atf_fail "Setting multipath in jail $1 failed". 235 fi 236} 237 238atf_test_case "output_tcp_flowid_mpath_success" "cleanup" 239output_tcp_flowid_mpath_success_head() 240{ 241 242 atf_set descr 'Test valid IPv4 TCP output flowid generation' 243 atf_set require.user root 244} 245 246output_tcp_flowid_mpath_success_body() 247{ 248 vnet_init 249 mpath_check 250 251 net_src="192.0.2." 252 net_dst="198.51.100." 253 ip_src="${net_src}1" 254 ip_dst="${net_dst}1" 255 plen=24 256 text="testtesttst" 257 258 script_name=`dirname $0`/../common/net_receiver.py 259 script_name=`realpath ${script_name}` 260 jname="v4t-output_tcp_flowid_mpath_success" 261 262 epair0=$(vnet_mkepair) 263 epair1=$(vnet_mkepair) 264 lo_src=$(vnet_mkloopback) 265 lo_dst=$(vnet_mkloopback) 266 267 vnet_mkjail ${jname}a ${epair0}a ${epair1}a ${lo_src} 268 mpath_enable ${jname}a 269 # Setup transit IPv4 networks 270 jexec ${jname}a ifconfig ${epair0}a up 271 jexec ${jname}a ifconfig ${epair0}a inet 203.0.113.1/30 272 jexec ${jname}a ifconfig ${epair1}a up 273 jexec ${jname}a ifconfig ${epair1}a inet 203.0.113.5/30 274 jexec ${jname}a ifconfig ${lo_src} up 275 276 vnet_mkjail ${jname}b ${epair0}b ${epair1}b ${lo_dst} 277 jexec ${jname}b ifconfig ${epair0}b up 278 jexec ${jname}b ifconfig ${epair0}b inet 203.0.113.2/30 279 jexec ${jname}b ifconfig ${epair1}b up 280 jexec ${jname}b ifconfig ${epair1}b inet 203.0.113.6/30 281 jexec ${jname}b ifconfig ${lo_dst} up 282 283 # DST ips/ports to test 284 ips="4 29 48 53 55 61 71 80 84 87 90 91 119 131 137 153 154 158 162 169 169 171 176 187 197 228 233 235 236 237 245 251" 285 ports="53540 49743 43067 9131 16734 5150 14379 40292 20634 51302 3387 24387 9282 14275 42103 26881 42461 29520 45714 11096" 286 287 jexec ${jname}a ifconfig ${lo_src} inet ${ip_src}/32 288 289 jexec ${jname}b ifconfig ${lo_dst} inet ${ip_dst}/32 290 for i in ${ips}; do 291 jexec ${jname}b ifconfig ${lo_dst} alias ${net_dst}${i}/32 292 done 293 294 # Add routes 295 # A -> towards B via epair0a 296 jexec ${jname}a route add -4 -net ${net_dst}0/${plen} 203.0.113.2 297 # A -> towards B via epair1a 298 jexec ${jname}a route add -4 -net ${net_dst}0/${plen} 203.0.113.6 299 300 # B towards A via epair0b 301 jexec ${jname}b route add -4 -net ${net_src}0/${plen} 203.0.113.1 302 303 # Base setup verification 304 atf_check -o match:'1 packets transmitted, 1 packets received' jexec ${jname}a ping -nc1 ${ip_dst} 305 306 # run listener 307 num_ports=`echo ${ports} | wc -w` 308 num_ips=`echo ${ips} | wc -w` 309 count_examples=$((num_ports*num_ips)) 310 listener_ports=`echo ${ports} | tr ' ' '\n' | sort -n | tr '\n' ',' | sed -e 's?,$??'` 311 args="--family inet --ports ${listener_ports} --count ${count_examples} --match_str ${text}" 312 echo jexec ${jname}b ${script_name} ${args} 313 jexec ${jname}b ${script_name} --test_name "test_listen_tcp" ${args} & 314 cmd_pid=$! 315 316 # wait for the app init 317 counter=0 318 init=0 319 while [ ${counter} -le 50 ]; do 320 _ports=`jexec ${jname}b sockstat -4ql | awk "\\\$3 == ${cmd_pid} {print \\\$6}"|awk -F: "{print \\\$2}" | sort -n | tr '\n' ','` 321 if [ "${_ports}" = "${listener_ports}," ]; then 322 init=1 323 break; 324 fi 325 done 326 if [ ${init} -eq 0 ]; then 327 jexec ${jname}b sockstat -6ql | awk "\$3 == ${cmd_pid}" 328 echo "App setup failed" 329 exit 1 330 fi 331 echo "App setup done" 332 333 # run sender 334 for _ip in ${ips}; do 335 ip="${net_dst}${_ip}" 336 for port in ${ports}; do 337 echo -n "${text}" | jexec ${jname}a nc -nN ${ip} ${port} 338 exit_code=$? 339 if [ $exit_code -ne 0 ]; then atf_fail "sender exit code $exit_code" ; fi 340 done 341 done 342 343 wait ${cmd_pid} 344 exit_code=$? 345 if [ $exit_code -ne 0 ]; then atf_fail "receiver exit code $exit_code" ; fi 346 347 pkt_0=`jexec ${jname}a netstat -Wf link -I ${epair0}a | head | awk '$1!~/^Name/{print$8}'` 348 pkt_1=`jexec ${jname}a netstat -Wf link -I ${epair1}a | head | awk '$1!~/^Name/{print$8}'` 349 if [ ${pkt_0} -le 10 ]; then 350 atf_fail "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}" 351 fi 352 if [ ${pkt_1} -le 10 ]; then 353 atf_fail "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}" 354 exit 1 355 fi 356 echo "TCP Balancing: 1: ${pkt_0} 2: ${pkt_1}" 357} 358 359output_tcp_flowid_mpath_success_cleanup() 360{ 361 vnet_cleanup 362} 363 364atf_test_case "output_udp_flowid_mpath_success" "cleanup" 365output_udp_flowid_mpath_success_head() 366{ 367 368 atf_set descr 'Test valid IPv4 UDP output flowid generation' 369 atf_set require.user root 370} 371 372output_udp_flowid_mpath_success_body() 373{ 374 375 vnet_init 376 mpath_check 377 378 # Note this test will spawn around ~100 nc processes 379 380 net_src="192.0.2." 381 net_dst="198.51.100." 382 ip_src="${net_src}1" 383 ip_dst="${net_dst}1" 384 plen=24 385 text="testtesttst" 386 387 script_name=`dirname $0`/../common/net_receiver.py 388 script_name=`realpath ${script_name}` 389 jname="v4t-output_tcp_flowid_mpath_success" 390 391 epair0=$(vnet_mkepair) 392 epair1=$(vnet_mkepair) 393 lo_src=$(vnet_mkloopback) 394 lo_dst=$(vnet_mkloopback) 395 396 vnet_mkjail ${jname}a ${epair0}a ${epair1}a ${lo_src} 397 mpath_enable ${jname}a 398 # Setup transit IPv4 networks 399 jexec ${jname}a ifconfig ${epair0}a up 400 jexec ${jname}a ifconfig ${epair0}a inet 203.0.113.1/30 401 jexec ${jname}a ifconfig ${epair1}a up 402 jexec ${jname}a ifconfig ${epair1}a inet 203.0.113.5/30 403 jexec ${jname}a ifconfig ${lo_src} up 404 405 vnet_mkjail ${jname}b ${epair0}b ${epair1}b ${lo_dst} 406 jexec ${jname}b ifconfig ${epair0}b up 407 jexec ${jname}b ifconfig ${epair0}b inet 203.0.113.2/30 408 jexec ${jname}b ifconfig ${epair1}b up 409 jexec ${jname}b ifconfig ${epair1}b inet 203.0.113.6/30 410 jexec ${jname}b ifconfig ${lo_dst} up 411 412 # DST ips/ports to test 413 ips="4 29 48 53 55 61 71 80 84 87 90 91 119 131 137 153 154 158 162 169 169 171 176 187 197 228 233 235 236 237 245 251" 414 ports="53540 49743 43067 9131 16734 5150 14379 40292 20634 51302 3387 24387 9282 14275 42103 26881 42461 29520 45714 11096" 415 416 jexec ${jname}a ifconfig ${lo_src} inet ${ip_src}/32 417 418 jexec ${jname}b ifconfig ${lo_dst} inet ${ip_dst}/32 419 for i in ${ips}; do 420 jexec ${jname}b ifconfig ${lo_dst} alias ${net_dst}${i}/32 421 done 422 423 # Add routes 424 # A -> towards B via epair0a 425 jexec ${jname}a route add -4 -net ${net_dst}0/${plen} 203.0.113.2 426 # A -> towards B via epair1a 427 jexec ${jname}a route add -4 -net ${net_dst}0/${plen} 203.0.113.6 428 429 # B towards A via epair0b 430 jexec ${jname}b route add -4 -net ${net_src}0/${plen} 203.0.113.1 431 432 # Base setup verification 433 atf_check -o match:'1 packets transmitted, 1 packets received' jexec ${jname}a ping -nc1 ${ip_dst} 434 435 # run listener 436 num_ports=`echo ${ports} | wc -w` 437 num_ips=`echo ${ips} | wc -w` 438 count_examples=$((num_ports*num_ips)) 439 listener_ports=`echo ${ports} | tr ' ' '\n' | sort -n | tr '\n' ',' | sed -e 's?,$??'` 440 args="--family inet --ports ${listener_ports} --count ${count_examples} --match_str ${text}" 441 echo jexec ${jname}b ${script_name} ${args} 442 jexec ${jname}b ${script_name} --test_name "test_listen_udp" ${args} & 443 cmd_pid=$! 444 445 # wait for the app init 446 counter=0 447 init=0 448 while [ ${counter} -le 50 ]; do 449 _ports=`jexec ${jname}b sockstat -4ql | awk "\\\$3 == ${cmd_pid} {print \\\$6}"|awk -F: "{print \\\$2}" | sort -n | tr '\n' ','` 450 if [ "${_ports}" = "${listener_ports}," ]; then 451 init=1 452 break; 453 fi 454 done 455 if [ ${init} -eq 0 ]; then 456 jexec ${jname}b sockstat -4ql | awk "\$3 == ${cmd_pid}" 457 echo "App setup failed" 458 exit 1 459 fi 460 echo "App setup done" 461 462 # run sender 463 for _ip in ${ips}; do 464 ip="${net_dst}${_ip}" 465 for port in ${ports}; do 466 # XXX: switch to something that allows immediate exit 467 echo -n "${text}" | jexec ${jname}a nc -nuNw1 ${ip} ${port} & 468 sleep 0.01 469 done 470 done 471 472 wait ${cmd_pid} 473 exit_code=$? 474 if [ $exit_code -ne 0 ]; then atf_fail "receiver exit code $exit_code" ; fi 475 476 pkt_0=`jexec ${jname}a netstat -Wf link -I ${epair0}a | head | awk '$1!~/^Name/{print$8}'` 477 pkt_1=`jexec ${jname}a netstat -Wf link -I ${epair1}a | head | awk '$1!~/^Name/{print$8}'` 478 if [ ${pkt_0} -le 10 ]; then 479 atf_fail "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}" 480 fi 481 if [ ${pkt_1} -le 10 ]; then 482 atf_fail "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}" 483 fi 484 echo "UDP BALANCING: 1: ${pkt_0} 2: ${pkt_1}" 485} 486 487output_udp_flowid_mpath_success_cleanup() 488{ 489 vnet_cleanup 490} 491 492atf_test_case "output_raw_flowid_mpath_success" "cleanup" 493output_raw_flowid_mpath_success_head() 494{ 495 496 atf_set descr 'Test valid IPv4 raw output flowid generation' 497 atf_set require.user root 498} 499 500output_raw_flowid_mpath_success_body() 501{ 502 503 vnet_init 504 mpath_check 505 506 net_src="192.0.2." 507 net_dst="198.51.100." 508 ip_src="${net_src}1" 509 ip_dst="${net_dst}1" 510 plen=24 511 text="testtesttst" 512 513 jname="v4t-output_tcp_flowid_mpath_success" 514 515 epair0=$(vnet_mkepair) 516 epair1=$(vnet_mkepair) 517 lo_src=$(vnet_mkloopback) 518 lo_dst=$(vnet_mkloopback) 519 520 vnet_mkjail ${jname}a ${epair0}a ${epair1}a ${lo_src} 521 mpath_enable ${jname}a 522 # Setup transit IPv4 networks 523 jexec ${jname}a ifconfig ${epair0}a up 524 jexec ${jname}a ifconfig ${epair0}a inet 203.0.113.1/30 525 jexec ${jname}a ifconfig ${epair1}a up 526 jexec ${jname}a ifconfig ${epair1}a inet 203.0.113.5/30 527 jexec ${jname}a ifconfig ${lo_src} up 528 529 vnet_mkjail ${jname}b ${epair0}b ${epair1}b ${lo_dst} 530 jexec ${jname}b ifconfig ${epair0}b up 531 jexec ${jname}b ifconfig ${epair0}b inet 203.0.113.2/30 532 jexec ${jname}b ifconfig ${epair1}b up 533 jexec ${jname}b ifconfig ${epair1}b inet 203.0.113.6/30 534 jexec ${jname}b ifconfig ${lo_dst} up 535 536 # DST ips/ports to test 537 ips="4 29 48 53 55 61 71 80 84 87 90 91 119 131 137 153 154 158 162 169 169 171 176 187 197 228 233 235 236 237 245 251" 538 539 jexec ${jname}a ifconfig ${lo_src} inet ${ip_src}/32 540 541 jexec ${jname}b ifconfig ${lo_dst} inet ${ip_dst}/32 542 for i in ${ips}; do 543 jexec ${jname}b ifconfig ${lo_dst} alias ${net_dst}${i}/32 544 done 545 546 # Add routes 547 # A -> towards B via epair0a 548 jexec ${jname}a route add -4 -net ${net_dst}0/${plen} 203.0.113.2 549 # A -> towards B via epair1a 550 jexec ${jname}a route add -4 -net ${net_dst}0/${plen} 203.0.113.6 551 552 # B towards A via epair0b 553 jexec ${jname}b route add -4 -net ${net_src}0/${plen} 203.0.113.1 554 555 # Base setup verification 556 atf_check -o match:'1 packets transmitted, 1 packets received' jexec ${jname}a ping -nc1 ${ip_dst} 557 558 # run sender 559 valid_message='1 packets transmitted, 1 packets received' 560 for _ip in ${ips}; do 561 ip="${net_dst}${_ip}" 562 atf_check -o match:"${valid_message}" jexec ${jname}a ping -nc1 ${ip} 563 done 564 565 pkt_0=`jexec ${jname}a netstat -Wf link -I ${epair0}a | head | awk '$1!~/^Name/{print$8}'` 566 pkt_1=`jexec ${jname}a netstat -Wf link -I ${epair1}a | head | awk '$1!~/^Name/{print$8}'` 567 568 jexec ${jname}a netstat -bWf link -I ${epair0}a 569 jexec ${jname}a netstat -bWf link -I ${epair1}a 570 if [ ${pkt_0} -le 10 ]; then 571 atf_fail "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}" 572 fi 573 if [ ${pkt_1} -le 10 ]; then 574 atf_fail "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}" 575 fi 576 echo "RAW BALANCING: 1: ${pkt_0} 2: ${pkt_1}" 577} 578 579output_raw_flowid_mpath_success_cleanup() 580{ 581 vnet_cleanup 582} 583 584atf_init_test_cases() 585{ 586 atf_add_test_case "output_tcp_setup_success" 587 atf_add_test_case "output_udp_setup_success" 588 atf_add_test_case "output_raw_success" 589 atf_add_test_case "output_tcp_flowid_mpath_success" 590 atf_add_test_case "output_udp_flowid_mpath_success" 591 atf_add_test_case "output_raw_flowid_mpath_success" 592} 593 594