1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3 4# Kselftest framework requirement - SKIP code is 4. 5ksft_skip=4 6 7############################################################################## 8# Defines 9 10if [[ ! -v DEVLINK_DEV ]]; then 11 DEVLINK_DEV=$(devlink port show "${NETIFS[p1]:-$NETIF_NO_CABLE}" -j \ 12 | jq -r '.port | keys[]' | cut -d/ -f-2) 13 if [ -z "$DEVLINK_DEV" ]; then 14 echo "SKIP: ${NETIFS[p1]} has no devlink device registered for it" 15 exit $ksft_skip 16 fi 17 if [[ "$(echo $DEVLINK_DEV | grep -c pci)" -eq 0 ]]; then 18 echo "SKIP: devlink device's bus is not PCI" 19 exit $ksft_skip 20 fi 21 22 DEVLINK_VIDDID=$(lspci -s $(echo $DEVLINK_DEV | cut -d"/" -f2) \ 23 -n | cut -d" " -f3) 24elif [[ ! -z "$DEVLINK_DEV" ]]; then 25 devlink dev show $DEVLINK_DEV &> /dev/null 26 if [ $? -ne 0 ]; then 27 echo "SKIP: devlink device \"$DEVLINK_DEV\" not found" 28 exit $ksft_skip 29 fi 30fi 31 32############################################################################## 33# Sanity checks 34 35devlink help 2>&1 | grep resource &> /dev/null 36if [ $? -ne 0 ]; then 37 echo "SKIP: iproute2 too old, missing devlink resource support" 38 exit $ksft_skip 39fi 40 41devlink help 2>&1 | grep trap &> /dev/null 42if [ $? -ne 0 ]; then 43 echo "SKIP: iproute2 too old, missing devlink trap support" 44 exit $ksft_skip 45fi 46 47devlink dev help 2>&1 | grep info &> /dev/null 48if [ $? -ne 0 ]; then 49 echo "SKIP: iproute2 too old, missing devlink dev info support" 50 exit $ksft_skip 51fi 52 53############################################################################## 54# Devlink helpers 55 56devlink_resource_names_to_path() 57{ 58 local resource 59 local path="" 60 61 for resource in "${@}"; do 62 if [ "$path" == "" ]; then 63 path="$resource" 64 else 65 path="${path}/$resource" 66 fi 67 done 68 69 echo "$path" 70} 71 72devlink_resource_get() 73{ 74 local name=$1 75 local resource_name=.[][\"$DEVLINK_DEV\"] 76 77 resource_name="$resource_name | .[] | select (.name == \"$name\")" 78 79 shift 80 for resource in "${@}"; do 81 resource_name="${resource_name} | .[\"resources\"][] | \ 82 select (.name == \"$resource\")" 83 done 84 85 devlink -j resource show "$DEVLINK_DEV" | jq "$resource_name" 86} 87 88devlink_resource_size_get() 89{ 90 local size=$(devlink_resource_get "$@" | jq '.["size_new"]') 91 92 if [ "$size" == "null" ]; then 93 devlink_resource_get "$@" | jq '.["size"]' 94 else 95 echo "$size" 96 fi 97} 98 99devlink_resource_size_set() 100{ 101 local new_size=$1 102 local path 103 104 shift 105 path=$(devlink_resource_names_to_path "$@") 106 devlink resource set "$DEVLINK_DEV" path "$path" size "$new_size" 107 check_err $? "Failed setting path $path to size $size" 108} 109 110devlink_resource_occ_get() 111{ 112 devlink_resource_get "$@" | jq '.["occ"]' 113} 114 115devlink_reload() 116{ 117 local still_pending 118 119 devlink dev reload "$DEVLINK_DEV" &> /dev/null 120 check_err $? "Failed reload" 121 122 still_pending=$(devlink resource show "$DEVLINK_DEV" | \ 123 grep -c "size_new") 124 check_err $still_pending "Failed reload - There are still unset sizes" 125} 126 127declare -A DEVLINK_ORIG 128 129# Changing pool type from static to dynamic causes reinterpretation of threshold 130# values. They therefore need to be saved before pool type is changed, then the 131# pool type can be changed, and then the new values need to be set up. Therefore 132# instead of saving the current state implicitly in the _set call, provide 133# functions for all three primitives: save, set, and restore. 134 135devlink_port_pool_threshold() 136{ 137 local port=$1; shift 138 local pool=$1; shift 139 140 devlink sb port pool show $port pool $pool -j \ 141 | jq '.port_pool."'"$port"'"[].threshold' 142} 143 144devlink_port_pool_th_save() 145{ 146 local port=$1; shift 147 local pool=$1; shift 148 local key="port_pool($port,$pool).threshold" 149 150 DEVLINK_ORIG[$key]=$(devlink_port_pool_threshold $port $pool) 151} 152 153devlink_port_pool_th_set() 154{ 155 local port=$1; shift 156 local pool=$1; shift 157 local th=$1; shift 158 159 devlink sb port pool set $port pool $pool th $th 160} 161 162devlink_port_pool_th_restore() 163{ 164 local port=$1; shift 165 local pool=$1; shift 166 local key="port_pool($port,$pool).threshold" 167 local -a orig=(${DEVLINK_ORIG[$key]}) 168 169 if [[ -z $orig ]]; then 170 echo "WARNING: Mismatched devlink_port_pool_th_restore" 171 else 172 devlink sb port pool set $port pool $pool th $orig 173 fi 174} 175 176devlink_pool_size_thtype() 177{ 178 local pool=$1; shift 179 180 devlink sb pool show "$DEVLINK_DEV" pool $pool -j \ 181 | jq -r '.pool[][] | (.size, .thtype)' 182} 183 184devlink_pool_size_thtype_save() 185{ 186 local pool=$1; shift 187 local key="pool($pool).size_thtype" 188 189 DEVLINK_ORIG[$key]=$(devlink_pool_size_thtype $pool) 190} 191 192devlink_pool_size_thtype_set() 193{ 194 local pool=$1; shift 195 local thtype=$1; shift 196 local size=$1; shift 197 198 devlink sb pool set "$DEVLINK_DEV" pool $pool size $size thtype $thtype 199} 200 201devlink_pool_size_thtype_restore() 202{ 203 local pool=$1; shift 204 local key="pool($pool).size_thtype" 205 local -a orig=(${DEVLINK_ORIG[$key]}) 206 207 if [[ -z ${orig[0]} ]]; then 208 echo "WARNING: Mismatched devlink_pool_size_thtype_restore" 209 else 210 devlink sb pool set "$DEVLINK_DEV" pool $pool \ 211 size ${orig[0]} thtype ${orig[1]} 212 fi 213} 214 215devlink_tc_bind_pool_th() 216{ 217 local port=$1; shift 218 local tc=$1; shift 219 local dir=$1; shift 220 221 devlink sb tc bind show $port tc $tc type $dir -j \ 222 | jq -r '.tc_bind[][] | (.pool, .threshold)' 223} 224 225devlink_tc_bind_pool_th_save() 226{ 227 local port=$1; shift 228 local tc=$1; shift 229 local dir=$1; shift 230 local key="tc_bind($port,$dir,$tc).pool_th" 231 232 DEVLINK_ORIG[$key]=$(devlink_tc_bind_pool_th $port $tc $dir) 233} 234 235devlink_tc_bind_pool_th_set() 236{ 237 local port=$1; shift 238 local tc=$1; shift 239 local dir=$1; shift 240 local pool=$1; shift 241 local th=$1; shift 242 243 devlink sb tc bind set $port tc $tc type $dir pool $pool th $th 244} 245 246devlink_tc_bind_pool_th_restore() 247{ 248 local port=$1; shift 249 local tc=$1; shift 250 local dir=$1; shift 251 local key="tc_bind($port,$dir,$tc).pool_th" 252 local -a orig=(${DEVLINK_ORIG[$key]}) 253 254 if [[ -z ${orig[0]} ]]; then 255 echo "WARNING: Mismatched devlink_tc_bind_pool_th_restore" 256 else 257 devlink sb tc bind set $port tc $tc type $dir \ 258 pool ${orig[0]} th ${orig[1]} 259 fi 260} 261 262devlink_traps_num_get() 263{ 264 devlink -j trap | jq '.[]["'$DEVLINK_DEV'"] | length' 265} 266 267devlink_traps_get() 268{ 269 devlink -j trap | jq -r '.[]["'$DEVLINK_DEV'"][].name' 270} 271 272devlink_trap_type_get() 273{ 274 local trap_name=$1; shift 275 276 devlink -j trap show $DEVLINK_DEV trap $trap_name \ 277 | jq -r '.[][][].type' 278} 279 280devlink_trap_action_set() 281{ 282 local trap_name=$1; shift 283 local action=$1; shift 284 285 # Pipe output to /dev/null to avoid expected warnings. 286 devlink trap set $DEVLINK_DEV trap $trap_name \ 287 action $action &> /dev/null 288} 289 290devlink_trap_action_get() 291{ 292 local trap_name=$1; shift 293 294 devlink -j trap show $DEVLINK_DEV trap $trap_name \ 295 | jq -r '.[][][].action' 296} 297 298devlink_trap_group_get() 299{ 300 devlink -j trap show $DEVLINK_DEV trap $trap_name \ 301 | jq -r '.[][][].group' 302} 303 304devlink_trap_metadata_test() 305{ 306 local trap_name=$1; shift 307 local metadata=$1; shift 308 309 devlink -jv trap show $DEVLINK_DEV trap $trap_name \ 310 | jq -e '.[][][].metadata | contains(["'$metadata'"])' \ 311 &> /dev/null 312} 313 314devlink_trap_rx_packets_get() 315{ 316 local trap_name=$1; shift 317 318 devlink -js trap show $DEVLINK_DEV trap $trap_name \ 319 | jq '.[][][]["stats"]["rx"]["packets"]' 320} 321 322devlink_trap_rx_bytes_get() 323{ 324 local trap_name=$1; shift 325 326 devlink -js trap show $DEVLINK_DEV trap $trap_name \ 327 | jq '.[][][]["stats"]["rx"]["bytes"]' 328} 329 330devlink_trap_drop_packets_get() 331{ 332 local trap_name=$1; shift 333 334 devlink -js trap show $DEVLINK_DEV trap $trap_name \ 335 | jq '.[][][]["stats"]["rx"]["dropped"]' 336} 337 338devlink_trap_stats_idle_test() 339{ 340 local trap_name=$1; shift 341 local t0_packets t0_bytes 342 local t1_packets t1_bytes 343 344 t0_packets=$(devlink_trap_rx_packets_get $trap_name) 345 t0_bytes=$(devlink_trap_rx_bytes_get $trap_name) 346 347 sleep 1 348 349 t1_packets=$(devlink_trap_rx_packets_get $trap_name) 350 t1_bytes=$(devlink_trap_rx_bytes_get $trap_name) 351 352 if [[ $t0_packets -eq $t1_packets && $t0_bytes -eq $t1_bytes ]]; then 353 return 0 354 else 355 return 1 356 fi 357} 358 359devlink_trap_drop_stats_idle_test() 360{ 361 local trap_name=$1; shift 362 local t0_packets t0_bytes 363 364 t0_packets=$(devlink_trap_drop_packets_get $trap_name) 365 366 sleep 1 367 368 t1_packets=$(devlink_trap_drop_packets_get $trap_name) 369 370 if [[ $t0_packets -eq $t1_packets ]]; then 371 return 0 372 else 373 return 1 374 fi 375} 376 377devlink_traps_enable_all() 378{ 379 local trap_name 380 381 for trap_name in $(devlink_traps_get); do 382 devlink_trap_action_set $trap_name "trap" 383 done 384} 385 386devlink_traps_disable_all() 387{ 388 for trap_name in $(devlink_traps_get); do 389 devlink_trap_action_set $trap_name "drop" 390 done 391} 392 393devlink_trap_groups_get() 394{ 395 devlink -j trap group | jq -r '.[]["'$DEVLINK_DEV'"][].name' 396} 397 398devlink_trap_group_action_set() 399{ 400 local group_name=$1; shift 401 local action=$1; shift 402 403 # Pipe output to /dev/null to avoid expected warnings. 404 devlink trap group set $DEVLINK_DEV group $group_name action $action \ 405 &> /dev/null 406} 407 408devlink_trap_group_rx_packets_get() 409{ 410 local group_name=$1; shift 411 412 devlink -js trap group show $DEVLINK_DEV group $group_name \ 413 | jq '.[][][]["stats"]["rx"]["packets"]' 414} 415 416devlink_trap_group_rx_bytes_get() 417{ 418 local group_name=$1; shift 419 420 devlink -js trap group show $DEVLINK_DEV group $group_name \ 421 | jq '.[][][]["stats"]["rx"]["bytes"]' 422} 423 424devlink_trap_group_stats_idle_test() 425{ 426 local group_name=$1; shift 427 local t0_packets t0_bytes 428 local t1_packets t1_bytes 429 430 t0_packets=$(devlink_trap_group_rx_packets_get $group_name) 431 t0_bytes=$(devlink_trap_group_rx_bytes_get $group_name) 432 433 sleep 1 434 435 t1_packets=$(devlink_trap_group_rx_packets_get $group_name) 436 t1_bytes=$(devlink_trap_group_rx_bytes_get $group_name) 437 438 if [[ $t0_packets -eq $t1_packets && $t0_bytes -eq $t1_bytes ]]; then 439 return 0 440 else 441 return 1 442 fi 443} 444 445devlink_trap_exception_test() 446{ 447 local trap_name=$1; shift 448 local group_name 449 450 group_name=$(devlink_trap_group_get $trap_name) 451 452 devlink_trap_stats_idle_test $trap_name 453 check_fail $? "Trap stats idle when packets should have been trapped" 454 455 devlink_trap_group_stats_idle_test $group_name 456 check_fail $? "Trap group idle when packets should have been trapped" 457} 458 459devlink_trap_drop_test() 460{ 461 local trap_name=$1; shift 462 local dev=$1; shift 463 local handle=$1; shift 464 local group_name 465 466 group_name=$(devlink_trap_group_get $trap_name) 467 468 # This is the common part of all the tests. It checks that stats are 469 # initially idle, then non-idle after changing the trap action and 470 # finally idle again. It also makes sure the packets are dropped and 471 # never forwarded. 472 devlink_trap_stats_idle_test $trap_name 473 check_err $? "Trap stats not idle with initial drop action" 474 devlink_trap_group_stats_idle_test $group_name 475 check_err $? "Trap group stats not idle with initial drop action" 476 477 devlink_trap_action_set $trap_name "trap" 478 devlink_trap_stats_idle_test $trap_name 479 check_fail $? "Trap stats idle after setting action to trap" 480 devlink_trap_group_stats_idle_test $group_name 481 check_fail $? "Trap group stats idle after setting action to trap" 482 483 devlink_trap_action_set $trap_name "drop" 484 485 devlink_trap_stats_idle_test $trap_name 486 check_err $? "Trap stats not idle after setting action to drop" 487 devlink_trap_group_stats_idle_test $group_name 488 check_err $? "Trap group stats not idle after setting action to drop" 489 490 tc_check_packets "dev $dev egress" $handle 0 491 check_err $? "Packets were not dropped" 492} 493 494devlink_trap_drop_cleanup() 495{ 496 local mz_pid=$1; shift 497 local dev=$1; shift 498 local proto=$1; shift 499 local pref=$1; shift 500 local handle=$1; shift 501 502 kill $mz_pid && wait $mz_pid &> /dev/null 503 tc filter del dev $dev egress protocol $proto pref $pref handle $handle flower 504} 505 506devlink_trap_stats_test() 507{ 508 local test_name=$1; shift 509 local trap_name=$1; shift 510 local send_one="$@" 511 local t0_packets 512 local t1_packets 513 514 RET=0 515 516 t0_packets=$(devlink_trap_rx_packets_get $trap_name) 517 518 $send_one && sleep 1 519 520 t1_packets=$(devlink_trap_rx_packets_get $trap_name) 521 522 if [[ $t1_packets -eq $t0_packets ]]; then 523 check_err 1 "Trap stats did not increase" 524 fi 525 526 log_test "$test_name" 527} 528 529devlink_trap_policers_num_get() 530{ 531 devlink -j -p trap policer show | jq '.[]["'$DEVLINK_DEV'"] | length' 532} 533 534devlink_trap_policer_rate_get() 535{ 536 local policer_id=$1; shift 537 538 devlink -j -p trap policer show $DEVLINK_DEV policer $policer_id \ 539 | jq '.[][][]["rate"]' 540} 541 542devlink_trap_policer_burst_get() 543{ 544 local policer_id=$1; shift 545 546 devlink -j -p trap policer show $DEVLINK_DEV policer $policer_id \ 547 | jq '.[][][]["burst"]' 548} 549 550devlink_trap_policer_rx_dropped_get() 551{ 552 local policer_id=$1; shift 553 554 devlink -j -p -s trap policer show $DEVLINK_DEV policer $policer_id \ 555 | jq '.[][][]["stats"]["rx"]["dropped"]' 556} 557 558devlink_trap_group_policer_get() 559{ 560 local group_name=$1; shift 561 562 devlink -j -p trap group show $DEVLINK_DEV group $group_name \ 563 | jq '.[][][]["policer"]' 564} 565 566devlink_port_by_netdev() 567{ 568 local if_name=$1 569 570 devlink -j port show $if_name | jq -e '.[] | keys' | jq -r '.[]' 571} 572 573devlink_cpu_port_get() 574{ 575 local cpu_dl_port_num=$(devlink port list | grep "$DEVLINK_DEV" | 576 grep cpu | cut -d/ -f3 | cut -d: -f1 | 577 sed -n '1p') 578 579 echo "$DEVLINK_DEV/$cpu_dl_port_num" 580} 581 582devlink_cell_size_get() 583{ 584 devlink sb pool show "$DEVLINK_DEV" pool 0 -j \ 585 | jq '.pool[][].cell_size' 586} 587 588devlink_pool_size_get() 589{ 590 devlink sb show "$DEVLINK_DEV" -j | jq '.[][][]["size"]' 591} 592