1# 2# SPDX-License-Identifier: BSD-2-Clause 3# 4# Copyright (c) 2020 Kristof Provost <kp@FreeBSD.org> 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions 8# are met: 9# 1. Redistributions of source code must retain the above copyright 10# notice, this list of conditions and the following disclaimer. 11# 2. Redistributions in binary form must reproduce the above copyright 12# notice, this list of conditions and the following disclaimer in the 13# documentation and/or other materials provided with the distribution. 14# 15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25# SUCH DAMAGE. 26 27. $(atf_get_srcdir)/../common/vnet.subr 28 29is_master() 30{ 31 jail=$1 32 itf=$2 33 34 jexec ${jail} ifconfig ${itf} | grep -E '(carp|vrrp)' | grep MASTER 35} 36 37wait_for_carp() 38{ 39 jail1=$1 40 itf1=$2 41 jail2=$3 42 itf2=$4 43 44 while [ -z "$(is_master ${jail1} ${itf1})" ] && 45 [ -z "$(is_master ${jail2} ${itf2})" ]; do 46 sleep 1 47 done 48 49 if [ -n "$(is_master ${jail1} ${itf1})" ] && 50 [ -n "$(is_master ${jail2} ${itf2})" ]; then 51 atf_fail "Both jails are master" 52 fi 53} 54 55carp_init() 56{ 57 if ! kldstat -q -m carp; then 58 atf_skip "This test requires carp" 59 fi 60 61 vnet_init 62} 63 64atf_test_case "basic_v4" "cleanup" 65basic_v4_head() 66{ 67 atf_set descr 'Basic CARP test (IPv4)' 68 atf_set require.user root 69} 70 71basic_v4_body() 72{ 73 carp_init 74 75 bridge=$(vnet_mkbridge) 76 epair_one=$(vnet_mkepair) 77 epair_two=$(vnet_mkepair) 78 79 vnet_mkjail carp_basic_v4_one ${bridge} ${epair_one}a ${epair_two}a 80 vnet_mkjail carp_basic_v4_two ${epair_one}b 81 vnet_mkjail carp_basic_v4_three ${epair_two}b 82 83 jexec carp_basic_v4_one ifconfig ${bridge} 192.0.2.4/29 up 84 jexec carp_basic_v4_one ifconfig ${bridge} addm ${epair_one}a \ 85 addm ${epair_two}a 86 jexec carp_basic_v4_one ifconfig ${epair_one}a up 87 jexec carp_basic_v4_one ifconfig ${epair_two}a up 88 89 jexec carp_basic_v4_two ifconfig ${epair_one}b 192.0.2.202/29 up 90 jexec carp_basic_v4_two ifconfig ${epair_one}b add vhid 1 192.0.2.1/29 91 92 jexec carp_basic_v4_three ifconfig ${epair_two}b 192.0.2.203/29 up 93 jexec carp_basic_v4_three ifconfig ${epair_two}b add vhid 1 \ 94 192.0.2.1/29 95 96 wait_for_carp carp_basic_v4_two ${epair_one}b \ 97 carp_basic_v4_three ${epair_two}b 98 99 atf_check -s exit:0 -o ignore jexec carp_basic_v4_one \ 100 ping -c 3 192.0.2.1 101} 102 103basic_v4_cleanup() 104{ 105 vnet_cleanup 106} 107 108atf_test_case "vrrp_v4" "cleanup" 109vrrp_v4_head() 110{ 111 atf_set descr 'Basic VRRP test (IPv4)' 112 atf_set require.user root 113} 114 115vrrp_v4_body() 116{ 117 carp_init 118 119 j=vrrp_basic_v4 120 121 bridge=$(vnet_mkbridge) 122 epair_one=$(vnet_mkepair) 123 epair_two=$(vnet_mkepair) 124 125 vnet_mkjail ${j}_one ${bridge} ${epair_one}a ${epair_two}a 126 vnet_mkjail ${j}_two ${epair_one}b 127 vnet_mkjail ${j}_three ${epair_two}b 128 129 jexec ${j}_one ifconfig ${bridge} 192.0.2.4/29 up 130 jexec ${j}_one ifconfig ${bridge} addm ${epair_one}a \ 131 addm ${epair_two}a 132 jexec ${j}_one ifconfig ${epair_one}a up 133 jexec ${j}_one ifconfig ${epair_two}a up 134 135 jexec ${j}_two ifconfig ${epair_one}b 192.0.2.202/29 up 136 jexec ${j}_two ifconfig ${epair_one}b add vhid 1 carpver 3 192.0.2.1/29 137 138 jexec ${j}_three ifconfig ${epair_two}b 192.0.2.203/29 up 139 jexec ${j}_three ifconfig ${epair_two}b add vhid 1 carpver 3 \ 140 192.0.2.1/29 141 142 wait_for_carp ${j}_two ${epair_one}b \ 143 ${j}_three ${epair_two}b 144 145 atf_check -s exit:0 -o ignore jexec ${j}_one \ 146 ping -c 3 192.0.2.1 147} 148 149vrrp_v4_cleanup() 150{ 151 vnet_cleanup 152} 153 154atf_test_case "unicast_v4" "cleanup" 155unicast_v4_head() 156{ 157 atf_set descr 'Unicast CARP test (IPv4)' 158 atf_set require.user root 159} 160 161unicast_v4_body() 162{ 163 carp_init 164 165 bridge=$(vnet_mkbridge) 166 epair_one=$(vnet_mkepair) 167 epair_two=$(vnet_mkepair) 168 169 vnet_mkjail carp_uni_v4_one ${bridge} ${epair_one}a ${epair_two}a 170 vnet_mkjail carp_uni_v4_two ${epair_one}b 171 vnet_mkjail carp_uni_v4_three ${epair_two}b 172 173 jexec carp_uni_v4_one ifconfig ${bridge} 192.0.2.4/29 up 174 jexec carp_uni_v4_one sysctl net.inet.ip.forwarding=1 175 jexec carp_uni_v4_one ifconfig ${bridge} addm ${epair_one}a \ 176 addm ${epair_two}a 177 jexec carp_uni_v4_one ifconfig ${epair_one}a up 178 jexec carp_uni_v4_one ifconfig ${epair_two}a up 179 jexec carp_uni_v4_one ifconfig ${bridge} inet alias 198.51.100.1/25 180 jexec carp_uni_v4_one ifconfig ${bridge} inet alias 198.51.100.129/25 181 182 jexec carp_uni_v4_two ifconfig ${epair_one}b 198.51.100.2/25 up 183 jexec carp_uni_v4_two route add default 198.51.100.1 184 jexec carp_uni_v4_two ifconfig ${epair_one}b add vhid 1 \ 185 peer 198.51.100.130 192.0.2.1/29 186 187 jexec carp_uni_v4_three ifconfig ${epair_two}b 198.51.100.130/25 up 188 jexec carp_uni_v4_three route add default 198.51.100.129 189 jexec carp_uni_v4_three ifconfig ${epair_two}b add vhid 1 \ 190 peer 198.51.100.2 192.0.2.1/29 191 192 # Sanity check 193 atf_check -s exit:0 -o ignore jexec carp_uni_v4_two \ 194 ping -c 1 198.51.100.130 195 196 wait_for_carp carp_uni_v4_two ${epair_one}b \ 197 carp_uni_v4_three ${epair_two}b 198 199 atf_check -s exit:0 -o ignore jexec carp_uni_v4_one \ 200 ping -c 3 192.0.2.1 201 202 jexec carp_uni_v4_two ifconfig 203 jexec carp_uni_v4_three ifconfig 204} 205 206unicast_v4_cleanup() 207{ 208 vnet_cleanup 209} 210 211atf_test_case "basic_v6" "cleanup" 212basic_v6_head() 213{ 214 atf_set descr 'Basic CARP test (IPv6)' 215 atf_set require.user root 216} 217 218basic_v6_body() 219{ 220 carp_init 221 222 bridge=$(vnet_mkbridge) 223 epair_one=$(vnet_mkepair) 224 epair_two=$(vnet_mkepair) 225 226 vnet_mkjail carp_basic_v6_one ${bridge} ${epair_one}a ${epair_two}a 227 vnet_mkjail carp_basic_v6_two ${epair_one}b 228 vnet_mkjail carp_basic_v6_three ${epair_two}b 229 230 jexec carp_basic_v6_one ifconfig ${bridge} inet6 2001:db8::0:4/64 up \ 231 no_dad 232 jexec carp_basic_v6_one ifconfig ${bridge} addm ${epair_one}a \ 233 addm ${epair_two}a 234 jexec carp_basic_v6_one ifconfig ${epair_one}a up 235 jexec carp_basic_v6_one ifconfig ${epair_two}a up 236 237 jexec carp_basic_v6_two ifconfig ${epair_one}b inet6 \ 238 2001:db8::1:2/64 up no_dad 239 jexec carp_basic_v6_two ifconfig ${epair_one}b inet6 add vhid 1 \ 240 2001:db8::0:1/64 241 242 jexec carp_basic_v6_three ifconfig ${epair_two}b inet6 2001:db8::1:3/64 up no_dad 243 jexec carp_basic_v6_three ifconfig ${epair_two}b inet6 add vhid 1 \ 244 2001:db8::0:1/64 245 246 wait_for_carp carp_basic_v6_two ${epair_one}b \ 247 carp_basic_v6_three ${epair_two}b 248 249 atf_check -s exit:0 -o ignore jexec carp_basic_v6_one \ 250 ping -6 -c 3 2001:db8::0:1 251} 252 253basic_v6_cleanup() 254{ 255 vnet_cleanup 256} 257 258atf_test_case "vrrp_v6" "cleanup" 259vrrp_v6_head() 260{ 261 atf_set descr 'Basic VRRP test (IPv6)' 262 atf_set require.user root 263} 264 265vrrp_v6_body() 266{ 267 carp_init 268 269 j=carp_basic_v6 270 271 bridge=$(vnet_mkbridge) 272 epair_one=$(vnet_mkepair) 273 epair_two=$(vnet_mkepair) 274 275 vnet_mkjail ${j}_one ${bridge} ${epair_one}a ${epair_two}a 276 vnet_mkjail ${j}_two ${epair_one}b 277 vnet_mkjail ${j}_three ${epair_two}b 278 279 jexec ${j}_one ifconfig ${bridge} inet6 2001:db8::0:4/64 up \ 280 no_dad 281 jexec ${j}_one ifconfig ${bridge} addm ${epair_one}a \ 282 addm ${epair_two}a 283 jexec ${j}_one ifconfig ${epair_one}a up 284 jexec ${j}_one ifconfig ${epair_two}a up 285 286 jexec ${j}_two ifconfig ${epair_one}b inet6 \ 287 2001:db8::1:2/64 up no_dad 288 jexec ${j}_two ifconfig ${epair_one}b inet6 add vhid 1 carpver 3 \ 289 2001:db8::0:1/64 290 291 jexec ${j}_three ifconfig ${epair_two}b inet6 2001:db8::1:3/64 up no_dad 292 jexec ${j}_three ifconfig ${epair_two}b inet6 add vhid 1 carpver 3 \ 293 2001:db8::0:1/64 294 295 wait_for_carp ${j}_two ${epair_one}b \ 296 ${j}_three ${epair_two}b 297 298 atf_check -s exit:0 -o ignore jexec ${j}_one \ 299 ping -6 -c 3 2001:db8::0:1 300} 301 302vrrp_v6_cleanup() 303{ 304 vnet_cleanup 305} 306 307atf_test_case "unicast_v6" "cleanup" 308unicast_v6_head() 309{ 310 atf_set descr 'Unicast CARP test (IPv6)' 311 atf_set require.user root 312} 313 314unicast_v6_body() 315{ 316 carp_init 317 318 bridge=$(vnet_mkbridge) 319 epair_one=$(vnet_mkepair) 320 epair_two=$(vnet_mkepair) 321 322 vnet_mkjail carp_uni_v6_one ${bridge} ${epair_one}a ${epair_two}a 323 vnet_mkjail carp_uni_v6_two ${epair_one}b 324 vnet_mkjail carp_uni_v6_three ${epair_two}b 325 326 jexec carp_uni_v6_one sysctl net.inet6.ip6.forwarding=1 327 jexec carp_uni_v6_one ifconfig ${bridge} addm ${epair_one}a \ 328 addm ${epair_two}a 329 jexec carp_uni_v6_one ifconfig ${epair_one}a up 330 jexec carp_uni_v6_one ifconfig ${epair_two}a up 331 jexec carp_uni_v6_one ifconfig ${bridge} inet6 2001:db8::0:4/64 up \ 332 no_dad 333 jexec carp_uni_v6_one ifconfig ${bridge} inet6 alias 2001:db8:1::1/64 \ 334 no_dad up 335 jexec carp_uni_v6_one ifconfig ${bridge} inet6 alias 2001:db8:2::1/64 \ 336 no_dad up 337 338 jexec carp_uni_v6_two ifconfig ${epair_one}b inet6 2001:db8:1::2/64 \ 339 no_dad up 340 jexec carp_uni_v6_two route -6 add default 2001:db8:1::1 341 jexec carp_uni_v6_two ifconfig ${epair_one}b inet6 add vhid 1 \ 342 peer6 2001:db8:2::2 \ 343 2001:db8::0:1/64 344 345 jexec carp_uni_v6_three ifconfig ${epair_two}b inet6 2001:db8:2::2/64 \ 346 no_dad up 347 jexec carp_uni_v6_three route -6 add default 2001:db8:2::1 348 jexec carp_uni_v6_three ifconfig ${epair_two}b inet6 add vhid 1 \ 349 peer6 2001:db8:1::2 \ 350 2001:db8::0:1/64 351 352 # Sanity check 353 atf_check -s exit:0 -o ignore jexec carp_uni_v6_two \ 354 ping -6 -c 1 2001:db8:2::2 355 356 wait_for_carp carp_uni_v6_two ${epair_one}b \ 357 carp_uni_v6_three ${epair_two}b 358 359 atf_check -s exit:0 -o ignore jexec carp_uni_v6_one \ 360 ping -6 -c 3 2001:db8::0:1 361} 362 363unicast_v6_cleanup() 364{ 365 vnet_cleanup 366} 367 368atf_test_case "unicast_ll_v6" "cleanup" 369unicast_ll_v6_head() 370{ 371 atf_set descr 'Unicast CARP test (IPv6, link-local)' 372 atf_set require.user root 373} 374 375unicast_ll_v6_body() 376{ 377 carp_init 378 379 j=carp_uni_ll_v6 380 381 bridge=$(vnet_mkbridge) 382 epair_one=$(vnet_mkepair) 383 epair_two=$(vnet_mkepair) 384 385 vnet_mkjail ${j}_one ${bridge} ${epair_one}a ${epair_two}a 386 vnet_mkjail ${j}_two ${epair_one}b 387 vnet_mkjail ${j}_three ${epair_two}b 388 389 jexec ${j}_one ifconfig ${bridge} addm ${epair_one}a \ 390 addm ${epair_two}a 391 jexec ${j}_one ifconfig ${epair_one}a up 392 jexec ${j}_one ifconfig ${epair_two}a up 393 jexec ${j}_one ifconfig ${bridge} inet6 2001:db8::0:4/64 up \ 394 no_dad 395 jexec ${j}_one ifconfig ${bridge} inet6 alias 2001:db8:1::1/64 \ 396 no_dad up 397 398 jexec ${j}_two ifconfig ${epair_one}b inet6 2001:db8:1::2/64 \ 399 no_dad up 400 jexec ${j}_three ifconfig ${epair_two}b inet6 2001:db8:1::3/64 \ 401 no_dad up 402 403 ll_one=$(jexec ${j}_two ifconfig ${epair_one}b | awk "/ .*%${epair_one}b.* / { print \$2 }" | cut -d % -f 1) 404 ll_two=$(jexec ${j}_three ifconfig ${epair_two}b | awk "/ .*%${epair_two}b.* / { print \$2 }" | cut -d % -f 1) 405 406 jexec ${j}_two ifconfig ${epair_one}b inet6 add vhid 1 \ 407 peer6 ${ll_two} \ 408 2001:db8::0:1/64 409 jexec ${j}_three ifconfig ${epair_two}b inet6 add vhid 1 \ 410 peer6 ${ll_one} \ 411 2001:db8::0:1/64 412 413 # Sanity check 414 atf_check -s exit:0 -o ignore jexec ${j}_two \ 415 ping -6 -c 1 2001:db8:1::3 416 417 wait_for_carp ${j}_two ${epair_one}b \ 418 ${j}_three ${epair_two}b 419 420 atf_check -s exit:0 -o ignore jexec ${j}_one \ 421 ping -6 -c 3 2001:db8::0:1 422} 423 424unicast_ll_v6_cleanup() 425{ 426 vnet_cleanup 427} 428 429atf_test_case "negative_demotion" "cleanup" 430negative_demotion_head() 431{ 432 atf_set descr 'Test PR #259528' 433 atf_set require.user root 434} 435 436negative_demotion_body() 437{ 438 carp_init 439 440 epair=$(vnet_mkepair) 441 442 vnet_mkjail one ${epair}a 443 jexec one sysctl net.inet.carp.preempt=1 444 jexec one ifconfig ${epair}a 192.0.2.1/24 up 445 jexec one ifconfig ${epair}a add vhid 1 192.0.2.254/24 \ 446 advskew 0 pass foobar 447 448 vnet_mkjail two ${epair}b 449 jexec two sysctl net.inet.carp.preempt=1 450 jexec two ifconfig ${epair}b 192.0.2.2/24 up 451 jexec two ifconfig ${epair}b add vhid 1 192.0.2.254/24 \ 452 advskew 100 pass foobar 453 454 # Allow things to settle 455 wait_for_carp one ${epair}a two ${epair}b 456 457 if is_master one ${epair}a && is_master two ${epair}b 458 then 459 atf_fail "Two masters!" 460 fi 461 462 jexec one sysctl net.inet.carp.demotion=-1 463 sleep 3 464 465 if is_master one ${epair}a && is_master two ${epair}b 466 then 467 atf_fail "Two masters!" 468 fi 469} 470 471negative_demotion_cleanup() 472{ 473 vnet_cleanup 474} 475 476 477 478atf_test_case "nd6_ns_source_mac" "cleanup" 479nd6_ns_source_mac_head() 480{ 481 atf_set descr 'CARP ndp neighbor solicitation MAC source test (IPv6)' 482 atf_set require.user root 483} 484 485nd6_ns_source_mac_body() 486{ 487 carp_init 488 489 bridge=$(vnet_mkbridge) 490 epair_one=$(vnet_mkepair) 491 epair_two=$(vnet_mkepair) 492 493 vnet_mkjail carp_ndp_v6_bridge ${bridge} ${epair_one}a ${epair_two}a 494 vnet_mkjail carp_ndp_v6_master ${epair_one}b 495 vnet_mkjail carp_ndp_v6_slave ${epair_two}b 496 497 jexec carp_ndp_v6_bridge ifconfig ${bridge} inet6 2001:db8::0:4/64 up \ 498 no_dad 499 jexec carp_ndp_v6_bridge ifconfig ${bridge} addm ${epair_one}a \ 500 addm ${epair_two}a 501 jexec carp_ndp_v6_bridge ifconfig ${epair_one}a up 502 jexec carp_ndp_v6_bridge ifconfig ${epair_two}a up 503 504 jexec carp_ndp_v6_master ifconfig ${epair_one}b inet6 \ 505 2001:db8::1:2/64 up no_dad 506 jexec carp_ndp_v6_master ifconfig ${epair_one}b inet6 add vhid 1 \ 507 advskew 0 2001:db8::0:1/64 508 509 jexec carp_ndp_v6_slave ifconfig ${epair_two}b inet6 \ 510 2001:db8::1:3/64 up no_dad 511 jexec carp_ndp_v6_slave ifconfig ${epair_two}b inet6 add vhid 1 \ 512 advskew 100 2001:db8::0:1/64 513 514 wait_for_carp carp_ndp_v6_master ${epair_one}b \ 515 carp_ndp_v6_slave ${epair_two}b 516 517 # carp_ndp_v6_master is MASTER 518 519 # trigger a NS from the virtual IP from the BACKUP 520 atf_check -s exit:2 -o ignore jexec carp_ndp_v6_slave \ 521 ping -6 -c 3 -S 2001:db8::0:1 2001:db8::0:4 522 523 # trigger a NS from the virtual IP from the MASTER, 524 # this ping should work 525 atf_check -s exit:0 -o ignore jexec carp_ndp_v6_master \ 526 ping -6 -c 3 -S 2001:db8::0:1 2001:db8::0:4 527 528 # ndp entry should be for the virtual mac 529 atf_check -o match:'2001:db8::1 +00:00:5e:00:01:01' \ 530 jexec carp_ndp_v6_bridge ndp -an 531} 532 533nd6_ns_source_mac_cleanup() 534{ 535 vnet_cleanup 536} 537 538 539atf_test_case "switch" "cleanup" 540switch_head() 541{ 542 atf_set descr 'Switch between master and backup' 543 atf_set require.user root 544} 545 546switch_body() 547{ 548 carp_init 549 550 epair=$(vnet_mkepair) 551 552 ifconfig ${epair}a up 553 ifconfig ${epair}a vhid 1 advskew 100 192.0.2.1/24 554 ifconfig ${epair}a vhid 1 state backup 555 ifconfig ${epair}a vhid 1 state master 556} 557 558switch_cleanup() 559{ 560 vnet_cleanup 561} 562 563atf_init_test_cases() 564{ 565 atf_add_test_case "basic_v4" 566 atf_add_test_case "vrrp_v4" 567 atf_add_test_case "unicast_v4" 568 atf_add_test_case "basic_v6" 569 atf_add_test_case "vrrp_v6" 570 atf_add_test_case "unicast_v6" 571 atf_add_test_case "unicast_ll_v6" 572 atf_add_test_case "negative_demotion" 573 atf_add_test_case "nd6_ns_source_mac" 574 atf_add_test_case "switch" 575} 576