1# $FreeBSD$ 2# 3# SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 "negative_demotion" "cleanup" 276negative_demotion_head() 277{ 278 atf_set descr 'Test PR #259528' 279 atf_set require.user root 280} 281 282negative_demotion_body() 283{ 284 carp_init 285 286 epair=$(vnet_mkepair) 287 288 vnet_mkjail one ${epair}a 289 jexec one sysctl net.inet.carp.preempt=1 290 jexec one ifconfig ${epair}a 192.0.2.1/24 up 291 jexec one ifconfig ${epair}a add vhid 1 192.0.2.254/24 \ 292 advskew 0 pass foobar 293 294 vnet_mkjail two ${epair}b 295 jexec two sysctl net.inet.carp.preempt=1 296 jexec two ifconfig ${epair}b 192.0.2.2/24 up 297 jexec two ifconfig ${epair}b add vhid 1 192.0.2.254/24 \ 298 advskew 100 pass foobar 299 300 # Allow things to settle 301 wait_for_carp one ${epair}a two ${epair}b 302 303 if is_master one ${epair}a && is_master two ${epair}b 304 then 305 atf_fail "Two masters!" 306 fi 307 308 jexec one sysctl net.inet.carp.demotion=-1 309 sleep 3 310 311 if is_master one ${epair}a && is_master two ${epair}b 312 then 313 atf_fail "Two masters!" 314 fi 315} 316 317negative_demotion_cleanup() 318{ 319 vnet_cleanup 320} 321 322 323 324atf_test_case "nd6_ns_source_mac" "cleanup" 325nd6_ns_source_mac_head() 326{ 327 atf_set descr 'CARP ndp neighbor solicitation MAC source test (IPv6)' 328 atf_set require.user root 329} 330 331nd6_ns_source_mac_body() 332{ 333 carp_init 334 335 bridge=$(vnet_mkbridge) 336 epair_one=$(vnet_mkepair) 337 epair_two=$(vnet_mkepair) 338 339 vnet_mkjail carp_ndp_v6_bridge ${bridge} ${epair_one}a ${epair_two}a 340 vnet_mkjail carp_ndp_v6_master ${epair_one}b 341 vnet_mkjail carp_ndp_v6_slave ${epair_two}b 342 343 jexec carp_ndp_v6_bridge ifconfig ${bridge} inet6 2001:db8::0:4/64 up \ 344 no_dad 345 jexec carp_ndp_v6_bridge ifconfig ${bridge} addm ${epair_one}a \ 346 addm ${epair_two}a 347 jexec carp_ndp_v6_bridge ifconfig ${epair_one}a up 348 jexec carp_ndp_v6_bridge ifconfig ${epair_two}a up 349 350 jexec carp_ndp_v6_master ifconfig ${epair_one}b inet6 \ 351 2001:db8::1:2/64 up no_dad 352 jexec carp_ndp_v6_master ifconfig ${epair_one}b inet6 add vhid 1 \ 353 advskew 0 2001:db8::0:1/64 354 355 jexec carp_ndp_v6_slave ifconfig ${epair_two}b inet6 \ 356 2001:db8::1:3/64 up no_dad 357 jexec carp_ndp_v6_slave ifconfig ${epair_two}b inet6 add vhid 1 \ 358 advskew 100 2001:db8::0:1/64 359 360 wait_for_carp carp_ndp_v6_master ${epair_one}b \ 361 carp_ndp_v6_slave ${epair_two}b 362 363 # carp_ndp_v6_master is MASTER 364 365 # trigger a NS from the virtual IP from the BACKUP 366 atf_check -s exit:2 -o ignore jexec carp_ndp_v6_slave \ 367 ping -6 -c 3 -S 2001:db8::0:1 2001:db8::0:4 368 369 # trigger a NS from the virtual IP from the MASTER, 370 # this ping should work 371 atf_check -s exit:0 -o ignore jexec carp_ndp_v6_master \ 372 ping -6 -c 3 -S 2001:db8::0:1 2001:db8::0:4 373 374 # ndp entry should be for the virtual mac 375 atf_check -o match:'2001:db8::1 +00:00:5e:00:01:01' \ 376 jexec carp_ndp_v6_bridge ndp -an 377} 378 379nd6_ns_source_mac_cleanup() 380{ 381 vnet_cleanup 382} 383 384 385atf_test_case "switch" "cleanup" 386switch_head() 387{ 388 atf_set descr 'Switch between master and backup' 389 atf_set require.user root 390} 391 392switch_body() 393{ 394 carp_init 395 396 epair=$(vnet_mkepair) 397 398 ifconfig ${epair}a up 399 ifconfig ${epair}a vhid 1 advskew 100 192.0.2.1/24 400 ifconfig ${epair}a vhid 1 state backup 401 ifconfig ${epair}a vhid 1 state master 402} 403 404switch_cleanup() 405{ 406 vnet_cleanup 407} 408 409atf_init_test_cases() 410{ 411 atf_add_test_case "basic_v4" 412 atf_add_test_case "unicast_v4" 413 atf_add_test_case "basic_v6" 414 atf_add_test_case "unicast_v6" 415 atf_add_test_case "negative_demotion" 416 atf_add_test_case "nd6_ns_source_mac" 417 atf_add_test_case "switch" 418} 419