1# tc(8) completion -*- shell-script -*- 2# Copyright 2016 6WIND S.A. 3# Copyright 2016 Quentin Monnet <quentin.monnet@6wind.com> 4 5QDISC_KIND=' choke codel bfifo pfifo pfifo_head_drop fq fq_codel gred hhf \ 6 mqprio multiq netem pfifo_fast pie fq_pie red rr sfb sfq tbf atm \ 7 cbq drr dsmark hfsc htb prio qfq ' 8FILTER_KIND=' basic bpf cgroup flow flower fw route rsvp tcindex u32 matchall ' 9ACTION_KIND=' gact mirred bpf sample ' 10 11# Takes a list of words in argument; each one of them is added to COMPREPLY if 12# it is not already present on the command line. Returns no value. 13_tc_once_attr() 14{ 15 local w subcword found 16 for w in $*; do 17 found=0 18 for (( subcword=3; subcword < ${#words[@]}-1; subcword++ )); do 19 if [[ $w == ${words[subcword]} ]]; then 20 found=1 21 break 22 fi 23 done 24 [[ $found -eq 0 ]] && \ 25 COMPREPLY+=( $( compgen -W "$w" -- "$cur" ) ) 26 done 27} 28 29# Takes a list of words in argument; each one of them is added to COMPREPLY if 30# it is not already present on the command line from the provided index. Returns 31# no value. 32_tc_once_attr_from() 33{ 34 local w subcword found from=$1 35 shift 36 for w in $*; do 37 found=0 38 for (( subcword=$from; subcword < ${#words[@]}-1; subcword++ )); do 39 if [[ $w == ${words[subcword]} ]]; then 40 found=1 41 break 42 fi 43 done 44 [[ $found -eq 0 ]] && \ 45 COMPREPLY+=( $( compgen -W "$w" -- "$cur" ) ) 46 done 47} 48 49# Takes a list of words in argument; adds them all to COMPREPLY if none of them 50# is already present on the command line. Returns no value. 51_tc_one_of_list() 52{ 53 local w subcword 54 for w in $*; do 55 for (( subcword=3; subcword < ${#words[@]}-1; subcword++ )); do 56 [[ $w == ${words[subcword]} ]] && return 1 57 done 58 done 59 COMPREPLY+=( $( compgen -W "$*" -- "$cur" ) ) 60} 61 62# Takes a list of words in argument; adds them all to COMPREPLY if none of them 63# is already present on the command line from the provided index. Returns no 64# value. 65_tc_one_of_list_from() 66{ 67 local w subcword from=$1 68 shift 69 for w in $*; do 70 for (( subcword=$from; subcword < ${#words[@]}-1; subcword++ )); do 71 [[ $w == ${words[subcword]} ]] && return 1 72 done 73 done 74 COMPREPLY+=( $( compgen -W "$*" -- "$cur" ) ) 75} 76 77# Returns "$cur ${cur}arg1 ${cur}arg2 ..." 78_tc_expand_units() 79{ 80 [[ $cur =~ ^[0-9]+ ]] || return 1 81 local value=${cur%%[^0-9]*} 82 [[ $cur == $value ]] && echo $cur 83 echo ${@/#/$value} 84} 85 86# Complete based on given word, usually $prev (or possibly the word before), 87# for when an argument or an option name has but a few possible arguments (so 88# tc does not take particular commands into account here). 89# Returns 0 is completion should stop after running this function, 1 otherwise. 90_tc_direct_complete() 91{ 92 case $1 in 93 # Command options 94 dev) 95 _available_interfaces 96 return 0 97 ;; 98 classid) 99 return 0 100 ;; 101 estimator) 102 local list=$( _tc_expand_units 'secs' 'msecs' 'usecs' ) 103 COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) ) 104 return 0 105 ;; 106 handle) 107 return 0 108 ;; 109 parent|flowid) 110 local i iface ids cmd 111 for (( i=3; i < ${#words[@]}-2; i++ )); do 112 [[ ${words[i]} == dev ]] && iface=${words[i+1]} 113 break 114 done 115 for cmd in qdisc class; do 116 if [[ -n $iface ]]; then 117 ids+=$( tc $cmd show dev $iface 2>/dev/null | \ 118 cut -d\ -f 3 )" " 119 else 120 ids+=$( tc $cmd show 2>/dev/null | cut -d\ -f 3 ) 121 fi 122 done 123 [[ $ids != " " ]] && \ 124 COMPREPLY+=( $( compgen -W "$ids" -- "$cur" ) ) 125 return 0 126 ;; 127 protocol) # list comes from lib/ll_proto.c 128 COMPREPLY+=( $( compgen -W ' 802.1Q 802.1ad 802_2 802_3 LLDP aarp \ 129 all aoe arp atalk atmfate atmmpoa ax25 bpq can control cust \ 130 ddcmp dec diag dna_dl dna_rc dna_rt econet ieeepup ieeepupat \ 131 ip ipv4 ipv6 ipx irda lat localtalk loop mobitex ppp_disc \ 132 ppp_mp ppp_ses ppptalk pup pupat rarp sca snap tipc tr_802_2 \ 133 wan_ppp x25' -- "$cur" ) ) 134 return 0 135 ;; 136 prio) 137 return 0 138 ;; 139 stab) 140 COMPREPLY+=( $( compgen -W 'mtu tsize mpu overhead 141 linklayer' -- "$cur" ) ) 142 ;; 143 144 # Qdiscs and classes options 145 alpha|bands|beta|buckets|corrupt|debug|decrement|default|\ 146 default_index|depth|direct_qlen|divisor|duplicate|ewma|flow_limit|\ 147 flows|hh_limit|increment|indices|linklayer|non_hh_weight|num_tc|\ 148 penalty_burst|penalty_rate|prio|priomap|probability|queues|r2q|\ 149 reorder|vq|vqs) 150 return 0 151 ;; 152 setup) 153 COMPREPLY+=( $( compgen -W 'vqs' -- "$cur" ) ) 154 return 0 155 ;; 156 hw) 157 COMPREPLY+=( $( compgen -W '1 0' -- "$cur" ) ) 158 return 0 159 ;; 160 distribution) 161 COMPREPLY+=( $( compgen -W 'uniform normal pareto 162 paretonormal' -- "$cur" ) ) 163 return 0 164 ;; 165 loss) 166 COMPREPLY+=( $( compgen -W 'random state gmodel' -- "$cur" ) ) 167 return 0 168 ;; 169 170 # Qdiscs and classes options options 171 gap|gmodel|state) 172 return 0 173 ;; 174 175 # Filters options 176 map) 177 COMPREPLY+=( $( compgen -W 'key' -- "$cur" ) ) 178 return 0 179 ;; 180 hash) 181 COMPREPLY+=( $( compgen -W 'keys' -- "$cur" ) ) 182 return 0 183 ;; 184 indev) 185 _available_interfaces 186 return 0 187 ;; 188 eth_type) 189 COMPREPLY+=( $( compgen -W 'ipv4 ipv6' -- "$cur" ) ) 190 return 0 191 ;; 192 ip_proto) 193 COMPREPLY+=( $( compgen -W 'tcp udp' -- "$cur" ) ) 194 return 0 195 ;; 196 197 # Filters options options 198 key|keys) 199 [[ ${words[@]} =~ graft ]] && return 1 200 COMPREPLY+=( $( compgen -W 'src dst proto proto-src proto-dst iif \ 201 priority mark nfct nfct-src nfct-dst nfct-proto-src \ 202 nfct-proto-dst rt-classid sk-uid sk-gid vlan-tag rxhash' -- \ 203 "$cur" ) ) 204 return 0 205 ;; 206 207 # BPF options - used for filters, actions, and exec 208 export|bytecode|bytecode-file|object-file) 209 _filedir 210 return 0 211 ;; 212 object-pinned|graft) # Pinned object is probably under /sys/fs/bpf/ 213 [[ -n "$cur" ]] && _filedir && return 0 214 COMPREPLY=( $( compgen -G "/sys/fs/bpf/*" -- "$cur" ) ) || _filedir 215 compopt -o nospace 216 return 0 217 ;; 218 section) 219 if (type objdump > /dev/null 2>&1) ; then 220 local fword objfile section_list 221 for (( fword=3; fword < ${#words[@]}-3; fword++ )); do 222 if [[ ${words[fword]} == object-file ]]; then 223 objfile=${words[fword+1]} 224 break 225 fi 226 done 227 section_list=$( objdump -h $objfile 2>/dev/null | \ 228 sed -n 's/^ *[0-9]\+ \([^ ]*\) *.*/\1/p' ) 229 COMPREPLY+=( $( compgen -W "$section_list" -- "$cur" ) ) 230 fi 231 return 0 232 ;; 233 import|run) 234 _filedir 235 return 0 236 ;; 237 type) 238 COMPREPLY+=( $( compgen -W 'cls act' -- "$cur" ) ) 239 return 0 240 ;; 241 242 # Actions options 243 random) 244 _tc_one_of_list 'netrand determ' 245 return 0 246 ;; 247 248 # Units for option arguments 249 bandwidth|maxrate|peakrate|rate) 250 local list=$( _tc_expand_units 'bit' \ 251 'kbit' 'kibit' 'kbps' 'kibps' \ 252 'mbit' 'mibit' 'mbps' 'mibps' \ 253 'gbit' 'gibit' 'gbps' 'gibps' \ 254 'tbit' 'tibit' 'tbps' 'tibps' ) 255 COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) ) 256 ;; 257 admit_bytes|avpkt|burst|cell|initial_quantum|limit|max|min|mtu|mpu|\ 258 overhead|quantum|redflowlist) 259 local list=$( _tc_expand_units \ 260 'b' 'kbit' 'k' 'mbit' 'm' 'gbit' 'g' ) 261 COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) ) 262 ;; 263 db|delay|evict_timeout|interval|latency|perturb|rehash|reset_timeout|\ 264 target|tupdate) 265 local list=$( _tc_expand_units 'secs' 'msecs' 'usecs' ) 266 COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) ) 267 ;; 268 esac 269 return 1 270} 271 272# Complete with options names for qdiscs. Each qdisc has its own set of options 273# and it seems we cannot really parse it from anywhere, so we add it manually 274# in this function. 275# Returns 0 is completion should stop after running this function, 1 otherwise. 276_tc_qdisc_options() 277{ 278 case $1 in 279 choke) 280 _tc_once_attr 'limit bandwidth ecn min max burst' 281 return 0 282 ;; 283 codel) 284 _tc_once_attr 'limit target interval' 285 _tc_one_of_list 'ecn noecn' 286 return 0 287 ;; 288 bfifo|pfifo|pfifo_head_drop) 289 _tc_once_attr 'limit' 290 return 0 291 ;; 292 fq) 293 _tc_once_attr 'limit flow_limit quantum initial_quantum maxrate \ 294 buckets' 295 _tc_one_of_list 'pacing nopacing' 296 return 0 297 ;; 298 fq_codel) 299 _tc_once_attr 'limit flows target interval quantum' 300 _tc_one_of_list 'ecn noecn' 301 return 0 302 ;; 303 gred) 304 _tc_once_attr 'setup vqs default grio vq prio limit min max avpkt \ 305 burst probability bandwidth ecn harddrop' 306 return 0 307 ;; 308 hhf) 309 _tc_once_attr 'limit quantum hh_limit reset_timeout admit_bytes \ 310 evict_timeout non_hh_weight' 311 return 0 312 ;; 313 mqprio) 314 _tc_once_attr 'num_tc map queues hw' 315 return 0 316 ;; 317 netem) 318 _tc_once_attr 'delay distribution corrupt duplicate loss ecn \ 319 reorder rate' 320 return 0 321 ;; 322 pie) 323 _tc_once_attr 'limit target tupdate alpha beta' 324 _tc_one_of_list 'bytemode nobytemode' 325 _tc_one_of_list 'ecn noecn' 326 _tc_one_of_list 'dq_rate_estimator no_dq_rate_estimator' 327 return 0 328 ;; 329 fq_pie) 330 _tc_once_attr 'limit flows target tupdate \ 331 alpha beta quantum memory_limit ecn_prob' 332 _tc_one_of_list 'ecn noecn' 333 _tc_one_of_list 'bytemode nobytemode' 334 _tc_one_of_list 'dq_rate_estimator no_dq_rate_estimator' 335 return 0 336 ;; 337 red) 338 _tc_once_attr 'limit min max avpkt burst adaptive probability \ 339 bandwidth ecn harddrop' 340 return 0 341 ;; 342 rr|prio) 343 _tc_once_attr 'bands priomap multiqueue' 344 return 0 345 ;; 346 sfb) 347 _tc_once_attr 'rehash db limit max target increment decrement \ 348 penalty_rate penalty_burst' 349 return 0 350 ;; 351 sfq) 352 _tc_once_attr 'limit perturb quantum divisor flows depth headdrop \ 353 redflowlimit min max avpkt burst probability ecn harddrop' 354 return 0 355 ;; 356 tbf) 357 _tc_once_attr 'limit burst rate mtu peakrate latency overhead \ 358 linklayer' 359 return 0 360 ;; 361 cbq) 362 _tc_once_attr 'bandwidth avpkt mpu cell ewma' 363 return 0 364 ;; 365 dsmark) 366 _tc_once_attr 'indices default_index set_tc_index' 367 return 0 368 ;; 369 hfsc) 370 _tc_once_attr 'default' 371 return 0 372 ;; 373 htb) 374 _tc_once_attr 'default r2q direct_qlen debug' 375 return 0 376 ;; 377 multiq|pfifo_fast|atm|drr|qfq) 378 return 0 379 ;; 380 esac 381 return 1 382} 383 384# Complete with options names for BPF filters or actions. 385# Returns 0 is completion should stop after running this function, 1 otherwise. 386_tc_bpf_options() 387{ 388 [[ ${words[${#words[@]}-3]} == object-file ]] && \ 389 _tc_once_attr 'section export' 390 [[ ${words[${#words[@]}-5]} == object-file ]] && \ 391 [[ ${words[${#words[@]}-3]} =~ (section|export) ]] && \ 392 _tc_once_attr 'section export' 393 _tc_one_of_list 'bytecode bytecode-file object-file object-pinned' 394 _tc_once_attr 'verbose index direct-action action classid' 395 return 0 396} 397 398# Complete with options names for filter actions. 399# This function is recursive, thus allowing multiple actions statement to be 400# parsed. 401# Returns 0 is completion should stop after running this function, 1 otherwise. 402_tc_filter_action_options() 403{ 404 for ((acwd=$1; acwd < ${#words[@]}-1; acwd++)); 405 do 406 if [[ action == ${words[acwd]} ]]; then 407 _tc_filter_action_options $((acwd+1)) && return 0 408 fi 409 done 410 411 local action acwd 412 for ((acwd=$1; acwd < ${#words[@]}-1; acwd++)); do 413 if [[ $ACTION_KIND =~ ' '${words[acwd]}' ' ]]; then 414 _tc_one_of_list_from $acwd action 415 _tc_action_options $acwd && return 0 416 fi 417 done 418 _tc_one_of_list_from $acwd $ACTION_KIND 419 return 0 420} 421 422# Complete with options names for filters. 423# Returns 0 is completion should stop after running this function, 1 otherwise. 424_tc_filter_options() 425{ 426 427 for ((acwd=$1; acwd < ${#words[@]}-1; acwd++)); 428 do 429 if [[ action == ${words[acwd]} ]]; then 430 _tc_filter_action_options $((acwd+1)) && return 0 431 fi 432 done 433 434 filter=${words[$1]} 435 case $filter in 436 basic) 437 _tc_once_attr 'match action classid' 438 return 0 439 ;; 440 bpf) 441 _tc_bpf_options 442 return 0 443 ;; 444 cgroup) 445 _tc_once_attr 'match action' 446 return 0 447 ;; 448 flow) 449 local i 450 for (( i=5; i < ${#words[@]}-1; i++ )); do 451 if [[ ${words[i]} =~ ^keys?$ ]]; then 452 _tc_direct_complete 'key' 453 COMPREPLY+=( $( compgen -W 'or and xor rshift addend' -- \ 454 "$cur" ) ) 455 break 456 fi 457 done 458 _tc_once_attr 'map hash divisor baseclass match action' 459 return 0 460 ;; 461 matchall) 462 _tc_once_attr 'action classid skip_sw skip_hw' 463 return 0 464 ;; 465 flower) 466 _tc_once_attr 'action classid indev dst_mac src_mac eth_type \ 467 ip_proto dst_ip src_ip dst_port src_port' 468 return 0 469 ;; 470 fw) 471 _tc_once_attr 'action classid' 472 return 0 473 ;; 474 route) 475 _tc_one_of_list 'from fromif' 476 _tc_once_attr 'to classid action' 477 return 0 478 ;; 479 rsvp) 480 _tc_once_attr 'ipproto session sender classid action tunnelid \ 481 tunnel flowlabel spi/ah spi/esp u8 u16 u32' 482 [[ ${words[${#words[@]}-3]} == tunnel ]] && \ 483 COMPREPLY+=( $( compgen -W 'skip' -- "$cur" ) ) 484 [[ ${words[${#words[@]}-3]} =~ u(8|16|32) ]] && \ 485 COMPREPLY+=( $( compgen -W 'mask' -- "$cur" ) ) 486 [[ ${words[${#words[@]}-3]} == mask ]] && \ 487 COMPREPLY+=( $( compgen -W 'at' -- "$cur" ) ) 488 return 0 489 ;; 490 tcindex) 491 _tc_once_attr 'hash mask shift classid action' 492 _tc_one_of_list 'pass_on fall_through' 493 return 0 494 ;; 495 u32) 496 _tc_once_attr 'match link classid action offset ht hashkey sample' 497 COMPREPLY+=( $( compgen -W 'ip ip6 udp tcp icmp u8 u16 u32 mark \ 498 divisor' -- "$cur" ) ) 499 return 0 500 ;; 501 esac 502 return 1 503} 504 505# Complete with options names for actions. 506# Returns 0 is completion should stop after running this function, 1 otherwise. 507_tc_action_options() 508{ 509 local from=$1 510 local action=${words[from]} 511 case $action in 512 bpf) 513 _tc_bpf_options 514 return 0 515 ;; 516 mirred) 517 _tc_one_of_list_from $from 'ingress egress' 518 _tc_one_of_list_from $from 'mirror redirect' 519 _tc_once_attr_from $from 'index dev' 520 return 0 521 ;; 522 sample) 523 _tc_once_attr_from $from 'rate' 524 _tc_once_attr_from $from 'trunc' 525 _tc_once_attr_from $from 'group' 526 return 0 527 ;; 528 gact) 529 _tc_one_of_list_from $from 'reclassify drop continue pass' 530 _tc_once_attr_from $from 'random' 531 return 0 532 ;; 533 esac 534 return 1 535} 536 537# Complete with options names for exec. 538# Returns 0 is completion should stop after running this function, 1 otherwise. 539_tc_exec_options() 540{ 541 case $1 in 542 import) 543 [[ ${words[${#words[@]}-3]} == import ]] && \ 544 _tc_once_attr 'run' 545 return 0 546 ;; 547 graft) 548 COMPREPLY+=( $( compgen -W 'key type' -- "$cur" ) ) 549 [[ ${words[${#words[@]}-3]} == object-file ]] && \ 550 _tc_once_attr 'type' 551 _tc_bpf_options 552 return 0 553 ;; 554 esac 555 return 1 556} 557 558# Main completion function 559# Logic is as follows: 560# 1. Check if previous word is a global option; if so, propose arguments. 561# 2. Check if current word is a global option; if so, propose completion. 562# 3. Check for the presence of a main command (qdisc|class|filter|...). If 563# there is one, first call _tc_direct_complete to see if previous word is 564# waiting for a particular completion. If so, propose completion and exit. 565# 4. Extract main command and -- if available -- its subcommand 566# (add|delete|show|...). 567# 5. Propose completion based on main and sub- command in use. Additional 568# functions may be called for qdiscs, classes or filter options. 569_tc() 570{ 571 local cur prev words cword 572 _init_completion || return 573 574 case $prev in 575 -V|-Version) 576 return 0 577 ;; 578 -b|-batch|-cf|-conf) 579 _filedir 580 return 0 581 ;; 582 -force) 583 COMPREPLY=( $( compgen -W '-batch' -- "$cur" ) ) 584 return 0 585 ;; 586 -nm|name) 587 [[ -r /etc/iproute2/tc_cls ]] || \ 588 COMPREPLY=( $( compgen -W '-conf' -- "$cur" ) ) 589 return 0 590 ;; 591 -n|-net|-netns) 592 local nslist=$( ip netns list 2>/dev/null ) 593 COMPREPLY+=( $( compgen -W "$nslist" -- "$cur" ) ) 594 return 0 595 ;; 596 -tshort) 597 _tc_once_attr '-statistics' 598 COMPREPLY+=( $( compgen -W 'monitor' -- "$cur" ) ) 599 return 0 600 ;; 601 -timestamp) 602 _tc_once_attr '-statistics -tshort' 603 COMPREPLY+=( $( compgen -W 'monitor' -- "$cur" ) ) 604 return 0 605 ;; 606 esac 607 608 # Search for main commands 609 local subcword cmd subcmd 610 for (( subcword=1; subcword < ${#words[@]}-1; subcword++ )); do 611 [[ ${words[subcword]} == -b?(atch) ]] && return 0 612 [[ -n $cmd ]] && subcmd=${words[subcword]} && break 613 [[ ${words[subcword]} != -* && \ 614 ${words[subcword-1]} != -@(n?(et?(ns))|c?(on)f) ]] && \ 615 cmd=${words[subcword]} 616 done 617 618 if [[ -z $cmd ]]; then 619 case $cur in 620 -*) 621 local c='-Version -statistics -details -raw -pretty \ 622 -iec -graphe -batch -name -netns -timestamp' 623 [[ $cword -eq 1 ]] && c+=' -force' 624 COMPREPLY=( $( compgen -W "$c" -- "$cur" ) ) 625 return 0 626 ;; 627 *) 628 COMPREPLY=( $( compgen -W "help $( tc help 2>&1 | \ 629 command sed \ 630 -e '/OBJECT := /!d' \ 631 -e 's/.*{//' \ 632 -e 's/}.*//' \ 633 -e \ 's/|//g' )" -- "$cur" ) ) 634 return 0 635 ;; 636 esac 637 fi 638 639 [[ $subcmd == help ]] && return 0 640 641 # For this set of commands we may create COMPREPLY just by analysing the 642 # previous word, if it expects for a specific list of options or values. 643 if [[ $cmd =~ (qdisc|class|filter|action|exec) ]]; then 644 _tc_direct_complete $prev && return 0 645 if [[ ${words[${#words[@]}-3]} == estimator ]]; then 646 local list=$( _tc_expand_units 'secs' 'msecs' 'usecs' ) 647 COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) ) && return 0 648 fi 649 fi 650 651 # Completion depends on main command and subcommand in use. 652 case $cmd in 653 qdisc) 654 case $subcmd in 655 add|change|replace|link|del|delete) 656 if [[ $(($cword-$subcword)) -eq 1 ]]; then 657 COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) ) 658 return 0 659 fi 660 local qdisc qdwd 661 for ((qdwd=$subcword; qdwd < ${#words[@]}-1; qdwd++)); do 662 if [[ $QDISC_KIND =~ ' '${words[qdwd]}' ' ]]; then 663 qdisc=${words[qdwd]} 664 _tc_qdisc_options $qdisc && return 0 665 fi 666 done 667 _tc_one_of_list $QDISC_KIND 668 _tc_one_of_list 'root ingress parent clsact' 669 _tc_once_attr 'handle estimator stab' 670 ;; 671 show) 672 _tc_once_attr 'dev' 673 _tc_one_of_list 'ingress clsact' 674 _tc_once_attr '-statistics -details -raw -pretty -iec \ 675 -graph -name' 676 ;; 677 help) 678 return 0 679 ;; 680 *) 681 [[ $cword -eq $subcword ]] && \ 682 COMPREPLY=( $( compgen -W 'help add delete change \ 683 replace link show' -- "$cur" ) ) 684 ;; 685 esac 686 ;; 687 688 class) 689 case $subcmd in 690 add|change|replace|del|delete) 691 if [[ $(($cword-$subcword)) -eq 1 ]]; then 692 COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) ) 693 return 0 694 fi 695 local qdisc qdwd 696 for ((qdwd=$subcword; qdwd < ${#words[@]}-1; qdwd++)); do 697 if [[ $QDISC_KIND =~ ' '${words[qdwd]}' ' ]]; then 698 qdisc=${words[qdwd]} 699 _tc_qdisc_options $qdisc && return 0 700 fi 701 done 702 _tc_one_of_list $QDISC_KIND 703 _tc_one_of_list 'root parent' 704 _tc_once_attr 'classid' 705 ;; 706 show) 707 _tc_once_attr 'dev' 708 _tc_one_of_list 'root parent' 709 _tc_once_attr '-statistics -details -raw -pretty -iec \ 710 -graph -name' 711 ;; 712 help) 713 return 0 714 ;; 715 *) 716 [[ $cword -eq $subcword ]] && \ 717 COMPREPLY=( $( compgen -W 'help add delete change \ 718 replace show' -- "$cur" ) ) 719 ;; 720 esac 721 ;; 722 723 filter) 724 case $subcmd in 725 add|change|replace|del|delete) 726 if [[ $(($cword-$subcword)) -eq 1 ]]; then 727 COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) ) 728 return 0 729 fi 730 local filter fltwd 731 for ((fltwd=$subcword; fltwd < ${#words[@]}-1; fltwd++)); 732 do 733 if [[ $FILTER_KIND =~ ' '${words[fltwd]}' ' ]]; then 734 _tc_filter_options $fltwd && return 0 735 fi 736 done 737 _tc_one_of_list $FILTER_KIND 738 _tc_one_of_list 'root ingress egress parent' 739 _tc_once_attr 'handle estimator pref protocol' 740 ;; 741 show) 742 _tc_once_attr 'dev' 743 _tc_one_of_list 'root ingress egress parent' 744 _tc_once_attr '-statistics -details -raw -pretty -iec \ 745 -graph -name' 746 ;; 747 help) 748 return 0 749 ;; 750 *) 751 [[ $cword -eq $subcword ]] && \ 752 COMPREPLY=( $( compgen -W 'help add delete change \ 753 replace show' -- "$cur" ) ) 754 ;; 755 esac 756 ;; 757 758 action) 759 case $subcmd in 760 add|change|replace) 761 local action acwd 762 for ((acwd=$subcword; acwd < ${#words[@]}-1; acwd++)); do 763 if [[ $ACTION_KIND =~ ' '${words[acwd]}' ' ]]; then 764 _tc_action_options $acwd && return 0 765 fi 766 done 767 _tc_one_of_list $ACTION_KIND 768 ;; 769 get|del|delete) 770 _tc_once_attr 'index' 771 ;; 772 lst|list|flush|show) 773 _tc_one_of_list $ACTION_KIND 774 ;; 775 *) 776 [[ $cword -eq $subcword ]] && \ 777 COMPREPLY=( $( compgen -W 'help add delete change \ 778 replace show list flush action' -- "$cur" ) ) 779 ;; 780 esac 781 ;; 782 783 monitor) 784 COMPREPLY=( $( compgen -W 'help' -- "$cur" ) ) 785 ;; 786 787 exec) 788 case $subcmd in 789 bpf) 790 local excmd exwd EXEC_KIND=' import debug graft ' 791 for ((exwd=$subcword; exwd < ${#words[@]}-1; exwd++)); do 792 if [[ $EXEC_KIND =~ ' '${words[exwd]}' ' ]]; then 793 excmd=${words[exwd]} 794 _tc_exec_options $excmd && return 0 795 fi 796 done 797 _tc_one_of_list $EXEC_KIND 798 ;; 799 *) 800 [[ $cword -eq $subcword ]] && \ 801 COMPREPLY=( $( compgen -W 'bpf' -- "$cur" ) ) 802 ;; 803 esac 804 ;; 805 esac 806} && 807complete -F _tc tc 808 809# ex: ts=4 sw=4 et filetype=sh 810