1 # tc(8) completion -*- shell-script -*-
2 # Copyright 2016 6WIND S.A.
3 # Copyright 2016 Quentin Monnet <quentin.monnet@6wind.com>
5 # Takes a list of words in argument; each one of them is added to COMPREPLY if
6 # it is not already present on the command line. Returns no value.
12 for (( subcword=3; subcword < ${#words[@]}-1; subcword++ )); do
13 if [[ $w == ${words[subcword]} ]]; then
18 [[ $found -eq 0 ]] && \
19 COMPREPLY+=( $( compgen -W "$w" -- "$cur" ) )
23 # Takes a list of words in argument; adds them all to COMPREPLY if none of them
24 # is already present on the command line. Returns no value.
29 for (( subcword=3; subcword < ${#words[@]}-1; subcword++ )); do
30 [[ $w == ${words[subcword]} ]] && return 1
33 COMPREPLY+=( $( compgen -W "$*" -- "$cur" ) )
36 # Returns "$cur ${cur}arg1 ${cur}arg2 ..."
39 [[ $cur =~ ^[0-9]+ ]] || return 1
40 local value=${cur%%[^0-9]*}
41 [[ $cur == $value ]] && echo $cur
45 # Complete based on given word, usually $prev (or possibly the word before),
46 # for when an argument or an option name has but a few possible arguments (so
47 # tc does not take particular commands into account here).
48 # Returns 0 is completion should stop after running this function, 1 otherwise.
61 local list=$( _tc_expand_units 'secs' 'msecs' 'usecs' )
62 COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) )
70 for (( i=3; i < ${#words[@]}-2; i++ )); do
71 [[ ${words[i]} == dev ]] && iface=${words[i+1]}
74 for cmd in qdisc class; do
75 if [[ -n $iface ]]; then
76 ids+=$( tc $cmd show dev $iface 2>/dev/null | \
79 ids+=$( tc $cmd show 2>/dev/null | cut -d\ -f 3 )
82 [[ $ids != " " ]] && \
83 COMPREPLY+=( $( compgen -W "$ids" -- "$cur" ) )
86 protocol) # list comes from lib/ll_proto.c
87 COMPREPLY+=( $( compgen -W ' 802.1Q 802.1ad 802_2 802_3 LLDP aarp \
88 all aoe arp atalk atmfate atmmpoa ax25 bpq can control cust \
89 ddcmp dec diag dna_dl dna_rc dna_rt econet ieeepup ieeepupat \
90 ip ipv4 ipv6 ipx irda lat localtalk loop mobitex ppp_disc \
91 ppp_mp ppp_ses ppptalk pup pupat rarp sca snap tipc tr_802_2 \
92 wan_ppp x25' -- "$cur" ) )
99 COMPREPLY+=( $( compgen -W 'mtu tsize mpu overhead
100 linklayer' -- "$cur" ) )
103 # Qdiscs and classes options
104 alpha|bands|beta|buckets|corrupt|debug|decrement|default|\
105 default_index|depth|direct_qlen|divisor|duplicate|ewma|flow_limit|\
106 flows|hh_limit|increment|indices|linklayer|non_hh_weight|num_tc|\
107 penalty_burst|penalty_rate|prio|priomap|probability|queues|r2q|\
112 COMPREPLY+=( $( compgen -W 'vqs' -- "$cur" ) )
116 COMPREPLY+=( $( compgen -W '1 0' -- "$cur" ) )
120 COMPREPLY+=( $( compgen -W 'uniform normal pareto
121 paretonormal' -- "$cur" ) )
125 COMPREPLY+=( $( compgen -W 'random state gmodel' -- "$cur" ) )
129 # Qdiscs and classes options options
136 COMPREPLY+=( $( compgen -W 'key' -- "$cur" ) )
140 COMPREPLY+=( $( compgen -W 'keys' -- "$cur" ) )
144 _available_interfaces
148 COMPREPLY+=( $( compgen -W 'ipv4 ipv6' -- "$cur" ) )
152 COMPREPLY+=( $( compgen -W 'tcp udp' -- "$cur" ) )
156 # Filters options options
158 [[ ${words[@]} =~ graft ]] && return 1
159 COMPREPLY+=( $( compgen -W 'src dst proto proto-src proto-dst iif \
160 priority mark nfct nfct-src nfct-dst nfct-proto-src \
161 nfct-proto-dst rt-classid sk-uid sk-gid vlan-tag rxhash' -- \
166 # BPF options - used for filters, actions, and exec
167 export|bytecode|bytecode-file|object-file)
171 object-pinned|graft) # Pinned object is probably under /sys/fs/bpf/
172 [[ -n "$cur" ]] && _filedir && return 0
173 COMPREPLY=( $( compgen -G "/sys/fs/bpf/*" -- "$cur" ) ) || _filedir
178 if (type objdump > /dev/null 2>&1) ; then
179 local fword objfile section_list
180 for (( fword=3; fword < ${#words[@]}-3; fword++ )); do
181 if [[ ${words[fword]} == object-file ]]; then
182 objfile=${words[fword+1]}
186 section_list=$( objdump -h $objfile 2>/dev/null | \
187 sed -n 's/^ *[0-9]\+ \([^ ]*\) *.*/\1/p' )
188 COMPREPLY+=( $( compgen -W "$section_list" -- "$cur" ) )
197 COMPREPLY+=( $( compgen -W 'cls act' -- "$cur" ) )
203 _tc_one_of_list 'netrand determ'
207 # Units for option arguments
208 bandwidth|maxrate|peakrate|rate)
209 local list=$( _tc_expand_units 'bit' \
210 'kbit' 'kibit' 'kbps' 'kibps' \
211 'mbit' 'mibit' 'mbps' 'mibps' \
212 'gbit' 'gibit' 'gbps' 'gibps' \
213 'tbit' 'tibit' 'tbps' 'tibps' )
214 COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) )
216 admit_bytes|avpkt|burst|cell|initial_quantum|limit|max|min|mtu|mpu|\
217 overhead|quantum|redflowlist)
218 local list=$( _tc_expand_units \
219 'b' 'kbit' 'k' 'mbit' 'm' 'gbit' 'g' )
220 COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) )
222 db|delay|evict_timeout|interval|latency|perturb|rehash|reset_timeout|\
224 local list=$( _tc_expand_units 'secs' 'msecs' 'usecs' )
225 COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) )
231 # Complete with options names for qdiscs. Each qdisc has its own set of options
232 # and it seems we cannot really parse it from anywhere, so we add it manually
234 # Returns 0 is completion should stop after running this function, 1 otherwise.
239 _tc_once_attr 'limit bandwidth ecn min max burst'
243 _tc_once_attr 'limit target interval'
244 _tc_one_of_list 'ecn noecn'
247 bfifo|pfifo|pfifo_head_drop)
248 _tc_once_attr 'limit'
252 _tc_once_attr 'limit flow_limit quantum initial_quantum maxrate \
254 _tc_one_of_list 'pacing nopacing'
258 _tc_once_attr 'limit flows target interval quantum'
259 _tc_one_of_list 'ecn noecn'
263 _tc_once_attr 'setup vqs default grio vq prio limit min max avpkt \
264 burst probability bandwidth'
268 _tc_once_attr 'limit quantum hh_limit reset_timeout admit_bytes \
269 evict_timeout non_hh_weight'
273 _tc_once_attr 'num_tc map queues hw'
277 _tc_once_attr 'delay distribution corrupt duplicate loss ecn \
282 _tc_once_attr 'limit target tupdate alpha beta'
283 _tc_one_of_list 'bytemode nobytemode'
284 _tc_one_of_list 'ecn noecn'
288 _tc_once_attr 'limit min max avpkt burst adaptive probability \
289 bandwidth ecn harddrop'
293 _tc_once_attr 'bands priomap multiqueue'
297 _tc_once_attr 'rehash db limit max target increment decrement \
298 penalty_rate penalty_burst'
302 _tc_once_attr 'limit perturb quantum divisor flows depth headdrop \
303 redflowlimit min max avpkt burst probability ecn harddrop'
307 _tc_once_attr 'limit burst rate mtu peakrate latency overhead \
312 _tc_once_attr 'bandwidth avpkt mpu cell ewma'
316 _tc_once_attr 'indices default_index set_tc_index'
320 _tc_once_attr 'default'
324 _tc_once_attr 'default r2q direct_qlen debug'
327 multiq|pfifo_fast|atm|drr|qfq)
334 # Complete with options names for BPF filters or actions.
335 # Returns 0 is completion should stop after running this function, 1 otherwise.
338 [[ ${words[${#words[@]}-3]} == object-file ]] && \
339 _tc_once_attr 'section export'
340 [[ ${words[${#words[@]}-5]} == object-file ]] && \
341 [[ ${words[${#words[@]}-3]} =~ (section|export) ]] && \
342 _tc_once_attr 'section export'
343 _tc_one_of_list 'bytecode bytecode-file object-file object-pinned'
344 _tc_once_attr 'verbose index direct-action action classid'
348 # Complete with options names for filters.
349 # Returns 0 is completion should stop after running this function, 1 otherwise.
354 _tc_once_attr 'match action classid'
362 _tc_once_attr 'match action'
367 for (( i=5; i < ${#words[@]}-1; i++ )); do
368 if [[ ${words[i]} =~ ^keys?$ ]]; then
369 _tc_direct_complete 'key'
370 COMPREPLY+=( $( compgen -W 'or and xor rshift addend' -- \
375 _tc_once_attr 'map hash divisor baseclass match action'
379 _tc_once_attr 'action classid indev dst_mac src_mac eth_type \
380 ip_proto dst_ip src_ip dst_port src_port'
384 _tc_once_attr 'action classid'
388 _tc_one_of_list 'from fromif'
389 _tc_once_attr 'to classid action'
393 _tc_once_attr 'ipproto session sender classid action tunnelid \
394 tunnel flowlabel spi/ah spi/esp u8 u16 u32'
395 [[ ${words[${#words[@]}-3]} == tunnel ]] && \
396 COMPREPLY+=( $( compgen -W 'skip' -- "$cur" ) )
397 [[ ${words[${#words[@]}-3]} =~ u(8|16|32) ]] && \
398 COMPREPLY+=( $( compgen -W 'mask' -- "$cur" ) )
399 [[ ${words[${#words[@]}-3]} == mask ]] && \
400 COMPREPLY+=( $( compgen -W 'at' -- "$cur" ) )
404 _tc_once_attr 'hash mask shift classid action'
405 _tc_one_of_list 'pass_on fall_through'
409 _tc_once_attr 'match link classid action offset ht hashkey sample'
410 COMPREPLY+=( $( compgen -W 'ip ip6 udp tcp icmp u8 u16 u32 mark \
411 divisor' -- "$cur" ) )
418 # Complete with options names for actions.
419 # Returns 0 is completion should stop after running this function, 1 otherwise.
428 _tc_one_of_list 'ingress egress'
429 _tc_one_of_list 'mirror redirect'
430 _tc_once_attr 'index dev'
434 _tc_one_of_list 'reclassify drop continue pass'
435 _tc_once_attr 'random'
442 # Complete with options names for exec.
443 # Returns 0 is completion should stop after running this function, 1 otherwise.
448 [[ ${words[${#words[@]}-3]} == import ]] && \
453 COMPREPLY+=( $( compgen -W 'key type' -- "$cur" ) )
454 [[ ${words[${#words[@]}-3]} == object-file ]] && \
463 # Main completion function
464 # Logic is as follows:
465 # 1. Check if previous word is a global option; if so, propose arguments.
466 # 2. Check if current word is a global option; if so, propose completion.
467 # 3. Check for the presence of a main command (qdisc|class|filter|...). If
468 # there is one, first call _tc_direct_complete to see if previous word is
469 # waiting for a particular completion. If so, propose completion and exit.
470 # 4. Extract main command and -- if available -- its subcommand
471 # (add|delete|show|...).
472 # 5. Propose completion based on main and sub- command in use. Additional
473 # functions may be called for qdiscs, classes or filter options.
476 local cur prev words cword
477 _init_completion || return
488 COMPREPLY=( $( compgen -W '-batch' -- "$cur" ) )
492 [[ -r /etc/iproute2/tc_cls ]] || \
493 COMPREPLY=( $( compgen -W '-conf' -- "$cur" ) )
497 local nslist=$( ip netns list 2>/dev/null )
498 COMPREPLY+=( $( compgen -W "$nslist" -- "$cur" ) )
502 _tc_once_attr '-statistics'
503 COMPREPLY+=( $( compgen -W 'monitor' -- "$cur" ) )
507 _tc_once_attr '-statistics -tshort'
508 COMPREPLY+=( $( compgen -W 'monitor' -- "$cur" ) )
513 # Search for main commands
514 local subcword cmd subcmd
515 for (( subcword=1; subcword < ${#words[@]}-1; subcword++ )); do
516 [[ ${words[subcword]} == -b?(atch) ]] && return 0
517 [[ -n $cmd ]] && subcmd=${words[subcword]} && break
518 [[ ${words[subcword]} != -* && \
519 ${words[subcword-1]} != -@(n?(et?(ns))|c?(on)f) ]] && \
520 cmd=${words[subcword]}
523 if [[ -z $cmd ]]; then
526 local c='-Version -statistics -details -raw -pretty \
527 -iec -graphe -batch -name -netns -timestamp'
528 [[ $cword -eq 1 ]] && c+=' -force'
529 COMPREPLY=( $( compgen -W "$c" -- "$cur" ) )
533 COMPREPLY=( $( compgen -W "help $( tc help 2>&1 | \
535 -e '/OBJECT := /!d' \
538 -e \ 's/|//g' )" -- "$cur" ) )
544 [[ $subcmd == help ]] && return 0
546 # For this set of commands we may create COMPREPLY just by analysing the
547 # previous word, if it expects for a specific list of options or values.
548 if [[ $cmd =~ (qdisc|class|filter|action|exec) ]]; then
549 _tc_direct_complete $prev && return 0
550 if [[ ${words[${#words[@]}-3]} == estimator ]]; then
551 local list=$( _tc_expand_units 'secs' 'msecs' 'usecs' )
552 COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) ) && return 0
556 # Completion depends on main command and subcommand in use.
560 add|change|replace|link|del|delete)
561 if [[ $(($cword-$subcword)) -eq 1 ]]; then
562 COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
565 local qdisc qdwd QDISC_KIND=' choke codel bfifo pfifo \
566 pfifo_head_drop fq fq_codel gred hhf mqprio multiq \
567 netem pfifo_fast pie red rr sfb sfq tbf atm cbq drr \
568 dsmark hfsc htb prio qfq '
569 for ((qdwd=$subcword; qdwd < ${#words[@]}-1; qdwd++)); do
570 if [[ $QDISC_KIND =~ ' '${words[qdwd]}' ' ]]; then
572 _tc_qdisc_options $qdisc && return 0
575 _tc_one_of_list $QDISC_KIND
576 _tc_one_of_list 'root ingress parent clsact'
577 _tc_once_attr 'handle estimator stab'
581 _tc_one_of_list 'ingress clsact'
582 _tc_once_attr '-statistics -details -raw -pretty -iec \
589 [[ $cword -eq $subcword ]] && \
590 COMPREPLY=( $( compgen -W 'help add delete change \
591 replace link show' -- "$cur" ) )
598 add|change|replace|del|delete)
599 if [[ $(($cword-$subcword)) -eq 1 ]]; then
600 COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
603 local qdisc qdwd QDISC_KIND=' choke codel bfifo pfifo \
604 pfifo_head_drop fq fq_codel gred hhf mqprio multiq \
605 netem pfifo_fast pie red rr sfb sfq tbf atm cbq drr \
606 dsmark hfsc htb prio qfq '
607 for ((qdwd=$subcword; qdwd < ${#words[@]}-1; qdwd++)); do
608 if [[ $QDISC_KIND =~ ' '${words[qdwd]}' ' ]]; then
610 _tc_qdisc_options $qdisc && return 0
613 _tc_one_of_list $QDISC_KIND
614 _tc_one_of_list 'root parent'
615 _tc_once_attr 'classid'
619 _tc_one_of_list 'root parent'
620 _tc_once_attr '-statistics -details -raw -pretty -iec \
627 [[ $cword -eq $subcword ]] && \
628 COMPREPLY=( $( compgen -W 'help add delete change \
629 replace show' -- "$cur" ) )
636 add|change|replace|del|delete)
637 if [[ $(($cword-$subcword)) -eq 1 ]]; then
638 COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
641 local filter fltwd FILTER_KIND=' basic bpf cgroup flow \
642 flower fw route rsvp tcindex u32 '
643 for ((fltwd=$subcword; fltwd < ${#words[@]}-1; fltwd++));
645 if [[ $FILTER_KIND =~ ' '${words[fltwd]}' ' ]]; then
646 filter=${words[fltwd]}
647 _tc_filter_options $filter && return 0
650 _tc_one_of_list $FILTER_KIND
651 _tc_one_of_list 'root ingress egress parent'
652 _tc_once_attr 'handle estimator pref protocol'
656 _tc_one_of_list 'root ingress egress parent'
657 _tc_once_attr '-statistics -details -raw -pretty -iec \
664 [[ $cword -eq $subcword ]] && \
665 COMPREPLY=( $( compgen -W 'help add delete change \
666 replace show' -- "$cur" ) )
674 local action acwd ACTION_KIND=' gact mirred bpf '
675 for ((acwd=$subcword; acwd < ${#words[@]}-1; acwd++)); do
676 if [[ $ACTION_KIND =~ ' '${words[acwd]}' ' ]]; then
677 action=${words[acwd]}
678 _tc_action_options $action && return 0
681 _tc_one_of_list $ACTION_KIND
684 _tc_once_attr 'index'
687 _tc_one_of_list $ACTION_KIND
690 [[ $cword -eq $subcword ]] && \
691 COMPREPLY=( $( compgen -W 'help add delete change \
692 replace show list flush action' -- "$cur" ) )
698 COMPREPLY=( $( compgen -W 'help' -- "$cur" ) )
704 local excmd exwd EXEC_KIND=' import debug graft '
705 for ((exwd=$subcword; exwd < ${#words[@]}-1; exwd++)); do
706 if [[ $EXEC_KIND =~ ' '${words[exwd]}' ' ]]; then
708 _tc_exec_options $excmd && return 0
711 _tc_one_of_list $EXEC_KIND
714 [[ $cword -eq $subcword ]] && \
715 COMPREPLY=( $( compgen -W 'bpf' -- "$cur" ) )
723 # ex: ts=4 sw=4 et filetype=sh