1 # bpftool(8) bash completion -*- shell-script -*-
3 # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
4 # Copyright (C) 2017-2018 Netronome Systems, Inc.
6 # Author: Quentin Monnet <quentin.monnet@netronome.com>
8 # Takes a list of words in argument; each one of them is added to COMPREPLY if
9 # it is not already present on the command line. Returns no value.
15 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
16 if [[ $w == ${words[idx]} ]]; then
21 [[ $found -eq 0 ]] && \
22 COMPREPLY+=( $( compgen -W "$w" -- "$cur" ) )
26 # Takes a list of words as argument; if any of those words is present on the
27 # command line, return 0. Otherwise, return 1.
28 _bpftool_search_list()
32 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
33 [[ $w == ${words[idx]} ]] && return 0
39 # Takes a list of words in argument; adds them all to COMPREPLY if none of them
40 # is already present on the command line. Returns no value.
41 _bpftool_one_of_list()
43 _bpftool_search_list $* && return 1
44 COMPREPLY+=( $( compgen -W "$*" -- "$cur" ) )
47 _bpftool_get_map_ids()
49 COMPREPLY+=( $( compgen -W "$( bpftool -jp map 2>&1 | \
50 command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
53 # Takes map type and adds matching map ids to the list of suggestions.
54 _bpftool_get_map_ids_for_type()
57 COMPREPLY+=( $( compgen -W "$( bpftool -jp map 2>&1 | \
58 command grep -C2 "$type" | \
59 command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
62 _bpftool_get_map_names()
64 COMPREPLY+=( $( compgen -W "$( bpftool -jp map 2>&1 | \
65 command sed -n 's/.*"name": \(.*\),$/\1/p' )" -- "$cur" ) )
68 # Takes map type and adds matching map names to the list of suggestions.
69 _bpftool_get_map_names_for_type()
72 COMPREPLY+=( $( compgen -W "$( bpftool -jp map 2>&1 | \
73 command grep -C2 "$type" | \
74 command sed -n 's/.*"name": \(.*\),$/\1/p' )" -- "$cur" ) )
77 _bpftool_get_prog_ids()
79 COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \
80 command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
83 _bpftool_get_prog_tags()
85 COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \
86 command sed -n 's/.*"tag": "\(.*\)",$/\1/p' )" -- "$cur" ) )
89 _bpftool_get_prog_names()
91 COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \
92 command sed -n 's/.*"name": "\(.*\)",$/\1/p' )" -- "$cur" ) )
95 _bpftool_get_btf_ids()
97 COMPREPLY+=( $( compgen -W "$( bpftool -jp btf 2>&1 | \
98 command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
101 _bpftool_get_link_ids()
103 COMPREPLY+=( $( compgen -W "$( bpftool -jp link 2>&1 | \
104 command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
107 _bpftool_get_obj_map_names()
113 maps=$(objdump -j maps -t $obj 2>/dev/null | \
114 command awk '/g . maps/ {print $NF}')
116 COMPREPLY+=( $( compgen -W "$maps" -- "$cur" ) )
119 _bpftool_get_obj_map_idxs()
125 nmaps=$(objdump -j maps -t $obj 2>/dev/null | grep -c 'g . maps')
127 COMPREPLY+=( $( compgen -W "$(seq 0 $((nmaps - 1)))" -- "$cur" ) )
132 COMPREPLY+=( $( compgen -W "$( ls /sys/class/net 2>/dev/null )" -- \
136 # Retrieve type of the map that we are operating on.
137 _bpftool_map_guess_map_type()
140 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
141 case "${words[$((idx-2))]}" in
143 keyword=${words[$((idx-1))]}
144 ref=${words[$((idx))]}
156 [[ -z $ref ]] && return 0
159 type=$(bpftool -jp map show $keyword $ref | \
160 command sed -n 's/.*"type": "\(.*\)",$/\1/p')
161 [[ -n $type ]] && printf $type
164 _bpftool_map_update_get_id()
168 # Is it the map to update, or a map to insert into the map to update?
169 # Search for "value" keyword.
171 for (( idx=7; idx < ${#words[@]}-1; idx++ )); do
172 if [[ ${words[idx]} == "value" ]]; then
177 if [[ $value -eq 0 ]]; then
180 _bpftool_get_map_ids_for_type stack
183 _bpftool_get_map_ids_for_type queue
192 # Id to complete is for a value. It can be either prog id or map id. This
193 # depends on the type of the map to update.
194 local type=$(_bpftool_map_guess_map_type)
196 array_of_maps|hash_of_maps)
201 _bpftool_get_prog_ids
210 _bpftool_map_update_get_name()
214 # Is it the map to update, or a map to insert into the map to update?
215 # Search for "value" keyword.
217 for (( idx=7; idx < ${#words[@]}-1; idx++ )); do
218 if [[ ${words[idx]} == "value" ]]; then
223 if [[ $value -eq 0 ]]; then
226 _bpftool_get_map_names_for_type stack
229 _bpftool_get_map_names_for_type queue
232 _bpftool_get_map_names
238 # Name to complete is for a value. It can be either prog name or map name. This
239 # depends on the type of the map to update.
240 local type=$(_bpftool_map_guess_map_type)
242 array_of_maps|hash_of_maps)
243 _bpftool_get_map_names
247 _bpftool_get_prog_names
258 local cur prev words objword
259 _init_completion || return
262 if [[ ${words[cword]} == -* ]]; then
263 local c='--version --json --pretty --bpffs --mapcompat --debug \
264 --use-loader --base-btf'
265 COMPREPLY=( $( compgen -W "$c" -- "$cur" ) )
269 # Deal with simplest keywords
271 help|hex|opcodes|visual|linum)
275 _bpftool_get_prog_tags
282 file|pinned|-B|--base-btf)
287 COMPREPLY=( $( compgen -W 'file' -- "$cur" ) )
292 # Remove all options so completions don't have to deal with them.
294 for (( i=1; i < ${#words[@]}; )); do
295 if [[ ${words[i]::1} == - ]] &&
296 [[ ${words[i]} != "-B" ]] && [[ ${words[i]} != "--base-btf" ]]; then
297 words=( "${words[@]:0:i}" "${words[@]:i+1}" )
298 [[ $i -le $cword ]] && cword=$(( cword - 1 ))
304 prev=${words[cword - 1]}
305 pprev=${words[cword - 2]}
307 local object=${words[1]} command=${words[2]}
309 if [[ -z $object || $cword -eq 1 ]]; then
312 COMPREPLY=( $( compgen -W "$( bpftool help 2>&1 | \
314 -e '/OBJECT := /!d' \
317 -e 's/|//g' )" -- "$cur" ) )
318 COMPREPLY+=( $( compgen -W 'batch help' -- "$cur" ) )
324 [[ $command == help ]] && return 0
326 # Completion depends on object and command in use
329 # Complete id and name, only for subcommands that use prog (but no
335 _bpftool_get_prog_ids
339 _bpftool_get_prog_names
346 local PROG_TYPE='id pinned tag name'
347 local MAP_TYPE='id pinned name'
348 local METRIC_TYPE='cycles instructions l1d_loads llc_misses'
351 [[ $prev != "$command" ]] && return 0
352 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
358 COMPREPLY+=( $( compgen -W "xlated jited" -- \
363 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- \
368 _bpftool_once_attr 'file'
369 if _bpftool_search_list 'xlated'; then
370 COMPREPLY+=( $( compgen -W 'opcodes visual linum' -- \
373 COMPREPLY+=( $( compgen -W 'opcodes linum' -- \
381 if [[ $prev == "$command" ]]; then
382 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
391 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
397 _bpftool_get_prog_ids
400 _bpftool_get_prog_names
409 local BPFTOOL_PROG_ATTACH_TYPES='msg_verdict \
410 skb_verdict stream_verdict stream_parser \
412 COMPREPLY=( $( compgen -W "$BPFTOOL_PROG_ATTACH_TYPES" -- "$cur" ) )
416 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
425 _bpftool_get_map_names
438 # Propose "load/loadall" to complete "bpftool prog load",
439 # or bash tries to complete "load" as a filename below.
440 if [[ ${#words[@]} -eq 3 ]]; then
441 COMPREPLY=( $( compgen -W "load loadall" -- "$cur" ) )
445 if [[ ${#words[@]} -lt 6 ]]; then
452 if [[ ${words[-4]} == "map" ]]; then
453 COMPREPLY=( $( compgen -W "id pinned" -- "$cur" ) )
456 if [[ ${words[-3]} == "map" ]]; then
457 if [[ ${words[-2]} == "idx" ]]; then
458 _bpftool_get_obj_map_idxs $obj
459 elif [[ ${words[-2]} == "name" ]]; then
460 _bpftool_get_obj_map_names $obj
464 if [[ ${words[-2]} == "map" ]]; then
465 COMPREPLY=( $( compgen -W "idx name" -- "$cur" ) )
471 local BPFTOOL_PROG_LOAD_TYPES='socket kprobe \
472 kretprobe classifier flow_dissector \
473 action tracepoint raw_tracepoint \
474 xdp perf_event cgroup/skb cgroup/sock \
475 cgroup/dev lwt_in lwt_out lwt_xmit \
476 lwt_seg6local sockops sk_skb sk_msg \
477 lirc_mode2 cgroup/bind4 cgroup/bind6 \
478 cgroup/connect4 cgroup/connect6 \
479 cgroup/getpeername4 cgroup/getpeername6 \
480 cgroup/getsockname4 cgroup/getsockname6 \
481 cgroup/sendmsg4 cgroup/sendmsg6 \
482 cgroup/recvmsg4 cgroup/recvmsg6 \
483 cgroup/post_bind4 cgroup/post_bind6 \
484 cgroup/sysctl cgroup/getsockopt \
485 cgroup/setsockopt cgroup/sock_release struct_ops \
486 fentry fexit freplace sk_lookup'
487 COMPREPLY=( $( compgen -W "$BPFTOOL_PROG_LOAD_TYPES" -- "$cur" ) )
495 _bpftool_get_map_names
503 COMPREPLY=( $( compgen -W "map" -- "$cur" ) )
504 _bpftool_once_attr 'type'
505 _bpftool_once_attr 'dev'
506 _bpftool_once_attr 'pinmaps'
517 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
523 _bpftool_get_prog_ids
526 _bpftool_get_prog_names
535 COMPREPLY=( $( compgen -W "$METRIC_TYPE duration" -- "$cur" ) )
544 COMPREPLY=( $( compgen -W "$METRIC_TYPE" -- "$cur" ) )
551 COMPREPLY=( $( compgen -W "$METRIC_TYPE" -- "$cur" ) )
557 if [[ ${#words[@]} -eq 4 ]]; then
558 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
563 _bpftool_get_prog_ids
567 _bpftool_get_prog_names
570 data_in|data_out|ctx_in|ctx_out)
574 repeat|data_size_out|ctx_size_out)
578 _bpftool_once_attr 'data_in data_out data_size_out \
579 ctx_in ctx_out ctx_size_out repeat'
585 [[ $prev == $object ]] && \
586 COMPREPLY=( $( compgen -W 'dump help pin attach detach \
587 load loadall show list tracelog run profile' -- "$cur" ) )
592 local STRUCT_OPS_TYPE='id name'
594 show|list|dump|unregister)
597 COMPREPLY=( $( compgen -W "$STRUCT_OPS_TYPE" -- "$cur" ) )
600 _bpftool_get_map_ids_for_type struct_ops
603 _bpftool_get_map_names_for_type struct_ops
613 [[ $prev == $object ]] && \
614 COMPREPLY=( $( compgen -W 'register unregister show list dump help' \
630 _bpftool_get_map_names
636 _bpftool_one_of_list $MAP_TYPE
642 [[ $prev == $object ]] && \
643 COMPREPLY=( $( compgen -W 'pin help' \
649 local MAP_TYPE='id pinned name'
651 show|list|dump|peek|pop|dequeue|freeze)
654 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
660 _bpftool_get_map_ids_for_type stack
661 _bpftool_get_map_ids_for_type queue
664 _bpftool_get_map_ids_for_type stack
667 _bpftool_get_map_ids_for_type queue
678 _bpftool_get_map_names_for_type stack
679 _bpftool_get_map_names_for_type queue
682 _bpftool_get_map_names_for_type stack
685 _bpftool_get_map_names_for_type queue
688 _bpftool_get_map_names
705 local BPFTOOL_MAP_CREATE_TYPES='hash array \
706 prog_array perf_event_array percpu_hash \
707 percpu_array stack_trace cgroup_array lru_hash \
708 lru_percpu_hash lpm_trie array_of_maps \
709 hash_of_maps devmap devmap_hash sockmap cpumap \
710 xskmap sockhash cgroup_storage reuseport_sockarray \
711 percpu_cgroup_storage queue stack sk_storage \
712 struct_ops inode_storage task_storage ringbuf'
713 COMPREPLY=( $( compgen -W "$BPFTOOL_MAP_CREATE_TYPES" -- "$cur" ) )
716 key|value|flags|entries)
720 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
729 _bpftool_get_map_names
737 _bpftool_once_attr 'type'
738 _bpftool_once_attr 'key'
739 _bpftool_once_attr 'value'
740 _bpftool_once_attr 'entries'
741 _bpftool_once_attr 'name'
742 _bpftool_once_attr 'flags'
743 if _bpftool_search_list 'array_of_maps' 'hash_of_maps'; then
744 _bpftool_once_attr 'inner_map'
746 _bpftool_once_attr 'dev'
751 lookup|getnext|delete)
754 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
762 _bpftool_get_map_names
766 COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) )
769 case $(_bpftool_map_guess_map_type) in
775 _bpftool_once_attr 'key'
783 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
787 _bpftool_map_update_get_id $command
791 _bpftool_map_update_get_name $command
795 COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) )
798 # We can have bytes, or references to a prog or a
799 # map, depending on the type of the map to update.
800 case "$(_bpftool_map_guess_map_type)" in
801 array_of_maps|hash_of_maps)
802 local MAP_TYPE='id pinned name'
803 COMPREPLY+=( $( compgen -W "$MAP_TYPE" \
808 local PROG_TYPE='id pinned tag name'
809 COMPREPLY+=( $( compgen -W "$PROG_TYPE" \
814 COMPREPLY+=( $( compgen -W 'hex' \
822 case $(_bpftool_map_guess_map_type) in
824 _bpftool_once_attr 'value'
829 _bpftool_once_attr 'key'
830 local UPDATE_FLAGS='any exist noexist'
831 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
832 if [[ ${words[idx]} == 'value' ]]; then
833 # 'value' is present, but is not the last
834 # word i.e. we can now have UPDATE_FLAGS.
835 _bpftool_one_of_list "$UPDATE_FLAGS"
839 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
840 if [[ ${words[idx]} == 'key' ]]; then
841 # 'key' is present, but is not the last
842 # word i.e. we can now have 'value'.
843 _bpftool_once_attr 'value'
855 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
861 _bpftool_get_map_names
869 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
873 _bpftool_get_map_ids_for_type perf_event_array
877 _bpftool_get_map_names_for_type perf_event_array
887 _bpftool_once_attr 'cpu'
888 _bpftool_once_attr 'index'
894 [[ $prev == $object ]] && \
895 COMPREPLY=( $( compgen -W 'delete dump getnext help \
896 lookup pin event_pipe show list update create \
897 peek push enqueue pop dequeue freeze' -- \
903 local PROG_TYPE='id pinned tag name'
904 local MAP_TYPE='id pinned name'
909 COMPREPLY+=( $( compgen -W "id map prog file" -- \
914 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
918 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
924 _bpftool_get_prog_ids
938 _bpftool_get_prog_names
941 _bpftool_get_map_names
947 COMPREPLY=( $( compgen -W "c raw" -- "$cur" ) )
953 _bpftool_once_attr 'format'
956 if [[ ${words[3]} == "map" ]] && [[ $cword == 6 ]]; then
957 COMPREPLY+=( $( compgen -W "key value kv all" -- "$cur" ) )
959 _bpftool_once_attr 'format'
971 COMPREPLY+=( $( compgen -W "id" -- "$cur" ) )
980 [[ $prev == $object ]] && \
981 COMPREPLY=( $( compgen -W 'dump help show list' \
999 _bpftool_once_attr 'name'
1005 [[ $prev == $object ]] && \
1006 COMPREPLY=( $( compgen -W 'object skeleton help' -- "$cur" ) )
1018 COMPREPLY=( $( compgen -W 'effective' -- "$cur" ) )
1024 local BPFTOOL_CGROUP_ATTACH_TYPES='ingress egress \
1025 sock_create sock_ops device \
1026 bind4 bind6 post_bind4 post_bind6 connect4 connect6 \
1027 getpeername4 getpeername6 getsockname4 getsockname6 \
1028 sendmsg4 sendmsg6 recvmsg4 recvmsg6 sysctl getsockopt \
1029 setsockopt sock_release'
1030 local ATTACH_FLAGS='multi override'
1031 local PROG_TYPE='id pinned tag name'
1032 # Check for $prev = $command first
1033 if [ $prev = $command ]; then
1036 # Then check for attach type. This is done outside of the
1037 # "case $prev in" to avoid writing the whole list of attach
1038 # types again as pattern to match (where we cannot reuse
1040 elif [[ $BPFTOOL_CGROUP_ATTACH_TYPES =~ $prev ]]; then
1041 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- \
1045 # case/esac for the other cases
1048 _bpftool_get_prog_ids
1052 if ! _bpftool_search_list "$BPFTOOL_CGROUP_ATTACH_TYPES"; then
1053 COMPREPLY=( $( compgen -W \
1054 "$BPFTOOL_CGROUP_ATTACH_TYPES" -- "$cur" ) )
1055 elif [[ "$command" == "attach" ]]; then
1056 # We have an attach type on the command line,
1057 # but it is not the previous word, or
1058 # "id|pinned|tag|name" (we already checked for
1059 # that). This should only leave the case when
1060 # we need attach flags for "attach" commamnd.
1061 _bpftool_one_of_list "$ATTACH_FLAGS"
1068 [[ $prev == $object ]] && \
1069 COMPREPLY=( $( compgen -W 'help attach detach \
1070 show list tree' -- "$cur" ) )
1077 [[ $prev == $object ]] && \
1078 COMPREPLY=( $( compgen -W 'help \
1079 show list' -- "$cur" ) )
1084 local PROG_TYPE='id pinned tag name'
1085 local ATTACH_TYPES='xdp xdpgeneric xdpdrv xdpoffload'
1088 [[ $prev != "$command" ]] && return 0
1089 COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
1095 COMPREPLY=( $( compgen -W "$ATTACH_TYPES" -- "$cur" ) )
1099 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
1105 _bpftool_get_prog_ids
1108 _bpftool_get_prog_names
1117 COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
1121 _bpftool_once_attr 'overwrite'
1129 COMPREPLY=( $( compgen -W "$ATTACH_TYPES" -- "$cur" ) )
1133 COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
1139 [[ $prev == $object ]] && \
1140 COMPREPLY=( $( compgen -W 'help \
1141 show list attach detach' -- "$cur" ) )
1148 [[ $prev == "prefix" ]] && return 0
1149 if _bpftool_search_list 'macros'; then
1150 _bpftool_once_attr 'prefix'
1152 COMPREPLY+=( $( compgen -W 'macros' -- "$cur" ) )
1154 _bpftool_one_of_list 'kernel dev'
1155 _bpftool_once_attr 'full unprivileged'
1159 [[ $prev == $object ]] && \
1160 COMPREPLY=( $( compgen -W 'help probe' -- "$cur" ) )
1166 show|list|pin|detach)
1169 _bpftool_get_link_ids
1176 local LINK_TYPE='id pinned'
1179 [[ $prev != "$command" ]] && return 0
1180 COMPREPLY=( $( compgen -W "$LINK_TYPE" -- "$cur" ) )
1184 if [[ $prev == "$command" ]]; then
1185 COMPREPLY=( $( compgen -W "$LINK_TYPE" -- "$cur" ) )
1192 [[ $prev == $object ]] && \
1193 COMPREPLY=( $( compgen -W 'help pin show list' -- "$cur" ) )
1199 complete -F _bpftool bpftool
1201 # ex: ts=4 sw=4 et filetype=sh