| # 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 |