]> git.proxmox.com Git - mirror_iproute2.git/commitdiff
bash-completion: devlink: add bash-completion function
authorDanielle Ratson <danieller@mellanox.com>
Wed, 25 Mar 2020 09:25:34 +0000 (11:25 +0200)
committerDavid Ahern <dsahern@gmail.com>
Wed, 25 Mar 2020 16:46:09 +0000 (16:46 +0000)
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>
Makefile
bash-completion/devlink [new file with mode: 0644]

index 0b79b1f1d0ec733f6155c265c25d33172e0e2887..25d05fac952a15ef7d6217ff9def8795b7b02c23 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -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:
diff --git a/bash-completion/devlink b/bash-completion/devlink
new file mode 100644 (file)
index 0000000..45fba75
--- /dev/null
@@ -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