bash-completion: devlink: add bash-completion function

Add function for command completion for devlink in bash, and update Makefile
to install it under /usr/share/bash-completion/completions/.

Signed-off-by: Danielle Ratson <danieller@mellanox.com>
Tested-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
Danielle Ratson 2020-03-25 11:25:34 +02:00 committed by David Ahern
parent 6c10fdca70
commit 5a3faf2949
2 changed files with 823 additions and 0 deletions

View File

@ -90,6 +90,7 @@ install: all
install -m 0644 $(shell find etc/iproute2 -maxdepth 1 -type f) $(DESTDIR)$(CONFDIR)
install -m 0755 -d $(DESTDIR)$(BASH_COMPDIR)
install -m 0644 bash-completion/tc $(DESTDIR)$(BASH_COMPDIR)
install -m 0644 bash-completion/devlink $(DESTDIR)$(BASH_COMPDIR)
install -m 0644 include/bpf_elf.h $(DESTDIR)$(HDRDIR)
snapshot:

822
bash-completion/devlink Normal file
View File

@ -0,0 +1,822 @@
# bash completion for devlink(8) -*- shell-script -*-
# Get all the optional commands for devlink
_devlink_get_optional_commands()
{
local object=$1; shift
local filter_options=""
local options="$(devlink $object help 2>&1 \
| command sed -n -e "s/^.*devlink $object //p" \
| cut -d " " -f 1)"
# Remove duplicate options from "devlink $OBJECT help" command
local opt
for opt in $options; do
if [[ $filter_options =~ $opt ]]; then
continue
else
filter_options="$filter_options $opt"
fi
done
echo $filter_options
}
# Complete based on given word, for when an argument or an option name has
# but a few possible arguments.
_devlink_direct_complete()
{
local dev port region value
case $1 in
dev)
value=$(devlink dev show 2>/dev/null)
;;
param_name)
dev=${words[4]}
value=$(devlink -j dev param show 2>/dev/null \
| jq ".param[\"$dev\"][].name")
;;
port)
value=$(devlink -j port show 2>/dev/null \
| jq '.port as $ports | $ports | keys[] as $key
| ($ports[$key].netdev // $key)')
;;
region)
value=$(devlink -j region show 2>/dev/null \
| jq '.regions' | jq 'keys[]')
;;
snapshot)
region=${words[3]}
value=$(devlink -j region show 2>/dev/null \
| jq ".regions[\"$region\"].snapshot[]")
;;
trap)
dev=${words[3]}
value=$(devlink -j trap show 2>/dev/null \
| jq ".trap[\"$dev\"][].name")
;;
trap_group)
dev=${words[4]}
value=$(devlink -j trap group show 2>/dev/null \
| jq ".trap_group[\"$dev\"][].name")
;;
health_dev)
value=$(devlink -j health show 2>/dev/null | jq '.health' \
| jq 'keys[]')
;;
reporter)
dev=${words[cword - 2]}
value=$(devlink -j health show 2>/dev/null \
| jq ".health[\"$dev\"][].reporter")
;;
pool)
dev=$pprev
value=$(devlink -j sb pool show 2>/dev/null \
| jq ".pool[\"$dev\"][].pool")
;;
port_pool)
port=${words[5]}
value=$(devlink -j sb port pool show 2>/dev/null \
| jq ".port_pool[\"$port\"][].pool")
;;
tc)
port=$pprev
value=$(devlink -j sb tc bind show 2>/dev/null \
| jq ".tc_bind[\"$port\"][].tc")
;;
esac
COMPREPLY+=( $( compgen -W "$value" -- "$cur" ) )
# Remove colon containing prefix from COMPREPLY items in order to avoid
# wordbreaks with colon.
__ltrim_colon_completions "$cur"
}
# Completion for devlink dev eswitch set
_devlink_dev_eswitch_set()
{
local -A settings=(
[mode]=notseen
[inline-mode]=notseen
[encap]=notseen
)
if [[ $cword -eq 5 ]]; then
COMPREPLY=( $( compgen -W "mode inline-mode encap" -- "$cur" ) )
fi
# Mark seen settings
local word
for word in "${words[@]:5:${#words[@]}-1}"; do
if [[ -n $word ]]; then
if [[ "${settings[$word]}" ]]; then
settings[$word]=seen
fi
fi
done
case $prev in
mode)
COMPREPLY=( $( compgen -W "legacy switchdev" -- "$cur" ) )
return
;;
inline-mode)
COMPREPLY=( $( compgen -W "none link network transport" -- \
"$cur" ) )
return
;;
encap)
COMPREPLY=( $( compgen -W "disable enable" -- "$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
COMPREPLY=( $( compgen -W "${comp_words[*]}" -- "$cur" ) )
}
# Completion for devlink dev eswitch
_devlink_dev_eswitch()
{
case "$cword" in
3)
COMPREPLY=( $( compgen -W "show set" -- "$cur" ) )
return
;;
4)
_devlink_direct_complete "dev"
return
;;
esac
case "${words[3]}" in
set)
_devlink_dev_eswitch_set
return
;;
show)
return
;;
esac
}
# Completion for devlink dev param set
_devlink_dev_param_set()
{
case $cword in
7)
COMPREPLY=( $( compgen -W "value" -- "$cur" ) )
return
;;
8)
# String argument
return
;;
9)
COMPREPLY=( $( compgen -W "cmode" -- "$cur" ) )
return
;;
10)
COMPREPLY=( $( compgen -W "runtime driverinit permanent" -- \
"$cur" ) )
return
;;
esac
}
# Completion for devlink dev param
_devlink_dev_param()
{
case "$cword" in
3)
COMPREPLY=( $( compgen -W "show set" -- "$cur" ) )
return
;;
4)
_devlink_direct_complete "dev"
return
;;
5)
COMPREPLY=( $( compgen -W "name" -- "$cur" ) )
return
;;
6)
_devlink_direct_complete "param_name"
return
;;
esac
if [[ "${words[3]}" == "set" ]]; then
_devlink_dev_param_set
fi
}
# Completion for devlink dev reload
_devlink_dev_reload()
{
case "$cword" in
4)
COMPREPLY=( $( compgen -W "netns" -- "$cur" ) )
return
;;
5)
local nslist=$( ip netns list 2>/dev/null )
COMPREPLY=( $( compgen -W "$nslist" -- "$cur" ) )
return
;;
esac
}
# Completion for devlink dev flash
_devlink_dev_flash()
{
case "$cword" in
4)
COMPREPLY=( $( compgen -W "file" -- "$cur" ) )
return
;;
5)
_filedir
return
;;
6)
COMPREPLY=( $( compgen -W "component" -- "$cur" ) )
return
;;
esac
}
# Completion for devlink dev
_devlink_dev()
{
case $command in
show|reload|info|flash)
if [[ $cword -le 3 ]]; then
_devlink_direct_complete "dev"
elif [[ $command == "reload" || $command == "flash" ]];then
_devlink_dev_$command
fi
return
;;
eswitch|param)
_devlink_dev_$command
return
;;
esac
}
# Completion for devlink port set
_devlink_port_set()
{
case "$cword" in
3)
_devlink_direct_complete "port"
return
;;
4)
COMPREPLY=( $( compgen -W "type" -- "$cur" ) )
return
;;
5)
COMPREPLY=( $( compgen -W "eth ib auto" -- "$cur" ) )
return
;;
esac
}
# Completion for devlink port split
_devlink_port_split()
{
case "$cword" in
3)
_devlink_direct_complete "port"
return
;;
4)
COMPREPLY=( $( compgen -W "count" -- "$cur" ) )
return
;;
5)
# Integer argument
return
;;
esac
}
# Completion for devlink port
_devlink_port()
{
case $command in
set)
_devlink_port_set
return
;;
split)
_devlink_port_split
return
;;
show|unsplit)
if [[ $cword -eq 3 ]]; then
_devlink_direct_complete "port"
fi
return
;;
esac
}
# Completion for devlink dpipe
_devlink_dpipe()
{
local options="$(devlink dpipe help 2>&1 \
| command sed -e '/OBJECT-LIST := /!d' \
-e 's/.*{ //' -e 's/}.*//' -e 's/|//g' )"
if [[ $cword -eq 2 ]]; then
COMPREPLY+=( $( compgen -W "$options" -- "$cur" ) )
fi
}
# Completion for devlink monitor
_devlink_monitor()
{
local options="$(devlink monitor help 2>&1 \
| command sed -e '/OBJECT-LIST := /!d' \
-e 's/.*{ //' -e 's/}.*//' -e 's/|//g' )"
if [[ $cword -eq 2 ]]; then
COMPREPLY+=( $( compgen -W "all $options" -- "$cur" ) )
fi
}
# Completion for the rest of devlink sb $command
_devlink_sb_command_options()
{
local subcmd
case $command in
pool)
subcmd=${words[3]}
if [[ $cword -eq 5 ]]; then
COMPREPLY=( $( compgen -W "pool" -- "$cur" ) )
fi
if [[ $subcmd == "set" ]]; then
case $cword in
7)
COMPREPLY+=( $( compgen -W "size" -- "$cur" ) )
;;
9)
COMPREPLY+=( $( compgen -W "thtype" -- "$cur" ) )
;;
esac
fi
;;
port)
subcmd=${words[4]}
if [[ $cword -eq 6 ]]; then
COMPREPLY+=( $( compgen -W "pool" -- "$cur" ) )
fi
if [[ $subcmd == "set" ]]; then
case $cword in
8)
COMPREPLY+=( $( compgen -W "th" -- "$cur" ) )
;;
esac
fi
;;
tc)
subcmd=${words[4]}
case $cword in
6)
COMPREPLY+=( $( compgen -W "tc" -- "$cur" ) )
;;
8)
COMPREPLY+=( $( compgen -W "type" -- "$cur" ) )
;;
esac
if [[ $subcmd == "set" ]]; then
case $cword in
10)
COMPREPLY+=( $( compgen -W "pool" -- "$cur" ) )
;;
12)
COMPREPLY+=( $( compgen -W "th" -- "$cur" ) )
;;
esac
fi
;;
esac
}
# Completion for devlink sb
_devlink_sb()
{
case $prev in
bind)
COMPREPLY=( $( compgen -W "set show" -- "$cur" ) )
;;
occupancy)
COMPREPLY=( $( compgen -W "show snapshot clearmax" -- "$cur" ) )
;;
pool)
if [[ $cword -eq 3 || $cword -eq 4 ]]; then
COMPREPLY=( $( compgen -W "set show" -- "$cur" ) )
elif [[ $command == "port" || $command == "tc" ]]; then
_devlink_direct_complete "port_pool"
else
_devlink_direct_complete "pool"
fi
;;
port)
if [[ $cword -eq 3 ]]; then
COMPREPLY=( $( compgen -W "pool" -- "$cur" ) )
fi
;;
show|set|snapshot|clearmax)
case $command in
show|pool|occupancy)
_devlink_direct_complete "dev"
if [[ $command == "occupancy" && $prev == "show" ]];then
_devlink_direct_complete "port"
fi
;;
port|tc)
_devlink_direct_complete "port"
;;
esac
;;
size)
# Integer argument
;;
thtype)
COMPREPLY=( $( compgen -W "static dynamic" -- "$cur" ) )
;;
th)
# Integer argument
;;
tc)
if [[ $cword -eq 3 ]]; then
COMPREPLY=( $( compgen -W "bind" -- "$cur" ) )
else
_devlink_direct_complete "tc"
fi
;;
type)
COMPREPLY=( $( compgen -W "ingress egress" -- "$cur" ) )
;;
esac
_devlink_sb_command_options
return
}
# Completion for devlink resource set path argument
_devlink_resource_path()
{
local path parents parent all_path
local dev=${words[3]}
local -a path
local all_path=$(
devlink resource show $dev \
| sed -E '# Of resource lines, keep only the name itself.
s/name ([^ ]*) .*/\1/
# Drop headers.
/:$/d
# First layer is not aligned enough, align it.
s/^/ /
# Use slashes as unary code for resource depth.
s, ,/,g
# Separate tally count from resource name.
s,/*,&\t,' \
| while read d name; do
while ((${#path[@]} > ${#d})); do
unset path[$((${#path[@]} - 1))]
done
path[$((${#d} - 1))]=$name
echo ${path[@]}
done \
| sed '# Convert paths to slash-separated
s,^,/,;s, ,/,g;s,$,/,'
)
COMPREPLY=( ${COMPREPLY[@]:-} $( compgen -W "$all_path" -- "$cur" ) )
}
# Completion for devlink resource set
_devlink_resource_set()
{
case "$cword" in
3)
_devlink_direct_complete "dev"
return
;;
4)
COMPREPLY=( $( compgen -W "path" -- "$cur" ) )
return
;;
5)
_devlink_resource_path
return
;;
6)
COMPREPLY=( $( compgen -W "size" -- "$cur" ) )
return
;;
7)
# Integer argument
return
;;
esac
}
# Completion for devlink resource
_devlink_resource()
{
case $command in
show)
if [[ $cword -eq 3 ]]; then
_devlink_direct_complete "dev"
fi
return
;;
set)
_devlink_resource_set
return
;;
esac
}
# Completion for devlink region read
_devlink_region_read()
{
case "$cword" in
6)
COMPREPLY=( $( compgen -W "address" -- "$cur" ) )
return
;;
7)
# Address argument, for example: 0x10
return
;;
8)
COMPREPLY=( $( compgen -W "length" -- "$cur" ) )
return
;;
9)
# Integer argument
return
;;
esac
}
# Completion for devlink region
_devlink_region()
{
if [[ $cword -eq 3 && $command != "help" ]]; then
_devlink_direct_complete "region"
fi
case $command in
show)
return
;;
del|dump|read)
case "$cword" in
4)
COMPREPLY=( $( compgen -W "snapshot" -- "$cur" ) )
;;
5)
_devlink_direct_complete "snapshot"
;;
esac
if [[ $command == "read" ]]; then
_devlink_region_read
fi
return
;;
esac
}
# Completion reporter for devlink health
_devlink_health_reporter()
{
local i=$1; shift
case $cword in
$((3 + $i)))
_devlink_direct_complete "health_dev"
;;
$((4 + $i)))
COMPREPLY=( $( compgen -W "reporter" -- "$cur" ) )
;;
$((5 + $i)))
_devlink_direct_complete "reporter"
;;
esac
}
# Completion for devlink health
_devlink_health()
{
case $command in
show|recover|diagnose|set)
_devlink_health_reporter 0
if [[ $command == "set" ]]; then
case $cword in
6)
COMPREPLY=( $( compgen -W "grace_period auto_recover" \
-- "$cur" ) )
;;
7)
case $prev in
grace_period)
# Integer argument- msec
;;
auto_recover)
COMPREPLY=( $( compgen -W "true false" -- \
"$cur" ) )
;;
esac
esac
fi
return
;;
dump)
if [[ $cword -eq 3 ]]; then
COMPREPLY=( $( compgen -W "show clear" -- "$cur" ) )
fi
_devlink_health_reporter 1
return
;;
esac
}
# Completion for action in devlink trap set
_devlink_trap_set_action()
{
local i=$1; shift
case $cword in
$((6 + $i)))
COMPREPLY=( $( compgen -W "action" -- "$cur" ) )
;;
$((7 + $i)))
COMPREPLY=( $( compgen -W "trap drop" -- "$cur" ) )
;;
esac
}
# Completion for devlink trap group
_devlink_trap_group()
{
case $cword in
3)
COMPREPLY=( $( compgen -W "set show" -- "$cur" ) )
return
;;
4)
_devlink_direct_complete "dev"
return
;;
5)
COMPREPLY=( $( compgen -W "group" -- "$cur" ) )
return
;;
6)
_devlink_direct_complete "trap_group"
return
;;
esac
if [[ ${words[3]} == "set" ]]; then
_devlink_trap_set_action 1
fi
}
# Completion for devlink trap
_devlink_trap()
{
case $command in
show|set)
case $cword in
3)
_devlink_direct_complete "dev"
;;
4)
COMPREPLY=( $( compgen -W "trap" -- "$cur" ) )
;;
5)
_devlink_direct_complete "trap"
;;
esac
if [[ $command == "set" ]]; then
_devlink_trap_set_action 0
fi
return
;;
group)
_devlink_trap_$command
return
;;
esac
}
# Complete any devlink command
_devlink()
{
local cur prev words cword
local opt='--Version --no-nice-names --json --pretty --verbose \
--statistics --force --Netns --batch'
local objects="$(devlink help 2>&1 | command sed -e '/OBJECT := /!d' \
-e 's/.*{//' -e 's/}.*//' -e \ 's/|//g' )"
_init_completion || return
# Gets the word-to-complete without considering the colon as word breaks
_get_comp_words_by_ref -n : cur prev words cword
if [[ $cword -eq 1 ]]; then
case $cur in
-*)
COMPREPLY=( $( compgen -W "$opt" -- "$cur" ) )
return 0
;;
*)
COMPREPLY=( $( compgen -W "$objects" -- "$cur" ) )
return 0
;;
esac
fi
# Deal with options
if [[ $prev == -* ]]; then
case $prev in
-V|--Version)
return 0
;;
-b|--batch)
_filedir
return 0
;;
--force)
COMPREPLY=( $( compgen -W "--batch" -- "$cur" ) )
return 0
;;
-N|--Netns)
local nslist=$( ip netns list 2>/dev/null )
COMPREPLY=( $( compgen -W "$nslist" -- "$cur" ) )
return 0
;;
-j|--json)
COMPREPLY=( $( compgen -W "--pretty $objects" -- "$cur" ) )
return 0
;;
*)
COMPREPLY=( $( compgen -W "$objects" -- "$cur" ) )
return 0
;;
esac
fi
# Remove all options so completions don't have to deal with them.
local i
for (( i=1; i < ${#words[@]}; )); do
if [[ ${words[i]::1} == - ]]; then
words=( "${words[@]:0:i}" "${words[@]:i+1}" )
[[ $i -le $cword ]] && cword=$(( cword - 1 ))
else
i=$(( ++i ))
fi
done
local object=${words[1]}
local command=${words[2]}
local pprev=${words[cword - 2]}
if [[ $objects =~ $object ]]; then
if [[ $cword -eq 2 ]]; then
COMPREPLY=( $( compgen -W "help" -- "$cur") )
if [[ $object != "monitor" && $object != "dpipe" ]]; then
COMPREPLY+=( $( compgen -W \
"$(_devlink_get_optional_commands $object)" -- "$cur" ) )
fi
fi
"_devlink_$object"
fi
} &&
complete -F _devlink devlink
# ex: ts=4 sw=4 et filetype=sh