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