1# $FreeBSD$ 2# 3# SPDX-License-Identifier: BSD-2-Clause 4# 5# Copyright (c) 2020 Kristof Provost <kp@FreeBSD.org> 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. $(atf_get_srcdir)/../common/vnet.subr 29 30is_master() 31{ 32 jail=$1 33 itf=$2 34 35 jexec ${jail} ifconfig ${itf} | grep carp | grep MASTER 36} 37 38wait_for_carp() 39{ 40 jail1=$1 41 itf1=$2 42 jail2=$3 43 itf2=$4 44 45 while [ -z "$(is_master ${jail1} ${itf1})" ] && 46 [ -z "$(is_master ${jail2} ${itf2})" ]; do 47 sleep 1 48 done 49 50 if [ -n "$(is_master ${jail1} ${itf1})" ] && 51 [ -n "$(is_master ${jail2} ${itf2})" ]; then 52 atf_fail "Both jails are master" 53 fi 54} 55 56carp_init() 57{ 58 if ! kldstat -q -m carp; then 59 atf_skip "This test requires carp" 60 fi 61 62 vnet_init 63} 64 65atf_test_case "basic_v4" "cleanup" 66basic_v4_head() 67{ 68 atf_set descr 'Basic CARP test (IPv4)' 69 atf_set require.user root 70} 71 72basic_v4_body() 73{ 74 carp_init 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 109 110atf_test_case "unicast_v4" "cleanup" 111unicast_v4_head() 112{ 113 atf_set descr 'Unicast CARP test (IPv4)' 114 atf_set require.user root 115} 116 117unicast_v4_body() 118{ 119 carp_init 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 178 bridge=$(vnet_mkbridge) 179 epair_one=$(vnet_mkepair) 180 epair_two=$(vnet_mkepair) 181 182 vnet_mkjail carp_basic_v6_one ${bridge} ${epair_one}a ${epair_two}a 183 vnet_mkjail carp_basic_v6_two ${epair_one}b 184 vnet_mkjail carp_basic_v6_three ${epair_two}b 185 186 jexec carp_basic_v6_one ifconfig ${bridge} inet6 2001:db8::0:4/64 up \ 187 no_dad 188 jexec carp_basic_v6_one ifconfig ${bridge} addm ${epair_one}a \ 189 addm ${epair_two}a 190 jexec carp_basic_v6_one ifconfig ${epair_one}a up 191 jexec carp_basic_v6_one ifconfig ${epair_two}a up 192 193 jexec carp_basic_v6_two ifconfig ${epair_one}b inet6 \ 194 2001:db8::1:2/64 up no_dad 195 jexec carp_basic_v6_two ifconfig ${epair_one}b inet6 add vhid 1 \ 196 2001:db8::0:1/64 197 198 jexec carp_basic_v6_three ifconfig ${epair_two}b inet6 2001:db8::1:3/64 up no_dad 199 jexec carp_basic_v6_three ifconfig ${epair_two}b inet6 add vhid 1 \ 200 2001:db8::0:1/64 201 202 wait_for_carp carp_basic_v6_two ${epair_one}b \ 203 carp_basic_v6_three ${epair_two}b 204 205 atf_check -s exit:0 -o ignore jexec carp_basic_v6_one \ 206 ping -6 -c 3 2001:db8::0:1 207} 208 209basic_v6_cleanup() 210{ 211 vnet_cleanup 212} 213 214atf_test_case "unicast_v6" "cleanup" 215unicast_v6_head() 216{ 217 atf_set descr 'Unicast CARP test (IPv6)' 218 atf_set require.user root 219} 220 221unicast_v6_body() 222{ 223 carp_init 224 225 bridge=$(vnet_mkbridge) 226 epair_one=$(vnet_mkepair) 227 epair_two=$(vnet_mkepair) 228 229 vnet_mkjail carp_uni_v6_one ${bridge} ${epair_one}a ${epair_two}a 230 vnet_mkjail carp_uni_v6_two ${epair_one}b 231 vnet_mkjail carp_uni_v6_three ${epair_two}b 232 233 jexec carp_uni_v6_one sysctl net.inet6.ip6.forwarding=1 234 jexec carp_uni_v6_one ifconfig ${bridge} addm ${epair_one}a \ 235 addm ${epair_two}a 236 jexec carp_uni_v6_one ifconfig ${epair_one}a up 237 jexec carp_uni_v6_one ifconfig ${epair_two}a up 238 jexec carp_uni_v6_one ifconfig ${bridge} inet6 2001:db8::0:4/64 up \ 239 no_dad 240 jexec carp_uni_v6_one ifconfig ${bridge} inet6 alias 2001:db8:1::1/64 \ 241 no_dad up 242 jexec carp_uni_v6_one ifconfig ${bridge} inet6 alias 2001:db8:2::1/64 \ 243 no_dad up 244 245 jexec carp_uni_v6_two ifconfig ${epair_one}b inet6 2001:db8:1::2/64 \ 246 no_dad up 247 jexec carp_uni_v6_two route -6 add default 2001:db8:1::1 248 jexec carp_uni_v6_two ifconfig ${epair_one}b inet6 add vhid 1 \ 249 peer6 2001:db8:2::2 \ 250 2001:db8::0:1/64 251 252 jexec carp_uni_v6_three ifconfig ${epair_two}b inet6 2001:db8:2::2/64 \ 253 no_dad up 254 jexec carp_uni_v6_three route -6 add default 2001:db8:2::1 255 jexec carp_uni_v6_three ifconfig ${epair_two}b inet6 add vhid 1 \ 256 peer6 2001:db8:1::2 \ 257 2001:db8::0:1/64 258 259 # Sanity check 260 atf_check -s exit:0 -o ignore jexec carp_uni_v6_two \ 261 ping -6 -c 1 2001:db8:2::2 262 263 wait_for_carp carp_uni_v6_two ${epair_one}b \ 264 carp_uni_v6_three ${epair_two}b 265 266 atf_check -s exit:0 -o ignore jexec carp_uni_v6_one \ 267 ping -6 -c 3 2001:db8::0:1 268} 269 270unicast_v6_cleanup() 271{ 272 vnet_cleanup 273} 274 275atf_test_case "unicast_ll_v6" "cleanup" 276unicast_ll_v6_head() 277{ 278 atf_set descr 'Unicast CARP test (IPv6, link-local)' 279 atf_set require.user root 280} 281 282unicast_ll_v6_body() 283{ 284 carp_init 285 286 j=carp_uni_ll_v6 287 288 bridge=$(vnet_mkbridge) 289 epair_one=$(vnet_mkepair) 290 epair_two=$(vnet_mkepair) 291 292 vnet_mkjail ${j}_one ${bridge} ${epair_one}a ${epair_two}a 293 vnet_mkjail ${j}_two ${epair_one}b 294 vnet_mkjail ${j}_three ${epair_two}b 295 296 jexec ${j}_one ifconfig ${bridge} addm ${epair_one}a \ 297 addm ${epair_two}a 298 jexec ${j}_one ifconfig ${epair_one}a up 299 jexec ${j}_one ifconfig ${epair_two}a up 300 jexec ${j}_one ifconfig ${bridge} inet6 2001:db8::0:4/64 up \ 301 no_dad 302 jexec ${j}_one ifconfig ${bridge} inet6 alias 2001:db8:1::1/64 \ 303 no_dad up 304 305 jexec ${j}_two ifconfig ${epair_one}b inet6 2001:db8:1::2/64 \ 306 no_dad up 307 jexec ${j}_three ifconfig ${epair_two}b inet6 2001:db8:1::3/64 \ 308 no_dad up 309 310 ll_one=$(jexec ${j}_two ifconfig ${epair_one}b | awk "/ .*%${epair_one}b.* / { print \$2 }" | cut -d % -f 1) 311 ll_two=$(jexec ${j}_three ifconfig ${epair_two}b | awk "/ .*%${epair_two}b.* / { print \$2 }" | cut -d % -f 1) 312 313 jexec ${j}_two ifconfig ${epair_one}b inet6 add vhid 1 \ 314 peer6 ${ll_two} \ 315 2001:db8::0:1/64 316 jexec ${j}_three ifconfig ${epair_two}b inet6 add vhid 1 \ 317 peer6 ${ll_one} \ 318 2001:db8::0:1/64 319 320 # Sanity check 321 atf_check -s exit:0 -o ignore jexec ${j}_two \ 322 ping -6 -c 1 2001:db8:1::3 323 324 wait_for_carp ${j}_two ${epair_one}b \ 325 ${j}_three ${epair_two}b 326 327 atf_check -s exit:0 -o ignore jexec ${j}_one \ 328 ping -6 -c 3 2001:db8::0:1 329} 330 331unicast_ll_v6_cleanup() 332{ 333 vnet_cleanup 334} 335 336atf_test_case "negative_demotion" "cleanup" 337negative_demotion_head() 338{ 339 atf_set descr 'Test PR #259528' 340 atf_set require.user root 341} 342 343negative_demotion_body() 344{ 345 carp_init 346 347 epair=$(vnet_mkepair) 348 349 vnet_mkjail one ${epair}a 350 jexec one sysctl net.inet.carp.preempt=1 351 jexec one ifconfig ${epair}a 192.0.2.1/24 up 352 jexec one ifconfig ${epair}a add vhid 1 192.0.2.254/24 \ 353 advskew 0 pass foobar 354 355 vnet_mkjail two ${epair}b 356 jexec two sysctl net.inet.carp.preempt=1 357 jexec two ifconfig ${epair}b 192.0.2.2/24 up 358 jexec two ifconfig ${epair}b add vhid 1 192.0.2.254/24 \ 359 advskew 100 pass foobar 360 361 # Allow things to settle 362 wait_for_carp one ${epair}a two ${epair}b 363 364 if is_master one ${epair}a && is_master two ${epair}b 365 then 366 atf_fail "Two masters!" 367 fi 368 369 jexec one sysctl net.inet.carp.demotion=-1 370 sleep 3 371 372 if is_master one ${epair}a && is_master two ${epair}b 373 then 374 atf_fail "Two masters!" 375 fi 376} 377 378negative_demotion_cleanup() 379{ 380 vnet_cleanup 381} 382 383 384 385atf_test_case "nd6_ns_source_mac" "cleanup" 386nd6_ns_source_mac_head() 387{ 388 atf_set descr 'CARP ndp neighbor solicitation MAC source test (IPv6)' 389 atf_set require.user root 390} 391 392nd6_ns_source_mac_body() 393{ 394 carp_init 395 396 bridge=$(vnet_mkbridge) 397 epair_one=$(vnet_mkepair) 398 epair_two=$(vnet_mkepair) 399 400 vnet_mkjail carp_ndp_v6_bridge ${bridge} ${epair_one}a ${epair_two}a 401 vnet_mkjail carp_ndp_v6_master ${epair_one}b 402 vnet_mkjail carp_ndp_v6_slave ${epair_two}b 403 404 jexec carp_ndp_v6_bridge ifconfig ${bridge} inet6 2001:db8::0:4/64 up \ 405 no_dad 406 jexec carp_ndp_v6_bridge ifconfig ${bridge} addm ${epair_one}a \ 407 addm ${epair_two}a 408 jexec carp_ndp_v6_bridge ifconfig ${epair_one}a up 409 jexec carp_ndp_v6_bridge ifconfig ${epair_two}a up 410 411 jexec carp_ndp_v6_master ifconfig ${epair_one}b inet6 \ 412 2001:db8::1:2/64 up no_dad 413 jexec carp_ndp_v6_master ifconfig ${epair_one}b inet6 add vhid 1 \ 414 advskew 0 2001:db8::0:1/64 415 416 jexec carp_ndp_v6_slave ifconfig ${epair_two}b inet6 \ 417 2001:db8::1:3/64 up no_dad 418 jexec carp_ndp_v6_slave ifconfig ${epair_two}b inet6 add vhid 1 \ 419 advskew 100 2001:db8::0:1/64 420 421 wait_for_carp carp_ndp_v6_master ${epair_one}b \ 422 carp_ndp_v6_slave ${epair_two}b 423 424 # carp_ndp_v6_master is MASTER 425 426 # trigger a NS from the virtual IP from the BACKUP 427 atf_check -s exit:2 -o ignore jexec carp_ndp_v6_slave \ 428 ping -6 -c 3 -S 2001:db8::0:1 2001:db8::0:4 429 430 # trigger a NS from the virtual IP from the MASTER, 431 # this ping should work 432 atf_check -s exit:0 -o ignore jexec carp_ndp_v6_master \ 433 ping -6 -c 3 -S 2001:db8::0:1 2001:db8::0:4 434 435 # ndp entry should be for the virtual mac 436 atf_check -o match:'2001:db8::1 +00:00:5e:00:01:01' \ 437 jexec carp_ndp_v6_bridge ndp -an 438} 439 440nd6_ns_source_mac_cleanup() 441{ 442 vnet_cleanup 443} 444 445 446atf_test_case "switch" "cleanup" 447switch_head() 448{ 449 atf_set descr 'Switch between master and backup' 450 atf_set require.user root 451} 452 453switch_body() 454{ 455 carp_init 456 457 epair=$(vnet_mkepair) 458 459 ifconfig ${epair}a up 460 ifconfig ${epair}a vhid 1 advskew 100 192.0.2.1/24 461 ifconfig ${epair}a vhid 1 state backup 462 ifconfig ${epair}a vhid 1 state master 463} 464 465switch_cleanup() 466{ 467 vnet_cleanup 468} 469 470atf_init_test_cases() 471{ 472 atf_add_test_case "basic_v4" 473 atf_add_test_case "unicast_v4" 474 atf_add_test_case "basic_v6" 475 atf_add_test_case "unicast_v6" 476 atf_add_test_case "unicast_ll_v6" 477 atf_add_test_case "negative_demotion" 478 atf_add_test_case "nd6_ns_source_mac" 479 atf_add_test_case "switch" 480} 481