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 if [ "$(atf_config_get ci false)" = "true" ]; then 194 atf_skip "https://bugs.freebsd.org/244168" 195 fi 196 197 local TAP0 TAP1 LAGG MAC SRCDIR 198 199 # Configure the lagg interface to use an RFC5737 nonrouteable addresses 200 ADDR="192.0.2.2" 201 MASK="24" 202 # ifconfig takes about 10ms to run. To increase race coverage, 203 # randomly delay the two commands relative to each other by 5ms either 204 # way. 205 MEAN_SLEEP_SECONDS=.005 206 MAX_SLEEP_USECS=10000 207 208 TAP0=`get_tap` 209 TAP1=`get_tap` 210 LAGG=`get_lagg` 211 212 # Up the lagg's children 213 ifconfig $TAP0 inet6 ifdisabled up 214 ifconfig $TAP1 inet6 ifdisabled up 215 216 SRCDIR=$( atf_get_srcdir ) 217 while true; do 218 ifconfig $LAGG inet6 ifdisabled 219 # We must open the tap devices to change their link states 220 cat /dev/$TAP0 > /dev/null & 221 CAT0_PID=$! 222 cat /dev/$TAP1 > /dev/null & 223 CAT1_PID=$! 224 ifconfig $LAGG up laggport $TAP0 laggport $TAP1 \ 225 ${ADDR}/${MASK} 2> /dev/null && 226 { sleep ${MEAN_SLEEP_SECONDS} && \ 227 kill $CAT0_PID && 228 kill $CAT1_PID && 229 echo -n . >> linkstate_count.txt ; } & 230 { ${SRCDIR}/randsleep ${MAX_SLEEP_USECS} && \ 231 ifconfig $LAGG destroy && 232 echo -n . >> destroy_count.txt ; } & 233 wait 234 ifconfig $LAGG create 235 done & 236 LOOP_PID=$! 237 238 sleep 60 239 kill $LOOP_PID 240 echo "Disconnected the children `stat -f %z linkstate_count.txt` times." 241 echo "Destroyed the lagg `stat -f %z destroy_count.txt` times." 242} 243lacp_linkstate_destroy_stress_cleanup() 244{ 245 cleanup_tap_and_lagg 246} 247 248atf_test_case up_destroy_stress cleanup 249up_destroy_stress_head() 250{ 251 atf_set "descr" "Simultaneously up and destroy a lagg" 252 atf_set "require.user" "root" 253} 254up_destroy_stress_body() 255{ 256 local TAP0 TAP1 LAGG MAC SRCDIR 257 258 # Configure the lagg interface to use an RFC5737 nonrouteable addresses 259 ADDR="192.0.2.2" 260 MASK="24" 261 # ifconfig takes about 10ms to run. To increase race coverage, 262 # randomly delay the two commands relative to each other by 5ms either 263 # way. 264 MEAN_SLEEP_SECONDS=.005 265 MAX_SLEEP_USECS=10000 266 267 TAP0=`get_tap` 268 TAP1=`get_tap` 269 TAP2=`get_tap` 270 TAP3=`get_tap` 271 LAGG=`get_lagg` 272 273 # Up the lagg's children 274 ifconfig $TAP0 inet6 ifdisabled up 275 ifconfig $TAP1 inet6 ifdisabled up 276 ifconfig $TAP2 inet6 ifdisabled up 277 ifconfig $TAP3 inet6 ifdisabled up 278 279 SRCDIR=$( atf_get_srcdir ) 280 while true; do 281 ifconfig $LAGG inet6 ifdisabled 282 { sleep ${MEAN_SLEEP_SECONDS} && \ 283 ifconfig $LAGG up laggport $TAP0 laggport $TAP1 \ 284 laggport $TAP2 laggport $TAP3 \ 285 ${ADDR}/${MASK} 2> /dev/null && 286 echo -n . >> up_count.txt ; } & 287 { ${SRCDIR}/randsleep ${MAX_SLEEP_USECS} && \ 288 ifconfig $LAGG destroy && 289 echo -n . >> destroy_count.txt ; } & 290 wait 291 ifconfig $LAGG create 292 done & 293 LOOP_PID=$! 294 295 sleep 60 296 kill $LOOP_PID 297 echo "Upped the lagg `stat -f %z up_count.txt` times." 298 echo "Destroyed it `stat -f %z destroy_count.txt` times." 299} 300up_destroy_stress_cleanup() 301{ 302 cleanup_tap_and_lagg 303} 304 305atf_test_case set_ether cleanup 306set_ether_head() 307{ 308 atf_set "descr" "Set a lagg's ethernet address" 309 atf_set "require.user" "root" 310} 311set_ether_body() 312{ 313 local TAP0 TAP1 LAGG MAC 314 315 # Configure the lagg interface to use an RFC5737 nonrouteable addresses 316 ADDR="192.0.2.2" 317 MASK="24" 318 MAC="00:11:22:33:44:55" 319 320 TAP0=`get_tap` 321 TAP1=`get_tap` 322 LAGG=`get_lagg` 323 324 # Create the lagg 325 ifconfig $TAP0 up 326 ifconfig $TAP1 up 327 atf_check ifconfig $LAGG up laggport $TAP0 laggport $TAP1 \ 328 ${ADDR}/${MASK} 329 330 # Change the lagg's ethernet address 331 atf_check ifconfig $LAGG ether ${MAC} 332 333 # Check that all members have the same MAC 334 atf_check -o match:"ether ${MAC}" ifconfig $LAGG 335 atf_check -o match:"ether ${MAC}" ifconfig $TAP0 336 atf_check -o match:"ether ${MAC}" ifconfig $TAP1 337} 338set_ether_cleanup() 339{ 340 cleanup_tap_and_lagg 341} 342 343atf_test_case updown cleanup 344updown_head() 345{ 346 atf_set "descr" "upping or downing a lagg ups or downs its children" 347 atf_set "require.user" "root" 348} 349updown_body() 350{ 351 local TAP0 TAP1 LAGG MAC 352 353 # Configure the lagg interface to use an RFC5737 nonrouteable addresses 354 ADDR="192.0.2.2" 355 MASK="24" 356 MAC="00:11:22:33:44:55" 357 358 TAP0=`get_tap` 359 TAP1=`get_tap` 360 LAGG=`get_lagg` 361 362 # Create the lagg 363 ifconfig $TAP0 up 364 ifconfig $TAP1 up 365 atf_check ifconfig $LAGG up laggport $TAP0 laggport $TAP1 \ 366 ${ADDR}/${MASK} 367 368 # Down the lagg 369 ifconfig $LAGG down 370 atf_check -o not-match:"flags=.*\<UP\>" ifconfig $LAGG 371 atf_check -o not-match:"flags=.*\<UP\>" ifconfig $TAP0 372 atf_check -o not-match:"flags=.*\<UP\>" ifconfig $TAP1 373 # Up the lagg again 374 ifconfig $LAGG up 375 atf_check -o match:"flags=.*\<UP\>" ifconfig $LAGG 376 atf_check -o match:"flags=.*\<UP\>" ifconfig $TAP0 377 atf_check -o match:"flags=.*\<UP\>" ifconfig $TAP1 378 379 # Check that no members have acquired an IPv6 link-local address by 380 # virtue of being upped. IPv6 link-local addresses should never be 381 # merged in any way to prevent scope violation. 382 atf_check -o not-match:"inet6 fe80:" ifconfig $TAP0 383 atf_check -o not-match:"inet6 fe80:" ifconfig $TAP1 384} 385updown_cleanup() 386{ 387 cleanup_tap_and_lagg 388} 389 390# Check for lock-order reversals. For best results, this test should be run 391# last. 392atf_test_case witness 393witness_head() 394{ 395 atf_set "descr" "Check witness(4) for lock-order reversals in if_lagg" 396} 397witness_body() 398{ 399 if [ "$(atf_config_get ci false)" = "true" ]; then 400 atf_skip "https://bugs.freebsd.org/244163 and https://bugs.freebsd.org/251726" 401 fi 402 if [ `sysctl -n debug.witness.watch` -ne 1 ]; then 403 atf_skip "witness(4) is not enabled" 404 fi 405 if `sysctl -n debug.witness.badstacks | grep -q 'at lagg_'`; then 406 sysctl debug.witness.badstacks 407 atf_fail "Lock-order reversals involving if_lagg.c detected" 408 fi 409} 410 411atf_init_test_cases() 412{ 413 atf_add_test_case create 414 atf_add_test_case create_destroy_stress 415 atf_add_test_case lacp_linkstate_destroy_stress 416 atf_add_test_case set_ether 417 atf_add_test_case status_stress 418 atf_add_test_case up_destroy_stress 419 atf_add_test_case updown 420 # For best results, keep the witness test last 421 atf_add_test_case witness 422} 423 424 425# Creates a new tap(4) interface, registers it for cleanup, and echoes it 426get_tap() 427{ 428 local TAPN=0 429 while ! ifconfig tap${TAPN} create > /dev/null 2>&1; do 430 if [ "$TAPN" -ge 8 ]; then 431 atf_skip "Could not create a tap(4) interface" 432 else 433 TAPN=$(($TAPN + 1)) 434 fi 435 done 436 local TAPD=tap${TAPN} 437 # Record the TAP device so we can clean it up later 438 echo ${TAPD} >> "devices_to_cleanup" 439 echo ${TAPD} 440} 441 442# Creates a new lagg(4) interface, registers it for cleanup, and echoes it 443get_lagg() 444{ 445 local LAGGN=0 446 while ! ifconfig lagg${LAGGN} create > /dev/null 2>&1; do 447 if [ "$LAGGN" -ge 8 ]; then 448 atf_skip "Could not create a lagg(4) interface" 449 else 450 LAGGN=$(($LAGGN + 1)) 451 fi 452 done 453 local LAGGD=lagg${LAGGN} 454 # Record the lagg device so we can clean it up later 455 echo ${LAGGD} >> "devices_to_cleanup" 456 echo ${LAGGD} 457} 458 459cleanup_tap_and_lagg() 460{ 461 local DEV 462 463 for DEV in `cat "devices_to_cleanup"`; do 464 ifconfig ${DEV} destroy 465 done 466 true 467} 468