Subskeletons are headers which require an already loaded program to operate. For example, when a BPF library is linked into a larger BPF object file, the library userspace needs a way to access its own global variables without requiring knowledge about the larger program at build time. As a result, subskeletons require a loaded bpf_object to open(). Further, they find their own symbols in the larger program by walking BTF type data at run time. At this time, programs, maps, and globals are supported through non-owning pointers. Signed-off-by: Delyan Kratunov <delyank@fb.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/bpf/ca8a48b4841c72d285ecce82371bef4a899756cb.1647473511.git.delyank@fb.com
1219 lines
44 KiB
Bash
1219 lines
44 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 \
|
|
--use-loader --base-btf --legacy'
|
|
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|-B|--base-btf)
|
|
_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} == - ]] &&
|
|
[[ ${words[i]} != "-B" ]] && [[ ${words[i]} != "--base-btf" ]]; 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 \
|
|
itlb_misses dtlb_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)
|
|
local BPFTOOL_PROG_ATTACH_TYPES='msg_verdict \
|
|
skb_verdict stream_verdict stream_parser \
|
|
flow_dissector'
|
|
COMPREPLY=( $( compgen -W "$BPFTOOL_PROG_ATTACH_TYPES" -- "$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)
|
|
local BPFTOOL_PROG_LOAD_TYPES='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 cgroup/sock_release struct_ops \
|
|
fentry fexit freplace sk_lookup'
|
|
COMPREPLY=( $( compgen -W "$BPFTOOL_PROG_LOAD_TYPES" -- "$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)
|
|
local BPFTOOL_MAP_CREATE_TYPES='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 ringbuf inode_storage task_storage \
|
|
bloom_filter'
|
|
COMPREPLY=( $( compgen -W "$BPFTOOL_MAP_CREATE_TYPES" -- "$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
|
|
object)
|
|
_filedir
|
|
return 0
|
|
;;
|
|
skeleton)
|
|
case $prev in
|
|
$command)
|
|
_filedir
|
|
return 0
|
|
;;
|
|
*)
|
|
_bpftool_once_attr 'name'
|
|
return 0
|
|
;;
|
|
esac
|
|
;;
|
|
subskeleton)
|
|
case $prev in
|
|
$command)
|
|
_filedir
|
|
return 0
|
|
;;
|
|
*)
|
|
_bpftool_once_attr 'name'
|
|
return 0
|
|
;;
|
|
esac
|
|
;;
|
|
min_core_btf)
|
|
_filedir
|
|
return 0
|
|
;;
|
|
*)
|
|
[[ $prev == $object ]] && \
|
|
COMPREPLY=( $( compgen -W 'object skeleton subskeleton help min_core_btf' -- "$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 BPFTOOL_CGROUP_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 sock_release'
|
|
local ATTACH_FLAGS='multi override'
|
|
local PROG_TYPE='id pinned tag name'
|
|
# Check for $prev = $command first
|
|
if [ $prev = $command ]; then
|
|
_filedir
|
|
return 0
|
|
# Then check for attach type. This is done outside of the
|
|
# "case $prev in" to avoid writing the whole list of attach
|
|
# types again as pattern to match (where we cannot reuse
|
|
# our variable).
|
|
elif [[ $BPFTOOL_CGROUP_ATTACH_TYPES =~ $prev ]]; then
|
|
COMPREPLY=( $( compgen -W "$PROG_TYPE" -- \
|
|
"$cur" ) )
|
|
return 0
|
|
fi
|
|
# case/esac for the other cases
|
|
case $prev in
|
|
id)
|
|
_bpftool_get_prog_ids
|
|
return 0
|
|
;;
|
|
*)
|
|
if ! _bpftool_search_list "$BPFTOOL_CGROUP_ATTACH_TYPES"; then
|
|
COMPREPLY=( $( compgen -W \
|
|
"$BPFTOOL_CGROUP_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
|