This patch adds struct_ops support to the bpftool. To recap a bit on the recent bpf_struct_ops feature on the kernel side: It currently supports "struct tcp_congestion_ops" to be implemented in bpf. At a high level, bpf_struct_ops is struct_ops map populated with a number of bpf progs. bpf_struct_ops currently supports the "struct tcp_congestion_ops". However, the bpf_struct_ops design is generic enough that other kernel struct ops can be supported in the future. Although struct_ops is map+progs at a high lever, there are differences in details. For example, 1) After registering a struct_ops, the struct_ops is held by the kernel subsystem (e.g. tcp-cc). Thus, there is no need to pin a struct_ops map or its progs in order to keep them around. 2) To iterate all struct_ops in a system, it iterates all maps in type BPF_MAP_TYPE_STRUCT_OPS. BPF_MAP_TYPE_STRUCT_OPS is the current usual filter. In the future, it may need to filter by other struct_ops specific properties. e.g. filter by tcp_congestion_ops or other kernel subsystem ops in the future. 3) struct_ops requires the running kernel having BTF info. That allows more flexibility in handling other kernel structs. e.g. it can always dump the latest bpf_map_info. 4) Also, "struct_ops" command is not intended to repeat all features already provided by "map" or "prog". For example, if there really is a need to pin the struct_ops map, the user can use the "map" cmd to do that. While the first attempt was to reuse parts from map/prog.c, it ended up not a lot to share. The only obvious item is the map_parse_fds() but that still requires modifications to accommodate struct_ops map specific filtering (for the immediate and the future needs). Together with the earlier mentioned differences, it is better to part away from map/prog.c. The initial set of subcmds are, register, unregister, show, and dump. For register, it registers all struct_ops maps that can be found in an obj file. Option can be added in the future to specify a particular struct_ops map. Also, the common bpf_tcp_cc is stateless (e.g. bpf_cubic.c and bpf_dctcp.c). The "reuse map" feature is not implemented in this patch and it can be considered later also. For other subcmds, please see the man doc for details. A sample output of dump: [root@arch-fb-vm1 bpf]# bpftool struct_ops dump name cubic [{ "bpf_map_info": { "type": 26, "id": 64, "key_size": 4, "value_size": 256, "max_entries": 1, "map_flags": 0, "name": "cubic", "ifindex": 0, "btf_vmlinux_value_type_id": 18452, "netns_dev": 0, "netns_ino": 0, "btf_id": 52, "btf_key_type_id": 0, "btf_value_type_id": 0 } },{ "bpf_struct_ops_tcp_congestion_ops": { "refcnt": { "refs": { "counter": 1 } }, "state": "BPF_STRUCT_OPS_STATE_INUSE", "data": { "list": { "next": 0, "prev": 0 }, "key": 0, "flags": 0, "init": "void (struct sock *) bictcp_init/prog_id:138", "release": "void (struct sock *) 0", "ssthresh": "u32 (struct sock *) bictcp_recalc_ssthresh/prog_id:141", "cong_avoid": "void (struct sock *, u32, u32) bictcp_cong_avoid/prog_id:140", "set_state": "void (struct sock *, u8) bictcp_state/prog_id:142", "cwnd_event": "void (struct sock *, enum tcp_ca_event) bictcp_cwnd_event/prog_id:139", "in_ack_event": "void (struct sock *, u32) 0", "undo_cwnd": "u32 (struct sock *) tcp_reno_undo_cwnd/prog_id:144", "pkts_acked": "void (struct sock *, const struct ack_sample *) bictcp_acked/prog_id:143", "min_tso_segs": "u32 (struct sock *) 0", "sndbuf_expand": "u32 (struct sock *) 0", "cong_control": "void (struct sock *, const struct rate_sample *) 0", "get_info": "size_t (struct sock *, u32, int *, union tcp_cc_info *) 0", "name": "bpf_cubic", "owner": 0 } } } ] Signed-off-by: Martin KaFai Lau <kafai@fb.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Quentin Monnet <quentin@isovalent.com> Link: https://lore.kernel.org/bpf/20200318171656.129650-1-kafai@fb.com
1090 lines
39 KiB
Bash
1090 lines
39 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_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/sendmsg4 cgroup/sendmsg6 \
|
|
cgroup/recvmsg4 cgroup/recvmsg6 \
|
|
cgroup/post_bind4 cgroup/post_bind6 \
|
|
cgroup/sysctl cgroup/getsockopt \
|
|
cgroup/setsockopt struct_ops \
|
|
fentry fexit freplace" -- \
|
|
"$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
|
|
;;
|
|
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' -- \
|
|
"$cur" ) )
|
|
return 0
|
|
;;
|
|
key|value|flags|name|entries)
|
|
return 0
|
|
;;
|
|
*)
|
|
_bpftool_once_attr 'type'
|
|
_bpftool_once_attr 'key'
|
|
_bpftool_once_attr 'value'
|
|
_bpftool_once_attr 'entries'
|
|
_bpftool_once_attr 'name'
|
|
_bpftool_once_attr 'flags'
|
|
_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 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|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'
|
|
return 0
|
|
;;
|
|
*)
|
|
[[ $prev == $object ]] && \
|
|
COMPREPLY=( $( compgen -W 'help probe' -- "$cur" ) )
|
|
;;
|
|
esac
|
|
;;
|
|
esac
|
|
} &&
|
|
complete -F _bpftool bpftool
|
|
|
|
# ex: ts=4 sw=4 et filetype=sh
|