There is no support for creating maps of types array-of-map or hash-of-map in bpftool. This is because the kernel needs an inner_map_fd to collect metadata on the inner maps to be supported by the new map, but bpftool does not provide a way to pass this file descriptor. Add a new optional "inner_map" keyword that can be used to pass a reference to a map, retrieve a fd to that map, and pass it as the inner_map_fd. Add related documentation and bash completion. Note that we can reference the inner map by its name, meaning we can have several times the keyword "name" with different meanings (mandatory outer map name, and possibly a name to use to find the inner_map_fd). The bash completion will offer it just once, and will not suggest "name" on the following command: # bpftool map create /sys/fs/bpf/my_outer_map type hash_of_maps \ inner_map name my_inner_map [TAB] Fixing that specific case seems too convoluted. Completion will work as expected, however, if the outer map name comes first and the "inner_map name ..." is passed second. Signed-off-by: Quentin Monnet <quentin@isovalent.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Andrii Nakryiko <andriin@fb.com> Link: https://lore.kernel.org/bpf/20200910102652.10509-4-quentin@isovalent.com
1182 lines
43 KiB
Bash
1182 lines
43 KiB
Bash
# bpftool(8) bash completion -*- shell-script -*-
|
|
#
|
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
|
# Copyright (C) 2017-2018 Netronome Systems, Inc.
|
|
#
|
|
# Author: Quentin Monnet <quentin.monnet@netronome.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.
|
|
_bpftool_once_attr()
|
|
{
|
|
local w idx found
|
|
for w in $*; do
|
|
found=0
|
|
for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
|
|
if [[ $w == ${words[idx]} ]]; then
|
|
found=1
|
|
break
|
|
fi
|
|
done
|
|
[[ $found -eq 0 ]] && \
|
|
COMPREPLY+=( $( compgen -W "$w" -- "$cur" ) )
|
|
done
|
|
}
|
|
|
|
# Takes a list of words as argument; if any of those words is present on the
|
|
# command line, return 0. Otherwise, return 1.
|
|
_bpftool_search_list()
|
|
{
|
|
local w idx
|
|
for w in $*; do
|
|
for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
|
|
[[ $w == ${words[idx]} ]] && return 0
|
|
done
|
|
done
|
|
return 1
|
|
}
|
|
|
|
# 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.
|
|
_bpftool_one_of_list()
|
|
{
|
|
_bpftool_search_list $* && return 1
|
|
COMPREPLY+=( $( compgen -W "$*" -- "$cur" ) )
|
|
}
|
|
|
|
_bpftool_get_map_ids()
|
|
{
|
|
COMPREPLY+=( $( compgen -W "$( bpftool -jp map 2>&1 | \
|
|
command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
|
|
}
|
|
|
|
# Takes map type and adds matching map ids to the list of suggestions.
|
|
_bpftool_get_map_ids_for_type()
|
|
{
|
|
local type="$1"
|
|
COMPREPLY+=( $( compgen -W "$( bpftool -jp map 2>&1 | \
|
|
command grep -C2 "$type" | \
|
|
command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
|
|
}
|
|
|
|
_bpftool_get_map_names()
|
|
{
|
|
COMPREPLY+=( $( compgen -W "$( bpftool -jp map 2>&1 | \
|
|
command sed -n 's/.*"name": \(.*\),$/\1/p' )" -- "$cur" ) )
|
|
}
|
|
|
|
# Takes map type and adds matching map names to the list of suggestions.
|
|
_bpftool_get_map_names_for_type()
|
|
{
|
|
local type="$1"
|
|
COMPREPLY+=( $( compgen -W "$( bpftool -jp map 2>&1 | \
|
|
command grep -C2 "$type" | \
|
|
command sed -n 's/.*"name": \(.*\),$/\1/p' )" -- "$cur" ) )
|
|
}
|
|
|
|
_bpftool_get_prog_ids()
|
|
{
|
|
COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \
|
|
command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
|
|
}
|
|
|
|
_bpftool_get_prog_tags()
|
|
{
|
|
COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \
|
|
command sed -n 's/.*"tag": "\(.*\)",$/\1/p' )" -- "$cur" ) )
|
|
}
|
|
|
|
_bpftool_get_prog_names()
|
|
{
|
|
COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \
|
|
command sed -n 's/.*"name": "\(.*\)",$/\1/p' )" -- "$cur" ) )
|
|
}
|
|
|
|
_bpftool_get_btf_ids()
|
|
{
|
|
COMPREPLY+=( $( compgen -W "$( bpftool -jp btf 2>&1 | \
|
|
command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
|
|
}
|
|
|
|
_bpftool_get_link_ids()
|
|
{
|
|
COMPREPLY+=( $( compgen -W "$( bpftool -jp link 2>&1 | \
|
|
command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
|
|
}
|
|
|
|
_bpftool_get_obj_map_names()
|
|
{
|
|
local obj
|
|
|
|
obj=$1
|
|
|
|
maps=$(objdump -j maps -t $obj 2>/dev/null | \
|
|
command awk '/g . maps/ {print $NF}')
|
|
|
|
COMPREPLY+=( $( compgen -W "$maps" -- "$cur" ) )
|
|
}
|
|
|
|
_bpftool_get_obj_map_idxs()
|
|
{
|
|
local obj
|
|
|
|
obj=$1
|
|
|
|
nmaps=$(objdump -j maps -t $obj 2>/dev/null | grep -c 'g . maps')
|
|
|
|
COMPREPLY+=( $( compgen -W "$(seq 0 $((nmaps - 1)))" -- "$cur" ) )
|
|
}
|
|
|
|
_sysfs_get_netdevs()
|
|
{
|
|
COMPREPLY+=( $( compgen -W "$( ls /sys/class/net 2>/dev/null )" -- \
|
|
"$cur" ) )
|
|
}
|
|
|
|
# Retrieve type of the map that we are operating on.
|
|
_bpftool_map_guess_map_type()
|
|
{
|
|
local keyword ref
|
|
for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
|
|
case "${words[$((idx-2))]}" in
|
|
lookup|update)
|
|
keyword=${words[$((idx-1))]}
|
|
ref=${words[$((idx))]}
|
|
;;
|
|
push)
|
|
printf "stack"
|
|
return 0
|
|
;;
|
|
enqueue)
|
|
printf "queue"
|
|
return 0
|
|
;;
|
|
esac
|
|
done
|
|
[[ -z $ref ]] && return 0
|
|
|
|
local type
|
|
type=$(bpftool -jp map show $keyword $ref | \
|
|
command sed -n 's/.*"type": "\(.*\)",$/\1/p')
|
|
[[ -n $type ]] && printf $type
|
|
}
|
|
|
|
_bpftool_map_update_get_id()
|
|
{
|
|
local command="$1"
|
|
|
|
# Is it the map to update, or a map to insert into the map to update?
|
|
# Search for "value" keyword.
|
|
local idx value
|
|
for (( idx=7; idx < ${#words[@]}-1; idx++ )); do
|
|
if [[ ${words[idx]} == "value" ]]; then
|
|
value=1
|
|
break
|
|
fi
|
|
done
|
|
if [[ $value -eq 0 ]]; then
|
|
case "$command" in
|
|
push)
|
|
_bpftool_get_map_ids_for_type stack
|
|
;;
|
|
enqueue)
|
|
_bpftool_get_map_ids_for_type queue
|
|
;;
|
|
*)
|
|
_bpftool_get_map_ids
|
|
;;
|
|
esac
|
|
return 0
|
|
fi
|
|
|
|
# Id to complete is for a value. It can be either prog id or map id. This
|
|
# depends on the type of the map to update.
|
|
local type=$(_bpftool_map_guess_map_type)
|
|
case $type in
|
|
array_of_maps|hash_of_maps)
|
|
_bpftool_get_map_ids
|
|
return 0
|
|
;;
|
|
prog_array)
|
|
_bpftool_get_prog_ids
|
|
return 0
|
|
;;
|
|
*)
|
|
return 0
|
|
;;
|
|
esac
|
|
}
|
|
|
|
_bpftool_map_update_get_name()
|
|
{
|
|
local command="$1"
|
|
|
|
# Is it the map to update, or a map to insert into the map to update?
|
|
# Search for "value" keyword.
|
|
local idx value
|
|
for (( idx=7; idx < ${#words[@]}-1; idx++ )); do
|
|
if [[ ${words[idx]} == "value" ]]; then
|
|
value=1
|
|
break
|
|
fi
|
|
done
|
|
if [[ $value -eq 0 ]]; then
|
|
case "$command" in
|
|
push)
|
|
_bpftool_get_map_names_for_type stack
|
|
;;
|
|
enqueue)
|
|
_bpftool_get_map_names_for_type queue
|
|
;;
|
|
*)
|
|
_bpftool_get_map_names
|
|
;;
|
|
esac
|
|
return 0
|
|
fi
|
|
|
|
# Name to complete is for a value. It can be either prog name or map name. This
|
|
# depends on the type of the map to update.
|
|
local type=$(_bpftool_map_guess_map_type)
|
|
case $type in
|
|
array_of_maps|hash_of_maps)
|
|
_bpftool_get_map_names
|
|
return 0
|
|
;;
|
|
prog_array)
|
|
_bpftool_get_prog_names
|
|
return 0
|
|
;;
|
|
*)
|
|
return 0
|
|
;;
|
|
esac
|
|
}
|
|
|
|
_bpftool()
|
|
{
|
|
local cur prev words objword
|
|
_init_completion || return
|
|
|
|
# Deal with options
|
|
if [[ ${words[cword]} == -* ]]; then
|
|
local c='--version --json --pretty --bpffs --mapcompat --debug'
|
|
COMPREPLY=( $( compgen -W "$c" -- "$cur" ) )
|
|
return 0
|
|
fi
|
|
|
|
# Deal with simplest keywords
|
|
case $prev in
|
|
help|hex|opcodes|visual|linum)
|
|
return 0
|
|
;;
|
|
tag)
|
|
_bpftool_get_prog_tags
|
|
return 0
|
|
;;
|
|
dev)
|
|
_sysfs_get_netdevs
|
|
return 0
|
|
;;
|
|
file|pinned)
|
|
_filedir
|
|
return 0
|
|
;;
|
|
batch)
|
|
COMPREPLY=( $( compgen -W 'file' -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
esac
|
|
|
|
# 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
|
|
cur=${words[cword]}
|
|
prev=${words[cword - 1]}
|
|
pprev=${words[cword - 2]}
|
|
|
|
local object=${words[1]} command=${words[2]}
|
|
|
|
if [[ -z $object || $cword -eq 1 ]]; then
|
|
case $cur in
|
|
*)
|
|
COMPREPLY=( $( compgen -W "$( bpftool help 2>&1 | \
|
|
command sed \
|
|
-e '/OBJECT := /!d' \
|
|
-e 's/.*{//' \
|
|
-e 's/}.*//' \
|
|
-e 's/|//g' )" -- "$cur" ) )
|
|
COMPREPLY+=( $( compgen -W 'batch help' -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
[[ $command == help ]] && return 0
|
|
|
|
# Completion depends on object and command in use
|
|
case $object in
|
|
prog)
|
|
# Complete id and name, only for subcommands that use prog (but no
|
|
# map) ids/names.
|
|
case $command in
|
|
show|list|dump|pin)
|
|
case $prev in
|
|
id)
|
|
_bpftool_get_prog_ids
|
|
return 0
|
|
;;
|
|
name)
|
|
_bpftool_get_prog_names
|
|
return 0
|
|
;;
|
|
esac
|
|
;;
|
|
esac
|
|
|
|
local PROG_TYPE='id pinned tag name'
|
|
local MAP_TYPE='id pinned name'
|
|
local METRIC_TYPE='cycles instructions l1d_loads llc_misses'
|
|
case $command in
|
|
show|list)
|
|
[[ $prev != "$command" ]] && return 0
|
|
COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
dump)
|
|
case $prev in
|
|
$command)
|
|
COMPREPLY+=( $( compgen -W "xlated jited" -- \
|
|
"$cur" ) )
|
|
return 0
|
|
;;
|
|
xlated|jited)
|
|
COMPREPLY=( $( compgen -W "$PROG_TYPE" -- \
|
|
"$cur" ) )
|
|
return 0
|
|
;;
|
|
*)
|
|
_bpftool_once_attr 'file'
|
|
if _bpftool_search_list 'xlated'; then
|
|
COMPREPLY+=( $( compgen -W 'opcodes visual linum' -- \
|
|
"$cur" ) )
|
|
else
|
|
COMPREPLY+=( $( compgen -W 'opcodes linum' -- \
|
|
"$cur" ) )
|
|
fi
|
|
return 0
|
|
;;
|
|
esac
|
|
;;
|
|
pin)
|
|
if [[ $prev == "$command" ]]; then
|
|
COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
|
|
else
|
|
_filedir
|
|
fi
|
|
return 0
|
|
;;
|
|
attach|detach)
|
|
case $cword in
|
|
3)
|
|
COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
4)
|
|
case $prev in
|
|
id)
|
|
_bpftool_get_prog_ids
|
|
;;
|
|
name)
|
|
_bpftool_get_prog_names
|
|
;;
|
|
pinned)
|
|
_filedir
|
|
;;
|
|
esac
|
|
return 0
|
|
;;
|
|
5)
|
|
COMPREPLY=( $( compgen -W 'msg_verdict stream_verdict \
|
|
stream_parser flow_dissector' -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
6)
|
|
COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
7)
|
|
case $prev in
|
|
id)
|
|
_bpftool_get_map_ids
|
|
;;
|
|
name)
|
|
_bpftool_get_map_names
|
|
;;
|
|
pinned)
|
|
_filedir
|
|
;;
|
|
esac
|
|
return 0
|
|
;;
|
|
esac
|
|
;;
|
|
load|loadall)
|
|
local obj
|
|
|
|
# Propose "load/loadall" to complete "bpftool prog load",
|
|
# or bash tries to complete "load" as a filename below.
|
|
if [[ ${#words[@]} -eq 3 ]]; then
|
|
COMPREPLY=( $( compgen -W "load loadall" -- "$cur" ) )
|
|
return 0
|
|
fi
|
|
|
|
if [[ ${#words[@]} -lt 6 ]]; then
|
|
_filedir
|
|
return 0
|
|
fi
|
|
|
|
obj=${words[3]}
|
|
|
|
if [[ ${words[-4]} == "map" ]]; then
|
|
COMPREPLY=( $( compgen -W "id pinned" -- "$cur" ) )
|
|
return 0
|
|
fi
|
|
if [[ ${words[-3]} == "map" ]]; then
|
|
if [[ ${words[-2]} == "idx" ]]; then
|
|
_bpftool_get_obj_map_idxs $obj
|
|
elif [[ ${words[-2]} == "name" ]]; then
|
|
_bpftool_get_obj_map_names $obj
|
|
fi
|
|
return 0
|
|
fi
|
|
if [[ ${words[-2]} == "map" ]]; then
|
|
COMPREPLY=( $( compgen -W "idx name" -- "$cur" ) )
|
|
return 0
|
|
fi
|
|
|
|
case $prev in
|
|
type)
|
|
COMPREPLY=( $( compgen -W "socket kprobe \
|
|
kretprobe classifier flow_dissector \
|
|
action tracepoint raw_tracepoint \
|
|
xdp perf_event cgroup/skb cgroup/sock \
|
|
cgroup/dev lwt_in lwt_out lwt_xmit \
|
|
lwt_seg6local sockops sk_skb sk_msg \
|
|
lirc_mode2 cgroup/bind4 cgroup/bind6 \
|
|
cgroup/connect4 cgroup/connect6 \
|
|
cgroup/getpeername4 cgroup/getpeername6 \
|
|
cgroup/getsockname4 cgroup/getsockname6 \
|
|
cgroup/sendmsg4 cgroup/sendmsg6 \
|
|
cgroup/recvmsg4 cgroup/recvmsg6 \
|
|
cgroup/post_bind4 cgroup/post_bind6 \
|
|
cgroup/sysctl cgroup/getsockopt \
|
|
cgroup/setsockopt struct_ops \
|
|
fentry fexit freplace sk_lookup" -- \
|
|
"$cur" ) )
|
|
return 0
|
|
;;
|
|
id)
|
|
_bpftool_get_map_ids
|
|
return 0
|
|
;;
|
|
name)
|
|
_bpftool_get_map_names
|
|
return 0
|
|
;;
|
|
pinned|pinmaps)
|
|
_filedir
|
|
return 0
|
|
;;
|
|
*)
|
|
COMPREPLY=( $( compgen -W "map" -- "$cur" ) )
|
|
_bpftool_once_attr 'type'
|
|
_bpftool_once_attr 'dev'
|
|
_bpftool_once_attr 'pinmaps'
|
|
return 0
|
|
;;
|
|
esac
|
|
;;
|
|
tracelog)
|
|
return 0
|
|
;;
|
|
profile)
|
|
case $cword in
|
|
3)
|
|
COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
4)
|
|
case $prev in
|
|
id)
|
|
_bpftool_get_prog_ids
|
|
;;
|
|
name)
|
|
_bpftool_get_prog_names
|
|
;;
|
|
pinned)
|
|
_filedir
|
|
;;
|
|
esac
|
|
return 0
|
|
;;
|
|
5)
|
|
COMPREPLY=( $( compgen -W "$METRIC_TYPE duration" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
6)
|
|
case $prev in
|
|
duration)
|
|
return 0
|
|
;;
|
|
*)
|
|
COMPREPLY=( $( compgen -W "$METRIC_TYPE" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
esac
|
|
return 0
|
|
;;
|
|
*)
|
|
COMPREPLY=( $( compgen -W "$METRIC_TYPE" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
esac
|
|
;;
|
|
run)
|
|
if [[ ${#words[@]} -eq 4 ]]; then
|
|
COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
|
|
return 0
|
|
fi
|
|
case $prev in
|
|
id)
|
|
_bpftool_get_prog_ids
|
|
return 0
|
|
;;
|
|
name)
|
|
_bpftool_get_prog_names
|
|
return 0
|
|
;;
|
|
data_in|data_out|ctx_in|ctx_out)
|
|
_filedir
|
|
return 0
|
|
;;
|
|
repeat|data_size_out|ctx_size_out)
|
|
return 0
|
|
;;
|
|
*)
|
|
_bpftool_once_attr 'data_in data_out data_size_out \
|
|
ctx_in ctx_out ctx_size_out repeat'
|
|
return 0
|
|
;;
|
|
esac
|
|
;;
|
|
*)
|
|
[[ $prev == $object ]] && \
|
|
COMPREPLY=( $( compgen -W 'dump help pin attach detach \
|
|
load loadall show list tracelog run profile' -- "$cur" ) )
|
|
;;
|
|
esac
|
|
;;
|
|
struct_ops)
|
|
local STRUCT_OPS_TYPE='id name'
|
|
case $command in
|
|
show|list|dump|unregister)
|
|
case $prev in
|
|
$command)
|
|
COMPREPLY=( $( compgen -W "$STRUCT_OPS_TYPE" -- "$cur" ) )
|
|
;;
|
|
id)
|
|
_bpftool_get_map_ids_for_type struct_ops
|
|
;;
|
|
name)
|
|
_bpftool_get_map_names_for_type struct_ops
|
|
;;
|
|
esac
|
|
return 0
|
|
;;
|
|
register)
|
|
_filedir
|
|
return 0
|
|
;;
|
|
*)
|
|
[[ $prev == $object ]] && \
|
|
COMPREPLY=( $( compgen -W 'register unregister show list dump help' \
|
|
-- "$cur" ) )
|
|
;;
|
|
esac
|
|
;;
|
|
iter)
|
|
case $command in
|
|
pin)
|
|
case $prev in
|
|
$command)
|
|
_filedir
|
|
;;
|
|
id)
|
|
_bpftool_get_map_ids
|
|
;;
|
|
name)
|
|
_bpftool_get_map_names
|
|
;;
|
|
pinned)
|
|
_filedir
|
|
;;
|
|
*)
|
|
_bpftool_one_of_list $MAP_TYPE
|
|
;;
|
|
esac
|
|
return 0
|
|
;;
|
|
*)
|
|
[[ $prev == $object ]] && \
|
|
COMPREPLY=( $( compgen -W 'pin help' \
|
|
-- "$cur" ) )
|
|
;;
|
|
esac
|
|
;;
|
|
map)
|
|
local MAP_TYPE='id pinned name'
|
|
case $command in
|
|
show|list|dump|peek|pop|dequeue|freeze)
|
|
case $prev in
|
|
$command)
|
|
COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
id)
|
|
case "$command" in
|
|
peek)
|
|
_bpftool_get_map_ids_for_type stack
|
|
_bpftool_get_map_ids_for_type queue
|
|
;;
|
|
pop)
|
|
_bpftool_get_map_ids_for_type stack
|
|
;;
|
|
dequeue)
|
|
_bpftool_get_map_ids_for_type queue
|
|
;;
|
|
*)
|
|
_bpftool_get_map_ids
|
|
;;
|
|
esac
|
|
return 0
|
|
;;
|
|
name)
|
|
case "$command" in
|
|
peek)
|
|
_bpftool_get_map_names_for_type stack
|
|
_bpftool_get_map_names_for_type queue
|
|
;;
|
|
pop)
|
|
_bpftool_get_map_names_for_type stack
|
|
;;
|
|
dequeue)
|
|
_bpftool_get_map_names_for_type queue
|
|
;;
|
|
*)
|
|
_bpftool_get_map_names
|
|
;;
|
|
esac
|
|
return 0
|
|
;;
|
|
*)
|
|
return 0
|
|
;;
|
|
esac
|
|
;;
|
|
create)
|
|
case $prev in
|
|
$command)
|
|
_filedir
|
|
return 0
|
|
;;
|
|
type)
|
|
COMPREPLY=( $( compgen -W 'hash array prog_array \
|
|
perf_event_array percpu_hash percpu_array \
|
|
stack_trace cgroup_array lru_hash \
|
|
lru_percpu_hash lpm_trie array_of_maps \
|
|
hash_of_maps devmap devmap_hash sockmap cpumap \
|
|
xskmap sockhash cgroup_storage reuseport_sockarray \
|
|
percpu_cgroup_storage queue stack sk_storage \
|
|
struct_ops inode_storage' -- \
|
|
"$cur" ) )
|
|
return 0
|
|
;;
|
|
key|value|flags|entries)
|
|
return 0
|
|
;;
|
|
inner_map)
|
|
COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
id)
|
|
_bpftool_get_map_ids
|
|
;;
|
|
name)
|
|
case $pprev in
|
|
inner_map)
|
|
_bpftool_get_map_names
|
|
;;
|
|
*)
|
|
return 0
|
|
;;
|
|
esac
|
|
;;
|
|
*)
|
|
_bpftool_once_attr 'type'
|
|
_bpftool_once_attr 'key'
|
|
_bpftool_once_attr 'value'
|
|
_bpftool_once_attr 'entries'
|
|
_bpftool_once_attr 'name'
|
|
_bpftool_once_attr 'flags'
|
|
if _bpftool_search_list 'array_of_maps' 'hash_of_maps'; then
|
|
_bpftool_once_attr 'inner_map'
|
|
fi
|
|
_bpftool_once_attr 'dev'
|
|
return 0
|
|
;;
|
|
esac
|
|
;;
|
|
lookup|getnext|delete)
|
|
case $prev in
|
|
$command)
|
|
COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
id)
|
|
_bpftool_get_map_ids
|
|
return 0
|
|
;;
|
|
name)
|
|
_bpftool_get_map_names
|
|
return 0
|
|
;;
|
|
key)
|
|
COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) )
|
|
;;
|
|
*)
|
|
case $(_bpftool_map_guess_map_type) in
|
|
queue|stack)
|
|
return 0
|
|
;;
|
|
esac
|
|
|
|
_bpftool_once_attr 'key'
|
|
return 0
|
|
;;
|
|
esac
|
|
;;
|
|
update|push|enqueue)
|
|
case $prev in
|
|
$command)
|
|
COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
id)
|
|
_bpftool_map_update_get_id $command
|
|
return 0
|
|
;;
|
|
name)
|
|
_bpftool_map_update_get_name $command
|
|
return 0
|
|
;;
|
|
key)
|
|
COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) )
|
|
;;
|
|
value)
|
|
# We can have bytes, or references to a prog or a
|
|
# map, depending on the type of the map to update.
|
|
case "$(_bpftool_map_guess_map_type)" in
|
|
array_of_maps|hash_of_maps)
|
|
local MAP_TYPE='id pinned name'
|
|
COMPREPLY+=( $( compgen -W "$MAP_TYPE" \
|
|
-- "$cur" ) )
|
|
return 0
|
|
;;
|
|
prog_array)
|
|
local PROG_TYPE='id pinned tag name'
|
|
COMPREPLY+=( $( compgen -W "$PROG_TYPE" \
|
|
-- "$cur" ) )
|
|
return 0
|
|
;;
|
|
*)
|
|
COMPREPLY+=( $( compgen -W 'hex' \
|
|
-- "$cur" ) )
|
|
return 0
|
|
;;
|
|
esac
|
|
return 0
|
|
;;
|
|
*)
|
|
case $(_bpftool_map_guess_map_type) in
|
|
queue|stack)
|
|
_bpftool_once_attr 'value'
|
|
return 0;
|
|
;;
|
|
esac
|
|
|
|
_bpftool_once_attr 'key'
|
|
local UPDATE_FLAGS='any exist noexist'
|
|
for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
|
|
if [[ ${words[idx]} == 'value' ]]; then
|
|
# 'value' is present, but is not the last
|
|
# word i.e. we can now have UPDATE_FLAGS.
|
|
_bpftool_one_of_list "$UPDATE_FLAGS"
|
|
return 0
|
|
fi
|
|
done
|
|
for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
|
|
if [[ ${words[idx]} == 'key' ]]; then
|
|
# 'key' is present, but is not the last
|
|
# word i.e. we can now have 'value'.
|
|
_bpftool_once_attr 'value'
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
return 0
|
|
;;
|
|
esac
|
|
;;
|
|
pin)
|
|
case $prev in
|
|
$command)
|
|
COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
|
|
;;
|
|
id)
|
|
_bpftool_get_map_ids
|
|
;;
|
|
name)
|
|
_bpftool_get_map_names
|
|
;;
|
|
esac
|
|
return 0
|
|
;;
|
|
event_pipe)
|
|
case $prev in
|
|
$command)
|
|
COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
id)
|
|
_bpftool_get_map_ids_for_type perf_event_array
|
|
return 0
|
|
;;
|
|
name)
|
|
_bpftool_get_map_names_for_type perf_event_array
|
|
return 0
|
|
;;
|
|
cpu)
|
|
return 0
|
|
;;
|
|
index)
|
|
return 0
|
|
;;
|
|
*)
|
|
_bpftool_once_attr 'cpu'
|
|
_bpftool_once_attr 'index'
|
|
return 0
|
|
;;
|
|
esac
|
|
;;
|
|
*)
|
|
[[ $prev == $object ]] && \
|
|
COMPREPLY=( $( compgen -W 'delete dump getnext help \
|
|
lookup pin event_pipe show list update create \
|
|
peek push enqueue pop dequeue freeze' -- \
|
|
"$cur" ) )
|
|
;;
|
|
esac
|
|
;;
|
|
btf)
|
|
local PROG_TYPE='id pinned tag name'
|
|
local MAP_TYPE='id pinned name'
|
|
case $command in
|
|
dump)
|
|
case $prev in
|
|
$command)
|
|
COMPREPLY+=( $( compgen -W "id map prog file" -- \
|
|
"$cur" ) )
|
|
return 0
|
|
;;
|
|
prog)
|
|
COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
map)
|
|
COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
id)
|
|
case $pprev in
|
|
prog)
|
|
_bpftool_get_prog_ids
|
|
;;
|
|
map)
|
|
_bpftool_get_map_ids
|
|
;;
|
|
$command)
|
|
_bpftool_get_btf_ids
|
|
;;
|
|
esac
|
|
return 0
|
|
;;
|
|
name)
|
|
case $pprev in
|
|
prog)
|
|
_bpftool_get_prog_names
|
|
;;
|
|
map)
|
|
_bpftool_get_map_names
|
|
;;
|
|
esac
|
|
return 0
|
|
;;
|
|
format)
|
|
COMPREPLY=( $( compgen -W "c raw" -- "$cur" ) )
|
|
;;
|
|
*)
|
|
# emit extra options
|
|
case ${words[3]} in
|
|
id|file)
|
|
_bpftool_once_attr 'format'
|
|
;;
|
|
map|prog)
|
|
if [[ ${words[3]} == "map" ]] && [[ $cword == 6 ]]; then
|
|
COMPREPLY+=( $( compgen -W "key value kv all" -- "$cur" ) )
|
|
fi
|
|
_bpftool_once_attr 'format'
|
|
;;
|
|
*)
|
|
;;
|
|
esac
|
|
return 0
|
|
;;
|
|
esac
|
|
;;
|
|
show|list)
|
|
case $prev in
|
|
$command)
|
|
COMPREPLY+=( $( compgen -W "id" -- "$cur" ) )
|
|
;;
|
|
id)
|
|
_bpftool_get_btf_ids
|
|
;;
|
|
esac
|
|
return 0
|
|
;;
|
|
*)
|
|
[[ $prev == $object ]] && \
|
|
COMPREPLY=( $( compgen -W 'dump help show list' \
|
|
-- "$cur" ) )
|
|
;;
|
|
esac
|
|
;;
|
|
gen)
|
|
case $command in
|
|
skeleton)
|
|
_filedir
|
|
;;
|
|
*)
|
|
[[ $prev == $object ]] && \
|
|
COMPREPLY=( $( compgen -W 'skeleton help' -- "$cur" ) )
|
|
;;
|
|
esac
|
|
;;
|
|
cgroup)
|
|
case $command in
|
|
show|list|tree)
|
|
case $cword in
|
|
3)
|
|
_filedir
|
|
;;
|
|
4)
|
|
COMPREPLY=( $( compgen -W 'effective' -- "$cur" ) )
|
|
;;
|
|
esac
|
|
return 0
|
|
;;
|
|
attach|detach)
|
|
local ATTACH_TYPES='ingress egress sock_create sock_ops \
|
|
device bind4 bind6 post_bind4 post_bind6 connect4 connect6 \
|
|
getpeername4 getpeername6 getsockname4 getsockname6 \
|
|
sendmsg4 sendmsg6 recvmsg4 recvmsg6 sysctl getsockopt \
|
|
setsockopt'
|
|
local ATTACH_FLAGS='multi override'
|
|
local PROG_TYPE='id pinned tag name'
|
|
case $prev in
|
|
$command)
|
|
_filedir
|
|
return 0
|
|
;;
|
|
ingress|egress|sock_create|sock_ops|device|bind4|bind6|\
|
|
post_bind4|post_bind6|connect4|connect6|getpeername4|\
|
|
getpeername6|getsockname4|getsockname6|sendmsg4|sendmsg6|\
|
|
recvmsg4|recvmsg6|sysctl|getsockopt|setsockopt)
|
|
COMPREPLY=( $( compgen -W "$PROG_TYPE" -- \
|
|
"$cur" ) )
|
|
return 0
|
|
;;
|
|
id)
|
|
_bpftool_get_prog_ids
|
|
return 0
|
|
;;
|
|
*)
|
|
if ! _bpftool_search_list "$ATTACH_TYPES"; then
|
|
COMPREPLY=( $( compgen -W "$ATTACH_TYPES" -- \
|
|
"$cur" ) )
|
|
elif [[ "$command" == "attach" ]]; then
|
|
# We have an attach type on the command line,
|
|
# but it is not the previous word, or
|
|
# "id|pinned|tag|name" (we already checked for
|
|
# that). This should only leave the case when
|
|
# we need attach flags for "attach" commamnd.
|
|
_bpftool_one_of_list "$ATTACH_FLAGS"
|
|
fi
|
|
return 0
|
|
;;
|
|
esac
|
|
;;
|
|
*)
|
|
[[ $prev == $object ]] && \
|
|
COMPREPLY=( $( compgen -W 'help attach detach \
|
|
show list tree' -- "$cur" ) )
|
|
;;
|
|
esac
|
|
;;
|
|
perf)
|
|
case $command in
|
|
*)
|
|
[[ $prev == $object ]] && \
|
|
COMPREPLY=( $( compgen -W 'help \
|
|
show list' -- "$cur" ) )
|
|
;;
|
|
esac
|
|
;;
|
|
net)
|
|
local PROG_TYPE='id pinned tag name'
|
|
local ATTACH_TYPES='xdp xdpgeneric xdpdrv xdpoffload'
|
|
case $command in
|
|
show|list)
|
|
[[ $prev != "$command" ]] && return 0
|
|
COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
attach)
|
|
case $cword in
|
|
3)
|
|
COMPREPLY=( $( compgen -W "$ATTACH_TYPES" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
4)
|
|
COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
5)
|
|
case $prev in
|
|
id)
|
|
_bpftool_get_prog_ids
|
|
;;
|
|
name)
|
|
_bpftool_get_prog_names
|
|
;;
|
|
pinned)
|
|
_filedir
|
|
;;
|
|
esac
|
|
return 0
|
|
;;
|
|
6)
|
|
COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
8)
|
|
_bpftool_once_attr 'overwrite'
|
|
return 0
|
|
;;
|
|
esac
|
|
;;
|
|
detach)
|
|
case $cword in
|
|
3)
|
|
COMPREPLY=( $( compgen -W "$ATTACH_TYPES" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
4)
|
|
COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
esac
|
|
;;
|
|
*)
|
|
[[ $prev == $object ]] && \
|
|
COMPREPLY=( $( compgen -W 'help \
|
|
show list attach detach' -- "$cur" ) )
|
|
;;
|
|
esac
|
|
;;
|
|
feature)
|
|
case $command in
|
|
probe)
|
|
[[ $prev == "prefix" ]] && return 0
|
|
if _bpftool_search_list 'macros'; then
|
|
_bpftool_once_attr 'prefix'
|
|
else
|
|
COMPREPLY+=( $( compgen -W 'macros' -- "$cur" ) )
|
|
fi
|
|
_bpftool_one_of_list 'kernel dev'
|
|
_bpftool_once_attr 'full unprivileged'
|
|
return 0
|
|
;;
|
|
*)
|
|
[[ $prev == $object ]] && \
|
|
COMPREPLY=( $( compgen -W 'help probe' -- "$cur" ) )
|
|
;;
|
|
esac
|
|
;;
|
|
link)
|
|
case $command in
|
|
show|list|pin|detach)
|
|
case $prev in
|
|
id)
|
|
_bpftool_get_link_ids
|
|
return 0
|
|
;;
|
|
esac
|
|
;;
|
|
esac
|
|
|
|
local LINK_TYPE='id pinned'
|
|
case $command in
|
|
show|list)
|
|
[[ $prev != "$command" ]] && return 0
|
|
COMPREPLY=( $( compgen -W "$LINK_TYPE" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
pin|detach)
|
|
if [[ $prev == "$command" ]]; then
|
|
COMPREPLY=( $( compgen -W "$LINK_TYPE" -- "$cur" ) )
|
|
else
|
|
_filedir
|
|
fi
|
|
return 0
|
|
;;
|
|
*)
|
|
[[ $prev == $object ]] && \
|
|
COMPREPLY=( $( compgen -W 'help pin show list' -- "$cur" ) )
|
|
;;
|
|
esac
|
|
;;
|
|
esac
|
|
} &&
|
|
complete -F _bpftool bpftool
|
|
|
|
# ex: ts=4 sw=4 et filetype=sh
|