Add map parameter to prog load which will allow reuse of existing maps instead of creating new ones. We need feature detection and compat code for reallocarray, since it's not available in many libc versions. Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com> Acked-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
560 lines
19 KiB
Bash
560 lines
19 KiB
Bash
# bpftool(8) bash completion -*- shell-script -*-
|
|
#
|
|
# Copyright (C) 2017-2018 Netronome Systems, Inc.
|
|
#
|
|
# This software is dual licensed under the GNU General License
|
|
# Version 2, June 1991 as shown in the file COPYING in the top-level
|
|
# directory of this source tree or the BSD 2-Clause License provided
|
|
# below. You have the option to license this software under the
|
|
# complete terms of either license.
|
|
#
|
|
# The BSD 2-Clause License:
|
|
#
|
|
# Redistribution and use in source and binary forms, with or
|
|
# without modification, are permitted provided that the following
|
|
# conditions are met:
|
|
#
|
|
# 1. Redistributions of source code must retain the above
|
|
# copyright notice, this list of conditions and the following
|
|
# disclaimer.
|
|
#
|
|
# 2. Redistributions in binary form must reproduce the above
|
|
# copyright notice, this list of conditions and the following
|
|
# disclaimer in the documentation and/or other materials
|
|
# provided with the distribution.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
# SOFTWARE.
|
|
#
|
|
# 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" ) )
|
|
}
|
|
|
|
_bpftool_get_perf_map_ids()
|
|
{
|
|
COMPREPLY+=( $( compgen -W "$( bpftool -jp map 2>&1 | \
|
|
command grep -C2 perf_event_array | \
|
|
command sed -n 's/.*"id": \(.*\),$/\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_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" ) )
|
|
}
|
|
|
|
# For bpftool map update: retrieve type of the map to update.
|
|
_bpftool_map_update_map_type()
|
|
{
|
|
local keyword ref
|
|
for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
|
|
if [[ ${words[$((idx-2))]} == "update" ]]; then
|
|
keyword=${words[$((idx-1))]}
|
|
ref=${words[$((idx))]}
|
|
fi
|
|
done
|
|
[[ -z $ref ]] && return 0
|
|
|
|
local type
|
|
type=$(bpftool -jp map show $keyword $ref | \
|
|
command sed -n 's/.*"type": "\(.*\)",$/\1/p')
|
|
printf $type
|
|
}
|
|
|
|
_bpftool_map_update_get_id()
|
|
{
|
|
# 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
|
|
[[ $value -eq 0 ]] && _bpftool_get_map_ids && return 0
|
|
|
|
# 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_update_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()
|
|
{
|
|
local cur prev words objword
|
|
_init_completion || return
|
|
|
|
# Deal with options
|
|
if [[ ${words[cword]} == -* ]]; then
|
|
local c='--version --json --pretty --bpffs'
|
|
COMPREPLY=( $( compgen -W "$c" -- "$cur" ) )
|
|
return 0
|
|
fi
|
|
|
|
# Deal with simplest keywords
|
|
case $prev in
|
|
help|hex|opcodes|visual)
|
|
return 0
|
|
;;
|
|
tag)
|
|
_bpftool_get_prog_tags
|
|
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]}
|
|
|
|
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)
|
|
if [[ $command != "load" ]]; then
|
|
case $prev in
|
|
id)
|
|
_bpftool_get_prog_ids
|
|
return 0
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
local PROG_TYPE='id pinned tag'
|
|
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' -- \
|
|
"$cur" ) )
|
|
else
|
|
COMPREPLY+=( $( compgen -W 'opcodes' -- \
|
|
"$cur" ) )
|
|
fi
|
|
return 0
|
|
;;
|
|
esac
|
|
;;
|
|
pin)
|
|
if [[ $prev == "$command" ]]; then
|
|
COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
|
|
else
|
|
_filedir
|
|
fi
|
|
return 0
|
|
;;
|
|
load)
|
|
local obj
|
|
|
|
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 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/post_bind4 cgroup/post_bind6" -- \
|
|
"$cur" ) )
|
|
return 0
|
|
;;
|
|
id)
|
|
_bpftool_get_map_ids
|
|
return 0
|
|
;;
|
|
pinned)
|
|
_filedir
|
|
return 0
|
|
;;
|
|
dev)
|
|
_sysfs_get_netdevs
|
|
return 0
|
|
;;
|
|
*)
|
|
COMPREPLY=( $( compgen -W "map" -- "$cur" ) )
|
|
_bpftool_once_attr 'type'
|
|
_bpftool_once_attr 'dev'
|
|
return 0
|
|
;;
|
|
esac
|
|
;;
|
|
*)
|
|
[[ $prev == $object ]] && \
|
|
COMPREPLY=( $( compgen -W 'dump help pin load \
|
|
show list' -- "$cur" ) )
|
|
;;
|
|
esac
|
|
;;
|
|
map)
|
|
local MAP_TYPE='id pinned'
|
|
case $command in
|
|
show|list|dump)
|
|
case $prev in
|
|
$command)
|
|
COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
id)
|
|
_bpftool_get_map_ids
|
|
return 0
|
|
;;
|
|
*)
|
|
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
|
|
;;
|
|
key)
|
|
COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) )
|
|
;;
|
|
*)
|
|
_bpftool_once_attr 'key'
|
|
return 0
|
|
;;
|
|
esac
|
|
;;
|
|
update)
|
|
case $prev in
|
|
$command)
|
|
COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
id)
|
|
_bpftool_map_update_get_id
|
|
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_update_map_type) in
|
|
array_of_maps|hash_of_maps)
|
|
local MAP_TYPE='id pinned'
|
|
COMPREPLY+=( $( compgen -W "$MAP_TYPE" \
|
|
-- "$cur" ) )
|
|
return 0
|
|
;;
|
|
prog_array)
|
|
local PROG_TYPE='id pinned tag'
|
|
COMPREPLY+=( $( compgen -W "$PROG_TYPE" \
|
|
-- "$cur" ) )
|
|
return 0
|
|
;;
|
|
*)
|
|
COMPREPLY+=( $( compgen -W 'hex' \
|
|
-- "$cur" ) )
|
|
return 0
|
|
;;
|
|
esac
|
|
return 0
|
|
;;
|
|
*)
|
|
_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)
|
|
if [[ $prev == "$command" ]]; then
|
|
COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
|
|
else
|
|
_filedir
|
|
fi
|
|
return 0
|
|
;;
|
|
event_pipe)
|
|
case $prev in
|
|
$command)
|
|
COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
|
|
return 0
|
|
;;
|
|
id)
|
|
_bpftool_get_perf_map_ids
|
|
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' -- \
|
|
"$cur" ) )
|
|
;;
|
|
esac
|
|
;;
|
|
cgroup)
|
|
case $command in
|
|
show|list)
|
|
_filedir
|
|
return 0
|
|
;;
|
|
tree)
|
|
_filedir
|
|
return 0
|
|
;;
|
|
attach|detach)
|
|
local ATTACH_TYPES='ingress egress sock_create sock_ops \
|
|
device bind4 bind6 post_bind4 post_bind6 connect4 \
|
|
connect6 sendmsg4 sendmsg6'
|
|
local ATTACH_FLAGS='multi override'
|
|
local PROG_TYPE='id pinned tag'
|
|
case $prev in
|
|
$command)
|
|
_filedir
|
|
return 0
|
|
;;
|
|
ingress|egress|sock_create|sock_ops|device|bind4|bind6|\
|
|
post_bind4|post_bind6|connect4|connect6|sendmsg4|\
|
|
sendmsg6)
|
|
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" (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
|
|
;;
|
|
esac
|
|
} &&
|
|
complete -F _bpftool bpftool
|
|
|
|
# ex: ts=4 sw=4 et filetype=sh
|