mirror of
https://git.proxmox.com/git/mirror_iproute2
synced 2025-10-06 00:23:53 +00:00

PIE now uses per packet timestamps to calculate queuing delay. The average dequeue rate based queue delay calculation is now made optional. This patch adds the option to enable or disable the use of Little's law to calculate queuing delay. Signed-off-by: Gautam Ramakrishnan <gautamramk@gmail.com> Signed-off-by: Leslie Monis <lesliemonis@gmail.com> Signed-off-by: Mohit P. Tahiliani <tahiliani@nitk.edu.in> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
802 lines
26 KiB
Bash
802 lines
26 KiB
Bash
# tc(8) completion -*- shell-script -*-
|
|
# Copyright 2016 6WIND S.A.
|
|
# Copyright 2016 Quentin Monnet <quentin.monnet@6wind.com>
|
|
|
|
QDISC_KIND=' choke codel bfifo pfifo pfifo_head_drop fq fq_codel gred hhf \
|
|
mqprio multiq netem pfifo_fast pie red rr sfb sfq tbf atm cbq drr \
|
|
dsmark hfsc htb prio qfq '
|
|
FILTER_KIND=' basic bpf cgroup flow flower fw route rsvp tcindex u32 matchall '
|
|
ACTION_KIND=' gact mirred bpf sample '
|
|
|
|
# Takes a list of words in argument; each one of them is added to COMPREPLY if
|
|
# it is not already present on the command line. Returns no value.
|
|
_tc_once_attr()
|
|
{
|
|
local w subcword found
|
|
for w in $*; do
|
|
found=0
|
|
for (( subcword=3; subcword < ${#words[@]}-1; subcword++ )); do
|
|
if [[ $w == ${words[subcword]} ]]; then
|
|
found=1
|
|
break
|
|
fi
|
|
done
|
|
[[ $found -eq 0 ]] && \
|
|
COMPREPLY+=( $( compgen -W "$w" -- "$cur" ) )
|
|
done
|
|
}
|
|
|
|
# Takes a list of words in argument; each one of them is added to COMPREPLY if
|
|
# it is not already present on the command line from the provided index. Returns
|
|
# no value.
|
|
_tc_once_attr_from()
|
|
{
|
|
local w subcword found from=$1
|
|
shift
|
|
for w in $*; do
|
|
found=0
|
|
for (( subcword=$from; subcword < ${#words[@]}-1; subcword++ )); do
|
|
if [[ $w == ${words[subcword]} ]]; then
|
|
found=1
|
|
break
|
|
fi
|
|
done
|
|
[[ $found -eq 0 ]] && \
|
|
COMPREPLY+=( $( compgen -W "$w" -- "$cur" ) )
|
|
done
|
|
}
|
|
|
|
# Takes a list of words in argument; adds them all to COMPREPLY if none of them
|
|
# is already present on the command line. Returns no value.
|
|
_tc_one_of_list()
|
|
{
|
|
local w subcword
|
|
for w in $*; do
|
|
for (( subcword=3; subcword < ${#words[@]}-1; subcword++ )); do
|
|
[[ $w == ${words[subcword]} ]] && return 1
|
|
done
|
|
done
|
|
COMPREPLY+=( $( compgen -W "$*" -- "$cur" ) )
|
|
}
|
|
|
|
# Takes a list of words in argument; adds them all to COMPREPLY if none of them
|
|
# is already present on the command line from the provided index. Returns no
|
|
# value.
|
|
_tc_one_of_list_from()
|
|
{
|
|
local w subcword from=$1
|
|
shift
|
|
for w in $*; do
|
|
for (( subcword=$from; subcword < ${#words[@]}-1; subcword++ )); do
|
|
[[ $w == ${words[subcword]} ]] && return 1
|
|
done
|
|
done
|
|
COMPREPLY+=( $( compgen -W "$*" -- "$cur" ) )
|
|
}
|
|
|
|
# Returns "$cur ${cur}arg1 ${cur}arg2 ..."
|
|
_tc_expand_units()
|
|
{
|
|
[[ $cur =~ ^[0-9]+ ]] || return 1
|
|
local value=${cur%%[^0-9]*}
|
|
[[ $cur == $value ]] && echo $cur
|
|
echo ${@/#/$value}
|
|
}
|
|
|
|
# Complete based on given word, usually $prev (or possibly the word before),
|
|
# for when an argument or an option name has but a few possible arguments (so
|
|
# tc does not take particular commands into account here).
|
|
# Returns 0 is completion should stop after running this function, 1 otherwise.
|
|
_tc_direct_complete()
|
|
{
|
|
case $1 in
|
|
# Command options
|
|
dev)
|
|
_available_interfaces
|
|
return 0
|
|
;;
|
|
classid)
|
|
return 0
|
|
;;
|
|
estimator)
|
|
local list=$( _tc_expand_units 'secs' 'msecs' 'usecs' )
|
|
COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
handle)
|
|
return 0
|
|
;;
|
|
parent|flowid)
|
|
local i iface ids cmd
|
|
for (( i=3; i < ${#words[@]}-2; i++ )); do
|
|
[[ ${words[i]} == dev ]] && iface=${words[i+1]}
|
|
break
|
|
done
|
|
for cmd in qdisc class; do
|
|
if [[ -n $iface ]]; then
|
|
ids+=$( tc $cmd show dev $iface 2>/dev/null | \
|
|
cut -d\ -f 3 )" "
|
|
else
|
|
ids+=$( tc $cmd show 2>/dev/null | cut -d\ -f 3 )
|
|
fi
|
|
done
|
|
[[ $ids != " " ]] && \
|
|
COMPREPLY+=( $( compgen -W "$ids" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
protocol) # list comes from lib/ll_proto.c
|
|
COMPREPLY+=( $( compgen -W ' 802.1Q 802.1ad 802_2 802_3 LLDP aarp \
|
|
all aoe arp atalk atmfate atmmpoa ax25 bpq can control cust \
|
|
ddcmp dec diag dna_dl dna_rc dna_rt econet ieeepup ieeepupat \
|
|
ip ipv4 ipv6 ipx irda lat localtalk loop mobitex ppp_disc \
|
|
ppp_mp ppp_ses ppptalk pup pupat rarp sca snap tipc tr_802_2 \
|
|
wan_ppp x25' -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
prio)
|
|
return 0
|
|
;;
|
|
stab)
|
|
COMPREPLY+=( $( compgen -W 'mtu tsize mpu overhead
|
|
linklayer' -- "$cur" ) )
|
|
;;
|
|
|
|
# Qdiscs and classes options
|
|
alpha|bands|beta|buckets|corrupt|debug|decrement|default|\
|
|
default_index|depth|direct_qlen|divisor|duplicate|ewma|flow_limit|\
|
|
flows|hh_limit|increment|indices|linklayer|non_hh_weight|num_tc|\
|
|
penalty_burst|penalty_rate|prio|priomap|probability|queues|r2q|\
|
|
reorder|vq|vqs)
|
|
return 0
|
|
;;
|
|
setup)
|
|
COMPREPLY+=( $( compgen -W 'vqs' -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
hw)
|
|
COMPREPLY+=( $( compgen -W '1 0' -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
distribution)
|
|
COMPREPLY+=( $( compgen -W 'uniform normal pareto
|
|
paretonormal' -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
loss)
|
|
COMPREPLY+=( $( compgen -W 'random state gmodel' -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
|
|
# Qdiscs and classes options options
|
|
gap|gmodel|state)
|
|
return 0
|
|
;;
|
|
|
|
# Filters options
|
|
map)
|
|
COMPREPLY+=( $( compgen -W 'key' -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
hash)
|
|
COMPREPLY+=( $( compgen -W 'keys' -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
indev)
|
|
_available_interfaces
|
|
return 0
|
|
;;
|
|
eth_type)
|
|
COMPREPLY+=( $( compgen -W 'ipv4 ipv6' -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
ip_proto)
|
|
COMPREPLY+=( $( compgen -W 'tcp udp' -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
|
|
# Filters options options
|
|
key|keys)
|
|
[[ ${words[@]} =~ graft ]] && return 1
|
|
COMPREPLY+=( $( compgen -W 'src dst proto proto-src proto-dst iif \
|
|
priority mark nfct nfct-src nfct-dst nfct-proto-src \
|
|
nfct-proto-dst rt-classid sk-uid sk-gid vlan-tag rxhash' -- \
|
|
"$cur" ) )
|
|
return 0
|
|
;;
|
|
|
|
# BPF options - used for filters, actions, and exec
|
|
export|bytecode|bytecode-file|object-file)
|
|
_filedir
|
|
return 0
|
|
;;
|
|
object-pinned|graft) # Pinned object is probably under /sys/fs/bpf/
|
|
[[ -n "$cur" ]] && _filedir && return 0
|
|
COMPREPLY=( $( compgen -G "/sys/fs/bpf/*" -- "$cur" ) ) || _filedir
|
|
compopt -o nospace
|
|
return 0
|
|
;;
|
|
section)
|
|
if (type objdump > /dev/null 2>&1) ; then
|
|
local fword objfile section_list
|
|
for (( fword=3; fword < ${#words[@]}-3; fword++ )); do
|
|
if [[ ${words[fword]} == object-file ]]; then
|
|
objfile=${words[fword+1]}
|
|
break
|
|
fi
|
|
done
|
|
section_list=$( objdump -h $objfile 2>/dev/null | \
|
|
sed -n 's/^ *[0-9]\+ \([^ ]*\) *.*/\1/p' )
|
|
COMPREPLY+=( $( compgen -W "$section_list" -- "$cur" ) )
|
|
fi
|
|
return 0
|
|
;;
|
|
import|run)
|
|
_filedir
|
|
return 0
|
|
;;
|
|
type)
|
|
COMPREPLY+=( $( compgen -W 'cls act' -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
|
|
# Actions options
|
|
random)
|
|
_tc_one_of_list 'netrand determ'
|
|
return 0
|
|
;;
|
|
|
|
# Units for option arguments
|
|
bandwidth|maxrate|peakrate|rate)
|
|
local list=$( _tc_expand_units 'bit' \
|
|
'kbit' 'kibit' 'kbps' 'kibps' \
|
|
'mbit' 'mibit' 'mbps' 'mibps' \
|
|
'gbit' 'gibit' 'gbps' 'gibps' \
|
|
'tbit' 'tibit' 'tbps' 'tibps' )
|
|
COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) )
|
|
;;
|
|
admit_bytes|avpkt|burst|cell|initial_quantum|limit|max|min|mtu|mpu|\
|
|
overhead|quantum|redflowlist)
|
|
local list=$( _tc_expand_units \
|
|
'b' 'kbit' 'k' 'mbit' 'm' 'gbit' 'g' )
|
|
COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) )
|
|
;;
|
|
db|delay|evict_timeout|interval|latency|perturb|rehash|reset_timeout|\
|
|
target|tupdate)
|
|
local list=$( _tc_expand_units 'secs' 'msecs' 'usecs' )
|
|
COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) )
|
|
;;
|
|
esac
|
|
return 1
|
|
}
|
|
|
|
# Complete with options names for qdiscs. Each qdisc has its own set of options
|
|
# and it seems we cannot really parse it from anywhere, so we add it manually
|
|
# in this function.
|
|
# Returns 0 is completion should stop after running this function, 1 otherwise.
|
|
_tc_qdisc_options()
|
|
{
|
|
case $1 in
|
|
choke)
|
|
_tc_once_attr 'limit bandwidth ecn min max burst'
|
|
return 0
|
|
;;
|
|
codel)
|
|
_tc_once_attr 'limit target interval'
|
|
_tc_one_of_list 'ecn noecn'
|
|
return 0
|
|
;;
|
|
bfifo|pfifo|pfifo_head_drop)
|
|
_tc_once_attr 'limit'
|
|
return 0
|
|
;;
|
|
fq)
|
|
_tc_once_attr 'limit flow_limit quantum initial_quantum maxrate \
|
|
buckets'
|
|
_tc_one_of_list 'pacing nopacing'
|
|
return 0
|
|
;;
|
|
fq_codel)
|
|
_tc_once_attr 'limit flows target interval quantum'
|
|
_tc_one_of_list 'ecn noecn'
|
|
return 0
|
|
;;
|
|
gred)
|
|
_tc_once_attr 'setup vqs default grio vq prio limit min max avpkt \
|
|
burst probability bandwidth ecn harddrop'
|
|
return 0
|
|
;;
|
|
hhf)
|
|
_tc_once_attr 'limit quantum hh_limit reset_timeout admit_bytes \
|
|
evict_timeout non_hh_weight'
|
|
return 0
|
|
;;
|
|
mqprio)
|
|
_tc_once_attr 'num_tc map queues hw'
|
|
return 0
|
|
;;
|
|
netem)
|
|
_tc_once_attr 'delay distribution corrupt duplicate loss ecn \
|
|
reorder rate'
|
|
return 0
|
|
;;
|
|
pie)
|
|
_tc_once_attr 'limit target tupdate alpha beta'
|
|
_tc_one_of_list 'bytemode nobytemode'
|
|
_tc_one_of_list 'ecn noecn'
|
|
_tc_one_of_list 'dq_rate_estimator no_dq_rate_estimator'
|
|
return 0
|
|
;;
|
|
red)
|
|
_tc_once_attr 'limit min max avpkt burst adaptive probability \
|
|
bandwidth ecn harddrop'
|
|
return 0
|
|
;;
|
|
rr|prio)
|
|
_tc_once_attr 'bands priomap multiqueue'
|
|
return 0
|
|
;;
|
|
sfb)
|
|
_tc_once_attr 'rehash db limit max target increment decrement \
|
|
penalty_rate penalty_burst'
|
|
return 0
|
|
;;
|
|
sfq)
|
|
_tc_once_attr 'limit perturb quantum divisor flows depth headdrop \
|
|
redflowlimit min max avpkt burst probability ecn harddrop'
|
|
return 0
|
|
;;
|
|
tbf)
|
|
_tc_once_attr 'limit burst rate mtu peakrate latency overhead \
|
|
linklayer'
|
|
return 0
|
|
;;
|
|
cbq)
|
|
_tc_once_attr 'bandwidth avpkt mpu cell ewma'
|
|
return 0
|
|
;;
|
|
dsmark)
|
|
_tc_once_attr 'indices default_index set_tc_index'
|
|
return 0
|
|
;;
|
|
hfsc)
|
|
_tc_once_attr 'default'
|
|
return 0
|
|
;;
|
|
htb)
|
|
_tc_once_attr 'default r2q direct_qlen debug'
|
|
return 0
|
|
;;
|
|
multiq|pfifo_fast|atm|drr|qfq)
|
|
return 0
|
|
;;
|
|
esac
|
|
return 1
|
|
}
|
|
|
|
# Complete with options names for BPF filters or actions.
|
|
# Returns 0 is completion should stop after running this function, 1 otherwise.
|
|
_tc_bpf_options()
|
|
{
|
|
[[ ${words[${#words[@]}-3]} == object-file ]] && \
|
|
_tc_once_attr 'section export'
|
|
[[ ${words[${#words[@]}-5]} == object-file ]] && \
|
|
[[ ${words[${#words[@]}-3]} =~ (section|export) ]] && \
|
|
_tc_once_attr 'section export'
|
|
_tc_one_of_list 'bytecode bytecode-file object-file object-pinned'
|
|
_tc_once_attr 'verbose index direct-action action classid'
|
|
return 0
|
|
}
|
|
|
|
# Complete with options names for filter actions.
|
|
# This function is recursive, thus allowing multiple actions statement to be
|
|
# parsed.
|
|
# Returns 0 is completion should stop after running this function, 1 otherwise.
|
|
_tc_filter_action_options()
|
|
{
|
|
for ((acwd=$1; acwd < ${#words[@]}-1; acwd++));
|
|
do
|
|
if [[ action == ${words[acwd]} ]]; then
|
|
_tc_filter_action_options $((acwd+1)) && return 0
|
|
fi
|
|
done
|
|
|
|
local action acwd
|
|
for ((acwd=$1; acwd < ${#words[@]}-1; acwd++)); do
|
|
if [[ $ACTION_KIND =~ ' '${words[acwd]}' ' ]]; then
|
|
_tc_one_of_list_from $acwd action
|
|
_tc_action_options $acwd && return 0
|
|
fi
|
|
done
|
|
_tc_one_of_list_from $acwd $ACTION_KIND
|
|
return 0
|
|
}
|
|
|
|
# Complete with options names for filters.
|
|
# Returns 0 is completion should stop after running this function, 1 otherwise.
|
|
_tc_filter_options()
|
|
{
|
|
|
|
for ((acwd=$1; acwd < ${#words[@]}-1; acwd++));
|
|
do
|
|
if [[ action == ${words[acwd]} ]]; then
|
|
_tc_filter_action_options $((acwd+1)) && return 0
|
|
fi
|
|
done
|
|
|
|
filter=${words[$1]}
|
|
case $filter in
|
|
basic)
|
|
_tc_once_attr 'match action classid'
|
|
return 0
|
|
;;
|
|
bpf)
|
|
_tc_bpf_options
|
|
return 0
|
|
;;
|
|
cgroup)
|
|
_tc_once_attr 'match action'
|
|
return 0
|
|
;;
|
|
flow)
|
|
local i
|
|
for (( i=5; i < ${#words[@]}-1; i++ )); do
|
|
if [[ ${words[i]} =~ ^keys?$ ]]; then
|
|
_tc_direct_complete 'key'
|
|
COMPREPLY+=( $( compgen -W 'or and xor rshift addend' -- \
|
|
"$cur" ) )
|
|
break
|
|
fi
|
|
done
|
|
_tc_once_attr 'map hash divisor baseclass match action'
|
|
return 0
|
|
;;
|
|
matchall)
|
|
_tc_once_attr 'action classid skip_sw skip_hw'
|
|
return 0
|
|
;;
|
|
flower)
|
|
_tc_once_attr 'action classid indev dst_mac src_mac eth_type \
|
|
ip_proto dst_ip src_ip dst_port src_port'
|
|
return 0
|
|
;;
|
|
fw)
|
|
_tc_once_attr 'action classid'
|
|
return 0
|
|
;;
|
|
route)
|
|
_tc_one_of_list 'from fromif'
|
|
_tc_once_attr 'to classid action'
|
|
return 0
|
|
;;
|
|
rsvp)
|
|
_tc_once_attr 'ipproto session sender classid action tunnelid \
|
|
tunnel flowlabel spi/ah spi/esp u8 u16 u32'
|
|
[[ ${words[${#words[@]}-3]} == tunnel ]] && \
|
|
COMPREPLY+=( $( compgen -W 'skip' -- "$cur" ) )
|
|
[[ ${words[${#words[@]}-3]} =~ u(8|16|32) ]] && \
|
|
COMPREPLY+=( $( compgen -W 'mask' -- "$cur" ) )
|
|
[[ ${words[${#words[@]}-3]} == mask ]] && \
|
|
COMPREPLY+=( $( compgen -W 'at' -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
tcindex)
|
|
_tc_once_attr 'hash mask shift classid action'
|
|
_tc_one_of_list 'pass_on fall_through'
|
|
return 0
|
|
;;
|
|
u32)
|
|
_tc_once_attr 'match link classid action offset ht hashkey sample'
|
|
COMPREPLY+=( $( compgen -W 'ip ip6 udp tcp icmp u8 u16 u32 mark \
|
|
divisor' -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
esac
|
|
return 1
|
|
}
|
|
|
|
# Complete with options names for actions.
|
|
# Returns 0 is completion should stop after running this function, 1 otherwise.
|
|
_tc_action_options()
|
|
{
|
|
local from=$1
|
|
local action=${words[from]}
|
|
case $action in
|
|
bpf)
|
|
_tc_bpf_options
|
|
return 0
|
|
;;
|
|
mirred)
|
|
_tc_one_of_list_from $from 'ingress egress'
|
|
_tc_one_of_list_from $from 'mirror redirect'
|
|
_tc_once_attr_from $from 'index dev'
|
|
return 0
|
|
;;
|
|
sample)
|
|
_tc_once_attr_from $from 'rate'
|
|
_tc_once_attr_from $from 'trunc'
|
|
_tc_once_attr_from $from 'group'
|
|
return 0
|
|
;;
|
|
gact)
|
|
_tc_one_of_list_from $from 'reclassify drop continue pass'
|
|
_tc_once_attr_from $from 'random'
|
|
return 0
|
|
;;
|
|
esac
|
|
return 1
|
|
}
|
|
|
|
# Complete with options names for exec.
|
|
# Returns 0 is completion should stop after running this function, 1 otherwise.
|
|
_tc_exec_options()
|
|
{
|
|
case $1 in
|
|
import)
|
|
[[ ${words[${#words[@]}-3]} == import ]] && \
|
|
_tc_once_attr 'run'
|
|
return 0
|
|
;;
|
|
graft)
|
|
COMPREPLY+=( $( compgen -W 'key type' -- "$cur" ) )
|
|
[[ ${words[${#words[@]}-3]} == object-file ]] && \
|
|
_tc_once_attr 'type'
|
|
_tc_bpf_options
|
|
return 0
|
|
;;
|
|
esac
|
|
return 1
|
|
}
|
|
|
|
# Main completion function
|
|
# Logic is as follows:
|
|
# 1. Check if previous word is a global option; if so, propose arguments.
|
|
# 2. Check if current word is a global option; if so, propose completion.
|
|
# 3. Check for the presence of a main command (qdisc|class|filter|...). If
|
|
# there is one, first call _tc_direct_complete to see if previous word is
|
|
# waiting for a particular completion. If so, propose completion and exit.
|
|
# 4. Extract main command and -- if available -- its subcommand
|
|
# (add|delete|show|...).
|
|
# 5. Propose completion based on main and sub- command in use. Additional
|
|
# functions may be called for qdiscs, classes or filter options.
|
|
_tc()
|
|
{
|
|
local cur prev words cword
|
|
_init_completion || return
|
|
|
|
case $prev in
|
|
-V|-Version)
|
|
return 0
|
|
;;
|
|
-b|-batch|-cf|-conf)
|
|
_filedir
|
|
return 0
|
|
;;
|
|
-force)
|
|
COMPREPLY=( $( compgen -W '-batch' -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
-nm|name)
|
|
[[ -r /etc/iproute2/tc_cls ]] || \
|
|
COMPREPLY=( $( compgen -W '-conf' -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
-n|-net|-netns)
|
|
local nslist=$( ip netns list 2>/dev/null )
|
|
COMPREPLY+=( $( compgen -W "$nslist" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
-tshort)
|
|
_tc_once_attr '-statistics'
|
|
COMPREPLY+=( $( compgen -W 'monitor' -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
-timestamp)
|
|
_tc_once_attr '-statistics -tshort'
|
|
COMPREPLY+=( $( compgen -W 'monitor' -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
esac
|
|
|
|
# Search for main commands
|
|
local subcword cmd subcmd
|
|
for (( subcword=1; subcword < ${#words[@]}-1; subcword++ )); do
|
|
[[ ${words[subcword]} == -b?(atch) ]] && return 0
|
|
[[ -n $cmd ]] && subcmd=${words[subcword]} && break
|
|
[[ ${words[subcword]} != -* && \
|
|
${words[subcword-1]} != -@(n?(et?(ns))|c?(on)f) ]] && \
|
|
cmd=${words[subcword]}
|
|
done
|
|
|
|
if [[ -z $cmd ]]; then
|
|
case $cur in
|
|
-*)
|
|
local c='-Version -statistics -details -raw -pretty \
|
|
-iec -graphe -batch -name -netns -timestamp'
|
|
[[ $cword -eq 1 ]] && c+=' -force'
|
|
COMPREPLY=( $( compgen -W "$c" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
*)
|
|
COMPREPLY=( $( compgen -W "help $( tc help 2>&1 | \
|
|
command sed \
|
|
-e '/OBJECT := /!d' \
|
|
-e 's/.*{//' \
|
|
-e 's/}.*//' \
|
|
-e \ 's/|//g' )" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
[[ $subcmd == help ]] && return 0
|
|
|
|
# For this set of commands we may create COMPREPLY just by analysing the
|
|
# previous word, if it expects for a specific list of options or values.
|
|
if [[ $cmd =~ (qdisc|class|filter|action|exec) ]]; then
|
|
_tc_direct_complete $prev && return 0
|
|
if [[ ${words[${#words[@]}-3]} == estimator ]]; then
|
|
local list=$( _tc_expand_units 'secs' 'msecs' 'usecs' )
|
|
COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) ) && return 0
|
|
fi
|
|
fi
|
|
|
|
# Completion depends on main command and subcommand in use.
|
|
case $cmd in
|
|
qdisc)
|
|
case $subcmd in
|
|
add|change|replace|link|del|delete)
|
|
if [[ $(($cword-$subcword)) -eq 1 ]]; then
|
|
COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
|
|
return 0
|
|
fi
|
|
local qdisc qdwd
|
|
for ((qdwd=$subcword; qdwd < ${#words[@]}-1; qdwd++)); do
|
|
if [[ $QDISC_KIND =~ ' '${words[qdwd]}' ' ]]; then
|
|
qdisc=${words[qdwd]}
|
|
_tc_qdisc_options $qdisc && return 0
|
|
fi
|
|
done
|
|
_tc_one_of_list $QDISC_KIND
|
|
_tc_one_of_list 'root ingress parent clsact'
|
|
_tc_once_attr 'handle estimator stab'
|
|
;;
|
|
show)
|
|
_tc_once_attr 'dev'
|
|
_tc_one_of_list 'ingress clsact'
|
|
_tc_once_attr '-statistics -details -raw -pretty -iec \
|
|
-graph -name'
|
|
;;
|
|
help)
|
|
return 0
|
|
;;
|
|
*)
|
|
[[ $cword -eq $subcword ]] && \
|
|
COMPREPLY=( $( compgen -W 'help add delete change \
|
|
replace link show' -- "$cur" ) )
|
|
;;
|
|
esac
|
|
;;
|
|
|
|
class)
|
|
case $subcmd in
|
|
add|change|replace|del|delete)
|
|
if [[ $(($cword-$subcword)) -eq 1 ]]; then
|
|
COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
|
|
return 0
|
|
fi
|
|
local qdisc qdwd
|
|
for ((qdwd=$subcword; qdwd < ${#words[@]}-1; qdwd++)); do
|
|
if [[ $QDISC_KIND =~ ' '${words[qdwd]}' ' ]]; then
|
|
qdisc=${words[qdwd]}
|
|
_tc_qdisc_options $qdisc && return 0
|
|
fi
|
|
done
|
|
_tc_one_of_list $QDISC_KIND
|
|
_tc_one_of_list 'root parent'
|
|
_tc_once_attr 'classid'
|
|
;;
|
|
show)
|
|
_tc_once_attr 'dev'
|
|
_tc_one_of_list 'root parent'
|
|
_tc_once_attr '-statistics -details -raw -pretty -iec \
|
|
-graph -name'
|
|
;;
|
|
help)
|
|
return 0
|
|
;;
|
|
*)
|
|
[[ $cword -eq $subcword ]] && \
|
|
COMPREPLY=( $( compgen -W 'help add delete change \
|
|
replace show' -- "$cur" ) )
|
|
;;
|
|
esac
|
|
;;
|
|
|
|
filter)
|
|
case $subcmd in
|
|
add|change|replace|del|delete)
|
|
if [[ $(($cword-$subcword)) -eq 1 ]]; then
|
|
COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
|
|
return 0
|
|
fi
|
|
local filter fltwd
|
|
for ((fltwd=$subcword; fltwd < ${#words[@]}-1; fltwd++));
|
|
do
|
|
if [[ $FILTER_KIND =~ ' '${words[fltwd]}' ' ]]; then
|
|
_tc_filter_options $fltwd && return 0
|
|
fi
|
|
done
|
|
_tc_one_of_list $FILTER_KIND
|
|
_tc_one_of_list 'root ingress egress parent'
|
|
_tc_once_attr 'handle estimator pref protocol'
|
|
;;
|
|
show)
|
|
_tc_once_attr 'dev'
|
|
_tc_one_of_list 'root ingress egress parent'
|
|
_tc_once_attr '-statistics -details -raw -pretty -iec \
|
|
-graph -name'
|
|
;;
|
|
help)
|
|
return 0
|
|
;;
|
|
*)
|
|
[[ $cword -eq $subcword ]] && \
|
|
COMPREPLY=( $( compgen -W 'help add delete change \
|
|
replace show' -- "$cur" ) )
|
|
;;
|
|
esac
|
|
;;
|
|
|
|
action)
|
|
case $subcmd in
|
|
add|change|replace)
|
|
local action acwd
|
|
for ((acwd=$subcword; acwd < ${#words[@]}-1; acwd++)); do
|
|
if [[ $ACTION_KIND =~ ' '${words[acwd]}' ' ]]; then
|
|
_tc_action_options $acwd && return 0
|
|
fi
|
|
done
|
|
_tc_one_of_list $ACTION_KIND
|
|
;;
|
|
get|del|delete)
|
|
_tc_once_attr 'index'
|
|
;;
|
|
lst|list|flush|show)
|
|
_tc_one_of_list $ACTION_KIND
|
|
;;
|
|
*)
|
|
[[ $cword -eq $subcword ]] && \
|
|
COMPREPLY=( $( compgen -W 'help add delete change \
|
|
replace show list flush action' -- "$cur" ) )
|
|
;;
|
|
esac
|
|
;;
|
|
|
|
monitor)
|
|
COMPREPLY=( $( compgen -W 'help' -- "$cur" ) )
|
|
;;
|
|
|
|
exec)
|
|
case $subcmd in
|
|
bpf)
|
|
local excmd exwd EXEC_KIND=' import debug graft '
|
|
for ((exwd=$subcword; exwd < ${#words[@]}-1; exwd++)); do
|
|
if [[ $EXEC_KIND =~ ' '${words[exwd]}' ' ]]; then
|
|
excmd=${words[exwd]}
|
|
_tc_exec_options $excmd && return 0
|
|
fi
|
|
done
|
|
_tc_one_of_list $EXEC_KIND
|
|
;;
|
|
*)
|
|
[[ $cword -eq $subcword ]] && \
|
|
COMPREPLY=( $( compgen -W 'bpf' -- "$cur" ) )
|
|
;;
|
|
esac
|
|
;;
|
|
esac
|
|
} &&
|
|
complete -F _tc tc
|
|
|
|
# ex: ts=4 sw=4 et filetype=sh
|