Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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 maps
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 nmaps
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 idx 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 cword comp_args
259 local json=0
260 _init_completion -- "$@" || return
261
262 # Deal with options
263 if [[ ${words[cword]} == -* ]]; then
264 local c='--version --json --pretty --bpffs --mapcompat --debug \
265 --use-loader --base-btf --sign -i -k'
266 COMPREPLY=( $( compgen -W "$c" -- "$cur" ) )
267 return 0
268 fi
269 if _bpftool_search_list -j --json -p --pretty; then
270 json=1
271 fi
272
273 # Deal with simplest keywords
274 case $prev in
275 help|hex)
276 return 0
277 ;;
278 tag)
279 _bpftool_get_prog_tags
280 return 0
281 ;;
282 dev|offload_dev|xdpmeta_dev)
283 _sysfs_get_netdevs
284 return 0
285 ;;
286 file|pinned|-B|--base-btf|-i|-k)
287 _filedir
288 return 0
289 ;;
290 batch)
291 COMPREPLY=( $( compgen -W 'file' -- "$cur" ) )
292 return 0
293 ;;
294 esac
295
296 # Remove all options so completions don't have to deal with them.
297 local i pprev
298 for (( i=1; i < ${#words[@]}; )); do
299 case ${words[i]} in
300 # Remove option and its argument
301 -B|--base-btf|-i|-k)
302 words=( "${words[@]:0:i}" "${words[@]:i+2}" )
303 [[ $i -le $(($cword + 1)) ]] && cword=$(( cword - 2 ))
304 ;;
305 # No argument, remove option only
306 -*)
307 words=( "${words[@]:0:i}" "${words[@]:i+1}" )
308 [[ $i -le $cword ]] && cword=$(( cword - 1 ))
309 ;;
310 *)
311 i=$(( ++i ))
312 ;;
313 esac
314 done
315 cur=${words[cword]}
316 prev=${words[cword - 1]}
317 pprev=${words[cword - 2]}
318
319 local object=${words[1]}
320
321 if [[ -z $object || $cword -eq 1 ]]; then
322 case $cur in
323 *)
324 COMPREPLY=( $( compgen -W "$( bpftool help 2>&1 | \
325 command sed \
326 -e '/OBJECT := /!d' \
327 -e 's/.*{//' \
328 -e 's/}.*//' \
329 -e 's/|//g' )" -- "$cur" ) )
330 COMPREPLY+=( $( compgen -W 'batch help' -- "$cur" ) )
331 return 0
332 ;;
333 esac
334 fi
335
336 local command=${words[2]}
337 [[ $command == help ]] && return 0
338
339 local MAP_TYPE='id pinned name'
340 local PROG_TYPE='id pinned tag name'
341
342 # Completion depends on object and command in use
343 case $object in
344 prog)
345 # Complete id and name, only for subcommands that use prog (but no
346 # map) ids/names.
347 case $command in
348 show|list|dump|pin)
349 case $prev in
350 id)
351 _bpftool_get_prog_ids
352 return 0
353 ;;
354 name)
355 _bpftool_get_prog_names
356 return 0
357 ;;
358 esac
359 ;;
360 esac
361
362 local METRIC_TYPE='cycles instructions l1d_loads llc_misses \
363 itlb_misses dtlb_misses'
364 case $command in
365 show|list)
366 [[ $prev != "$command" ]] && return 0
367 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
368 return 0
369 ;;
370 dump)
371 case $prev in
372 $command)
373 COMPREPLY+=( $( compgen -W "xlated jited" -- \
374 "$cur" ) )
375 return 0
376 ;;
377 xlated|jited)
378 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- \
379 "$cur" ) )
380 return 0
381 ;;
382 *)
383 # "file" is not compatible with other keywords here
384 if _bpftool_search_list 'file'; then
385 return 0
386 fi
387 if ! _bpftool_search_list 'linum opcodes visual'; then
388 _bpftool_once_attr 'file'
389 fi
390 _bpftool_once_attr 'linum opcodes'
391 if _bpftool_search_list 'xlated' && [[ "$json" == 0 ]]; then
392 _bpftool_once_attr 'visual'
393 fi
394 return 0
395 ;;
396 esac
397 ;;
398 pin)
399 if [[ $prev == "$command" ]]; then
400 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
401 else
402 _filedir
403 fi
404 return 0
405 ;;
406 attach|detach)
407 case $cword in
408 3)
409 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
410 return 0
411 ;;
412 4)
413 case $prev in
414 id)
415 _bpftool_get_prog_ids
416 ;;
417 name)
418 _bpftool_get_prog_names
419 ;;
420 pinned)
421 _filedir
422 ;;
423 esac
424 return 0
425 ;;
426 5)
427 local BPFTOOL_PROG_ATTACH_TYPES='sk_msg_verdict \
428 sk_skb_verdict sk_skb_stream_verdict sk_skb_stream_parser \
429 flow_dissector'
430 COMPREPLY=( $( compgen -W "$BPFTOOL_PROG_ATTACH_TYPES" -- "$cur" ) )
431 return 0
432 ;;
433 6)
434 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
435 return 0
436 ;;
437 7)
438 case $prev in
439 id)
440 _bpftool_get_map_ids
441 ;;
442 name)
443 _bpftool_get_map_names
444 ;;
445 pinned)
446 _filedir
447 ;;
448 esac
449 return 0
450 ;;
451 esac
452 ;;
453 load|loadall)
454 local obj
455
456 # Propose "load/loadall" to complete "bpftool prog load",
457 # or bash tries to complete "load" as a filename below.
458 if [[ ${#words[@]} -eq 3 ]]; then
459 COMPREPLY=( $( compgen -W "load loadall" -- "$cur" ) )
460 return 0
461 fi
462
463 if [[ ${#words[@]} -lt 6 ]]; then
464 _filedir
465 return 0
466 fi
467
468 obj=${words[3]}
469
470 if [[ ${words[-4]} == "map" ]]; then
471 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
472 return 0
473 fi
474 if [[ ${words[-3]} == "map" ]]; then
475 if [[ ${words[-2]} == "idx" ]]; then
476 _bpftool_get_obj_map_idxs $obj
477 elif [[ ${words[-2]} == "name" ]]; then
478 _bpftool_get_obj_map_names $obj
479 fi
480 return 0
481 fi
482 if [[ ${words[-2]} == "map" ]]; then
483 COMPREPLY=( $( compgen -W "idx name" -- "$cur" ) )
484 return 0
485 fi
486
487 case $prev in
488 type)
489 local BPFTOOL_PROG_LOAD_TYPES='socket kprobe \
490 kretprobe classifier flow_dissector \
491 action tracepoint raw_tracepoint \
492 xdp perf_event cgroup/skb cgroup/sock \
493 cgroup/dev lwt_in lwt_out lwt_xmit \
494 lwt_seg6local sockops sk_skb sk_msg lirc_mode2 \
495 cgroup/bind4 cgroup/bind6 \
496 cgroup/connect4 cgroup/connect6 cgroup/connect_unix \
497 cgroup/getpeername4 cgroup/getpeername6 cgroup/getpeername_unix \
498 cgroup/getsockname4 cgroup/getsockname6 cgroup/getsockname_unix \
499 cgroup/sendmsg4 cgroup/sendmsg6 cgroup/sendmsg_unix \
500 cgroup/recvmsg4 cgroup/recvmsg6 cgroup/recvmsg_unix \
501 cgroup/post_bind4 cgroup/post_bind6 \
502 cgroup/sysctl cgroup/getsockopt \
503 cgroup/setsockopt cgroup/sock_release struct_ops \
504 fentry fexit freplace sk_lookup'
505 COMPREPLY=( $( compgen -W "$BPFTOOL_PROG_LOAD_TYPES" -- "$cur" ) )
506 return 0
507 ;;
508 id)
509 _bpftool_get_map_ids
510 return 0
511 ;;
512 name)
513 _bpftool_get_map_names
514 return 0
515 ;;
516 pinned|pinmaps|kernel_btf)
517 _filedir
518 return 0
519 ;;
520 *)
521 COMPREPLY=( $( compgen -W "map" -- "$cur" ) )
522 _bpftool_once_attr 'type pinmaps autoattach kernel_btf'
523 _bpftool_one_of_list 'offload_dev xdpmeta_dev'
524 return 0
525 ;;
526 esac
527 ;;
528 tracelog)
529 case $prev in
530 $command)
531 COMPREPLY+=( $( compgen -W "stdout stderr" -- \
532 "$cur" ) )
533 return 0
534 ;;
535 stdout|stderr)
536 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- \
537 "$cur" ) )
538 return 0
539 ;;
540 *)
541 return 0
542 ;;
543 esac
544 ;;
545 profile)
546 case $cword in
547 3)
548 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
549 return 0
550 ;;
551 4)
552 case $prev in
553 id)
554 _bpftool_get_prog_ids
555 ;;
556 name)
557 _bpftool_get_prog_names
558 ;;
559 pinned)
560 _filedir
561 ;;
562 esac
563 return 0
564 ;;
565 5)
566 COMPREPLY=( $( compgen -W "$METRIC_TYPE duration" -- "$cur" ) )
567 return 0
568 ;;
569 *)
570 [[ $prev == duration ]] && return 0
571 _bpftool_once_attr "$METRIC_TYPE"
572 return 0
573 ;;
574 esac
575 ;;
576 run)
577 if [[ ${#words[@]} -eq 4 ]]; then
578 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
579 return 0
580 fi
581 case $prev in
582 id)
583 _bpftool_get_prog_ids
584 return 0
585 ;;
586 name)
587 _bpftool_get_prog_names
588 return 0
589 ;;
590 data_in|data_out|ctx_in|ctx_out)
591 _filedir
592 return 0
593 ;;
594 repeat|data_size_out|ctx_size_out)
595 return 0
596 ;;
597 *)
598 _bpftool_once_attr 'data_in data_out data_size_out \
599 ctx_in ctx_out ctx_size_out repeat'
600 return 0
601 ;;
602 esac
603 ;;
604 *)
605 [[ $prev == $object ]] && \
606 COMPREPLY=( $( compgen -W 'dump help pin attach detach \
607 load loadall show list tracelog run profile' -- "$cur" ) )
608 ;;
609 esac
610 ;;
611 struct_ops)
612 local STRUCT_OPS_TYPE='id name'
613 case $command in
614 show|list|dump|unregister)
615 case $prev in
616 $command)
617 COMPREPLY=( $( compgen -W "$STRUCT_OPS_TYPE" -- "$cur" ) )
618 ;;
619 id)
620 _bpftool_get_map_ids_for_type struct_ops
621 ;;
622 name)
623 _bpftool_get_map_names_for_type struct_ops
624 ;;
625 esac
626 return 0
627 ;;
628 register)
629 [[ $prev == $command ]] && _filedir
630 return 0
631 ;;
632 *)
633 [[ $prev == $object ]] && \
634 COMPREPLY=( $( compgen -W 'register unregister show list dump help' \
635 -- "$cur" ) )
636 ;;
637 esac
638 ;;
639 iter)
640 case $command in
641 pin)
642 case $prev in
643 $command)
644 _filedir
645 ;;
646 id)
647 _bpftool_get_map_ids
648 ;;
649 name)
650 _bpftool_get_map_names
651 ;;
652 pinned)
653 _filedir
654 ;;
655 map)
656 _bpftool_one_of_list $MAP_TYPE
657 ;;
658 *)
659 _bpftool_once_attr 'map'
660 ;;
661 esac
662 return 0
663 ;;
664 *)
665 [[ $prev == $object ]] && \
666 COMPREPLY=( $( compgen -W 'pin help' \
667 -- "$cur" ) )
668 ;;
669 esac
670 ;;
671 map)
672 case $command in
673 show|list|dump|peek|pop|dequeue|freeze)
674 case $prev in
675 $command)
676 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
677 return 0
678 ;;
679 id)
680 case "$command" in
681 peek)
682 _bpftool_get_map_ids_for_type stack
683 _bpftool_get_map_ids_for_type queue
684 ;;
685 pop)
686 _bpftool_get_map_ids_for_type stack
687 ;;
688 dequeue)
689 _bpftool_get_map_ids_for_type queue
690 ;;
691 *)
692 _bpftool_get_map_ids
693 ;;
694 esac
695 return 0
696 ;;
697 name)
698 case "$command" in
699 peek)
700 _bpftool_get_map_names_for_type stack
701 _bpftool_get_map_names_for_type queue
702 ;;
703 pop)
704 _bpftool_get_map_names_for_type stack
705 ;;
706 dequeue)
707 _bpftool_get_map_names_for_type queue
708 ;;
709 *)
710 _bpftool_get_map_names
711 ;;
712 esac
713 return 0
714 ;;
715 *)
716 return 0
717 ;;
718 esac
719 ;;
720 create)
721 case $prev in
722 $command)
723 _filedir
724 return 0
725 ;;
726 type)
727 local BPFTOOL_MAP_CREATE_TYPES="$(bpftool feature list_builtins map_types 2>/dev/null | \
728 grep -v '^unspec$')"
729 COMPREPLY=( $( compgen -W "$BPFTOOL_MAP_CREATE_TYPES" -- "$cur" ) )
730 return 0
731 ;;
732 key|value|flags|entries)
733 return 0
734 ;;
735 inner_map)
736 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
737 return 0
738 ;;
739 id)
740 _bpftool_get_map_ids
741 ;;
742 name)
743 case $pprev in
744 inner_map)
745 _bpftool_get_map_names
746 ;;
747 *)
748 return 0
749 ;;
750 esac
751 ;;
752 *)
753 _bpftool_once_attr 'type key value entries name flags offload_dev'
754 if _bpftool_search_list 'array_of_maps' 'hash_of_maps'; then
755 _bpftool_once_attr 'inner_map'
756 fi
757 return 0
758 ;;
759 esac
760 ;;
761 lookup|getnext|delete)
762 case $prev in
763 $command)
764 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
765 return 0
766 ;;
767 id)
768 _bpftool_get_map_ids
769 return 0
770 ;;
771 name)
772 _bpftool_get_map_names
773 return 0
774 ;;
775 key)
776 COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) )
777 ;;
778 *)
779 case $(_bpftool_map_guess_map_type) in
780 queue|stack)
781 return 0
782 ;;
783 esac
784
785 _bpftool_once_attr 'key'
786 return 0
787 ;;
788 esac
789 ;;
790 update|push|enqueue)
791 case $prev in
792 $command)
793 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
794 return 0
795 ;;
796 id)
797 _bpftool_map_update_get_id $command
798 return 0
799 ;;
800 name)
801 _bpftool_map_update_get_name $command
802 return 0
803 ;;
804 key)
805 COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) )
806 ;;
807 value)
808 # We can have bytes, or references to a prog or a
809 # map, depending on the type of the map to update.
810 case "$(_bpftool_map_guess_map_type)" in
811 array_of_maps|hash_of_maps)
812 COMPREPLY+=( $( compgen -W "$MAP_TYPE" \
813 -- "$cur" ) )
814 return 0
815 ;;
816 prog_array)
817 COMPREPLY+=( $( compgen -W "$PROG_TYPE" \
818 -- "$cur" ) )
819 return 0
820 ;;
821 *)
822 COMPREPLY+=( $( compgen -W 'hex' \
823 -- "$cur" ) )
824 return 0
825 ;;
826 esac
827 return 0
828 ;;
829 *)
830 case $(_bpftool_map_guess_map_type) in
831 queue|stack)
832 _bpftool_once_attr 'value'
833 return 0;
834 ;;
835 esac
836
837 _bpftool_once_attr 'key'
838 local UPDATE_FLAGS='any exist noexist' idx
839 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
840 if [[ ${words[idx]} == 'value' ]]; then
841 # 'value' is present, but is not the last
842 # word i.e. we can now have UPDATE_FLAGS.
843 _bpftool_one_of_list "$UPDATE_FLAGS"
844 return 0
845 fi
846 done
847 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
848 if [[ ${words[idx]} == 'key' ]]; then
849 # 'key' is present, but is not the last
850 # word i.e. we can now have 'value'.
851 _bpftool_once_attr 'value'
852 return 0
853 fi
854 done
855
856 return 0
857 ;;
858 esac
859 ;;
860 pin)
861 case $prev in
862 $command)
863 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
864 ;;
865 id)
866 _bpftool_get_map_ids
867 ;;
868 name)
869 _bpftool_get_map_names
870 ;;
871 esac
872 return 0
873 ;;
874 event_pipe)
875 case $prev in
876 $command)
877 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
878 return 0
879 ;;
880 id)
881 _bpftool_get_map_ids_for_type perf_event_array
882 return 0
883 ;;
884 name)
885 _bpftool_get_map_names_for_type perf_event_array
886 return 0
887 ;;
888 cpu)
889 return 0
890 ;;
891 index)
892 return 0
893 ;;
894 *)
895 _bpftool_once_attr 'cpu index'
896 return 0
897 ;;
898 esac
899 ;;
900 *)
901 [[ $prev == $object ]] && \
902 COMPREPLY=( $( compgen -W 'delete dump getnext help \
903 lookup pin event_pipe show list update create \
904 peek push enqueue pop dequeue freeze' -- \
905 "$cur" ) )
906 ;;
907 esac
908 ;;
909 btf)
910 local MAP_TYPE='id pinned name'
911 case $command in
912 dump)
913 case $prev in
914 $command)
915 COMPREPLY+=( $( compgen -W "id map prog file" -- \
916 "$cur" ) )
917 return 0
918 ;;
919 prog)
920 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
921 return 0
922 ;;
923 map)
924 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
925 return 0
926 ;;
927 id)
928 case $pprev in
929 prog)
930 _bpftool_get_prog_ids
931 ;;
932 map)
933 _bpftool_get_map_ids
934 ;;
935 $command)
936 _bpftool_get_btf_ids
937 ;;
938 esac
939 return 0
940 ;;
941 name)
942 case $pprev in
943 prog)
944 _bpftool_get_prog_names
945 ;;
946 map)
947 _bpftool_get_map_names
948 ;;
949 esac
950 return 0
951 ;;
952 format)
953 COMPREPLY=( $( compgen -W "c raw" -- "$cur" ) )
954 ;;
955 root_id)
956 return 0;
957 ;;
958 c)
959 COMPREPLY=( $( compgen -W "unsorted root_id" -- "$cur" ) )
960 ;;
961 *)
962 # emit extra options
963 case ${words[3]} in
964 id|file)
965 COMPREPLY=( $( compgen -W "root_id" -- "$cur" ) )
966 _bpftool_once_attr 'format'
967 ;;
968 map|prog)
969 if [[ ${words[3]} == "map" ]] && [[ $cword == 6 ]]; then
970 COMPREPLY+=( $( compgen -W "key value kv all" -- "$cur" ) )
971 fi
972 COMPREPLY=( $( compgen -W "root_id" -- "$cur" ) )
973 _bpftool_once_attr 'format'
974 ;;
975 *)
976 ;;
977 esac
978 return 0
979 ;;
980 esac
981 ;;
982 show|list)
983 case $prev in
984 $command)
985 COMPREPLY+=( $( compgen -W "id" -- "$cur" ) )
986 ;;
987 id)
988 _bpftool_get_btf_ids
989 ;;
990 esac
991 return 0
992 ;;
993 *)
994 [[ $prev == $object ]] && \
995 COMPREPLY=( $( compgen -W 'dump help show list' \
996 -- "$cur" ) )
997 ;;
998 esac
999 ;;
1000 gen)
1001 case $command in
1002 object)
1003 _filedir
1004 return 0
1005 ;;
1006 skeleton)
1007 case $prev in
1008 $command)
1009 _filedir
1010 return 0
1011 ;;
1012 *)
1013 _bpftool_once_attr 'name'
1014 return 0
1015 ;;
1016 esac
1017 ;;
1018 subskeleton)
1019 case $prev in
1020 $command)
1021 _filedir
1022 return 0
1023 ;;
1024 *)
1025 _bpftool_once_attr 'name'
1026 return 0
1027 ;;
1028 esac
1029 ;;
1030 min_core_btf)
1031 _filedir
1032 return 0
1033 ;;
1034 *)
1035 [[ $prev == $object ]] && \
1036 COMPREPLY=( $( compgen -W 'object skeleton subskeleton help min_core_btf' -- "$cur" ) )
1037 ;;
1038 esac
1039 ;;
1040 cgroup)
1041 case $command in
1042 show|list|tree)
1043 case $cword in
1044 3)
1045 _filedir
1046 ;;
1047 4)
1048 COMPREPLY=( $( compgen -W 'effective' -- "$cur" ) )
1049 ;;
1050 esac
1051 return 0
1052 ;;
1053 attach|detach)
1054 local BPFTOOL_CGROUP_ATTACH_TYPES="$(bpftool feature list_builtins attach_types 2>/dev/null | \
1055 grep '^cgroup_')"
1056 local ATTACH_FLAGS='multi override'
1057 # Check for $prev = $command first
1058 if [ $prev = $command ]; then
1059 _filedir
1060 return 0
1061 # Then check for attach type. This is done outside of the
1062 # "case $prev in" to avoid writing the whole list of attach
1063 # types again as pattern to match (where we cannot reuse
1064 # our variable).
1065 elif [[ $BPFTOOL_CGROUP_ATTACH_TYPES =~ $prev ]]; then
1066 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- \
1067 "$cur" ) )
1068 return 0
1069 fi
1070 # case/esac for the other cases
1071 case $prev in
1072 id)
1073 _bpftool_get_prog_ids
1074 return 0
1075 ;;
1076 *)
1077 if ! _bpftool_search_list "$BPFTOOL_CGROUP_ATTACH_TYPES"; then
1078 COMPREPLY=( $( compgen -W \
1079 "$BPFTOOL_CGROUP_ATTACH_TYPES" -- "$cur" ) )
1080 elif [[ "$command" == "attach" ]]; then
1081 # We have an attach type on the command line,
1082 # but it is not the previous word, or
1083 # "id|pinned|tag|name" (we already checked for
1084 # that). This should only leave the case when
1085 # we need attach flags for "attach" commamnd.
1086 _bpftool_one_of_list "$ATTACH_FLAGS"
1087 fi
1088 return 0
1089 ;;
1090 esac
1091 ;;
1092 *)
1093 [[ $prev == $object ]] && \
1094 COMPREPLY=( $( compgen -W 'help attach detach \
1095 show list tree' -- "$cur" ) )
1096 ;;
1097 esac
1098 ;;
1099 perf)
1100 case $command in
1101 *)
1102 [[ $prev == $object ]] && \
1103 COMPREPLY=( $( compgen -W 'help \
1104 show list' -- "$cur" ) )
1105 ;;
1106 esac
1107 ;;
1108 net)
1109 local ATTACH_TYPES='xdp xdpgeneric xdpdrv xdpoffload tcx_ingress tcx_egress'
1110 case $command in
1111 show|list)
1112 [[ $prev != "$command" ]] && return 0
1113 COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
1114 return 0
1115 ;;
1116 attach)
1117 case $cword in
1118 3)
1119 COMPREPLY=( $( compgen -W "$ATTACH_TYPES" -- "$cur" ) )
1120 return 0
1121 ;;
1122 4)
1123 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
1124 return 0
1125 ;;
1126 5)
1127 case $prev in
1128 id)
1129 _bpftool_get_prog_ids
1130 ;;
1131 name)
1132 _bpftool_get_prog_names
1133 ;;
1134 pinned)
1135 _filedir
1136 ;;
1137 esac
1138 return 0
1139 ;;
1140 6)
1141 COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
1142 return 0
1143 ;;
1144 8)
1145 _bpftool_once_attr 'overwrite'
1146 return 0
1147 ;;
1148 esac
1149 ;;
1150 detach)
1151 case $cword in
1152 3)
1153 COMPREPLY=( $( compgen -W "$ATTACH_TYPES" -- "$cur" ) )
1154 return 0
1155 ;;
1156 4)
1157 COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
1158 return 0
1159 ;;
1160 esac
1161 ;;
1162 *)
1163 [[ $prev == $object ]] && \
1164 COMPREPLY=( $( compgen -W 'help \
1165 show list attach detach' -- "$cur" ) )
1166 ;;
1167 esac
1168 ;;
1169 feature)
1170 case $command in
1171 probe)
1172 [[ $prev == "prefix" ]] && return 0
1173 if _bpftool_search_list 'macros'; then
1174 _bpftool_once_attr 'prefix'
1175 else
1176 COMPREPLY+=( $( compgen -W 'macros' -- "$cur" ) )
1177 fi
1178 _bpftool_one_of_list 'kernel dev'
1179 _bpftool_once_attr 'full unprivileged'
1180 return 0
1181 ;;
1182 list_builtins)
1183 [[ $prev != "$command" ]] && return 0
1184 COMPREPLY=( $( compgen -W 'prog_types map_types \
1185 attach_types link_types helpers' -- "$cur" ) )
1186 ;;
1187 *)
1188 [[ $prev == $object ]] && \
1189 COMPREPLY=( $( compgen -W 'help list_builtins probe' -- "$cur" ) )
1190 ;;
1191 esac
1192 ;;
1193 link)
1194 case $command in
1195 show|list|pin|detach)
1196 case $prev in
1197 id)
1198 _bpftool_get_link_ids
1199 return 0
1200 ;;
1201 esac
1202 ;;
1203 esac
1204
1205 local LINK_TYPE='id pinned'
1206 case $command in
1207 show|list)
1208 [[ $prev != "$command" ]] && return 0
1209 COMPREPLY=( $( compgen -W "$LINK_TYPE" -- "$cur" ) )
1210 return 0
1211 ;;
1212 pin|detach)
1213 if [[ $prev == "$command" ]]; then
1214 COMPREPLY=( $( compgen -W "$LINK_TYPE" -- "$cur" ) )
1215 elif [[ $pprev == "$command" ]]; then
1216 _filedir
1217 fi
1218 return 0
1219 ;;
1220 *)
1221 [[ $prev == $object ]] && \
1222 COMPREPLY=( $( compgen -W 'help pin detach show list' -- "$cur" ) )
1223 ;;
1224 esac
1225 ;;
1226 token)
1227 case $command in
1228 show|list)
1229 return 0
1230 ;;
1231 *)
1232 [[ $prev == $object ]] && \
1233 COMPREPLY=( $( compgen -W 'help show list' -- "$cur" ) )
1234 ;;
1235 esac
1236 ;;
1237 esac
1238} &&
1239complete -F _bpftool bpftool
1240
1241# ex: ts=4 sw=4 et filetype=sh