Loading...
1# bpftool(8) bash completion -*- shell-script -*-
2#
3# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
4# Copyright (C) 2017-2018 Netronome Systems, Inc.
5#
6# Author: Quentin Monnet <quentin.monnet@netronome.com>
7
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.
10_bpftool_once_attr()
11{
12 local w idx found
13 for w in $*; do
14 found=0
15 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
16 if [[ $w == ${words[idx]} ]]; then
17 found=1
18 break
19 fi
20 done
21 [[ $found -eq 0 ]] && \
22 COMPREPLY+=( $( compgen -W "$w" -- "$cur" ) )
23 done
24}
25
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()
29{
30 local w idx
31 for w in $*; do
32 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
33 [[ $w == ${words[idx]} ]] && return 0
34 done
35 done
36 return 1
37}
38
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()
42{
43 _bpftool_search_list $* && return 1
44 COMPREPLY+=( $( compgen -W "$*" -- "$cur" ) )
45}
46
47_bpftool_get_map_ids()
48{
49 COMPREPLY+=( $( compgen -W "$( bpftool -jp map 2>&1 | \
50 command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
51}
52
53# Takes map type and adds matching map ids to the list of suggestions.
54_bpftool_get_map_ids_for_type()
55{
56 local type="$1"
57 COMPREPLY+=( $( compgen -W "$( bpftool -jp map 2>&1 | \
58 command grep -C2 "$type" | \
59 command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
60}
61
62_bpftool_get_map_names()
63{
64 COMPREPLY+=( $( compgen -W "$( bpftool -jp map 2>&1 | \
65 command sed -n 's/.*"name": \(.*\),$/\1/p' )" -- "$cur" ) )
66}
67
68# Takes map type and adds matching map names to the list of suggestions.
69_bpftool_get_map_names_for_type()
70{
71 local type="$1"
72 COMPREPLY+=( $( compgen -W "$( bpftool -jp map 2>&1 | \
73 command grep -C2 "$type" | \
74 command sed -n 's/.*"name": \(.*\),$/\1/p' )" -- "$cur" ) )
75}
76
77_bpftool_get_prog_ids()
78{
79 COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \
80 command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
81}
82
83_bpftool_get_prog_tags()
84{
85 COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \
86 command sed -n 's/.*"tag": "\(.*\)",$/\1/p' )" -- "$cur" ) )
87}
88
89_bpftool_get_prog_names()
90{
91 COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \
92 command sed -n 's/.*"name": "\(.*\)",$/\1/p' )" -- "$cur" ) )
93}
94
95_bpftool_get_btf_ids()
96{
97 COMPREPLY+=( $( compgen -W "$( bpftool -jp btf 2>&1 | \
98 command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
99}
100
101_bpftool_get_link_ids()
102{
103 COMPREPLY+=( $( compgen -W "$( bpftool -jp link 2>&1 | \
104 command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
105}
106
107_bpftool_get_obj_map_names()
108{
109 local obj
110
111 obj=$1
112
113 maps=$(objdump -j maps -t $obj 2>/dev/null | \
114 command awk '/g . maps/ {print $NF}')
115
116 COMPREPLY+=( $( compgen -W "$maps" -- "$cur" ) )
117}
118
119_bpftool_get_obj_map_idxs()
120{
121 local obj
122
123 obj=$1
124
125 nmaps=$(objdump -j maps -t $obj 2>/dev/null | grep -c 'g . maps')
126
127 COMPREPLY+=( $( compgen -W "$(seq 0 $((nmaps - 1)))" -- "$cur" ) )
128}
129
130_sysfs_get_netdevs()
131{
132 COMPREPLY+=( $( compgen -W "$( ls /sys/class/net 2>/dev/null )" -- \
133 "$cur" ) )
134}
135
136# Retrieve type of the map that we are operating on.
137_bpftool_map_guess_map_type()
138{
139 local keyword ref
140 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
141 case "${words[$((idx-2))]}" in
142 lookup|update)
143 keyword=${words[$((idx-1))]}
144 ref=${words[$((idx))]}
145 ;;
146 push)
147 printf "stack"
148 return 0
149 ;;
150 enqueue)
151 printf "queue"
152 return 0
153 ;;
154 esac
155 done
156 [[ -z $ref ]] && return 0
157
158 local type
159 type=$(bpftool -jp map show $keyword $ref | \
160 command sed -n 's/.*"type": "\(.*\)",$/\1/p')
161 [[ -n $type ]] && printf $type
162}
163
164_bpftool_map_update_get_id()
165{
166 local command="$1"
167
168 # Is it the map to update, or a map to insert into the map to update?
169 # Search for "value" keyword.
170 local idx value
171 for (( idx=7; idx < ${#words[@]}-1; idx++ )); do
172 if [[ ${words[idx]} == "value" ]]; then
173 value=1
174 break
175 fi
176 done
177 if [[ $value -eq 0 ]]; then
178 case "$command" in
179 push)
180 _bpftool_get_map_ids_for_type stack
181 ;;
182 enqueue)
183 _bpftool_get_map_ids_for_type queue
184 ;;
185 *)
186 _bpftool_get_map_ids
187 ;;
188 esac
189 return 0
190 fi
191
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)
195 case $type in
196 array_of_maps|hash_of_maps)
197 _bpftool_get_map_ids
198 return 0
199 ;;
200 prog_array)
201 _bpftool_get_prog_ids
202 return 0
203 ;;
204 *)
205 return 0
206 ;;
207 esac
208}
209
210_bpftool_map_update_get_name()
211{
212 local command="$1"
213
214 # Is it the map to update, or a map to insert into the map to update?
215 # Search for "value" keyword.
216 local idx value
217 for (( idx=7; idx < ${#words[@]}-1; idx++ )); do
218 if [[ ${words[idx]} == "value" ]]; then
219 value=1
220 break
221 fi
222 done
223 if [[ $value -eq 0 ]]; then
224 case "$command" in
225 push)
226 _bpftool_get_map_names_for_type stack
227 ;;
228 enqueue)
229 _bpftool_get_map_names_for_type queue
230 ;;
231 *)
232 _bpftool_get_map_names
233 ;;
234 esac
235 return 0
236 fi
237
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)
241 case $type in
242 array_of_maps|hash_of_maps)
243 _bpftool_get_map_names
244 return 0
245 ;;
246 prog_array)
247 _bpftool_get_prog_names
248 return 0
249 ;;
250 *)
251 return 0
252 ;;
253 esac
254}
255
256_bpftool()
257{
258 local cur prev words objword json=0
259 _init_completion || return
260
261 # Deal with options
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" ) )
266 return 0
267 fi
268 if _bpftool_search_list -j --json -p --pretty; then
269 json=1
270 fi
271
272 # Deal with simplest keywords
273 case $prev in
274 help|hex)
275 return 0
276 ;;
277 tag)
278 _bpftool_get_prog_tags
279 return 0
280 ;;
281 dev|offload_dev|xdpmeta_dev)
282 _sysfs_get_netdevs
283 return 0
284 ;;
285 file|pinned|-B|--base-btf)
286 _filedir
287 return 0
288 ;;
289 batch)
290 COMPREPLY=( $( compgen -W 'file' -- "$cur" ) )
291 return 0
292 ;;
293 esac
294
295 # Remove all options so completions don't have to deal with them.
296 local i
297 for (( i=1; i < ${#words[@]}; )); do
298 if [[ ${words[i]::1} == - ]] &&
299 [[ ${words[i]} != "-B" ]] && [[ ${words[i]} != "--base-btf" ]]; then
300 words=( "${words[@]:0:i}" "${words[@]:i+1}" )
301 [[ $i -le $cword ]] && cword=$(( cword - 1 ))
302 else
303 i=$(( ++i ))
304 fi
305 done
306 cur=${words[cword]}
307 prev=${words[cword - 1]}
308 pprev=${words[cword - 2]}
309
310 local object=${words[1]} command=${words[2]}
311
312 if [[ -z $object || $cword -eq 1 ]]; then
313 case $cur in
314 *)
315 COMPREPLY=( $( compgen -W "$( bpftool help 2>&1 | \
316 command sed \
317 -e '/OBJECT := /!d' \
318 -e 's/.*{//' \
319 -e 's/}.*//' \
320 -e 's/|//g' )" -- "$cur" ) )
321 COMPREPLY+=( $( compgen -W 'batch help' -- "$cur" ) )
322 return 0
323 ;;
324 esac
325 fi
326
327 [[ $command == help ]] && return 0
328
329 # Completion depends on object and command in use
330 case $object in
331 prog)
332 # Complete id and name, only for subcommands that use prog (but no
333 # map) ids/names.
334 case $command in
335 show|list|dump|pin)
336 case $prev in
337 id)
338 _bpftool_get_prog_ids
339 return 0
340 ;;
341 name)
342 _bpftool_get_prog_names
343 return 0
344 ;;
345 esac
346 ;;
347 esac
348
349 local PROG_TYPE='id pinned tag name'
350 local MAP_TYPE='id pinned name'
351 local METRIC_TYPE='cycles instructions l1d_loads llc_misses \
352 itlb_misses dtlb_misses'
353 case $command in
354 show|list)
355 [[ $prev != "$command" ]] && return 0
356 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
357 return 0
358 ;;
359 dump)
360 case $prev in
361 $command)
362 COMPREPLY+=( $( compgen -W "xlated jited" -- \
363 "$cur" ) )
364 return 0
365 ;;
366 xlated|jited)
367 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- \
368 "$cur" ) )
369 return 0
370 ;;
371 *)
372 # "file" is not compatible with other keywords here
373 if _bpftool_search_list 'file'; then
374 return 0
375 fi
376 if ! _bpftool_search_list 'linum opcodes visual'; then
377 _bpftool_once_attr 'file'
378 fi
379 _bpftool_once_attr 'linum opcodes'
380 if _bpftool_search_list 'xlated' && [[ "$json" == 0 ]]; then
381 _bpftool_once_attr 'visual'
382 fi
383 return 0
384 ;;
385 esac
386 ;;
387 pin)
388 if [[ $prev == "$command" ]]; then
389 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
390 else
391 _filedir
392 fi
393 return 0
394 ;;
395 attach|detach)
396 case $cword in
397 3)
398 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
399 return 0
400 ;;
401 4)
402 case $prev in
403 id)
404 _bpftool_get_prog_ids
405 ;;
406 name)
407 _bpftool_get_prog_names
408 ;;
409 pinned)
410 _filedir
411 ;;
412 esac
413 return 0
414 ;;
415 5)
416 local BPFTOOL_PROG_ATTACH_TYPES='sk_msg_verdict \
417 sk_skb_verdict sk_skb_stream_verdict sk_skb_stream_parser \
418 flow_dissector'
419 COMPREPLY=( $( compgen -W "$BPFTOOL_PROG_ATTACH_TYPES" -- "$cur" ) )
420 return 0
421 ;;
422 6)
423 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
424 return 0
425 ;;
426 7)
427 case $prev in
428 id)
429 _bpftool_get_map_ids
430 ;;
431 name)
432 _bpftool_get_map_names
433 ;;
434 pinned)
435 _filedir
436 ;;
437 esac
438 return 0
439 ;;
440 esac
441 ;;
442 load|loadall)
443 local obj
444
445 # Propose "load/loadall" to complete "bpftool prog load",
446 # or bash tries to complete "load" as a filename below.
447 if [[ ${#words[@]} -eq 3 ]]; then
448 COMPREPLY=( $( compgen -W "load loadall" -- "$cur" ) )
449 return 0
450 fi
451
452 if [[ ${#words[@]} -lt 6 ]]; then
453 _filedir
454 return 0
455 fi
456
457 obj=${words[3]}
458
459 if [[ ${words[-4]} == "map" ]]; then
460 COMPREPLY=( $( compgen -W "id pinned" -- "$cur" ) )
461 return 0
462 fi
463 if [[ ${words[-3]} == "map" ]]; then
464 if [[ ${words[-2]} == "idx" ]]; then
465 _bpftool_get_obj_map_idxs $obj
466 elif [[ ${words[-2]} == "name" ]]; then
467 _bpftool_get_obj_map_names $obj
468 fi
469 return 0
470 fi
471 if [[ ${words[-2]} == "map" ]]; then
472 COMPREPLY=( $( compgen -W "idx name" -- "$cur" ) )
473 return 0
474 fi
475
476 case $prev in
477 type)
478 local BPFTOOL_PROG_LOAD_TYPES='socket kprobe \
479 kretprobe classifier flow_dissector \
480 action tracepoint raw_tracepoint \
481 xdp perf_event cgroup/skb cgroup/sock \
482 cgroup/dev lwt_in lwt_out lwt_xmit \
483 lwt_seg6local sockops sk_skb sk_msg lirc_mode2 \
484 cgroup/bind4 cgroup/bind6 \
485 cgroup/connect4 cgroup/connect6 cgroup/connect_unix \
486 cgroup/getpeername4 cgroup/getpeername6 cgroup/getpeername_unix \
487 cgroup/getsockname4 cgroup/getsockname6 cgroup/getsockname_unix \
488 cgroup/sendmsg4 cgroup/sendmsg6 cgroup/sendmsg_unix \
489 cgroup/recvmsg4 cgroup/recvmsg6 cgroup/recvmsg_unix \
490 cgroup/post_bind4 cgroup/post_bind6 \
491 cgroup/sysctl cgroup/getsockopt \
492 cgroup/setsockopt cgroup/sock_release struct_ops \
493 fentry fexit freplace sk_lookup'
494 COMPREPLY=( $( compgen -W "$BPFTOOL_PROG_LOAD_TYPES" -- "$cur" ) )
495 return 0
496 ;;
497 id)
498 _bpftool_get_map_ids
499 return 0
500 ;;
501 name)
502 _bpftool_get_map_names
503 return 0
504 ;;
505 pinned|pinmaps)
506 _filedir
507 return 0
508 ;;
509 *)
510 COMPREPLY=( $( compgen -W "map" -- "$cur" ) )
511 _bpftool_once_attr 'type pinmaps autoattach'
512 _bpftool_one_of_list 'offload_dev xdpmeta_dev'
513 return 0
514 ;;
515 esac
516 ;;
517 tracelog)
518 return 0
519 ;;
520 profile)
521 case $cword in
522 3)
523 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
524 return 0
525 ;;
526 4)
527 case $prev in
528 id)
529 _bpftool_get_prog_ids
530 ;;
531 name)
532 _bpftool_get_prog_names
533 ;;
534 pinned)
535 _filedir
536 ;;
537 esac
538 return 0
539 ;;
540 5)
541 COMPREPLY=( $( compgen -W "$METRIC_TYPE duration" -- "$cur" ) )
542 return 0
543 ;;
544 6)
545 case $prev in
546 duration)
547 return 0
548 ;;
549 *)
550 COMPREPLY=( $( compgen -W "$METRIC_TYPE" -- "$cur" ) )
551 return 0
552 ;;
553 esac
554 return 0
555 ;;
556 *)
557 COMPREPLY=( $( compgen -W "$METRIC_TYPE" -- "$cur" ) )
558 return 0
559 ;;
560 esac
561 ;;
562 run)
563 if [[ ${#words[@]} -eq 4 ]]; then
564 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
565 return 0
566 fi
567 case $prev in
568 id)
569 _bpftool_get_prog_ids
570 return 0
571 ;;
572 name)
573 _bpftool_get_prog_names
574 return 0
575 ;;
576 data_in|data_out|ctx_in|ctx_out)
577 _filedir
578 return 0
579 ;;
580 repeat|data_size_out|ctx_size_out)
581 return 0
582 ;;
583 *)
584 _bpftool_once_attr 'data_in data_out data_size_out \
585 ctx_in ctx_out ctx_size_out repeat'
586 return 0
587 ;;
588 esac
589 ;;
590 *)
591 [[ $prev == $object ]] && \
592 COMPREPLY=( $( compgen -W 'dump help pin attach detach \
593 load loadall show list tracelog run profile' -- "$cur" ) )
594 ;;
595 esac
596 ;;
597 struct_ops)
598 local STRUCT_OPS_TYPE='id name'
599 case $command in
600 show|list|dump|unregister)
601 case $prev in
602 $command)
603 COMPREPLY=( $( compgen -W "$STRUCT_OPS_TYPE" -- "$cur" ) )
604 ;;
605 id)
606 _bpftool_get_map_ids_for_type struct_ops
607 ;;
608 name)
609 _bpftool_get_map_names_for_type struct_ops
610 ;;
611 esac
612 return 0
613 ;;
614 register)
615 _filedir
616 return 0
617 ;;
618 *)
619 [[ $prev == $object ]] && \
620 COMPREPLY=( $( compgen -W 'register unregister show list dump help' \
621 -- "$cur" ) )
622 ;;
623 esac
624 ;;
625 iter)
626 case $command in
627 pin)
628 case $prev in
629 $command)
630 _filedir
631 ;;
632 id)
633 _bpftool_get_map_ids
634 ;;
635 name)
636 _bpftool_get_map_names
637 ;;
638 pinned)
639 _filedir
640 ;;
641 *)
642 _bpftool_one_of_list $MAP_TYPE
643 ;;
644 esac
645 return 0
646 ;;
647 *)
648 [[ $prev == $object ]] && \
649 COMPREPLY=( $( compgen -W 'pin help' \
650 -- "$cur" ) )
651 ;;
652 esac
653 ;;
654 map)
655 local MAP_TYPE='id pinned name'
656 case $command in
657 show|list|dump|peek|pop|dequeue|freeze)
658 case $prev in
659 $command)
660 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
661 return 0
662 ;;
663 id)
664 case "$command" in
665 peek)
666 _bpftool_get_map_ids_for_type stack
667 _bpftool_get_map_ids_for_type queue
668 ;;
669 pop)
670 _bpftool_get_map_ids_for_type stack
671 ;;
672 dequeue)
673 _bpftool_get_map_ids_for_type queue
674 ;;
675 *)
676 _bpftool_get_map_ids
677 ;;
678 esac
679 return 0
680 ;;
681 name)
682 case "$command" in
683 peek)
684 _bpftool_get_map_names_for_type stack
685 _bpftool_get_map_names_for_type queue
686 ;;
687 pop)
688 _bpftool_get_map_names_for_type stack
689 ;;
690 dequeue)
691 _bpftool_get_map_names_for_type queue
692 ;;
693 *)
694 _bpftool_get_map_names
695 ;;
696 esac
697 return 0
698 ;;
699 *)
700 return 0
701 ;;
702 esac
703 ;;
704 create)
705 case $prev in
706 $command)
707 _filedir
708 return 0
709 ;;
710 type)
711 local BPFTOOL_MAP_CREATE_TYPES="$(bpftool feature list_builtins map_types 2>/dev/null | \
712 grep -v '^unspec$')"
713 COMPREPLY=( $( compgen -W "$BPFTOOL_MAP_CREATE_TYPES" -- "$cur" ) )
714 return 0
715 ;;
716 key|value|flags|entries)
717 return 0
718 ;;
719 inner_map)
720 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
721 return 0
722 ;;
723 id)
724 _bpftool_get_map_ids
725 ;;
726 name)
727 case $pprev in
728 inner_map)
729 _bpftool_get_map_names
730 ;;
731 *)
732 return 0
733 ;;
734 esac
735 ;;
736 *)
737 _bpftool_once_attr 'type key value entries name flags offload_dev'
738 if _bpftool_search_list 'array_of_maps' 'hash_of_maps'; then
739 _bpftool_once_attr 'inner_map'
740 fi
741 return 0
742 ;;
743 esac
744 ;;
745 lookup|getnext|delete)
746 case $prev in
747 $command)
748 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
749 return 0
750 ;;
751 id)
752 _bpftool_get_map_ids
753 return 0
754 ;;
755 name)
756 _bpftool_get_map_names
757 return 0
758 ;;
759 key)
760 COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) )
761 ;;
762 *)
763 case $(_bpftool_map_guess_map_type) in
764 queue|stack)
765 return 0
766 ;;
767 esac
768
769 _bpftool_once_attr 'key'
770 return 0
771 ;;
772 esac
773 ;;
774 update|push|enqueue)
775 case $prev in
776 $command)
777 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
778 return 0
779 ;;
780 id)
781 _bpftool_map_update_get_id $command
782 return 0
783 ;;
784 name)
785 _bpftool_map_update_get_name $command
786 return 0
787 ;;
788 key)
789 COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) )
790 ;;
791 value)
792 # We can have bytes, or references to a prog or a
793 # map, depending on the type of the map to update.
794 case "$(_bpftool_map_guess_map_type)" in
795 array_of_maps|hash_of_maps)
796 local MAP_TYPE='id pinned name'
797 COMPREPLY+=( $( compgen -W "$MAP_TYPE" \
798 -- "$cur" ) )
799 return 0
800 ;;
801 prog_array)
802 local PROG_TYPE='id pinned tag name'
803 COMPREPLY+=( $( compgen -W "$PROG_TYPE" \
804 -- "$cur" ) )
805 return 0
806 ;;
807 *)
808 COMPREPLY+=( $( compgen -W 'hex' \
809 -- "$cur" ) )
810 return 0
811 ;;
812 esac
813 return 0
814 ;;
815 *)
816 case $(_bpftool_map_guess_map_type) in
817 queue|stack)
818 _bpftool_once_attr 'value'
819 return 0;
820 ;;
821 esac
822
823 _bpftool_once_attr 'key'
824 local UPDATE_FLAGS='any exist noexist'
825 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
826 if [[ ${words[idx]} == 'value' ]]; then
827 # 'value' is present, but is not the last
828 # word i.e. we can now have UPDATE_FLAGS.
829 _bpftool_one_of_list "$UPDATE_FLAGS"
830 return 0
831 fi
832 done
833 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
834 if [[ ${words[idx]} == 'key' ]]; then
835 # 'key' is present, but is not the last
836 # word i.e. we can now have 'value'.
837 _bpftool_once_attr 'value'
838 return 0
839 fi
840 done
841
842 return 0
843 ;;
844 esac
845 ;;
846 pin)
847 case $prev in
848 $command)
849 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
850 ;;
851 id)
852 _bpftool_get_map_ids
853 ;;
854 name)
855 _bpftool_get_map_names
856 ;;
857 esac
858 return 0
859 ;;
860 event_pipe)
861 case $prev in
862 $command)
863 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
864 return 0
865 ;;
866 id)
867 _bpftool_get_map_ids_for_type perf_event_array
868 return 0
869 ;;
870 name)
871 _bpftool_get_map_names_for_type perf_event_array
872 return 0
873 ;;
874 cpu)
875 return 0
876 ;;
877 index)
878 return 0
879 ;;
880 *)
881 _bpftool_once_attr 'cpu index'
882 return 0
883 ;;
884 esac
885 ;;
886 *)
887 [[ $prev == $object ]] && \
888 COMPREPLY=( $( compgen -W 'delete dump getnext help \
889 lookup pin event_pipe show list update create \
890 peek push enqueue pop dequeue freeze' -- \
891 "$cur" ) )
892 ;;
893 esac
894 ;;
895 btf)
896 local PROG_TYPE='id pinned tag name'
897 local MAP_TYPE='id pinned name'
898 case $command in
899 dump)
900 case $prev in
901 $command)
902 COMPREPLY+=( $( compgen -W "id map prog file" -- \
903 "$cur" ) )
904 return 0
905 ;;
906 prog)
907 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
908 return 0
909 ;;
910 map)
911 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
912 return 0
913 ;;
914 id)
915 case $pprev in
916 prog)
917 _bpftool_get_prog_ids
918 ;;
919 map)
920 _bpftool_get_map_ids
921 ;;
922 $command)
923 _bpftool_get_btf_ids
924 ;;
925 esac
926 return 0
927 ;;
928 name)
929 case $pprev in
930 prog)
931 _bpftool_get_prog_names
932 ;;
933 map)
934 _bpftool_get_map_names
935 ;;
936 esac
937 return 0
938 ;;
939 format)
940 COMPREPLY=( $( compgen -W "c raw" -- "$cur" ) )
941 ;;
942 *)
943 # emit extra options
944 case ${words[3]} in
945 id|file)
946 _bpftool_once_attr 'format'
947 ;;
948 map|prog)
949 if [[ ${words[3]} == "map" ]] && [[ $cword == 6 ]]; then
950 COMPREPLY+=( $( compgen -W "key value kv all" -- "$cur" ) )
951 fi
952 _bpftool_once_attr 'format'
953 ;;
954 *)
955 ;;
956 esac
957 return 0
958 ;;
959 esac
960 ;;
961 show|list)
962 case $prev in
963 $command)
964 COMPREPLY+=( $( compgen -W "id" -- "$cur" ) )
965 ;;
966 id)
967 _bpftool_get_btf_ids
968 ;;
969 esac
970 return 0
971 ;;
972 *)
973 [[ $prev == $object ]] && \
974 COMPREPLY=( $( compgen -W 'dump help show list' \
975 -- "$cur" ) )
976 ;;
977 esac
978 ;;
979 gen)
980 case $command in
981 object)
982 _filedir
983 return 0
984 ;;
985 skeleton)
986 case $prev in
987 $command)
988 _filedir
989 return 0
990 ;;
991 *)
992 _bpftool_once_attr 'name'
993 return 0
994 ;;
995 esac
996 ;;
997 subskeleton)
998 case $prev in
999 $command)
1000 _filedir
1001 return 0
1002 ;;
1003 *)
1004 _bpftool_once_attr 'name'
1005 return 0
1006 ;;
1007 esac
1008 ;;
1009 min_core_btf)
1010 _filedir
1011 return 0
1012 ;;
1013 *)
1014 [[ $prev == $object ]] && \
1015 COMPREPLY=( $( compgen -W 'object skeleton subskeleton help min_core_btf' -- "$cur" ) )
1016 ;;
1017 esac
1018 ;;
1019 cgroup)
1020 case $command in
1021 show|list|tree)
1022 case $cword in
1023 3)
1024 _filedir
1025 ;;
1026 4)
1027 COMPREPLY=( $( compgen -W 'effective' -- "$cur" ) )
1028 ;;
1029 esac
1030 return 0
1031 ;;
1032 attach|detach)
1033 local BPFTOOL_CGROUP_ATTACH_TYPES="$(bpftool feature list_builtins attach_types 2>/dev/null | \
1034 grep '^cgroup_')"
1035 local ATTACH_FLAGS='multi override'
1036 local PROG_TYPE='id pinned tag name'
1037 # Check for $prev = $command first
1038 if [ $prev = $command ]; then
1039 _filedir
1040 return 0
1041 # Then check for attach type. This is done outside of the
1042 # "case $prev in" to avoid writing the whole list of attach
1043 # types again as pattern to match (where we cannot reuse
1044 # our variable).
1045 elif [[ $BPFTOOL_CGROUP_ATTACH_TYPES =~ $prev ]]; then
1046 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- \
1047 "$cur" ) )
1048 return 0
1049 fi
1050 # case/esac for the other cases
1051 case $prev in
1052 id)
1053 _bpftool_get_prog_ids
1054 return 0
1055 ;;
1056 *)
1057 if ! _bpftool_search_list "$BPFTOOL_CGROUP_ATTACH_TYPES"; then
1058 COMPREPLY=( $( compgen -W \
1059 "$BPFTOOL_CGROUP_ATTACH_TYPES" -- "$cur" ) )
1060 elif [[ "$command" == "attach" ]]; then
1061 # We have an attach type on the command line,
1062 # but it is not the previous word, or
1063 # "id|pinned|tag|name" (we already checked for
1064 # that). This should only leave the case when
1065 # we need attach flags for "attach" commamnd.
1066 _bpftool_one_of_list "$ATTACH_FLAGS"
1067 fi
1068 return 0
1069 ;;
1070 esac
1071 ;;
1072 *)
1073 [[ $prev == $object ]] && \
1074 COMPREPLY=( $( compgen -W 'help attach detach \
1075 show list tree' -- "$cur" ) )
1076 ;;
1077 esac
1078 ;;
1079 perf)
1080 case $command in
1081 *)
1082 [[ $prev == $object ]] && \
1083 COMPREPLY=( $( compgen -W 'help \
1084 show list' -- "$cur" ) )
1085 ;;
1086 esac
1087 ;;
1088 net)
1089 local PROG_TYPE='id pinned tag name'
1090 local ATTACH_TYPES='xdp xdpgeneric xdpdrv xdpoffload'
1091 case $command in
1092 show|list)
1093 [[ $prev != "$command" ]] && return 0
1094 COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
1095 return 0
1096 ;;
1097 attach)
1098 case $cword in
1099 3)
1100 COMPREPLY=( $( compgen -W "$ATTACH_TYPES" -- "$cur" ) )
1101 return 0
1102 ;;
1103 4)
1104 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
1105 return 0
1106 ;;
1107 5)
1108 case $prev in
1109 id)
1110 _bpftool_get_prog_ids
1111 ;;
1112 name)
1113 _bpftool_get_prog_names
1114 ;;
1115 pinned)
1116 _filedir
1117 ;;
1118 esac
1119 return 0
1120 ;;
1121 6)
1122 COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
1123 return 0
1124 ;;
1125 8)
1126 _bpftool_once_attr 'overwrite'
1127 return 0
1128 ;;
1129 esac
1130 ;;
1131 detach)
1132 case $cword in
1133 3)
1134 COMPREPLY=( $( compgen -W "$ATTACH_TYPES" -- "$cur" ) )
1135 return 0
1136 ;;
1137 4)
1138 COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
1139 return 0
1140 ;;
1141 esac
1142 ;;
1143 *)
1144 [[ $prev == $object ]] && \
1145 COMPREPLY=( $( compgen -W 'help \
1146 show list attach detach' -- "$cur" ) )
1147 ;;
1148 esac
1149 ;;
1150 feature)
1151 case $command in
1152 probe)
1153 [[ $prev == "prefix" ]] && return 0
1154 if _bpftool_search_list 'macros'; then
1155 _bpftool_once_attr 'prefix'
1156 else
1157 COMPREPLY+=( $( compgen -W 'macros' -- "$cur" ) )
1158 fi
1159 _bpftool_one_of_list 'kernel dev'
1160 _bpftool_once_attr 'full unprivileged'
1161 return 0
1162 ;;
1163 list_builtins)
1164 [[ $prev != "$command" ]] && return 0
1165 COMPREPLY=( $( compgen -W 'prog_types map_types \
1166 attach_types link_types helpers' -- "$cur" ) )
1167 ;;
1168 *)
1169 [[ $prev == $object ]] && \
1170 COMPREPLY=( $( compgen -W 'help list_builtins probe' -- "$cur" ) )
1171 ;;
1172 esac
1173 ;;
1174 link)
1175 case $command in
1176 show|list|pin|detach)
1177 case $prev in
1178 id)
1179 _bpftool_get_link_ids
1180 return 0
1181 ;;
1182 esac
1183 ;;
1184 esac
1185
1186 local LINK_TYPE='id pinned'
1187 case $command in
1188 show|list)
1189 [[ $prev != "$command" ]] && return 0
1190 COMPREPLY=( $( compgen -W "$LINK_TYPE" -- "$cur" ) )
1191 return 0
1192 ;;
1193 pin|detach)
1194 if [[ $prev == "$command" ]]; then
1195 COMPREPLY=( $( compgen -W "$LINK_TYPE" -- "$cur" ) )
1196 else
1197 _filedir
1198 fi
1199 return 0
1200 ;;
1201 *)
1202 [[ $prev == $object ]] && \
1203 COMPREPLY=( $( compgen -W 'help pin show list' -- "$cur" ) )
1204 ;;
1205 esac
1206 ;;
1207 esac
1208} &&
1209complete -F _bpftool bpftool
1210
1211# ex: ts=4 sw=4 et filetype=sh
1# bpftool(8) bash completion -*- shell-script -*-
2#
3# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
4# Copyright (C) 2017-2018 Netronome Systems, Inc.
5#
6# Author: Quentin Monnet <quentin.monnet@netronome.com>
7
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.
10_bpftool_once_attr()
11{
12 local w idx found
13 for w in $*; do
14 found=0
15 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
16 if [[ $w == ${words[idx]} ]]; then
17 found=1
18 break
19 fi
20 done
21 [[ $found -eq 0 ]] && \
22 COMPREPLY+=( $( compgen -W "$w" -- "$cur" ) )
23 done
24}
25
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()
29{
30 local w idx
31 for w in $*; do
32 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
33 [[ $w == ${words[idx]} ]] && return 0
34 done
35 done
36 return 1
37}
38
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()
42{
43 _bpftool_search_list $* && return 1
44 COMPREPLY+=( $( compgen -W "$*" -- "$cur" ) )
45}
46
47_bpftool_get_map_ids()
48{
49 COMPREPLY+=( $( compgen -W "$( bpftool -jp map 2>&1 | \
50 command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
51}
52
53# Takes map type and adds matching map ids to the list of suggestions.
54_bpftool_get_map_ids_for_type()
55{
56 local type="$1"
57 COMPREPLY+=( $( compgen -W "$( bpftool -jp map 2>&1 | \
58 command grep -C2 "$type" | \
59 command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
60}
61
62_bpftool_get_map_names()
63{
64 COMPREPLY+=( $( compgen -W "$( bpftool -jp map 2>&1 | \
65 command sed -n 's/.*"name": \(.*\),$/\1/p' )" -- "$cur" ) )
66}
67
68# Takes map type and adds matching map names to the list of suggestions.
69_bpftool_get_map_names_for_type()
70{
71 local type="$1"
72 COMPREPLY+=( $( compgen -W "$( bpftool -jp map 2>&1 | \
73 command grep -C2 "$type" | \
74 command sed -n 's/.*"name": \(.*\),$/\1/p' )" -- "$cur" ) )
75}
76
77_bpftool_get_prog_ids()
78{
79 COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \
80 command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
81}
82
83_bpftool_get_prog_tags()
84{
85 COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \
86 command sed -n 's/.*"tag": "\(.*\)",$/\1/p' )" -- "$cur" ) )
87}
88
89_bpftool_get_prog_names()
90{
91 COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \
92 command sed -n 's/.*"name": "\(.*\)",$/\1/p' )" -- "$cur" ) )
93}
94
95_bpftool_get_btf_ids()
96{
97 COMPREPLY+=( $( compgen -W "$( bpftool -jp btf 2>&1 | \
98 command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
99}
100
101_bpftool_get_link_ids()
102{
103 COMPREPLY+=( $( compgen -W "$( bpftool -jp link 2>&1 | \
104 command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
105}
106
107_bpftool_get_obj_map_names()
108{
109 local obj
110
111 obj=$1
112
113 maps=$(objdump -j maps -t $obj 2>/dev/null | \
114 command awk '/g . maps/ {print $NF}')
115
116 COMPREPLY+=( $( compgen -W "$maps" -- "$cur" ) )
117}
118
119_bpftool_get_obj_map_idxs()
120{
121 local obj
122
123 obj=$1
124
125 nmaps=$(objdump -j maps -t $obj 2>/dev/null | grep -c 'g . maps')
126
127 COMPREPLY+=( $( compgen -W "$(seq 0 $((nmaps - 1)))" -- "$cur" ) )
128}
129
130_sysfs_get_netdevs()
131{
132 COMPREPLY+=( $( compgen -W "$( ls /sys/class/net 2>/dev/null )" -- \
133 "$cur" ) )
134}
135
136# Retrieve type of the map that we are operating on.
137_bpftool_map_guess_map_type()
138{
139 local keyword ref
140 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
141 case "${words[$((idx-2))]}" in
142 lookup|update)
143 keyword=${words[$((idx-1))]}
144 ref=${words[$((idx))]}
145 ;;
146 push)
147 printf "stack"
148 return 0
149 ;;
150 enqueue)
151 printf "queue"
152 return 0
153 ;;
154 esac
155 done
156 [[ -z $ref ]] && return 0
157
158 local type
159 type=$(bpftool -jp map show $keyword $ref | \
160 command sed -n 's/.*"type": "\(.*\)",$/\1/p')
161 [[ -n $type ]] && printf $type
162}
163
164_bpftool_map_update_get_id()
165{
166 local command="$1"
167
168 # Is it the map to update, or a map to insert into the map to update?
169 # Search for "value" keyword.
170 local idx value
171 for (( idx=7; idx < ${#words[@]}-1; idx++ )); do
172 if [[ ${words[idx]} == "value" ]]; then
173 value=1
174 break
175 fi
176 done
177 if [[ $value -eq 0 ]]; then
178 case "$command" in
179 push)
180 _bpftool_get_map_ids_for_type stack
181 ;;
182 enqueue)
183 _bpftool_get_map_ids_for_type queue
184 ;;
185 *)
186 _bpftool_get_map_ids
187 ;;
188 esac
189 return 0
190 fi
191
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)
195 case $type in
196 array_of_maps|hash_of_maps)
197 _bpftool_get_map_ids
198 return 0
199 ;;
200 prog_array)
201 _bpftool_get_prog_ids
202 return 0
203 ;;
204 *)
205 return 0
206 ;;
207 esac
208}
209
210_bpftool_map_update_get_name()
211{
212 local command="$1"
213
214 # Is it the map to update, or a map to insert into the map to update?
215 # Search for "value" keyword.
216 local idx value
217 for (( idx=7; idx < ${#words[@]}-1; idx++ )); do
218 if [[ ${words[idx]} == "value" ]]; then
219 value=1
220 break
221 fi
222 done
223 if [[ $value -eq 0 ]]; then
224 case "$command" in
225 push)
226 _bpftool_get_map_names_for_type stack
227 ;;
228 enqueue)
229 _bpftool_get_map_names_for_type queue
230 ;;
231 *)
232 _bpftool_get_map_names
233 ;;
234 esac
235 return 0
236 fi
237
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)
241 case $type in
242 array_of_maps|hash_of_maps)
243 _bpftool_get_map_names
244 return 0
245 ;;
246 prog_array)
247 _bpftool_get_prog_names
248 return 0
249 ;;
250 *)
251 return 0
252 ;;
253 esac
254}
255
256_bpftool()
257{
258 local cur prev words objword
259 _init_completion || return
260
261 # Deal with options
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" ) )
266 return 0
267 fi
268
269 # Deal with simplest keywords
270 case $prev in
271 help|hex|opcodes|visual|linum)
272 return 0
273 ;;
274 tag)
275 _bpftool_get_prog_tags
276 return 0
277 ;;
278 dev)
279 _sysfs_get_netdevs
280 return 0
281 ;;
282 file|pinned|-B|--base-btf)
283 _filedir
284 return 0
285 ;;
286 batch)
287 COMPREPLY=( $( compgen -W 'file' -- "$cur" ) )
288 return 0
289 ;;
290 esac
291
292 # Remove all options so completions don't have to deal with them.
293 local i
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 ))
299 else
300 i=$(( ++i ))
301 fi
302 done
303 cur=${words[cword]}
304 prev=${words[cword - 1]}
305 pprev=${words[cword - 2]}
306
307 local object=${words[1]} command=${words[2]}
308
309 if [[ -z $object || $cword -eq 1 ]]; then
310 case $cur in
311 *)
312 COMPREPLY=( $( compgen -W "$( bpftool help 2>&1 | \
313 command sed \
314 -e '/OBJECT := /!d' \
315 -e 's/.*{//' \
316 -e 's/}.*//' \
317 -e 's/|//g' )" -- "$cur" ) )
318 COMPREPLY+=( $( compgen -W 'batch help' -- "$cur" ) )
319 return 0
320 ;;
321 esac
322 fi
323
324 [[ $command == help ]] && return 0
325
326 # Completion depends on object and command in use
327 case $object in
328 prog)
329 # Complete id and name, only for subcommands that use prog (but no
330 # map) ids/names.
331 case $command in
332 show|list|dump|pin)
333 case $prev in
334 id)
335 _bpftool_get_prog_ids
336 return 0
337 ;;
338 name)
339 _bpftool_get_prog_names
340 return 0
341 ;;
342 esac
343 ;;
344 esac
345
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 \
349 itlb_misses dtlb_misses'
350 case $command in
351 show|list)
352 [[ $prev != "$command" ]] && return 0
353 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
354 return 0
355 ;;
356 dump)
357 case $prev in
358 $command)
359 COMPREPLY+=( $( compgen -W "xlated jited" -- \
360 "$cur" ) )
361 return 0
362 ;;
363 xlated|jited)
364 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- \
365 "$cur" ) )
366 return 0
367 ;;
368 *)
369 _bpftool_once_attr 'file'
370 if _bpftool_search_list 'xlated'; then
371 COMPREPLY+=( $( compgen -W 'opcodes visual linum' -- \
372 "$cur" ) )
373 else
374 COMPREPLY+=( $( compgen -W 'opcodes linum' -- \
375 "$cur" ) )
376 fi
377 return 0
378 ;;
379 esac
380 ;;
381 pin)
382 if [[ $prev == "$command" ]]; then
383 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
384 else
385 _filedir
386 fi
387 return 0
388 ;;
389 attach|detach)
390 case $cword in
391 3)
392 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
393 return 0
394 ;;
395 4)
396 case $prev in
397 id)
398 _bpftool_get_prog_ids
399 ;;
400 name)
401 _bpftool_get_prog_names
402 ;;
403 pinned)
404 _filedir
405 ;;
406 esac
407 return 0
408 ;;
409 5)
410 local BPFTOOL_PROG_ATTACH_TYPES='sk_msg_verdict \
411 sk_skb_verdict sk_skb_stream_verdict sk_skb_stream_parser \
412 flow_dissector'
413 COMPREPLY=( $( compgen -W "$BPFTOOL_PROG_ATTACH_TYPES" -- "$cur" ) )
414 return 0
415 ;;
416 6)
417 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
418 return 0
419 ;;
420 7)
421 case $prev in
422 id)
423 _bpftool_get_map_ids
424 ;;
425 name)
426 _bpftool_get_map_names
427 ;;
428 pinned)
429 _filedir
430 ;;
431 esac
432 return 0
433 ;;
434 esac
435 ;;
436 load|loadall)
437 local obj
438
439 # Propose "load/loadall" to complete "bpftool prog load",
440 # or bash tries to complete "load" as a filename below.
441 if [[ ${#words[@]} -eq 3 ]]; then
442 COMPREPLY=( $( compgen -W "load loadall" -- "$cur" ) )
443 return 0
444 fi
445
446 if [[ ${#words[@]} -lt 6 ]]; then
447 _filedir
448 return 0
449 fi
450
451 obj=${words[3]}
452
453 if [[ ${words[-4]} == "map" ]]; then
454 COMPREPLY=( $( compgen -W "id pinned" -- "$cur" ) )
455 return 0
456 fi
457 if [[ ${words[-3]} == "map" ]]; then
458 if [[ ${words[-2]} == "idx" ]]; then
459 _bpftool_get_obj_map_idxs $obj
460 elif [[ ${words[-2]} == "name" ]]; then
461 _bpftool_get_obj_map_names $obj
462 fi
463 return 0
464 fi
465 if [[ ${words[-2]} == "map" ]]; then
466 COMPREPLY=( $( compgen -W "idx name" -- "$cur" ) )
467 return 0
468 fi
469
470 case $prev in
471 type)
472 local BPFTOOL_PROG_LOAD_TYPES='socket kprobe \
473 kretprobe classifier flow_dissector \
474 action tracepoint raw_tracepoint \
475 xdp perf_event cgroup/skb cgroup/sock \
476 cgroup/dev lwt_in lwt_out lwt_xmit \
477 lwt_seg6local sockops sk_skb sk_msg \
478 lirc_mode2 cgroup/bind4 cgroup/bind6 \
479 cgroup/connect4 cgroup/connect6 \
480 cgroup/getpeername4 cgroup/getpeername6 \
481 cgroup/getsockname4 cgroup/getsockname6 \
482 cgroup/sendmsg4 cgroup/sendmsg6 \
483 cgroup/recvmsg4 cgroup/recvmsg6 \
484 cgroup/post_bind4 cgroup/post_bind6 \
485 cgroup/sysctl cgroup/getsockopt \
486 cgroup/setsockopt cgroup/sock_release struct_ops \
487 fentry fexit freplace sk_lookup'
488 COMPREPLY=( $( compgen -W "$BPFTOOL_PROG_LOAD_TYPES" -- "$cur" ) )
489 return 0
490 ;;
491 id)
492 _bpftool_get_map_ids
493 return 0
494 ;;
495 name)
496 _bpftool_get_map_names
497 return 0
498 ;;
499 pinned|pinmaps)
500 _filedir
501 return 0
502 ;;
503 *)
504 COMPREPLY=( $( compgen -W "map" -- "$cur" ) )
505 _bpftool_once_attr 'type'
506 _bpftool_once_attr 'dev'
507 _bpftool_once_attr 'pinmaps'
508 _bpftool_once_attr 'autoattach'
509 return 0
510 ;;
511 esac
512 ;;
513 tracelog)
514 return 0
515 ;;
516 profile)
517 case $cword in
518 3)
519 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
520 return 0
521 ;;
522 4)
523 case $prev in
524 id)
525 _bpftool_get_prog_ids
526 ;;
527 name)
528 _bpftool_get_prog_names
529 ;;
530 pinned)
531 _filedir
532 ;;
533 esac
534 return 0
535 ;;
536 5)
537 COMPREPLY=( $( compgen -W "$METRIC_TYPE duration" -- "$cur" ) )
538 return 0
539 ;;
540 6)
541 case $prev in
542 duration)
543 return 0
544 ;;
545 *)
546 COMPREPLY=( $( compgen -W "$METRIC_TYPE" -- "$cur" ) )
547 return 0
548 ;;
549 esac
550 return 0
551 ;;
552 *)
553 COMPREPLY=( $( compgen -W "$METRIC_TYPE" -- "$cur" ) )
554 return 0
555 ;;
556 esac
557 ;;
558 run)
559 if [[ ${#words[@]} -eq 4 ]]; then
560 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
561 return 0
562 fi
563 case $prev in
564 id)
565 _bpftool_get_prog_ids
566 return 0
567 ;;
568 name)
569 _bpftool_get_prog_names
570 return 0
571 ;;
572 data_in|data_out|ctx_in|ctx_out)
573 _filedir
574 return 0
575 ;;
576 repeat|data_size_out|ctx_size_out)
577 return 0
578 ;;
579 *)
580 _bpftool_once_attr 'data_in data_out data_size_out \
581 ctx_in ctx_out ctx_size_out repeat'
582 return 0
583 ;;
584 esac
585 ;;
586 *)
587 [[ $prev == $object ]] && \
588 COMPREPLY=( $( compgen -W 'dump help pin attach detach \
589 load loadall show list tracelog run profile' -- "$cur" ) )
590 ;;
591 esac
592 ;;
593 struct_ops)
594 local STRUCT_OPS_TYPE='id name'
595 case $command in
596 show|list|dump|unregister)
597 case $prev in
598 $command)
599 COMPREPLY=( $( compgen -W "$STRUCT_OPS_TYPE" -- "$cur" ) )
600 ;;
601 id)
602 _bpftool_get_map_ids_for_type struct_ops
603 ;;
604 name)
605 _bpftool_get_map_names_for_type struct_ops
606 ;;
607 esac
608 return 0
609 ;;
610 register)
611 _filedir
612 return 0
613 ;;
614 *)
615 [[ $prev == $object ]] && \
616 COMPREPLY=( $( compgen -W 'register unregister show list dump help' \
617 -- "$cur" ) )
618 ;;
619 esac
620 ;;
621 iter)
622 case $command in
623 pin)
624 case $prev in
625 $command)
626 _filedir
627 ;;
628 id)
629 _bpftool_get_map_ids
630 ;;
631 name)
632 _bpftool_get_map_names
633 ;;
634 pinned)
635 _filedir
636 ;;
637 *)
638 _bpftool_one_of_list $MAP_TYPE
639 ;;
640 esac
641 return 0
642 ;;
643 *)
644 [[ $prev == $object ]] && \
645 COMPREPLY=( $( compgen -W 'pin help' \
646 -- "$cur" ) )
647 ;;
648 esac
649 ;;
650 map)
651 local MAP_TYPE='id pinned name'
652 case $command in
653 show|list|dump|peek|pop|dequeue|freeze)
654 case $prev in
655 $command)
656 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
657 return 0
658 ;;
659 id)
660 case "$command" in
661 peek)
662 _bpftool_get_map_ids_for_type stack
663 _bpftool_get_map_ids_for_type queue
664 ;;
665 pop)
666 _bpftool_get_map_ids_for_type stack
667 ;;
668 dequeue)
669 _bpftool_get_map_ids_for_type queue
670 ;;
671 *)
672 _bpftool_get_map_ids
673 ;;
674 esac
675 return 0
676 ;;
677 name)
678 case "$command" in
679 peek)
680 _bpftool_get_map_names_for_type stack
681 _bpftool_get_map_names_for_type queue
682 ;;
683 pop)
684 _bpftool_get_map_names_for_type stack
685 ;;
686 dequeue)
687 _bpftool_get_map_names_for_type queue
688 ;;
689 *)
690 _bpftool_get_map_names
691 ;;
692 esac
693 return 0
694 ;;
695 *)
696 return 0
697 ;;
698 esac
699 ;;
700 create)
701 case $prev in
702 $command)
703 _filedir
704 return 0
705 ;;
706 type)
707 local BPFTOOL_MAP_CREATE_TYPES="$(bpftool feature list_builtins map_types 2>/dev/null | \
708 grep -v '^unspec$')"
709 COMPREPLY=( $( compgen -W "$BPFTOOL_MAP_CREATE_TYPES" -- "$cur" ) )
710 return 0
711 ;;
712 key|value|flags|entries)
713 return 0
714 ;;
715 inner_map)
716 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
717 return 0
718 ;;
719 id)
720 _bpftool_get_map_ids
721 ;;
722 name)
723 case $pprev in
724 inner_map)
725 _bpftool_get_map_names
726 ;;
727 *)
728 return 0
729 ;;
730 esac
731 ;;
732 *)
733 _bpftool_once_attr 'type'
734 _bpftool_once_attr 'key'
735 _bpftool_once_attr 'value'
736 _bpftool_once_attr 'entries'
737 _bpftool_once_attr 'name'
738 _bpftool_once_attr 'flags'
739 if _bpftool_search_list 'array_of_maps' 'hash_of_maps'; then
740 _bpftool_once_attr 'inner_map'
741 fi
742 _bpftool_once_attr 'dev'
743 return 0
744 ;;
745 esac
746 ;;
747 lookup|getnext|delete)
748 case $prev in
749 $command)
750 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
751 return 0
752 ;;
753 id)
754 _bpftool_get_map_ids
755 return 0
756 ;;
757 name)
758 _bpftool_get_map_names
759 return 0
760 ;;
761 key)
762 COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) )
763 ;;
764 *)
765 case $(_bpftool_map_guess_map_type) in
766 queue|stack)
767 return 0
768 ;;
769 esac
770
771 _bpftool_once_attr 'key'
772 return 0
773 ;;
774 esac
775 ;;
776 update|push|enqueue)
777 case $prev in
778 $command)
779 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
780 return 0
781 ;;
782 id)
783 _bpftool_map_update_get_id $command
784 return 0
785 ;;
786 name)
787 _bpftool_map_update_get_name $command
788 return 0
789 ;;
790 key)
791 COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) )
792 ;;
793 value)
794 # We can have bytes, or references to a prog or a
795 # map, depending on the type of the map to update.
796 case "$(_bpftool_map_guess_map_type)" in
797 array_of_maps|hash_of_maps)
798 local MAP_TYPE='id pinned name'
799 COMPREPLY+=( $( compgen -W "$MAP_TYPE" \
800 -- "$cur" ) )
801 return 0
802 ;;
803 prog_array)
804 local PROG_TYPE='id pinned tag name'
805 COMPREPLY+=( $( compgen -W "$PROG_TYPE" \
806 -- "$cur" ) )
807 return 0
808 ;;
809 *)
810 COMPREPLY+=( $( compgen -W 'hex' \
811 -- "$cur" ) )
812 return 0
813 ;;
814 esac
815 return 0
816 ;;
817 *)
818 case $(_bpftool_map_guess_map_type) in
819 queue|stack)
820 _bpftool_once_attr 'value'
821 return 0;
822 ;;
823 esac
824
825 _bpftool_once_attr 'key'
826 local UPDATE_FLAGS='any exist noexist'
827 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
828 if [[ ${words[idx]} == 'value' ]]; then
829 # 'value' is present, but is not the last
830 # word i.e. we can now have UPDATE_FLAGS.
831 _bpftool_one_of_list "$UPDATE_FLAGS"
832 return 0
833 fi
834 done
835 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
836 if [[ ${words[idx]} == 'key' ]]; then
837 # 'key' is present, but is not the last
838 # word i.e. we can now have 'value'.
839 _bpftool_once_attr 'value'
840 return 0
841 fi
842 done
843
844 return 0
845 ;;
846 esac
847 ;;
848 pin)
849 case $prev in
850 $command)
851 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
852 ;;
853 id)
854 _bpftool_get_map_ids
855 ;;
856 name)
857 _bpftool_get_map_names
858 ;;
859 esac
860 return 0
861 ;;
862 event_pipe)
863 case $prev in
864 $command)
865 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
866 return 0
867 ;;
868 id)
869 _bpftool_get_map_ids_for_type perf_event_array
870 return 0
871 ;;
872 name)
873 _bpftool_get_map_names_for_type perf_event_array
874 return 0
875 ;;
876 cpu)
877 return 0
878 ;;
879 index)
880 return 0
881 ;;
882 *)
883 _bpftool_once_attr 'cpu'
884 _bpftool_once_attr 'index'
885 return 0
886 ;;
887 esac
888 ;;
889 *)
890 [[ $prev == $object ]] && \
891 COMPREPLY=( $( compgen -W 'delete dump getnext help \
892 lookup pin event_pipe show list update create \
893 peek push enqueue pop dequeue freeze' -- \
894 "$cur" ) )
895 ;;
896 esac
897 ;;
898 btf)
899 local PROG_TYPE='id pinned tag name'
900 local MAP_TYPE='id pinned name'
901 case $command in
902 dump)
903 case $prev in
904 $command)
905 COMPREPLY+=( $( compgen -W "id map prog file" -- \
906 "$cur" ) )
907 return 0
908 ;;
909 prog)
910 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
911 return 0
912 ;;
913 map)
914 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
915 return 0
916 ;;
917 id)
918 case $pprev in
919 prog)
920 _bpftool_get_prog_ids
921 ;;
922 map)
923 _bpftool_get_map_ids
924 ;;
925 $command)
926 _bpftool_get_btf_ids
927 ;;
928 esac
929 return 0
930 ;;
931 name)
932 case $pprev in
933 prog)
934 _bpftool_get_prog_names
935 ;;
936 map)
937 _bpftool_get_map_names
938 ;;
939 esac
940 return 0
941 ;;
942 format)
943 COMPREPLY=( $( compgen -W "c raw" -- "$cur" ) )
944 ;;
945 *)
946 # emit extra options
947 case ${words[3]} in
948 id|file)
949 _bpftool_once_attr 'format'
950 ;;
951 map|prog)
952 if [[ ${words[3]} == "map" ]] && [[ $cword == 6 ]]; then
953 COMPREPLY+=( $( compgen -W "key value kv all" -- "$cur" ) )
954 fi
955 _bpftool_once_attr 'format'
956 ;;
957 *)
958 ;;
959 esac
960 return 0
961 ;;
962 esac
963 ;;
964 show|list)
965 case $prev in
966 $command)
967 COMPREPLY+=( $( compgen -W "id" -- "$cur" ) )
968 ;;
969 id)
970 _bpftool_get_btf_ids
971 ;;
972 esac
973 return 0
974 ;;
975 *)
976 [[ $prev == $object ]] && \
977 COMPREPLY=( $( compgen -W 'dump help show list' \
978 -- "$cur" ) )
979 ;;
980 esac
981 ;;
982 gen)
983 case $command in
984 object)
985 _filedir
986 return 0
987 ;;
988 skeleton)
989 case $prev in
990 $command)
991 _filedir
992 return 0
993 ;;
994 *)
995 _bpftool_once_attr 'name'
996 return 0
997 ;;
998 esac
999 ;;
1000 subskeleton)
1001 case $prev in
1002 $command)
1003 _filedir
1004 return 0
1005 ;;
1006 *)
1007 _bpftool_once_attr 'name'
1008 return 0
1009 ;;
1010 esac
1011 ;;
1012 min_core_btf)
1013 _filedir
1014 return 0
1015 ;;
1016 *)
1017 [[ $prev == $object ]] && \
1018 COMPREPLY=( $( compgen -W 'object skeleton subskeleton help min_core_btf' -- "$cur" ) )
1019 ;;
1020 esac
1021 ;;
1022 cgroup)
1023 case $command in
1024 show|list|tree)
1025 case $cword in
1026 3)
1027 _filedir
1028 ;;
1029 4)
1030 COMPREPLY=( $( compgen -W 'effective' -- "$cur" ) )
1031 ;;
1032 esac
1033 return 0
1034 ;;
1035 attach|detach)
1036 local BPFTOOL_CGROUP_ATTACH_TYPES="$(bpftool feature list_builtins attach_types 2>/dev/null | \
1037 grep '^cgroup_')"
1038 local ATTACH_FLAGS='multi override'
1039 local PROG_TYPE='id pinned tag name'
1040 # Check for $prev = $command first
1041 if [ $prev = $command ]; then
1042 _filedir
1043 return 0
1044 # Then check for attach type. This is done outside of the
1045 # "case $prev in" to avoid writing the whole list of attach
1046 # types again as pattern to match (where we cannot reuse
1047 # our variable).
1048 elif [[ $BPFTOOL_CGROUP_ATTACH_TYPES =~ $prev ]]; then
1049 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- \
1050 "$cur" ) )
1051 return 0
1052 fi
1053 # case/esac for the other cases
1054 case $prev in
1055 id)
1056 _bpftool_get_prog_ids
1057 return 0
1058 ;;
1059 *)
1060 if ! _bpftool_search_list "$BPFTOOL_CGROUP_ATTACH_TYPES"; then
1061 COMPREPLY=( $( compgen -W \
1062 "$BPFTOOL_CGROUP_ATTACH_TYPES" -- "$cur" ) )
1063 elif [[ "$command" == "attach" ]]; then
1064 # We have an attach type on the command line,
1065 # but it is not the previous word, or
1066 # "id|pinned|tag|name" (we already checked for
1067 # that). This should only leave the case when
1068 # we need attach flags for "attach" commamnd.
1069 _bpftool_one_of_list "$ATTACH_FLAGS"
1070 fi
1071 return 0
1072 ;;
1073 esac
1074 ;;
1075 *)
1076 [[ $prev == $object ]] && \
1077 COMPREPLY=( $( compgen -W 'help attach detach \
1078 show list tree' -- "$cur" ) )
1079 ;;
1080 esac
1081 ;;
1082 perf)
1083 case $command in
1084 *)
1085 [[ $prev == $object ]] && \
1086 COMPREPLY=( $( compgen -W 'help \
1087 show list' -- "$cur" ) )
1088 ;;
1089 esac
1090 ;;
1091 net)
1092 local PROG_TYPE='id pinned tag name'
1093 local ATTACH_TYPES='xdp xdpgeneric xdpdrv xdpoffload'
1094 case $command in
1095 show|list)
1096 [[ $prev != "$command" ]] && return 0
1097 COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
1098 return 0
1099 ;;
1100 attach)
1101 case $cword in
1102 3)
1103 COMPREPLY=( $( compgen -W "$ATTACH_TYPES" -- "$cur" ) )
1104 return 0
1105 ;;
1106 4)
1107 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
1108 return 0
1109 ;;
1110 5)
1111 case $prev in
1112 id)
1113 _bpftool_get_prog_ids
1114 ;;
1115 name)
1116 _bpftool_get_prog_names
1117 ;;
1118 pinned)
1119 _filedir
1120 ;;
1121 esac
1122 return 0
1123 ;;
1124 6)
1125 COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
1126 return 0
1127 ;;
1128 8)
1129 _bpftool_once_attr 'overwrite'
1130 return 0
1131 ;;
1132 esac
1133 ;;
1134 detach)
1135 case $cword in
1136 3)
1137 COMPREPLY=( $( compgen -W "$ATTACH_TYPES" -- "$cur" ) )
1138 return 0
1139 ;;
1140 4)
1141 COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
1142 return 0
1143 ;;
1144 esac
1145 ;;
1146 *)
1147 [[ $prev == $object ]] && \
1148 COMPREPLY=( $( compgen -W 'help \
1149 show list attach detach' -- "$cur" ) )
1150 ;;
1151 esac
1152 ;;
1153 feature)
1154 case $command in
1155 probe)
1156 [[ $prev == "prefix" ]] && return 0
1157 if _bpftool_search_list 'macros'; then
1158 _bpftool_once_attr 'prefix'
1159 else
1160 COMPREPLY+=( $( compgen -W 'macros' -- "$cur" ) )
1161 fi
1162 _bpftool_one_of_list 'kernel dev'
1163 _bpftool_once_attr 'full unprivileged'
1164 return 0
1165 ;;
1166 list_builtins)
1167 [[ $prev != "$command" ]] && return 0
1168 COMPREPLY=( $( compgen -W 'prog_types map_types \
1169 attach_types link_types helpers' -- "$cur" ) )
1170 ;;
1171 *)
1172 [[ $prev == $object ]] && \
1173 COMPREPLY=( $( compgen -W 'help list_builtins probe' -- "$cur" ) )
1174 ;;
1175 esac
1176 ;;
1177 link)
1178 case $command in
1179 show|list|pin|detach)
1180 case $prev in
1181 id)
1182 _bpftool_get_link_ids
1183 return 0
1184 ;;
1185 esac
1186 ;;
1187 esac
1188
1189 local LINK_TYPE='id pinned'
1190 case $command in
1191 show|list)
1192 [[ $prev != "$command" ]] && return 0
1193 COMPREPLY=( $( compgen -W "$LINK_TYPE" -- "$cur" ) )
1194 return 0
1195 ;;
1196 pin|detach)
1197 if [[ $prev == "$command" ]]; then
1198 COMPREPLY=( $( compgen -W "$LINK_TYPE" -- "$cur" ) )
1199 else
1200 _filedir
1201 fi
1202 return 0
1203 ;;
1204 *)
1205 [[ $prev == $object ]] && \
1206 COMPREPLY=( $( compgen -W 'help pin show list' -- "$cur" ) )
1207 ;;
1208 esac
1209 ;;
1210 esac
1211} &&
1212complete -F _bpftool bpftool
1213
1214# ex: ts=4 sw=4 et filetype=sh