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 carp | 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 108 109atf_test_case "unicast_v4" "cleanup" 110unicast_v4_head() 111{ 112 atf_set descr 'Unicast CARP test (IPv4)' 113 atf_set require.user root 114} 115 116unicast_v4_body() 117{ 118 carp_init 119 120 bridge=$(vnet_mkbridge) 121 epair_one=$(vnet_mkepair) 122 epair_two=$(vnet_mkepair) 123 124 vnet_mkjail carp_uni_v4_one ${bridge} ${epair_one}a ${epair_two}a 125 vnet_mkjail carp_uni_v4_two ${epair_one}b 126 vnet_mkjail carp_uni_v4_three ${epair_two}b 127 128 jexec carp_uni_v4_one ifconfig ${bridge} 192.0.2.4/29 up 129 jexec carp_uni_v4_one sysctl net.inet.ip.forwarding=1 130 jexec carp_uni_v4_one ifconfig ${bridge} addm ${epair_one}a \ 131 addm ${epair_two}a 132 jexec carp_uni_v4_one ifconfig ${epair_one}a up 133 jexec carp_uni_v4_one ifconfig ${epair_two}a up 134 jexec carp_uni_v4_one ifconfig ${bridge} inet alias 198.51.100.1/25 135 jexec carp_uni_v4_one ifconfig ${bridge} inet alias 198.51.100.129/25 136 137 jexec carp_uni_v4_two ifconfig ${epair_one}b 198.51.100.2/25 up 138 jexec carp_uni_v4_two route add default 198.51.100.1 139 jexec carp_uni_v4_two ifconfig ${epair_one}b add vhid 1 \ 140 peer 198.51.100.130 192.0.2.1/29 141 142 jexec carp_uni_v4_three ifconfig ${epair_two}b 198.51.100.130/25 up 143 jexec carp_uni_v4_three route add default 198.51.100.129 144 jexec carp_uni_v4_three ifconfig ${epair_two}b add vhid 1 \ 145 peer 198.51.100.2 192.0.2.1/29 146 147 # Sanity check 148 atf_check -s exit:0 -o ignore jexec carp_uni_v4_two \ 149 ping -c 1 198.51.100.130 150 151 wait_for_carp carp_uni_v4_two ${epair_one}b \ 152 carp_uni_v4_three ${epair_two}b 153 154 atf_check -s exit:0 -o ignore jexec carp_uni_v4_one \ 155 ping -c 3 192.0.2.1 156 157 jexec carp_uni_v4_two ifconfig 158 jexec carp_uni_v4_three ifconfig 159} 160 161unicast_v4_cleanup() 162{ 163 vnet_cleanup 164} 165 166atf_test_case "basic_v6" "cleanup" 167basic_v6_head() 168{ 169 atf_set descr 'Basic CARP test (IPv6)' 170 atf_set require.user root 171} 172 173basic_v6_body() 174{ 175 carp_init 176 177 bridge=$(vnet_mkbridge) 178 epair_one=$(vnet_mkepair) 179 epair_two=$(vnet_mkepair) 180 181 vnet_mkjail carp_basic_v6_one ${bridge} ${epair_one}a ${epair_two}a 182 vnet_mkjail carp_basic_v6_two ${epair_one}b 183 vnet_mkjail carp_basic_v6_three ${epair_two}b 184 185 jexec carp_basic_v6_one ifconfig ${bridge} inet6 2001:db8::0:4/64 up \ 186 no_dad 187 jexec carp_basic_v6_one ifconfig ${bridge} addm ${epair_one}a \ 188 addm ${epair_two}a 189 jexec carp_basic_v6_one ifconfig ${epair_one}a up 190 jexec carp_basic_v6_one ifconfig ${epair_two}a up 191 192 jexec carp_basic_v6_two ifconfig ${epair_one}b inet6 \ 193 2001:db8::1:2/64 up no_dad 194 jexec carp_basic_v6_two ifconfig ${epair_one}b inet6 add vhid 1 \ 195 2001:db8::0:1/64 196 197 jexec carp_basic_v6_three ifconfig ${epair_two}b inet6 2001:db8::1:3/64 up no_dad 198 jexec carp_basic_v6_three ifconfig ${epair_two}b inet6 add vhid 1 \ 199 2001:db8::0:1/64 200 201 wait_for_carp carp_basic_v6_two ${epair_one}b \ 202 carp_basic_v6_three ${epair_two}b 203 204 atf_check -s exit:0 -o ignore jexec carp_basic_v6_one \ 205 ping -6 -c 3 2001:db8::0:1 206} 207 208basic_v6_cleanup() 209{ 210 vnet_cleanup 211} 212 213atf_test_case "unicast_v6" "cleanup" 214unicast_v6_head() 215{ 216 atf_set descr 'Unicast CARP test (IPv6)' 217 atf_set require.user root 218} 219 220unicast_v6_body() 221{ 222 carp_init 223 224 bridge=$(vnet_mkbridge) 225 epair_one=$(vnet_mkepair) 226 epair_two=$(vnet_mkepair) 227 228 vnet_mkjail carp_uni_v6_one ${bridge} ${epair_one}a ${epair_two}a 229 vnet_mkjail carp_uni_v6_two ${epair_one}b 230 vnet_mkjail carp_uni_v6_three ${epair_two}b 231 232 jexec carp_uni_v6_one sysctl net.inet6.ip6.forwarding=1 233 jexec carp_uni_v6_one ifconfig ${bridge} addm ${epair_one}a \ 234 addm ${epair_two}a 235 jexec carp_uni_v6_one ifconfig ${epair_one}a up 236 jexec carp_uni_v6_one ifconfig ${epair_two}a up 237 jexec carp_uni_v6_one ifconfig ${bridge} inet6 2001:db8::0:4/64 up \ 238 no_dad 239 jexec carp_uni_v6_one ifconfig ${bridge} inet6 alias 2001:db8:1::1/64 \ 240 no_dad up 241 jexec carp_uni_v6_one ifconfig ${bridge} inet6 alias 2001:db8:2::1/64 \ 242 no_dad up 243 244 jexec carp_uni_v6_two ifconfig ${epair_one}b inet6 2001:db8:1::2/64 \ 245 no_dad up 246 jexec carp_uni_v6_two route -6 add default 2001:db8:1::1 247 jexec carp_uni_v6_two ifconfig ${epair_one}b inet6 add vhid 1 \ 248 peer6 2001:db8:2::2 \ 249 2001:db8::0:1/64 250 251 jexec carp_uni_v6_three ifconfig ${epair_two}b inet6 2001:db8:2::2/64 \ 252 no_dad up 253 jexec carp_uni_v6_three route -6 add default 2001:db8:2::1 254 jexec carp_uni_v6_three ifconfig ${epair_two}b inet6 add vhid 1 \ 255 peer6 2001:db8:1::2 \ 256 2001:db8::0:1/64 257 258 # Sanity check 259 atf_check -s exit:0 -o ignore jexec carp_uni_v6_two \ 260 ping -6 -c 1 2001:db8:2::2 261 262 wait_for_carp carp_uni_v6_two ${epair_one}b \ 263 carp_uni_v6_three ${epair_two}b 264 265 atf_check -s exit:0 -o ignore jexec carp_uni_v6_one \ 266 ping -6 -c 3 2001:db8::0:1 267} 268 269unicast_v6_cleanup() 270{ 271 vnet_cleanup 272} 273 274atf_test_case "unicast_ll_v6" "cleanup" 275unicast_ll_v6_head() 276{ 277 atf_set descr 'Unicast CARP test (IPv6, link-local)' 278 atf_set require.user root 279} 280 281unicast_ll_v6_body() 282{ 283 carp_init 284 285 j=carp_uni_ll_v6 286 287 bridge=$(vnet_mkbridge) 288 epair_one=$(vnet_mkepair) 289 epair_two=$(vnet_mkepair) 290 291 vnet_mkjail ${j}_one ${bridge} ${epair_one}a ${epair_two}a 292 vnet_mkjail ${j}_two ${epair_one}b 293 vnet_mkjail ${j}_three ${epair_two}b 294 295 jexec ${j}_one ifconfig ${bridge} addm ${epair_one}a \ 296 addm ${epair_two}a 297 jexec ${j}_one ifconfig ${epair_one}a up 298 jexec ${j}_one ifconfig ${epair_two}a up 299 jexec ${j}_one ifconfig ${bridge} inet6 2001:db8::0:4/64 up \ 300 no_dad 301 jexec ${j}_one ifconfig ${bridge} inet6 alias 2001:db8:1::1/64 \ 302 no_dad up 303 304 jexec ${j}_two ifconfig ${epair_one}b inet6 2001:db8:1::2/64 \ 305 no_dad up 306 jexec ${j}_three ifconfig ${epair_two}b inet6 2001:db8:1::3/64 \ 307 no_dad up 308 309 ll_one=$(jexec ${j}_two ifconfig ${epair_one}b | awk "/ .*%${epair_one}b.* / { print \$2 }" | cut -d % -f 1) 310 ll_two=$(jexec ${j}_three ifconfig ${epair_two}b | awk "/ .*%${epair_two}b.* / { print \$2 }" | cut -d % -f 1) 311 312 jexec ${j}_two ifconfig ${epair_one}b inet6 add vhid 1 \ 313 peer6 ${ll_two} \ 314 2001:db8::0:1/64 315 jexec ${j}_three ifconfig ${epair_two}b inet6 add vhid 1 \ 316 peer6 ${ll_one} \ 317 2001:db8::0:1/64 318 319 # Sanity check 320 atf_check -s exit:0 -o ignore jexec ${j}_two \ 321 ping -6 -c 1 2001:db8:1::3 322 323 wait_for_carp ${j}_two ${epair_one}b \ 324 ${j}_three ${epair_two}b 325 326 atf_check -s exit:0 -o ignore jexec ${j}_one \ 327 ping -6 -c 3 2001:db8::0:1 328} 329 330unicast_ll_v6_cleanup() 331{ 332 vnet_cleanup 333} 334 335atf_test_case "negative_demotion" "cleanup" 336negative_demotion_head() 337{ 338 atf_set descr 'Test PR #259528' 339 atf_set require.user root 340} 341 342negative_demotion_body() 343{ 344 carp_init 345 346 epair=$(vnet_mkepair) 347 348 vnet_mkjail one ${epair}a 349 jexec one sysctl net.inet.carp.preempt=1 350 jexec one ifconfig ${epair}a 192.0.2.1/24 up 351 jexec one ifconfig ${epair}a add vhid 1 192.0.2.254/24 \ 352 advskew 0 pass foobar 353 354 vnet_mkjail two ${epair}b 355 jexec two sysctl net.inet.carp.preempt=1 356 jexec two ifconfig ${epair}b 192.0.2.2/24 up 357 jexec two ifconfig ${epair}b add vhid 1 192.0.2.254/24 \ 358 advskew 100 pass foobar 359 360 # Allow things to settle 361 wait_for_carp one ${epair}a two ${epair}b 362 363 if is_master one ${epair}a && is_master two ${epair}b 364 then 365 atf_fail "Two masters!" 366 fi 367 368 jexec one sysctl net.inet.carp.demotion=-1 369 sleep 3 370 371 if is_master one ${epair}a && is_master two ${epair}b 372 then 373 atf_fail "Two masters!" 374 fi 375} 376 377negative_demotion_cleanup() 378{ 379 vnet_cleanup 380} 381 382 383 384atf_test_case "nd6_ns_source_mac" "cleanup" 385nd6_ns_source_mac_head() 386{ 387 atf_set descr 'CARP ndp neighbor solicitation MAC source test (IPv6)' 388 atf_set require.user root 389} 390 391nd6_ns_source_mac_body() 392{ 393 carp_init 394 395 bridge=$(vnet_mkbridge) 396 epair_one=$(vnet_mkepair) 397 epair_two=$(vnet_mkepair) 398 399 vnet_mkjail carp_ndp_v6_bridge ${bridge} ${epair_one}a ${epair_two}a 400 vnet_mkjail carp_ndp_v6_master ${epair_one}b 401 vnet_mkjail carp_ndp_v6_slave ${epair_two}b 402 403 jexec carp_ndp_v6_bridge ifconfig ${bridge} inet6 2001:db8::0:4/64 up \ 404 no_dad 405 jexec carp_ndp_v6_bridge ifconfig ${bridge} addm ${epair_one}a \ 406 addm ${epair_two}a 407 jexec carp_ndp_v6_bridge ifconfig ${epair_one}a up 408 jexec carp_ndp_v6_bridge ifconfig ${epair_two}a up 409 410 jexec carp_ndp_v6_master ifconfig ${epair_one}b inet6 \ 411 2001:db8::1:2/64 up no_dad 412 jexec carp_ndp_v6_master ifconfig ${epair_one}b inet6 add vhid 1 \ 413 advskew 0 2001:db8::0:1/64 414 415 jexec carp_ndp_v6_slave ifconfig ${epair_two}b inet6 \ 416 2001:db8::1:3/64 up no_dad 417 jexec carp_ndp_v6_slave ifconfig ${epair_two}b inet6 add vhid 1 \ 418 advskew 100 2001:db8::0:1/64 419 420 wait_for_carp carp_ndp_v6_master ${epair_one}b \ 421 carp_ndp_v6_slave ${epair_two}b 422 423 # carp_ndp_v6_master is MASTER 424 425 # trigger a NS from the virtual IP from the BACKUP 426 atf_check -s exit:2 -o ignore jexec carp_ndp_v6_slave \ 427 ping -6 -c 3 -S 2001:db8::0:1 2001:db8::0:4 428 429 # trigger a NS from the virtual IP from the MASTER, 430 # this ping should work 431 atf_check -s exit:0 -o ignore jexec carp_ndp_v6_master \ 432 ping -6 -c 3 -S 2001:db8::0:1 2001:db8::0:4 433 434 # ndp entry should be for the virtual mac 435 atf_check -o match:'2001:db8::1 +00:00:5e:00:01:01' \ 436 jexec carp_ndp_v6_bridge ndp -an 437} 438 439nd6_ns_source_mac_cleanup() 440{ 441 vnet_cleanup 442} 443 444 445atf_test_case "switch" "cleanup" 446switch_head() 447{ 448 atf_set descr 'Switch between master and backup' 449 atf_set require.user root 450} 451 452switch_body() 453{ 454 carp_init 455 456 epair=$(vnet_mkepair) 457 458 ifconfig ${epair}a up 459 ifconfig ${epair}a vhid 1 advskew 100 192.0.2.1/24 460 ifconfig ${epair}a vhid 1 state backup 461 ifconfig ${epair}a vhid 1 state master 462} 463 464switch_cleanup() 465{ 466 vnet_cleanup 467} 468 469atf_init_test_cases() 470{ 471 atf_add_test_case "basic_v4" 472 atf_add_test_case "unicast_v4" 473 atf_add_test_case "basic_v6" 474 atf_add_test_case "unicast_v6" 475 atf_add_test_case "unicast_ll_v6" 476 atf_add_test_case "negative_demotion" 477 atf_add_test_case "nd6_ns_source_mac" 478 atf_add_test_case "switch" 479} 480