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 sfb sfq tbf \ 7 drr hfsc htb prio qfq dualpi2' 8FILTER_KIND=' basic bpf cgroup flow flower fw route 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 ethercat ieeepup \ 131 ieeepupat ip ipv4 ipv6 ipx irda lat localtalk loop mobitex \ 132 ppp_disc ppp_mp ppp_ses ppptalk profinet pup pupat rarp sca \ 133 snap tipc tr_802_2 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 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 hfsc) 362 _tc_once_attr 'default' 363 return 0 364 ;; 365 htb) 366 _tc_once_attr 'default r2q direct_qlen debug' 367 return 0 368 ;; 369 dualpi2) 370 _tc_once_attr 'limit memlimit coupling_factor step_thresh \ 371 min_qlen_step classic_protection max_rtt typical_rtt \ 372 target tupdate alpha beta' 373 _tc_one_of_list 'drop_on_overload overflow' 374 _tc_one_of_list 'drop_enqueue drop_dequeue' 375 _tc_one_of_list 'l4s_ect any_ect' 376 _tc_one_of_list 'split_gso no_split_gso' 377 ;; 378 multiq|pfifo_fast|drr|qfq) 379 return 0 380 ;; 381 esac 382 return 1 383} 384 385# Complete with options names for BPF filters or actions. 386# Returns 0 is completion should stop after running this function, 1 otherwise. 387_tc_bpf_options() 388{ 389 [[ ${words[${#words[@]}-3]} == object-file ]] && \ 390 _tc_once_attr 'section export' 391 [[ ${words[${#words[@]}-5]} == object-file ]] && \ 392 [[ ${words[${#words[@]}-3]} =~ (section|export) ]] && \ 393 _tc_once_attr 'section export' 394 _tc_one_of_list 'bytecode bytecode-file object-file object-pinned' 395 _tc_once_attr 'verbose index direct-action action classid' 396 return 0 397} 398 399# Complete with options names for filter actions. 400# This function is recursive, thus allowing multiple actions statement to be 401# parsed. 402# Returns 0 is completion should stop after running this function, 1 otherwise. 403_tc_filter_action_options() 404{ 405 for ((acwd=$1; acwd < ${#words[@]}-1; acwd++)); 406 do 407 if [[ action == ${words[acwd]} ]]; then 408 _tc_filter_action_options $((acwd+1)) && return 0 409 fi 410 done 411 412 local action acwd 413 for ((acwd=$1; acwd < ${#words[@]}-1; acwd++)); do 414 if [[ $ACTION_KIND =~ ' '${words[acwd]}' ' ]]; then 415 _tc_one_of_list_from $acwd action 416 _tc_action_options $acwd && return 0 417 fi 418 done 419 _tc_one_of_list_from $acwd $ACTION_KIND 420 return 0 421} 422 423# Complete with options names for filters. 424# Returns 0 is completion should stop after running this function, 1 otherwise. 425_tc_filter_options() 426{ 427 428 for ((acwd=$1; acwd < ${#words[@]}-1; acwd++)); 429 do 430 if [[ action == ${words[acwd]} ]]; then 431 _tc_filter_action_options $((acwd+1)) && return 0 432 fi 433 done 434 435 filter=${words[$1]} 436 case $filter in 437 basic) 438 _tc_once_attr 'match action classid' 439 return 0 440 ;; 441 bpf) 442 _tc_bpf_options 443 return 0 444 ;; 445 cgroup) 446 _tc_once_attr 'match action' 447 return 0 448 ;; 449 flow) 450 local i 451 for (( i=5; i < ${#words[@]}-1; i++ )); do 452 if [[ ${words[i]} =~ ^keys?$ ]]; then 453 _tc_direct_complete 'key' 454 COMPREPLY+=( $( compgen -W 'or and xor rshift addend' -- \ 455 "$cur" ) ) 456 break 457 fi 458 done 459 _tc_once_attr 'map hash divisor baseclass match action' 460 return 0 461 ;; 462 matchall) 463 _tc_once_attr 'action classid skip_sw skip_hw' 464 return 0 465 ;; 466 flower) 467 _tc_once_attr 'action classid indev dst_mac src_mac eth_type \ 468 ip_proto dst_ip src_ip dst_port src_port' 469 return 0 470 ;; 471 fw) 472 _tc_once_attr 'action classid' 473 return 0 474 ;; 475 route) 476 _tc_one_of_list 'from fromif' 477 _tc_once_attr 'to classid action' 478 return 0 479 ;; 480 u32) 481 _tc_once_attr 'match link classid action offset ht hashkey sample' 482 COMPREPLY+=( $( compgen -W 'ip ip6 udp tcp icmp u8 u16 u32 mark \ 483 divisor' -- "$cur" ) ) 484 return 0 485 ;; 486 esac 487 return 1 488} 489 490# Complete with options names for actions. 491# Returns 0 is completion should stop after running this function, 1 otherwise. 492_tc_action_options() 493{ 494 local from=$1 495 local action=${words[from]} 496 case $action in 497 bpf) 498 _tc_bpf_options 499 return 0 500 ;; 501 mirred) 502 _tc_one_of_list_from $from 'ingress egress' 503 _tc_one_of_list_from $from 'mirror redirect' 504 _tc_once_attr_from $from 'index dev' 505 return 0 506 ;; 507 sample) 508 _tc_once_attr_from $from 'rate' 509 _tc_once_attr_from $from 'trunc' 510 _tc_once_attr_from $from 'group' 511 return 0 512 ;; 513 gact) 514 _tc_one_of_list_from $from 'reclassify drop continue pass' 515 _tc_once_attr_from $from 'random' 516 return 0 517 ;; 518 esac 519 return 1 520} 521 522# Complete with options names for exec. 523# Returns 0 is completion should stop after running this function, 1 otherwise. 524_tc_exec_options() 525{ 526 case $1 in 527 import) 528 [[ ${words[${#words[@]}-3]} == import ]] && \ 529 _tc_once_attr 'run' 530 return 0 531 ;; 532 graft) 533 COMPREPLY+=( $( compgen -W 'key type' -- "$cur" ) ) 534 [[ ${words[${#words[@]}-3]} == object-file ]] && \ 535 _tc_once_attr 'type' 536 _tc_bpf_options 537 return 0 538 ;; 539 esac 540 return 1 541} 542 543# Main completion function 544# Logic is as follows: 545# 1. Check if previous word is a global option; if so, propose arguments. 546# 2. Check if current word is a global option; if so, propose completion. 547# 3. Check for the presence of a main command (qdisc|class|filter|...). If 548# there is one, first call _tc_direct_complete to see if previous word is 549# waiting for a particular completion. If so, propose completion and exit. 550# 4. Extract main command and -- if available -- its subcommand 551# (add|delete|show|...). 552# 5. Propose completion based on main and sub- command in use. Additional 553# functions may be called for qdiscs, classes or filter options. 554_tc() 555{ 556 local cur prev words cword 557 _init_completion || return 558 559 case $prev in 560 -V|-Version) 561 return 0 562 ;; 563 -b|-batch|-cf|-conf) 564 _filedir 565 return 0 566 ;; 567 -force) 568 COMPREPLY=( $( compgen -W '-batch' -- "$cur" ) ) 569 return 0 570 ;; 571 -nm|name) 572 [[ -r /etc/iproute2/tc_cls ]] || \ 573 COMPREPLY=( $( compgen -W '-conf' -- "$cur" ) ) 574 return 0 575 ;; 576 -n|-net|-netns) 577 local nslist=$( ip netns list 2>/dev/null ) 578 COMPREPLY+=( $( compgen -W "$nslist" -- "$cur" ) ) 579 return 0 580 ;; 581 -tshort) 582 _tc_once_attr '-statistics' 583 COMPREPLY+=( $( compgen -W 'monitor' -- "$cur" ) ) 584 return 0 585 ;; 586 -timestamp) 587 _tc_once_attr '-statistics -tshort' 588 COMPREPLY+=( $( compgen -W 'monitor' -- "$cur" ) ) 589 return 0 590 ;; 591 esac 592 593 # Search for main commands 594 local subcword cmd subcmd 595 for (( subcword=1; subcword < ${#words[@]}-1; subcword++ )); do 596 [[ ${words[subcword]} == -b?(atch) ]] && return 0 597 [[ -n $cmd ]] && subcmd=${words[subcword]} && break 598 [[ ${words[subcword]} != -* && \ 599 ${words[subcword-1]} != -@(n?(et?(ns))|c?(on)f) ]] && \ 600 cmd=${words[subcword]} 601 done 602 603 if [[ -z $cmd ]]; then 604 case $cur in 605 -*) 606 local c='-Version -statistics -details -raw -pretty \ 607 -iec -graphe -batch -name -netns -timestamp' 608 [[ $cword -eq 1 ]] && c+=' -force' 609 COMPREPLY=( $( compgen -W "$c" -- "$cur" ) ) 610 return 0 611 ;; 612 *) 613 COMPREPLY=( $( compgen -W "help $( tc help 2>&1 | \ 614 command sed \ 615 -e '/OBJECT := /!d' \ 616 -e 's/.*{//' \ 617 -e 's/}.*//' \ 618 -e \ 's/|//g' )" -- "$cur" ) ) 619 return 0 620 ;; 621 esac 622 fi 623 624 [[ $subcmd == help ]] && return 0 625 626 # For this set of commands we may create COMPREPLY just by analysing the 627 # previous word, if it expects for a specific list of options or values. 628 if [[ $cmd =~ (qdisc|class|filter|action|exec) ]]; then 629 _tc_direct_complete $prev && return 0 630 if [[ ${words[${#words[@]}-3]} == estimator ]]; then 631 local list=$( _tc_expand_units 'secs' 'msecs' 'usecs' ) 632 COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) ) && return 0 633 fi 634 fi 635 636 # Completion depends on main command and subcommand in use. 637 case $cmd in 638 qdisc) 639 case $subcmd in 640 add|change|replace|link|del|delete) 641 if [[ $(($cword-$subcword)) -eq 1 ]]; then 642 COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) ) 643 return 0 644 fi 645 local qdisc qdwd 646 for ((qdwd=$subcword; qdwd < ${#words[@]}-1; qdwd++)); do 647 if [[ $QDISC_KIND =~ ' '${words[qdwd]}' ' ]]; then 648 qdisc=${words[qdwd]} 649 _tc_qdisc_options $qdisc && return 0 650 fi 651 done 652 _tc_one_of_list $QDISC_KIND 653 _tc_one_of_list 'root ingress parent clsact' 654 _tc_once_attr 'handle estimator stab' 655 ;; 656 show) 657 _tc_once_attr 'dev' 658 _tc_one_of_list 'ingress clsact' 659 _tc_once_attr '-statistics -details -raw -pretty -iec \ 660 -graph -name' 661 ;; 662 help) 663 return 0 664 ;; 665 *) 666 [[ $cword -eq $subcword ]] && \ 667 COMPREPLY=( $( compgen -W 'help add delete change \ 668 replace link show' -- "$cur" ) ) 669 ;; 670 esac 671 ;; 672 673 class) 674 case $subcmd in 675 add|change|replace|del|delete) 676 if [[ $(($cword-$subcword)) -eq 1 ]]; then 677 COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) ) 678 return 0 679 fi 680 local qdisc qdwd 681 for ((qdwd=$subcword; qdwd < ${#words[@]}-1; qdwd++)); do 682 if [[ $QDISC_KIND =~ ' '${words[qdwd]}' ' ]]; then 683 qdisc=${words[qdwd]} 684 _tc_qdisc_options $qdisc && return 0 685 fi 686 done 687 _tc_one_of_list $QDISC_KIND 688 _tc_one_of_list 'root parent' 689 _tc_once_attr 'classid' 690 ;; 691 show) 692 _tc_once_attr 'dev' 693 _tc_one_of_list 'root parent' 694 _tc_once_attr '-statistics -details -raw -pretty -iec \ 695 -graph -name' 696 ;; 697 help) 698 return 0 699 ;; 700 *) 701 [[ $cword -eq $subcword ]] && \ 702 COMPREPLY=( $( compgen -W 'help add delete change \ 703 replace show' -- "$cur" ) ) 704 ;; 705 esac 706 ;; 707 708 filter) 709 case $subcmd in 710 add|change|replace|del|delete) 711 if [[ $(($cword-$subcword)) -eq 1 ]]; then 712 COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) ) 713 return 0 714 fi 715 local filter fltwd 716 for ((fltwd=$subcword; fltwd < ${#words[@]}-1; fltwd++)); 717 do 718 if [[ $FILTER_KIND =~ ' '${words[fltwd]}' ' ]]; then 719 _tc_filter_options $fltwd && return 0 720 fi 721 done 722 _tc_one_of_list $FILTER_KIND 723 _tc_one_of_list 'root ingress egress parent' 724 _tc_once_attr 'handle estimator pref protocol' 725 ;; 726 show) 727 _tc_once_attr 'dev' 728 _tc_one_of_list 'root ingress egress parent' 729 _tc_once_attr '-statistics -details -raw -pretty -iec \ 730 -graph -name' 731 ;; 732 help) 733 return 0 734 ;; 735 *) 736 [[ $cword -eq $subcword ]] && \ 737 COMPREPLY=( $( compgen -W 'help add delete change \ 738 replace show' -- "$cur" ) ) 739 ;; 740 esac 741 ;; 742 743 action) 744 case $subcmd in 745 add|change|replace) 746 local action acwd 747 for ((acwd=$subcword; acwd < ${#words[@]}-1; acwd++)); do 748 if [[ $ACTION_KIND =~ ' '${words[acwd]}' ' ]]; then 749 _tc_action_options $acwd && return 0 750 fi 751 done 752 _tc_one_of_list $ACTION_KIND 753 ;; 754 get|del|delete) 755 _tc_once_attr 'index' 756 ;; 757 lst|list|flush|show) 758 _tc_one_of_list $ACTION_KIND 759 ;; 760 *) 761 [[ $cword -eq $subcword ]] && \ 762 COMPREPLY=( $( compgen -W 'help add delete change \ 763 replace show list flush action' -- "$cur" ) ) 764 ;; 765 esac 766 ;; 767 768 monitor) 769 COMPREPLY=( $( compgen -W 'help' -- "$cur" ) ) 770 ;; 771 772 exec) 773 case $subcmd in 774 bpf) 775 local excmd exwd EXEC_KIND=' import debug graft ' 776 for ((exwd=$subcword; exwd < ${#words[@]}-1; exwd++)); do 777 if [[ $EXEC_KIND =~ ' '${words[exwd]}' ' ]]; then 778 excmd=${words[exwd]} 779 _tc_exec_options $excmd && return 0 780 fi 781 done 782 _tc_one_of_list $EXEC_KIND 783 ;; 784 *) 785 [[ $cword -eq $subcword ]] && \ 786 COMPREPLY=( $( compgen -W 'bpf' -- "$cur" ) ) 787 ;; 788 esac 789 ;; 790 esac 791} && 792complete -F _tc tc 793 794# ex: ts=4 sw=4 et filetype=sh 795

