1# 2# Copyright (c) 2014 Spectra Logic Corporation 3# All rights reserved. 4# 5# Redistribution and use in source and binary forms, with or without 6# modification, are permitted provided that the following conditions 7# are met: 8# 1. Redistributions of source code must retain the above copyright 9# notice, this list of conditions, and the following disclaimer, 10# without modification. 11# 2. Redistributions in binary form must reproduce at minimum a disclaimer 12# substantially similar to the "NO WARRANTY" disclaimer below 13# ("Disclaimer") and any redistribution must be conditioned upon 14# including a substantially similar Disclaimer requirement for further 15# binary redistribution. 16# 17# NO WARRANTY 18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 21# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22# HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28# POSSIBILITY OF SUCH DAMAGES. 29# 30# Authors: Alan Somers (Spectra Logic Corporation) 31# 32 33atf_test_case create cleanup 34create_head() 35{ 36 atf_set "descr" "Create a lagg and assign an address" 37 atf_set "require.user" "root" 38} 39create_body() 40{ 41 local TAP0 TAP1 LAGG MAC 42 43 # Configure the lagg interface to use an RFC5737 nonrouteable addresses 44 ADDR="192.0.2.2" 45 MASK="24" 46 47 TAP0=`get_tap` 48 TAP1=`get_tap` 49 LAGG=`get_lagg` 50 51 # Create the lagg 52 ifconfig $TAP0 up 53 ifconfig $TAP1 up 54 atf_check ifconfig $LAGG up laggport $TAP0 laggport $TAP1 \ 55 ${ADDR}/${MASK} 56 atf_check -o match:"inet ${ADDR}" ifconfig $LAGG 57 atf_check -o match:"laggport: ${TAP0}" ifconfig $LAGG 58 atf_check -o match:"laggport: ${TAP1}" ifconfig $LAGG 59 60 # Check that all members have the same MAC 61 MAC=`ifconfig $LAGG | awk '/ether/ {print $2}'` 62 atf_check -o match:"ether ${MAC}" ifconfig $TAP0 63 atf_check -o match:"ether ${MAC}" ifconfig $TAP1 64 65 # Check that no members have an IPv6 link-local address. IPv6 66 # link-local addresses should never be merged in any way to prevent 67 # scope violation. 68 atf_check -o not-match:"inet6 fe80:" ifconfig $TAP0 69 atf_check -o not-match:"inet6 fe80:" ifconfig $TAP1 70} 71create_cleanup() 72{ 73 cleanup_tap_and_lagg 74} 75 76atf_test_case status_stress cleanup 77status_stress_head() 78{ 79 atf_set "descr" "Simultaneously query a lagg while also creating or destroying it." 80 atf_set "require.user" "root" 81} 82status_stress_body() 83{ 84 local TAP0 TAP1 LAGG MAC 85 86 # Configure the lagg interface to use an RFC5737 nonrouteable addresses 87 ADDR="192.0.2.2" 88 MASK="24" 89 90 TAP0=`get_tap` 91 TAP1=`get_tap` 92 TAP2=`get_tap` 93 TAP3=`get_tap` 94 LAGG=`get_lagg` 95 96 # Up the lagg's children 97 ifconfig $TAP0 inet6 ifdisabled up 98 ifconfig $TAP1 inet6 ifdisabled up 99 ifconfig $TAP2 inet6 ifdisabled up 100 ifconfig $TAP3 inet6 ifdisabled up 101 102 # First thread: create and destroy the lagg 103 while true; do 104 ifconfig $LAGG destroy 2>&1 105 ifconfig $LAGG create 2>/dev/null 106 ifconfig $LAGG inet6 ifdisabled 107 ifconfig $LAGG up laggport $TAP0 laggport $TAP1 laggport $TAP2\ 108 laggport $TAP3 ${ADDR}/${MASK} 2>/dev/null 109 echo -n . >> creator_count.txt 110 done & 111 CREATOR_PID=$! 112 113 # Second thread: Query the lagg's status 114 while true; do 115 ifconfig -am 2> /dev/null > /dev/null 116 echo -n . >> querier_count.txt 117 done & 118 QUERIER_PID=$! 119 120 sleep 60 121 kill $CREATOR_PID 122 kill $QUERIER_PID 123 echo "Created the lagg `stat -f %z creator_count.txt` times." 124 echo "Queried its status `stat -f %z querier_count.txt` times" 125} 126status_stress_cleanup() 127{ 128 cleanup_tap_and_lagg 129} 130 131atf_test_case create_destroy_stress cleanup 132create_destroy_stress_head() 133{ 134 atf_set "descr" "Simultaneously create and destroy a lagg" 135 atf_set "require.user" "root" 136} 137create_destroy_stress_body() 138{ 139 local TAP0 TAP1 LAGG MAC 140 141 TAP0=`get_tap` 142 TAP1=`get_tap` 143 TAP2=`get_tap` 144 TAP3=`get_tap` 145 LAGG=`get_lagg` 146 147 # Up the lagg's children 148 ifconfig $TAP0 inet6 ifdisabled up 149 ifconfig $TAP1 inet6 ifdisabled up 150 ifconfig $TAP2 inet6 ifdisabled up 151 ifconfig $TAP3 inet6 ifdisabled up 152 153 # First thread: create the lagg 154 while true; do 155 ifconfig $LAGG create 2>/dev/null && \ 156 echo -n . >> creator_count.txt 157 done & 158 CREATOR_PID=$! 159 160 # Second thread: destroy the lagg 161 while true; do 162 ifconfig $LAGG destroy 2>/dev/null && \ 163 echo -n . >> destroyer_count.txt 164 done & 165 DESTROYER_PID=$! 166 167 sleep 60 168 kill $CREATOR_PID 169 kill $DESTROYER_PID 170 echo "Created the lagg `stat -f %z creator_count.txt` times." 171 echo "Destroyed it `stat -f %z destroyer_count.txt` times." 172} 173create_destroy_stress_cleanup() 174{ 175 cleanup_tap_and_lagg 176} 177 178# This test regresses a panic that is particular to LACP. If the child's link 179# state changes while the lagg is being destroyed, lacp_linkstate can 180# use-after-free. The problem is compounded by two factors: 181# 1) In SpectraBSD, downing the parent will also down the child 182# 2) The cxgbe driver will show the link state as "no carrier" as soon as you 183# down the interface. 184# TeamTrack: P2_30328 185atf_test_case lacp_linkstate_destroy_stress cleanup 186lacp_linkstate_destroy_stress_head() 187{ 188 atf_set "descr" "Simultaneously destroy an LACP lagg and change its childrens link states" 189 atf_set "require.user" "root" 190} 191lacp_linkstate_destroy_stress_body() 192{ 193 local TAP0 TAP1 LAGG MAC SRCDIR 194 195 # Configure the lagg interface to use an RFC5737 nonrouteable addresses 196 ADDR="192.0.2.2" 197 MASK="24" 198 # ifconfig takes about 10ms to run. To increase race coverage, 199 # randomly delay the two commands relative to each other by 5ms either 200 # way. 201 MEAN_SLEEP_SECONDS=.005 202 MAX_SLEEP_USECS=10000 203 204 TAP0=`get_tap` 205 TAP1=`get_tap` 206 LAGG=`get_lagg` 207 208 # Up the lagg's children 209 ifconfig $TAP0 inet6 ifdisabled up 210 ifconfig $TAP1 inet6 ifdisabled up 211 212 SRCDIR=$( atf_get_srcdir ) 213 while true; do 214 ifconfig $LAGG inet6 ifdisabled 215 # We must open the tap devices to change their link states 216 cat /dev/$TAP0 > /dev/null & 217 CAT0_PID=$! 218 cat /dev/$TAP1 > /dev/null & 219 CAT1_PID=$! 220 ifconfig $LAGG up laggport $TAP0 laggport $TAP1 \ 221 ${ADDR}/${MASK} 2> /dev/null && 222 { sleep ${MEAN_SLEEP_SECONDS} && \ 223 kill $CAT0_PID && 224 kill $CAT1_PID && 225 echo -n . >> linkstate_count.txt ; } & 226 { ${SRCDIR}/randsleep ${MAX_SLEEP_USECS} && \ 227 ifconfig $LAGG destroy && 228 echo -n . >> destroy_count.txt ; } & 229 wait 230 ifconfig $LAGG create 231 done & 232 LOOP_PID=$! 233 234 sleep 60 235 kill $LOOP_PID 236 echo "Disconnected the children `stat -f %z linkstate_count.txt` times." 237 echo "Destroyed the lagg `stat -f %z destroy_count.txt` times." 238} 239lacp_linkstate_destroy_stress_cleanup() 240{ 241 cleanup_tap_and_lagg 242} 243 244atf_test_case up_destroy_stress cleanup 245up_destroy_stress_head() 246{ 247 atf_set "descr" "Simultaneously up and destroy a lagg" 248 atf_set "require.user" "root" 249} 250up_destroy_stress_body() 251{ 252 local TAP0 TAP1 LAGG MAC SRCDIR 253 254 # Configure the lagg interface to use an RFC5737 nonrouteable addresses 255 ADDR="192.0.2.2" 256 MASK="24" 257 # ifconfig takes about 10ms to run. To increase race coverage, 258 # randomly delay the two commands relative to each other by 5ms either 259 # way. 260 MEAN_SLEEP_SECONDS=.005 261 MAX_SLEEP_USECS=10000 262 263 TAP0=`get_tap` 264 TAP1=`get_tap` 265 TAP2=`get_tap` 266 TAP3=`get_tap` 267 LAGG=`get_lagg` 268 269 # Up the lagg's children 270 ifconfig $TAP0 inet6 ifdisabled up 271 ifconfig $TAP1 inet6 ifdisabled up 272 ifconfig $TAP2 inet6 ifdisabled up 273 ifconfig $TAP3 inet6 ifdisabled up 274 275 SRCDIR=$( atf_get_srcdir ) 276 while true; do 277 ifconfig $LAGG inet6 ifdisabled 278 { sleep ${MEAN_SLEEP_SECONDS} && \ 279 ifconfig $LAGG up laggport $TAP0 laggport $TAP1 \ 280 laggport $TAP2 laggport $TAP3 \ 281 ${ADDR}/${MASK} 2> /dev/null && 282 echo -n . >> up_count.txt ; } & 283 { ${SRCDIR}/randsleep ${MAX_SLEEP_USECS} && \ 284 ifconfig $LAGG destroy && 285 echo -n . >> destroy_count.txt ; } & 286 wait 287 ifconfig $LAGG create 288 done & 289 LOOP_PID=$! 290 291 sleep 60 292 kill $LOOP_PID 293 echo "Upped the lagg `stat -f %z up_count.txt` times." 294 echo "Destroyed it `stat -f %z destroy_count.txt` times." 295} 296up_destroy_stress_cleanup() 297{ 298 cleanup_tap_and_lagg 299} 300 301atf_test_case set_ether cleanup 302set_ether_head() 303{ 304 atf_set "descr" "Set a lagg's ethernet address" 305 atf_set "require.user" "root" 306} 307set_ether_body() 308{ 309 local TAP0 TAP1 LAGG MAC 310 311 # Configure the lagg interface to use an RFC5737 nonrouteable addresses 312 ADDR="192.0.2.2" 313 MASK="24" 314 MAC="00:11:22:33:44:55" 315 316 TAP0=`get_tap` 317 TAP1=`get_tap` 318 LAGG=`get_lagg` 319 320 # Create the lagg 321 ifconfig $TAP0 up 322 ifconfig $TAP1 up 323 atf_check ifconfig $LAGG up laggport $TAP0 laggport $TAP1 \ 324 ${ADDR}/${MASK} 325 326 # Change the lagg's ethernet address 327 atf_check ifconfig $LAGG ether ${MAC} 328 329 # Check that all members have the same MAC 330 atf_check -o match:"ether ${MAC}" ifconfig $LAGG 331 atf_check -o match:"ether ${MAC}" ifconfig $TAP0 332 atf_check -o match:"ether ${MAC}" ifconfig $TAP1 333} 334set_ether_cleanup() 335{ 336 cleanup_tap_and_lagg 337} 338 339atf_test_case updown cleanup 340updown_head() 341{ 342 atf_set "descr" "upping or downing a lagg ups or downs its children" 343 atf_set "require.user" "root" 344} 345updown_body() 346{ 347 local TAP0 TAP1 LAGG MAC 348 349 # Configure the lagg interface to use an RFC5737 nonrouteable addresses 350 ADDR="192.0.2.2" 351 MASK="24" 352 MAC="00:11:22:33:44:55" 353 354 TAP0=`get_tap` 355 TAP1=`get_tap` 356 LAGG=`get_lagg` 357 358 # Create the lagg 359 ifconfig $TAP0 up 360 ifconfig $TAP1 up 361 atf_check ifconfig $LAGG up laggport $TAP0 laggport $TAP1 \ 362 ${ADDR}/${MASK} 363 364 # Down the lagg 365 ifconfig $LAGG down 366 atf_check -o not-match:"flags=.*\<UP\>" ifconfig $LAGG 367 atf_check -o not-match:"flags=.*\<UP\>" ifconfig $TAP0 368 atf_check -o not-match:"flags=.*\<UP\>" ifconfig $TAP1 369 # Up the lagg again 370 ifconfig $LAGG up 371 atf_check -o match:"flags=.*\<UP\>" ifconfig $LAGG 372 atf_check -o match:"flags=.*\<UP\>" ifconfig $TAP0 373 atf_check -o match:"flags=.*\<UP\>" ifconfig $TAP1 374 375 # Check that no members have acquired an IPv6 link-local address by 376 # virtue of being upped. IPv6 link-local addresses should never be 377 # merged in any way to prevent scope violation. 378 atf_check -o not-match:"inet6 fe80:" ifconfig $TAP0 379 atf_check -o not-match:"inet6 fe80:" ifconfig $TAP1 380} 381updown_cleanup() 382{ 383 cleanup_tap_and_lagg 384} 385 386# Check for lock-order reversals. For best results, this test should be run 387# last. 388atf_test_case witness 389witness_head() 390{ 391 atf_set "descr" "Check witness(4) for lock-order reversals in if_lagg" 392} 393witness_body() 394{ 395 if [ "$(atf_config_get ci false)" = "true" ]; then 396 atf_skip "https://bugs.freebsd.org/244163 and https://bugs.freebsd.org/251726" 397 fi 398 if [ `sysctl -n debug.witness.watch` -ne 1 ]; then 399 atf_skip "witness(4) is not enabled" 400 fi 401 if `sysctl -n debug.witness.badstacks | grep -q 'at lagg_'`; then 402 sysctl debug.witness.badstacks 403 atf_fail "Lock-order reversals involving if_lagg.c detected" 404 fi 405} 406 407atf_init_test_cases() 408{ 409 atf_add_test_case create 410 atf_add_test_case create_destroy_stress 411 atf_add_test_case lacp_linkstate_destroy_stress 412 atf_add_test_case set_ether 413 atf_add_test_case status_stress 414 atf_add_test_case up_destroy_stress 415 atf_add_test_case updown 416 # For best results, keep the witness test last 417 atf_add_test_case witness 418} 419 420 421# Creates a new tap(4) interface, registers it for cleanup, and echoes it 422get_tap() 423{ 424 local TAPN=0 425 while ! ifconfig tap${TAPN} create > /dev/null 2>&1; do 426 if [ "$TAPN" -ge 8 ]; then 427 atf_skip "Could not create a tap(4) interface" 428 else 429 TAPN=$(($TAPN + 1)) 430 fi 431 done 432 local TAPD=tap${TAPN} 433 # Record the TAP device so we can clean it up later 434 echo ${TAPD} >> "devices_to_cleanup" 435 echo ${TAPD} 436} 437 438# Creates a new lagg(4) interface, registers it for cleanup, and echoes it 439get_lagg() 440{ 441 local LAGGN=0 442 while ! ifconfig lagg${LAGGN} create > /dev/null 2>&1; do 443 if [ "$LAGGN" -ge 8 ]; then 444 atf_skip "Could not create a lagg(4) interface" 445 else 446 LAGGN=$(($LAGGN + 1)) 447 fi 448 done 449 local LAGGD=lagg${LAGGN} 450 # Record the lagg device so we can clean it up later 451 echo ${LAGGD} >> "devices_to_cleanup" 452 echo ${LAGGD} 453} 454 455cleanup_tap_and_lagg() 456{ 457 local DEV 458 459 for DEV in `cat "devices_to_cleanup"`; do 460 ifconfig ${DEV} destroy 461 done 462 true 463} 464