mirror of
https://git.proxmox.com/git/mirror_iproute2
synced 2025-10-09 19:25:37 +00:00

The sample tc action allows sampling packets matching a classifier. It peeks randomly packets, and samples them using the psample netlink channel. The user can specify the psample group, which the packet will be sampled to, the sampling rate and the packet truncation (to save kernel-user traffic). The sampled packets contain informative metadata, for example, the input interface and the original packet length. The action syntax: tc filter add [...] \ action sample rate <RATE> group <GROUP> [trunc <SIZE>] [...] Where: RATE := The sampling rate which is the ratio of packets observed at the data source to the samples generated GROUP := the psample module sampling group SIZE := optional truncation size An example for a common usecase of the sample tc action: to sample ingress traffic from interface eth1, one may use the commands: tc qdisc add dev eth1 handle ffff: ingress tc filter add dev eth1 parent ffff: \ matchall action sample rate 12 group 4 Where the first command adds an ingress qdisc and the second starts sampling randomly with an average of one sampled packet per 12 packets on dev eth1 to psample group 4. Reviewed-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: Yotam Gigi <yotamg@mellanox.com>
730 lines
25 KiB
Bash
730 lines
25 KiB
Bash
# tc(8) completion -*- shell-script -*-
|
|
# Copyright 2016 6WIND S.A.
|
|
# Copyright 2016 Quentin Monnet <quentin.monnet@6wind.com>
|
|
|
|
# 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; 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" ) )
|
|
}
|
|
|
|
# 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'
|
|
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'
|
|
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 filters.
|
|
# Returns 0 is completion should stop after running this function, 1 otherwise.
|
|
_tc_filter_options()
|
|
{
|
|
case $1 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
|
|
;;
|
|
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()
|
|
{
|
|
case $1 in
|
|
bpf)
|
|
_tc_bpf_options
|
|
return 0
|
|
;;
|
|
mirred)
|
|
_tc_one_of_list 'ingress egress'
|
|
_tc_one_of_list 'mirror redirect'
|
|
_tc_once_attr 'index dev'
|
|
return 0
|
|
;;
|
|
sample)
|
|
_tc_once_attr 'rate'
|
|
_tc_once_attr 'trunc'
|
|
_tc_once_attr 'group'
|
|
return 0
|
|
;;
|
|
gact)
|
|
_tc_one_of_list 'reclassify drop continue pass'
|
|
_tc_once_attr '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 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 '
|
|
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 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 '
|
|
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 FILTER_KIND=' basic bpf cgroup flow \
|
|
flower fw route rsvp tcindex u32 '
|
|
for ((fltwd=$subcword; fltwd < ${#words[@]}-1; fltwd++));
|
|
do
|
|
if [[ $FILTER_KIND =~ ' '${words[fltwd]}' ' ]]; then
|
|
filter=${words[fltwd]}
|
|
_tc_filter_options $filter && 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 ACTION_KIND=' gact mirred bpf sample '
|
|
for ((acwd=$subcword; acwd < ${#words[@]}-1; acwd++)); do
|
|
if [[ $ACTION_KIND =~ ' '${words[acwd]}' ' ]]; then
|
|
action=${words[acwd]}
|
|
_tc_action_options $action && 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
|