1252 lines
24 KiB
Bash
1252 lines
24 KiB
Bash
# bash completion for ethtool(8) -*- shell-script -*-
|
|
# shellcheck shell=bash disable=SC2207
|
|
|
|
# Complete a word representing a set of characters.
|
|
# @param $@ chars Characters which may be present in completed set.
|
|
_ethtool_compgen_letterset()
|
|
{
|
|
local char
|
|
for char; do
|
|
case "$cur" in
|
|
*"$char"*)
|
|
# $cur already contains $char
|
|
;;
|
|
*)
|
|
COMPREPLY+=( "$cur$char" )
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# Generate completions for words matched case-insensitively
|
|
# @param $@ choices Completion choices.
|
|
_ethtool_compgen_nocase()
|
|
{
|
|
local reset
|
|
reset=$( shopt -p nocasematch )
|
|
shopt -s nocasematch
|
|
|
|
local choice
|
|
for choice; do
|
|
case "$choice" in
|
|
"$cur"*) COMPREPLY+=( "$choice" ) ;;
|
|
esac
|
|
done
|
|
|
|
$reset
|
|
}
|
|
|
|
# Gets names from a section of ethtool output.
|
|
# @param $1 section_bre POSIX BRE matching section heading (without : at end).
|
|
# @param $@ ethtool arguments
|
|
_ethtool_get_names_in_section()
|
|
{
|
|
local section_bre="$1"
|
|
shift
|
|
|
|
PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin" \
|
|
ethtool "$@" 2>/dev/null |
|
|
command sed -n "
|
|
# Line is section heading iff it ends with :
|
|
# From requested section heading to next section heading
|
|
/^$section_bre:$/,/:$/ {
|
|
# If line is section heading, ignore it
|
|
/:$/d
|
|
# Remove value and separator, if present
|
|
s/[[:space:]]*:.*//
|
|
# Remove leading space, if present
|
|
s/^[[:space:]]*//
|
|
# Print the line
|
|
p
|
|
}"
|
|
}
|
|
|
|
# Complete an RSS Context ID
|
|
_ethtool_context()
|
|
{
|
|
COMPREPLY=(
|
|
$(PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin" \
|
|
ethtool --show-nfc "${words[2]}" 2>/dev/null |
|
|
command sed -n 's/^[[:space:]]*RSS Context ID:[[:space:]]*\([0-9]*\)$/\1/p' |
|
|
sort -u) )
|
|
}
|
|
|
|
# Complete a network flow traffic type
|
|
# Available OPTIONS:
|
|
# --hash Complete only types suitable for rx hashing
|
|
_ethtool_flow_type()
|
|
{
|
|
local types='ah4 ah6 esp4 esp6 ether sctp4 sctp6 tcp4 tcp6 udp4 udp6'
|
|
if [ "${1-}" != --hash ]; then
|
|
types="$types ip4 ip6"
|
|
fi
|
|
COMPREPLY=( $( compgen -W "$types" -- "$cur" ) )
|
|
}
|
|
|
|
# Completion for ethtool --change
|
|
_ethtool_change()
|
|
{
|
|
local -A settings=(
|
|
[advertise]=notseen
|
|
[autoneg]=notseen
|
|
[duplex]=notseen
|
|
[mdix]=notseen
|
|
[msglvl]=notseen
|
|
[port]=notseen
|
|
[phyad]=notseen
|
|
[speed]=notseen
|
|
[wol]=notseen
|
|
[xcvr]=notseen
|
|
)
|
|
|
|
local -A msgtypes=(
|
|
[drv]=notseen
|
|
[hw]=notseen
|
|
[ifdown]=notseen
|
|
[ifup]=notseen
|
|
[intr]=notseen
|
|
[link]=notseen
|
|
[pktdata]=notseen
|
|
[probe]=notseen
|
|
[rx_err]=notseen
|
|
[rx_status]=notseen
|
|
[timer]=notseen
|
|
[tx_done]=notseen
|
|
[tx_err]=notseen
|
|
[tx_queued]=notseen
|
|
[wol]=notseen
|
|
)
|
|
|
|
# Mark seen settings and msgtypes, and whether in msglvl sub-command
|
|
local in_msglvl=
|
|
local word
|
|
for word in "${words[@]:3:${#words[@]}-4}"; do
|
|
if [ "$in_msglvl" ] && [ "${msgtypes[$word]+set}" ]; then
|
|
msgtypes[$word]=seen
|
|
elif [ "${settings[$word]+set}" ]; then
|
|
settings[$word]=seen
|
|
if [ "$word" = msglvl ]; then
|
|
in_msglvl=1
|
|
else
|
|
in_msglvl=
|
|
fi
|
|
fi
|
|
done
|
|
|
|
if [ "$in_msglvl" ] && [ "${msgtypes[$prev]+set}" ]; then
|
|
# All msgtypes take an on/off argument
|
|
COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
|
|
return
|
|
fi
|
|
|
|
case "$prev" in
|
|
advertise)
|
|
# Hex number
|
|
return ;;
|
|
autoneg)
|
|
COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
|
|
return ;;
|
|
duplex)
|
|
COMPREPLY=( $( compgen -W 'half full' -- "$cur" ) )
|
|
return ;;
|
|
mdix)
|
|
COMPREPLY=( $( compgen -W 'auto on off' -- "$cur" ) )
|
|
return ;;
|
|
msglvl)
|
|
# Unsigned integer or msgtype
|
|
COMPREPLY=( $( compgen -W "${!msgtypes[*]}" -- "$cur" ) )
|
|
return ;;
|
|
port)
|
|
COMPREPLY=( $( compgen -W 'aui bnc fibre mii tp' -- "$cur" ) )
|
|
return ;;
|
|
phyad)
|
|
# Integer
|
|
return ;;
|
|
sopass)
|
|
_mac_addresses
|
|
return ;;
|
|
speed)
|
|
# Number
|
|
return ;;
|
|
wol)
|
|
# $cur is a set of wol type characters.
|
|
_ethtool_compgen_letterset p u m b a g s f d
|
|
return ;;
|
|
xcvr)
|
|
COMPREPLY=( $( compgen -W 'internal external' -- "$cur" ) )
|
|
return ;;
|
|
esac
|
|
|
|
local -a comp_words=()
|
|
|
|
# Add settings not seen to completions
|
|
local setting
|
|
for setting in "${!settings[@]}"; do
|
|
if [ "${settings[$setting]}" = notseen ]; then
|
|
comp_words+=( "$setting" )
|
|
fi
|
|
done
|
|
|
|
# Add settings not seen to completions
|
|
if [ "$in_msglvl" ]; then
|
|
local msgtype
|
|
for msgtype in "${!msgtypes[@]}"; do
|
|
if [ "${msgtypes[$msgtype]}" = notseen ]; then
|
|
comp_words+=( "$msgtype" )
|
|
fi
|
|
done
|
|
fi
|
|
|
|
COMPREPLY=( $( compgen -W "${comp_words[*]}" -- "$cur" ) )
|
|
}
|
|
|
|
# Completion for ethtool --change-eeprom
|
|
_ethtool_change_eeprom()
|
|
{
|
|
local -A settings=(
|
|
[length]=1
|
|
[magic]=1
|
|
[offset]=1
|
|
[value]=1
|
|
)
|
|
|
|
if [ "${settings[$prev]+set}" ]; then
|
|
# All settings take an unsigned integer argument
|
|
return
|
|
fi
|
|
|
|
# Remove settings which have been seen
|
|
local word
|
|
for word in "${words[@]:3:${#words[@]}-4}"; do
|
|
unset "settings[$word]"
|
|
done
|
|
|
|
COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) )
|
|
}
|
|
|
|
# Completion for ethtool --coalesce
|
|
_ethtool_coalesce()
|
|
{
|
|
local -A settings=(
|
|
[adaptive-rx]=1
|
|
[adaptive-tx]=1
|
|
[pkt-rate-high]=1
|
|
[pkt-rate-low]=1
|
|
[rx-frames]=1
|
|
[rx-frames-high]=1
|
|
[rx-frames-irq]=1
|
|
[rx-frames-low]=1
|
|
[rx-usecs]=1
|
|
[rx-usecs-high]=1
|
|
[rx-usecs-irq]=1
|
|
[rx-usecs-low]=1
|
|
[sample-interval]=1
|
|
[stats-block-usecs]=1
|
|
[tx-frames]=1
|
|
[tx-frames-high]=1
|
|
[tx-frames-irq]=1
|
|
[tx-frames-low]=1
|
|
[tx-usecs]=1
|
|
[tx-usecs-high]=1
|
|
[tx-usecs-irq]=1
|
|
[tx-usecs-low]=1
|
|
)
|
|
|
|
case "$prev" in
|
|
adaptive-rx|\
|
|
adaptive-tx)
|
|
COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
|
|
return ;;
|
|
esac
|
|
|
|
if [ "${settings[$prev]+set}" ]; then
|
|
# Unsigned integer
|
|
return
|
|
fi
|
|
|
|
# Remove settings which have been seen
|
|
local word
|
|
for word in "${words[@]:3:${#words[@]}-4}"; do
|
|
unset "settings[$word]"
|
|
done
|
|
|
|
COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) )
|
|
}
|
|
|
|
# Completion for ethtool --config-nfc <devname> flow-type
|
|
_ethtool_config_nfc_flow_type()
|
|
{
|
|
if [ "$cword" -eq 4 ]; then
|
|
_ethtool_flow_type --spec
|
|
return
|
|
fi
|
|
|
|
case "$prev" in
|
|
context)
|
|
_ethtool_context
|
|
return ;;
|
|
dst|\
|
|
dst-mac|\
|
|
src)
|
|
# TODO: Complete only local for dst and remote for src
|
|
_mac_addresses
|
|
return ;;
|
|
dst-ip)
|
|
# Note: RX classification, so dst is usually local
|
|
case "${words[4]}" in
|
|
*4) _ip_addresses -4 return ;;
|
|
*6) _ip_addresses -6 return ;;
|
|
esac
|
|
return ;;
|
|
src-ip)
|
|
# Note: RX classification, so src is usually remote
|
|
# TODO: Remote IP addresses (ARP cache + /etc/hosts + ?)
|
|
return ;;
|
|
m|\
|
|
*-mask)
|
|
# MAC, IP, or integer bitmask
|
|
return ;;
|
|
esac
|
|
|
|
local -A settings=(
|
|
[action]=1
|
|
[context]=1
|
|
[loc]=1
|
|
[queue]=1
|
|
[vf]=1
|
|
)
|
|
|
|
if [ "${settings[$prev]+set}" ]; then
|
|
# Integer
|
|
return
|
|
fi
|
|
|
|
case "${words[4]}" in
|
|
ah4|\
|
|
esp4)
|
|
local -A fields=(
|
|
[dst-ip]=1
|
|
[dst-mac]=1
|
|
[spi]=1
|
|
[src-ip]=1
|
|
[tos]=1
|
|
[user-def]=1
|
|
[vlan-etype]=1
|
|
[vlan]=1
|
|
)
|
|
;;
|
|
ah6|\
|
|
esp6)
|
|
local -A fields=(
|
|
[dst-ip]=1
|
|
[dst-mac]=1
|
|
[spi]=1
|
|
[src-ip]=1
|
|
[tclass]=1
|
|
[user-def]=1
|
|
[vlan-etype]=1
|
|
[vlan]=1
|
|
)
|
|
;;
|
|
ether)
|
|
local -A fields=(
|
|
[dst]=1
|
|
[proto]=1
|
|
[src]=1
|
|
[user-def]=1
|
|
[vlan-etype]=1
|
|
[vlan]=1
|
|
)
|
|
;;
|
|
ip4)
|
|
local -A fields=(
|
|
[dst-ip]=1
|
|
[dst-mac]=1
|
|
[dst-port]=1
|
|
[l4data]=1
|
|
[l4proto]=1
|
|
[spi]=1
|
|
[src-ip]=1
|
|
[src-port]=1
|
|
[tos]=1
|
|
[user-def]=1
|
|
[vlan-etype]=1
|
|
[vlan]=1
|
|
)
|
|
;;
|
|
ip6)
|
|
local -A fields=(
|
|
[dst-ip]=1
|
|
[dst-mac]=1
|
|
[dst-port]=1
|
|
[l4data]=1
|
|
[l4proto]=1
|
|
[spi]=1
|
|
[src-ip]=1
|
|
[src-port]=1
|
|
[tclass]=1
|
|
[user-def]=1
|
|
[vlan-etype]=1
|
|
[vlan]=1
|
|
)
|
|
;;
|
|
sctp4|\
|
|
tcp4|\
|
|
udp4)
|
|
local -A fields=(
|
|
[dst-ip]=1
|
|
[dst-mac]=1
|
|
[dst-port]=1
|
|
[src-ip]=1
|
|
[src-port]=1
|
|
[tos]=1
|
|
[user-def]=1
|
|
[vlan-etype]=1
|
|
[vlan]=1
|
|
)
|
|
;;
|
|
sctp6|\
|
|
tcp6|\
|
|
udp6)
|
|
local -A fields=(
|
|
[dst-ip]=1
|
|
[dst-mac]=1
|
|
[dst-port]=1
|
|
[src-ip]=1
|
|
[src-port]=1
|
|
[tclass]=1
|
|
[user-def]=1
|
|
[vlan-etype]=1
|
|
[vlan]=1
|
|
)
|
|
;;
|
|
*)
|
|
return ;;
|
|
esac
|
|
|
|
if [ "${fields[$prev]+set}" ]; then
|
|
# Integer
|
|
return
|
|
fi
|
|
|
|
# If the previous 2 words were a field+value, suggest a mask
|
|
local mask=
|
|
if [ "${fields[${words[$cword-2]}]+set}" ]; then
|
|
mask="m ${words[$cword-2]}-mask"
|
|
fi
|
|
|
|
# Remove fields and settings which have been seen
|
|
local word
|
|
for word in "${words[@]:5:${#words[@]}-6}"; do
|
|
unset "fields[$word]" "settings[$word]"
|
|
done
|
|
|
|
# Remove mutually-exclusive options
|
|
if ! [ "${settings[action]+set}" ]; then
|
|
unset 'settings[queue]' 'settings[vf]'
|
|
fi
|
|
if ! [ "${settings[queue]+set}" ]; then
|
|
unset 'settings[action]'
|
|
fi
|
|
if ! [ "${settings[vf]+set}" ]; then
|
|
unset 'settings[action]'
|
|
fi
|
|
|
|
COMPREPLY=( $( compgen -W "$mask ${!fields[*]} ${!settings[*]}" -- "$cur" ) )
|
|
}
|
|
|
|
# Completion for ethtool --config-nfc
|
|
_ethtool_config_nfc()
|
|
{
|
|
if [ "$cword" -eq 3 ]; then
|
|
COMPREPLY=( $( compgen -W 'delete flow-type rx-flow-hash' -- "$cur" ) )
|
|
return
|
|
fi
|
|
|
|
case "${words[3]}" in
|
|
delete)
|
|
# Unsigned integer
|
|
return ;;
|
|
flow-type)
|
|
_ethtool_config_nfc_flow_type
|
|
return ;;
|
|
rx-flow-hash)
|
|
case "$cword" in
|
|
4)
|
|
_ethtool_flow_type --hash
|
|
return ;;
|
|
5)
|
|
_ethtool_compgen_letterset m v t s d f n r
|
|
return ;;
|
|
6)
|
|
COMPREPLY=( $( compgen -W context -- "$cur" ) )
|
|
return ;;
|
|
7)
|
|
_ethtool_context
|
|
return ;;
|
|
esac
|
|
return ;;
|
|
esac
|
|
}
|
|
|
|
# Completion for ethtool --eeprom-dump
|
|
_ethtool_eeprom_dump()
|
|
{
|
|
local -A settings=(
|
|
[length]=1
|
|
[offset]=1
|
|
[raw]=1
|
|
)
|
|
|
|
if [ "$prev" = raw ]; then
|
|
COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
|
|
return
|
|
fi
|
|
|
|
if [ "${settings[$prev]+set}" ]; then
|
|
# Unsigned integer argument
|
|
return
|
|
fi
|
|
|
|
# Remove settings which have been seen
|
|
local word
|
|
for word in "${words[@]:3:${#words[@]}-4}"; do
|
|
unset "settings[$word]"
|
|
done
|
|
|
|
COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) )
|
|
}
|
|
|
|
# Completion for ethtool --features
|
|
_ethtool_features()
|
|
{
|
|
local -A abbreviations=(
|
|
[generic-receive-offload]=gro
|
|
[generic-segmentation-offload]=gso
|
|
[large-receive-offload]=lro
|
|
[ntuple-filters]=ntuple
|
|
[receive-hashing]=rxhash
|
|
[rx-checksumming]=rx
|
|
[rx-vlan-offload]=rxvlan
|
|
[scatter-gather]=sg
|
|
[tcp-segmentation-offload]=tso
|
|
[tx-checksumming]=tx
|
|
[tx-vlan-offload]=txvlan
|
|
[udp-fragmentation-offload]=ufo
|
|
)
|
|
|
|
local -A features=()
|
|
local feature status fixed
|
|
# shellcheck disable=SC2034
|
|
while read -r feature status fixed; do
|
|
if [ -z "$feature" ]; then
|
|
# Ignore blank line from empty expansion in here-document
|
|
continue
|
|
fi
|
|
|
|
if [ "$feature" = Features ]; then
|
|
# Ignore heading
|
|
continue
|
|
fi
|
|
|
|
if [ "$fixed" = '[fixed]' ]; then
|
|
# Fixed features can't be changed
|
|
continue
|
|
fi
|
|
|
|
feature=${feature%:}
|
|
if [ "${abbreviations[$feature]+set}" ]; then
|
|
features[${abbreviations[$feature]}]=1
|
|
else
|
|
features[$feature]=1
|
|
fi
|
|
done <<ETHTOOL_FEATURES
|
|
$(PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin" \
|
|
ethtool --show-features "${words[2]}" 2>/dev/null)
|
|
ETHTOOL_FEATURES
|
|
|
|
if [ "${features[$prev]+set}" ]; then
|
|
COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
|
|
return
|
|
fi
|
|
|
|
# Remove features which have been seen
|
|
local word
|
|
for word in "${words[@]:3:${#words[@]}-4}"; do
|
|
unset "features[$word]"
|
|
done
|
|
|
|
COMPREPLY=( $( compgen -W "${!features[*]}" -- "$cur" ) )
|
|
}
|
|
|
|
# Complete the current word as a kernel firmware file (for request_firmware)
|
|
# See https://www.kernel.org/doc/html/latest/driver-api/firmware/core.html
|
|
_ethtool_firmware()
|
|
{
|
|
local -a firmware_paths=(
|
|
/lib/firmware/updates/
|
|
/lib/firmware/
|
|
)
|
|
|
|
local release
|
|
if release=$( uname -r 2>/dev/null ); then
|
|
firmware_paths+=(
|
|
"/lib/firmware/updates/$release/"
|
|
"/lib/firmware/$release/"
|
|
)
|
|
fi
|
|
|
|
local fw_path_para
|
|
if fw_path_para=$( cat /sys/module/firmware_class/parameters/path 2>/dev/null ) \
|
|
&& [ -n "$fw_path_para" ]; then
|
|
firmware_paths+=( "$fw_path_para" )
|
|
fi
|
|
|
|
local -A firmware_files=()
|
|
|
|
local firmware_path
|
|
for firmware_path in "${firmware_paths[@]}"; do
|
|
local firmware_file
|
|
for firmware_file in "$firmware_path"*; do
|
|
if [ -f "$firmware_file" ]; then
|
|
firmware_files[${firmware_file##*/}]=1
|
|
fi
|
|
done
|
|
done
|
|
|
|
local IFS='
|
|
'
|
|
COMPREPLY=( $( compgen -W "${!firmware_files[*]}" -- "$cur" ) )
|
|
}
|
|
|
|
# Completion for ethtool --flash
|
|
_ethtool_flash()
|
|
{
|
|
if [ "$cword" -eq 3 ]; then
|
|
_ethtool_firmware
|
|
return
|
|
fi
|
|
}
|
|
|
|
# Completion for ethtool --get-dump
|
|
_ethtool_get_dump()
|
|
{
|
|
case "$cword" in
|
|
3)
|
|
COMPREPLY=( $( compgen -W data -- "$cur" ) )
|
|
return ;;
|
|
4)
|
|
# Output filename
|
|
local IFS='
|
|
'
|
|
COMPREPLY=( $( compgen -f -- "$cur" ) )
|
|
return ;;
|
|
esac
|
|
}
|
|
|
|
# Completion for ethtool --get-phy-tunable
|
|
_ethtool_get_phy_tunable()
|
|
{
|
|
if [ "$cword" -eq 3 ]; then
|
|
COMPREPLY=( $( compgen -W downshift -- "$cur" ) )
|
|
return
|
|
fi
|
|
}
|
|
|
|
# Completion for ethtool --module-info
|
|
_ethtool_module_info()
|
|
{
|
|
local -A settings=(
|
|
[hex]=1
|
|
[length]=1
|
|
[offset]=1
|
|
[raw]=1
|
|
)
|
|
|
|
case "$prev" in
|
|
hex|\
|
|
raw)
|
|
COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
|
|
return ;;
|
|
esac
|
|
|
|
if [ "${settings[$prev]+set}" ]; then
|
|
# Unsigned integer argument
|
|
return
|
|
fi
|
|
|
|
# Remove settings which have been seen
|
|
local word
|
|
for word in "${words[@]:3:${#words[@]}-4}"; do
|
|
unset "settings[$word]"
|
|
done
|
|
|
|
COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) )
|
|
}
|
|
|
|
# Completion for ethtool --pause
|
|
_ethtool_pause()
|
|
{
|
|
local -A settings=(
|
|
[autoneg]=1
|
|
[rx]=1
|
|
[tx]=1
|
|
)
|
|
|
|
if [ "${settings[$prev]+set}" ]; then
|
|
COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
|
|
return
|
|
fi
|
|
|
|
# Remove settings which have been seen
|
|
local word
|
|
for word in "${words[@]:3:${#words[@]}-4}"; do
|
|
unset "settings[$word]"
|
|
done
|
|
|
|
COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) )
|
|
}
|
|
|
|
# Completion for ethtool --per-queue
|
|
_ethtool_per_queue()
|
|
{
|
|
local -a subcommands=(
|
|
--coalesce
|
|
--show-coalesce
|
|
)
|
|
|
|
if [ "$cword" -eq 3 ]; then
|
|
COMPREPLY=( $( compgen -W "queue_mask ${subcommands[*]}" -- "$cur" ) )
|
|
return
|
|
fi
|
|
|
|
local sc_start=3
|
|
if [ "${words[3]}" = queue_mask ] ; then
|
|
case "$cword" in
|
|
4)
|
|
# Hex number
|
|
return ;;
|
|
5)
|
|
COMPREPLY=( $( compgen -W "${subcommands[*]}" -- "$cur" ) )
|
|
return ;;
|
|
esac
|
|
|
|
sc_start=5
|
|
fi
|
|
|
|
case "${words[$sc_start]}" in
|
|
--coalesce)
|
|
# Remove --per-queue args to match normal --coalesce invocation
|
|
local words=(
|
|
"${words[0]}"
|
|
--coalesce
|
|
"${words[2]}"
|
|
"${words[@]:$sc_start+1:${#words[@]}-$sc_start-1}"
|
|
)
|
|
_ethtool_coalesce
|
|
return ;;
|
|
--show-coalesce)
|
|
# No args
|
|
return ;;
|
|
esac
|
|
}
|
|
|
|
# Completion for ethtool --register-dump
|
|
_ethtool_register_dump()
|
|
{
|
|
local -A settings=(
|
|
[file]=1
|
|
[hex]=1
|
|
[raw]=1
|
|
)
|
|
|
|
case "$prev" in
|
|
hex|\
|
|
raw)
|
|
COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
|
|
return ;;
|
|
file)
|
|
local IFS='
|
|
'
|
|
COMPREPLY=( $( compgen -f -- "$cur" ) )
|
|
return ;;
|
|
esac
|
|
|
|
# Remove settings which have been seen
|
|
local word
|
|
for word in "${words[@]:3:${#words[@]}-4}"; do
|
|
unset "settings[$word]"
|
|
done
|
|
|
|
COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) )
|
|
}
|
|
|
|
# Completion for ethtool --reset
|
|
_ethtool_reset()
|
|
{
|
|
if [ "$prev" = flags ]; then
|
|
# Unsigned integer
|
|
return
|
|
fi
|
|
|
|
local -A flag_names=(
|
|
[ap]=1
|
|
[dma]=1
|
|
[filter]=1
|
|
[irq]=1
|
|
[mac]=1
|
|
[mgmt]=1
|
|
[offload]=1
|
|
[phy]=1
|
|
[ram]=1
|
|
)
|
|
|
|
local -A all_flag_names=()
|
|
local flag_name
|
|
for flag_name in "${!flag_names[@]}"; do
|
|
all_flag_names[$flag_name]=1
|
|
all_flag_names[$flag_name-shared]=1
|
|
done
|
|
|
|
# Remove all_flag_names which have been seen
|
|
local any_dedicated=
|
|
local word
|
|
for word in "${words[@]:3:${#words[@]}-4}"; do
|
|
case "$word" in
|
|
all)
|
|
# Flags are always additive.
|
|
# Nothing to add after "all".
|
|
return ;;
|
|
dedicated)
|
|
any_dedicated=1
|
|
# "dedicated" sets all non-shared flags
|
|
for flag_name in "${!flag_names[@]}"; do
|
|
unset "all_flag_names[$flag_name]"
|
|
done
|
|
continue ;;
|
|
esac
|
|
|
|
if [ "${flag_names[$word]+set}" ]; then
|
|
any_dedicated=1
|
|
fi
|
|
|
|
unset "all_flag_names[$word]"
|
|
done
|
|
|
|
COMPREPLY=( $( compgen -W "${!all_flag_names[*]}" -- "$cur" ) )
|
|
|
|
# Although it is permitted to mix named and un-named flags or duplicate
|
|
# flags with "all" or "dedicated", it's not likely intentional.
|
|
# Reconsider if a real use-case (or good consistency argument) is found.
|
|
if [ "$cword" -eq 3 ]; then
|
|
COMPREPLY+=( all dedicated flags )
|
|
elif [ -z "$any_dedicated" ]; then
|
|
COMPREPLY+=( dedicated )
|
|
fi
|
|
}
|
|
|
|
# Completion for ethtool --rxfh
|
|
_ethtool_rxfh()
|
|
{
|
|
local -A settings=(
|
|
[context]=1
|
|
[default]=1
|
|
[delete]=1
|
|
[equal]=1
|
|
[hfunc]=1
|
|
[hkey]=1
|
|
[weight]=1
|
|
)
|
|
|
|
case "$prev" in
|
|
context)
|
|
_ethtool_context
|
|
# "new" to create a new context
|
|
COMPREPLY+=( new )
|
|
return ;;
|
|
equal)
|
|
# Positive integer
|
|
return ;;
|
|
hfunc)
|
|
# Complete available RSS hash functions
|
|
COMPREPLY=(
|
|
$(_ethtool_get_names_in_section 'RSS hash function' \
|
|
--show-rxfh "${words[2]}")
|
|
)
|
|
return ;;
|
|
hkey)
|
|
# Pairs of hex digits separated by :
|
|
return ;;
|
|
weight)
|
|
# Non-negative integer
|
|
return ;;
|
|
esac
|
|
|
|
local word
|
|
for word in "${words[@]:3:${#words[@]}-4}"; do
|
|
# Remove settings which have been seen
|
|
unset "settings[$word]"
|
|
|
|
# Remove settings which are mutually-exclusive with seen settings
|
|
case "$word" in
|
|
context)
|
|
unset 'settings[default]'
|
|
;;
|
|
default)
|
|
unset \
|
|
'settings[context]' \
|
|
'settings[delete]' \
|
|
'settings[equal]' \
|
|
'settings[weight]'
|
|
;;
|
|
delete)
|
|
unset \
|
|
'settings[default]' \
|
|
'settings[equal]' \
|
|
'settings[hkey]' \
|
|
'settings[weight]'
|
|
;;
|
|
equal)
|
|
unset \
|
|
'settings[default]' \
|
|
'settings[delete]' \
|
|
'settings[weight]'
|
|
;;
|
|
hkey)
|
|
unset 'settings[delete]'
|
|
;;
|
|
weight)
|
|
unset \
|
|
'settings[default]' \
|
|
'settings[delete]' \
|
|
'settings[equal]'
|
|
;;
|
|
esac
|
|
done
|
|
|
|
|
|
COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) )
|
|
}
|
|
|
|
# Completion for ethtool --set-channels
|
|
_ethtool_set_channels()
|
|
{
|
|
local -A settings=(
|
|
[combined]=1
|
|
[other]=1
|
|
[rx]=1
|
|
[tx]=1
|
|
)
|
|
|
|
if [ "${settings[$prev]+set}" ]; then
|
|
# Unsigned integer argument
|
|
return
|
|
fi
|
|
|
|
# Remove settings which have been seen
|
|
local word
|
|
for word in "${words[@]:3:${#words[@]}-4}"; do
|
|
unset "settings[$word]"
|
|
done
|
|
|
|
COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) )
|
|
}
|
|
|
|
# Completion for ethtool --set-eee
|
|
_ethtool_set_eee()
|
|
{
|
|
local -A settings=(
|
|
[advertise]=1
|
|
[eee]=1
|
|
[tx-lpi]=1
|
|
[tx-timer]=1
|
|
)
|
|
|
|
case "$prev" in
|
|
advertise|\
|
|
tx-timer)
|
|
# Unsigned integer
|
|
return ;;
|
|
eee|\
|
|
tx-lpi)
|
|
COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
|
|
return ;;
|
|
esac
|
|
|
|
# Remove settings which have been seen
|
|
local word
|
|
for word in "${words[@]:3:${#words[@]}-4}"; do
|
|
unset "settings[$word]"
|
|
done
|
|
|
|
COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) )
|
|
}
|
|
|
|
# Completion for ethtool --set-fec
|
|
_ethtool_set_fec()
|
|
{
|
|
if [ "$cword" -eq 3 ]; then
|
|
COMPREPLY=( $( compgen -W encoding -- "$cur" ) )
|
|
return
|
|
fi
|
|
|
|
local -A modes=(
|
|
[auto]=auto
|
|
[rs]=RS
|
|
[off]=off
|
|
[baser]=BaseR
|
|
)
|
|
|
|
# Remove modes which have been seen
|
|
local word
|
|
for word in "${words[@]:3:${#words[@]}-4}"; do
|
|
# ethtool recognizes modes case-insensitively
|
|
unset "modes[${word,,}]"
|
|
done
|
|
|
|
_ethtool_compgen_nocase "${modes[@]}"
|
|
}
|
|
|
|
# Completion for ethtool --set-phy-tunable
|
|
_ethtool_set_phy_tunable()
|
|
{
|
|
case "$cword" in
|
|
3)
|
|
COMPREPLY=( $( compgen -W downshift -- "$cur" ) )
|
|
return ;;
|
|
4)
|
|
COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
|
|
return ;;
|
|
5)
|
|
COMPREPLY=( $( compgen -W count -- "$cur" ) )
|
|
return ;;
|
|
esac
|
|
}
|
|
|
|
# Completion for ethtool --set-priv-flags
|
|
_ethtool_set_priv_flags()
|
|
{
|
|
if [ $(( cword % 2 )) -eq 0 ]; then
|
|
COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
|
|
return
|
|
fi
|
|
|
|
# Get available private flags
|
|
local -A flags=()
|
|
local flag
|
|
while IFS= read -r flag; do
|
|
# Ignore blank line from empty here-document
|
|
if [ -n "$flag" ]; then
|
|
flags[$flag]=1
|
|
fi
|
|
done <<ETHTOOL_PRIV_FLAGS
|
|
$(_ethtool_get_names_in_section \
|
|
'Private flags for [[:graph:]]*' --show-priv-flags "${words[2]}")
|
|
ETHTOOL_PRIV_FLAGS
|
|
|
|
# Remove flags which have been seen
|
|
local word
|
|
for word in "${words[@]:3:${#words[@]}-4}"; do
|
|
unset "flags[$word]"
|
|
done
|
|
|
|
COMPREPLY=( $( compgen -W "${!flags[*]}" -- "$cur" ) )
|
|
}
|
|
|
|
# Completion for ethtool --set-ring
|
|
_ethtool_set_ring()
|
|
{
|
|
local -A settings=(
|
|
[rx-jumbo]=1
|
|
[rx-mini]=1
|
|
[rx]=1
|
|
[tx]=1
|
|
)
|
|
|
|
if [ "${settings[$prev]+set}" ]; then
|
|
# Unsigned integer argument
|
|
return
|
|
fi
|
|
|
|
# Remove settings which have been seen
|
|
local word
|
|
for word in "${words[@]:3:${#words[@]}-4}"; do
|
|
unset "settings[$word]"
|
|
done
|
|
|
|
COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) )
|
|
}
|
|
|
|
# Completion for ethtool --show-nfc
|
|
_ethtool_show_nfc()
|
|
{
|
|
if [ "$cword" -eq 3 ]; then
|
|
COMPREPLY=( $( compgen -W 'rule rx-flow-hash' -- "$cur" ) )
|
|
return
|
|
fi
|
|
|
|
case "${words[3]}" in
|
|
rule)
|
|
if [ "$cword" -eq 4 ]; then
|
|
COMPREPLY=(
|
|
$(PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin" \
|
|
ethtool --show-nfc "${words[2]}" 2>/dev/null |
|
|
command sed -n 's/^Filter:[[:space:]]*\([0-9]*\)$/\1/p')
|
|
)
|
|
fi
|
|
return ;;
|
|
rx-flow-hash)
|
|
case "$cword" in
|
|
4)
|
|
_ethtool_flow_type --hash
|
|
return ;;
|
|
5)
|
|
COMPREPLY=( $( compgen -W context -- "$cur" ) )
|
|
return ;;
|
|
6)
|
|
_ethtool_context
|
|
return ;;
|
|
esac
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Completion for ethtool --show-rxfh
|
|
_ethtool_show_rxfh()
|
|
{
|
|
case "$cword" in
|
|
3)
|
|
COMPREPLY=( $( compgen -W context -- "$cur" ) )
|
|
return ;;
|
|
4)
|
|
_ethtool_context
|
|
return ;;
|
|
esac
|
|
}
|
|
|
|
# Completion for ethtool --test
|
|
_ethtool_test()
|
|
{
|
|
if [ "$cword" -eq 3 ]; then
|
|
COMPREPLY=( $( compgen -W 'external_lb offline online' -- "$cur" ) )
|
|
return
|
|
fi
|
|
}
|
|
|
|
|
|
# Complete any ethtool command
|
|
_ethtool()
|
|
{
|
|
local cur prev words cword
|
|
_init_completion || return
|
|
|
|
# Per "Contributing to bash-completion", complete non-duplicate long opts
|
|
local -A suggested_funcs=(
|
|
[--change-eeprom]=change_eeprom
|
|
[--change]=change
|
|
[--coalesce]=coalesce
|
|
[--config-nfc]=config_nfc
|
|
[--driver]=devname
|
|
[--dump-module-eeprom]=module_info
|
|
[--eeprom-dump]=eeprom_dump
|
|
[--features]=features
|
|
[--flash]=flash
|
|
[--get-dump]=get_dump
|
|
[--get-phy-tunable]=get_phy_tunable
|
|
[--identify]=devname
|
|
[--module-info]=module_info
|
|
[--negotiate]=devname
|
|
[--offload]=features
|
|
[--pause]=pause
|
|
[--per-queue]=per_queue
|
|
[--phy-statistics]=devname
|
|
[--register-dump]=register_dump
|
|
[--reset]=reset
|
|
[--set-channels]=set_channels
|
|
[--set-dump]=devname
|
|
[--set-eee]=set_eee
|
|
[--set-fec]=set_fec
|
|
[--set-phy-tunable]=set_phy_tunable
|
|
[--set-priv-flags]=set_priv_flags
|
|
[--set-ring]=set_ring
|
|
[--set-rxfh-indir]=rxfh
|
|
[--show-channels]=devname
|
|
[--show-coalesce]=devname
|
|
[--show-eee]=devname
|
|
[--show-features]=devname
|
|
[--show-fec]=devname
|
|
[--show-nfc]=show_nfc
|
|
[--show-offload]=devname
|
|
[--show-pause]=devname
|
|
[--show-permaddr]=devname
|
|
[--show-priv-flags]=devname
|
|
[--show-ring]=devname
|
|
[--show-rxfh]=show_rxfh
|
|
[--show-time-stamping]=devname
|
|
[--statistics]=devname
|
|
[--test]=test
|
|
)
|
|
local -A other_funcs=(
|
|
[--config-ntuple]=config_nfc
|
|
[--rxfh]=rxfh
|
|
[--show-ntuple]=show_nfc
|
|
[--show-rxfh-indir]=devname
|
|
[-A]=pause
|
|
[-C]=coalesce
|
|
[-E]=change_eeprom
|
|
[-G]=set_ring
|
|
[-K]=features
|
|
[-L]=set_channels
|
|
[-N]=config_nfc
|
|
[-P]=devname
|
|
[-Q]=per_queue
|
|
[-S]=devname
|
|
[-T]=devname
|
|
[-U]=config_nfc
|
|
[-W]=devname
|
|
[-X]=rxfh
|
|
[-a]=devname
|
|
[-c]=devname
|
|
[-d]=register_dump
|
|
[-e]=eeprom_dump
|
|
[-f]=flash
|
|
[-g]=devname
|
|
[-i]=devname
|
|
[-k]=devname
|
|
[-l]=devname
|
|
[-m]=module_info
|
|
[-n]=show_nfc
|
|
[-p]=devname
|
|
[-r]=devname
|
|
[-s]=change
|
|
[-t]=test
|
|
[-u]=show_nfc
|
|
[-w]=get_dump
|
|
[-x]=devname
|
|
)
|
|
|
|
if [ "$cword" -le 1 ]; then
|
|
_available_interfaces
|
|
COMPREPLY+=(
|
|
$( compgen -W "--help --version ${!suggested_funcs[*]}" -- "$cur" )
|
|
)
|
|
return
|
|
fi
|
|
|
|
local func=${suggested_funcs[${words[1]}]-${other_funcs[${words[1]}]-}}
|
|
if [ "$func" ]; then
|
|
# All sub-commands have devname as their first argument
|
|
if [ "$cword" -eq 2 ]; then
|
|
_available_interfaces
|
|
return
|
|
fi
|
|
|
|
if [ "$func" != devname ]; then
|
|
"_ethtool_$func"
|
|
fi
|
|
fi
|
|
} &&
|
|
complete -F _ethtool ethtool
|
|
|
|
# ex: filetype=sh sts=8 sw=8 ts=8 noet
|