]> git.ipfire.org Git - thirdparty/kernel/stable.git/blob - tools/bpf/bpftool/bash-completion/bpftool
Merge tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git...
[thirdparty/kernel/stable.git] / tools / bpf / bpftool / bash-completion / bpftool
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_prog_ids()
63 {
64 COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \
65 command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) )
66 }
67
68 _bpftool_get_prog_tags()
69 {
70 COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \
71 command sed -n 's/.*"tag": "\(.*\)",$/\1/p' )" -- "$cur" ) )
72 }
73
74 _bpftool_get_obj_map_names()
75 {
76 local obj
77
78 obj=$1
79
80 maps=$(objdump -j maps -t $obj 2>/dev/null | \
81 command awk '/g . maps/ {print $NF}')
82
83 COMPREPLY+=( $( compgen -W "$maps" -- "$cur" ) )
84 }
85
86 _bpftool_get_obj_map_idxs()
87 {
88 local obj
89
90 obj=$1
91
92 nmaps=$(objdump -j maps -t $obj 2>/dev/null | grep -c 'g . maps')
93
94 COMPREPLY+=( $( compgen -W "$(seq 0 $((nmaps - 1)))" -- "$cur" ) )
95 }
96
97 _sysfs_get_netdevs()
98 {
99 COMPREPLY+=( $( compgen -W "$( ls /sys/class/net 2>/dev/null )" -- \
100 "$cur" ) )
101 }
102
103 # Retrieve type of the map that we are operating on.
104 _bpftool_map_guess_map_type()
105 {
106 local keyword ref
107 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
108 case "${words[$((idx-2))]}" in
109 lookup|update)
110 keyword=${words[$((idx-1))]}
111 ref=${words[$((idx))]}
112 ;;
113 push)
114 printf "stack"
115 return 0
116 ;;
117 enqueue)
118 printf "queue"
119 return 0
120 ;;
121 esac
122 done
123 [[ -z $ref ]] && return 0
124
125 local type
126 type=$(bpftool -jp map show $keyword $ref | \
127 command sed -n 's/.*"type": "\(.*\)",$/\1/p')
128 [[ -n $type ]] && printf $type
129 }
130
131 _bpftool_map_update_get_id()
132 {
133 local command="$1"
134
135 # Is it the map to update, or a map to insert into the map to update?
136 # Search for "value" keyword.
137 local idx value
138 for (( idx=7; idx < ${#words[@]}-1; idx++ )); do
139 if [[ ${words[idx]} == "value" ]]; then
140 value=1
141 break
142 fi
143 done
144 if [[ $value -eq 0 ]]; then
145 case "$command" in
146 push)
147 _bpftool_get_map_ids_for_type stack
148 ;;
149 enqueue)
150 _bpftool_get_map_ids_for_type queue
151 ;;
152 *)
153 _bpftool_get_map_ids
154 ;;
155 esac
156 return 0
157 fi
158
159 # Id to complete is for a value. It can be either prog id or map id. This
160 # depends on the type of the map to update.
161 local type=$(_bpftool_map_guess_map_type)
162 case $type in
163 array_of_maps|hash_of_maps)
164 _bpftool_get_map_ids
165 return 0
166 ;;
167 prog_array)
168 _bpftool_get_prog_ids
169 return 0
170 ;;
171 *)
172 return 0
173 ;;
174 esac
175 }
176
177 _bpftool()
178 {
179 local cur prev words objword
180 _init_completion || return
181
182 # Deal with options
183 if [[ ${words[cword]} == -* ]]; then
184 local c='--version --json --pretty --bpffs --mapcompat'
185 COMPREPLY=( $( compgen -W "$c" -- "$cur" ) )
186 return 0
187 fi
188
189 # Deal with simplest keywords
190 case $prev in
191 help|hex|opcodes|visual|linum)
192 return 0
193 ;;
194 tag)
195 _bpftool_get_prog_tags
196 return 0
197 ;;
198 file|pinned)
199 _filedir
200 return 0
201 ;;
202 batch)
203 COMPREPLY=( $( compgen -W 'file' -- "$cur" ) )
204 return 0
205 ;;
206 esac
207
208 # Remove all options so completions don't have to deal with them.
209 local i
210 for (( i=1; i < ${#words[@]}; )); do
211 if [[ ${words[i]::1} == - ]]; then
212 words=( "${words[@]:0:i}" "${words[@]:i+1}" )
213 [[ $i -le $cword ]] && cword=$(( cword - 1 ))
214 else
215 i=$(( ++i ))
216 fi
217 done
218 cur=${words[cword]}
219 prev=${words[cword - 1]}
220 pprev=${words[cword - 2]}
221
222 local object=${words[1]} command=${words[2]}
223
224 if [[ -z $object || $cword -eq 1 ]]; then
225 case $cur in
226 *)
227 COMPREPLY=( $( compgen -W "$( bpftool help 2>&1 | \
228 command sed \
229 -e '/OBJECT := /!d' \
230 -e 's/.*{//' \
231 -e 's/}.*//' \
232 -e 's/|//g' )" -- "$cur" ) )
233 COMPREPLY+=( $( compgen -W 'batch help' -- "$cur" ) )
234 return 0
235 ;;
236 esac
237 fi
238
239 [[ $command == help ]] && return 0
240
241 # Completion depends on object and command in use
242 case $object in
243 prog)
244 # Complete id, only for subcommands that use prog (but no map) ids
245 case $command in
246 show|list|dump|pin)
247 case $prev in
248 id)
249 _bpftool_get_prog_ids
250 return 0
251 ;;
252 esac
253 ;;
254 esac
255
256 local PROG_TYPE='id pinned tag'
257 local MAP_TYPE='id pinned'
258 case $command in
259 show|list)
260 [[ $prev != "$command" ]] && return 0
261 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
262 return 0
263 ;;
264 dump)
265 case $prev in
266 $command)
267 COMPREPLY+=( $( compgen -W "xlated jited" -- \
268 "$cur" ) )
269 return 0
270 ;;
271 xlated|jited)
272 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- \
273 "$cur" ) )
274 return 0
275 ;;
276 *)
277 _bpftool_once_attr 'file'
278 if _bpftool_search_list 'xlated'; then
279 COMPREPLY+=( $( compgen -W 'opcodes visual linum' -- \
280 "$cur" ) )
281 else
282 COMPREPLY+=( $( compgen -W 'opcodes linum' -- \
283 "$cur" ) )
284 fi
285 return 0
286 ;;
287 esac
288 ;;
289 pin)
290 if [[ $prev == "$command" ]]; then
291 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
292 else
293 _filedir
294 fi
295 return 0
296 ;;
297 attach|detach)
298 case $cword in
299 3)
300 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
301 return 0
302 ;;
303 4)
304 case $prev in
305 id)
306 _bpftool_get_prog_ids
307 ;;
308 pinned)
309 _filedir
310 ;;
311 esac
312 return 0
313 ;;
314 5)
315 COMPREPLY=( $( compgen -W 'msg_verdict stream_verdict \
316 stream_parser flow_dissector' -- "$cur" ) )
317 return 0
318 ;;
319 6)
320 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
321 return 0
322 ;;
323 7)
324 case $prev in
325 id)
326 _bpftool_get_map_ids
327 ;;
328 pinned)
329 _filedir
330 ;;
331 esac
332 return 0
333 ;;
334 esac
335 ;;
336 load|loadall)
337 local obj
338
339 if [[ ${#words[@]} -lt 6 ]]; then
340 _filedir
341 return 0
342 fi
343
344 obj=${words[3]}
345
346 if [[ ${words[-4]} == "map" ]]; then
347 COMPREPLY=( $( compgen -W "id pinned" -- "$cur" ) )
348 return 0
349 fi
350 if [[ ${words[-3]} == "map" ]]; then
351 if [[ ${words[-2]} == "idx" ]]; then
352 _bpftool_get_obj_map_idxs $obj
353 elif [[ ${words[-2]} == "name" ]]; then
354 _bpftool_get_obj_map_names $obj
355 fi
356 return 0
357 fi
358 if [[ ${words[-2]} == "map" ]]; then
359 COMPREPLY=( $( compgen -W "idx name" -- "$cur" ) )
360 return 0
361 fi
362
363 case $prev in
364 type)
365 COMPREPLY=( $( compgen -W "socket kprobe \
366 kretprobe classifier flow_dissector \
367 action tracepoint raw_tracepoint \
368 xdp perf_event cgroup/skb cgroup/sock \
369 cgroup/dev lwt_in lwt_out lwt_xmit \
370 lwt_seg6local sockops sk_skb sk_msg \
371 lirc_mode2 cgroup/bind4 cgroup/bind6 \
372 cgroup/connect4 cgroup/connect6 \
373 cgroup/sendmsg4 cgroup/sendmsg6 \
374 cgroup/post_bind4 cgroup/post_bind6 \
375 cgroup/sysctl" -- \
376 "$cur" ) )
377 return 0
378 ;;
379 id)
380 _bpftool_get_map_ids
381 return 0
382 ;;
383 pinned|pinmaps)
384 _filedir
385 return 0
386 ;;
387 dev)
388 _sysfs_get_netdevs
389 return 0
390 ;;
391 *)
392 COMPREPLY=( $( compgen -W "map" -- "$cur" ) )
393 _bpftool_once_attr 'type'
394 _bpftool_once_attr 'dev'
395 _bpftool_once_attr 'pinmaps'
396 return 0
397 ;;
398 esac
399 ;;
400 tracelog)
401 return 0
402 ;;
403 *)
404 [[ $prev == $object ]] && \
405 COMPREPLY=( $( compgen -W 'dump help pin attach detach load \
406 show list tracelog' -- "$cur" ) )
407 ;;
408 esac
409 ;;
410 map)
411 local MAP_TYPE='id pinned'
412 case $command in
413 show|list|dump|peek|pop|dequeue)
414 case $prev in
415 $command)
416 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
417 return 0
418 ;;
419 id)
420 case "$command" in
421 peek)
422 _bpftool_get_map_ids_for_type stack
423 _bpftool_get_map_ids_for_type queue
424 ;;
425 pop)
426 _bpftool_get_map_ids_for_type stack
427 ;;
428 dequeue)
429 _bpftool_get_map_ids_for_type queue
430 ;;
431 *)
432 _bpftool_get_map_ids
433 ;;
434 esac
435 return 0
436 ;;
437 *)
438 return 0
439 ;;
440 esac
441 ;;
442 create)
443 case $prev in
444 $command)
445 _filedir
446 return 0
447 ;;
448 type)
449 COMPREPLY=( $( compgen -W 'hash array prog_array \
450 perf_event_array percpu_hash percpu_array \
451 stack_trace cgroup_array lru_hash \
452 lru_percpu_hash lpm_trie array_of_maps \
453 hash_of_maps devmap sockmap cpumap xskmap \
454 sockhash cgroup_storage reuseport_sockarray \
455 percpu_cgroup_storage queue stack' -- \
456 "$cur" ) )
457 return 0
458 ;;
459 key|value|flags|name|entries)
460 return 0
461 ;;
462 dev)
463 _sysfs_get_netdevs
464 return 0
465 ;;
466 *)
467 _bpftool_once_attr 'type'
468 _bpftool_once_attr 'key'
469 _bpftool_once_attr 'value'
470 _bpftool_once_attr 'entries'
471 _bpftool_once_attr 'name'
472 _bpftool_once_attr 'flags'
473 _bpftool_once_attr 'dev'
474 return 0
475 ;;
476 esac
477 ;;
478 lookup|getnext|delete)
479 case $prev in
480 $command)
481 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
482 return 0
483 ;;
484 id)
485 _bpftool_get_map_ids
486 return 0
487 ;;
488 key)
489 COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) )
490 ;;
491 *)
492 case $(_bpftool_map_guess_map_type) in
493 queue|stack)
494 return 0
495 ;;
496 esac
497
498 _bpftool_once_attr 'key'
499 return 0
500 ;;
501 esac
502 ;;
503 update|push|enqueue)
504 case $prev in
505 $command)
506 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
507 return 0
508 ;;
509 id)
510 _bpftool_map_update_get_id $command
511 return 0
512 ;;
513 key)
514 COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) )
515 ;;
516 value)
517 # We can have bytes, or references to a prog or a
518 # map, depending on the type of the map to update.
519 case "$(_bpftool_map_guess_map_type)" in
520 array_of_maps|hash_of_maps)
521 local MAP_TYPE='id pinned'
522 COMPREPLY+=( $( compgen -W "$MAP_TYPE" \
523 -- "$cur" ) )
524 return 0
525 ;;
526 prog_array)
527 local PROG_TYPE='id pinned tag'
528 COMPREPLY+=( $( compgen -W "$PROG_TYPE" \
529 -- "$cur" ) )
530 return 0
531 ;;
532 *)
533 COMPREPLY+=( $( compgen -W 'hex' \
534 -- "$cur" ) )
535 return 0
536 ;;
537 esac
538 return 0
539 ;;
540 *)
541 case $(_bpftool_map_guess_map_type) in
542 queue|stack)
543 _bpftool_once_attr 'value'
544 return 0;
545 ;;
546 esac
547
548 _bpftool_once_attr 'key'
549 local UPDATE_FLAGS='any exist noexist'
550 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
551 if [[ ${words[idx]} == 'value' ]]; then
552 # 'value' is present, but is not the last
553 # word i.e. we can now have UPDATE_FLAGS.
554 _bpftool_one_of_list "$UPDATE_FLAGS"
555 return 0
556 fi
557 done
558 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
559 if [[ ${words[idx]} == 'key' ]]; then
560 # 'key' is present, but is not the last
561 # word i.e. we can now have 'value'.
562 _bpftool_once_attr 'value'
563 return 0
564 fi
565 done
566
567 return 0
568 ;;
569 esac
570 ;;
571 pin)
572 if [[ $prev == "$command" ]]; then
573 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
574 else
575 _filedir
576 fi
577 return 0
578 ;;
579 event_pipe)
580 case $prev in
581 $command)
582 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
583 return 0
584 ;;
585 id)
586 _bpftool_get_map_ids_for_type perf_event_array
587 return 0
588 ;;
589 cpu)
590 return 0
591 ;;
592 index)
593 return 0
594 ;;
595 *)
596 _bpftool_once_attr 'cpu'
597 _bpftool_once_attr 'index'
598 return 0
599 ;;
600 esac
601 ;;
602 *)
603 [[ $prev == $object ]] && \
604 COMPREPLY=( $( compgen -W 'delete dump getnext help \
605 lookup pin event_pipe show list update create \
606 peek push enqueue pop dequeue' -- \
607 "$cur" ) )
608 ;;
609 esac
610 ;;
611 btf)
612 local PROG_TYPE='id pinned tag'
613 local MAP_TYPE='id pinned'
614 case $command in
615 dump)
616 case $prev in
617 $command)
618 COMPREPLY+=( $( compgen -W "id map prog file" -- \
619 "$cur" ) )
620 return 0
621 ;;
622 prog)
623 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
624 return 0
625 ;;
626 map)
627 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) )
628 return 0
629 ;;
630 id)
631 case $pprev in
632 prog)
633 _bpftool_get_prog_ids
634 ;;
635 map)
636 _bpftool_get_map_ids
637 ;;
638 esac
639 return 0
640 ;;
641 *)
642 if [[ $cword == 6 ]] && [[ ${words[3]} == "map" ]]; then
643 COMPREPLY+=( $( compgen -W 'key value kv all' -- \
644 "$cur" ) )
645 fi
646 return 0
647 ;;
648 esac
649 ;;
650 *)
651 [[ $prev == $object ]] && \
652 COMPREPLY=( $( compgen -W 'dump help' -- "$cur" ) )
653 ;;
654 esac
655 ;;
656 cgroup)
657 case $command in
658 show|list)
659 _filedir
660 return 0
661 ;;
662 tree)
663 _filedir
664 return 0
665 ;;
666 attach|detach)
667 local ATTACH_TYPES='ingress egress sock_create sock_ops \
668 device bind4 bind6 post_bind4 post_bind6 connect4 \
669 connect6 sendmsg4 sendmsg6 sysctl'
670 local ATTACH_FLAGS='multi override'
671 local PROG_TYPE='id pinned tag'
672 case $prev in
673 $command)
674 _filedir
675 return 0
676 ;;
677 ingress|egress|sock_create|sock_ops|device|bind4|bind6|\
678 post_bind4|post_bind6|connect4|connect6|sendmsg4|\
679 sendmsg6|sysctl)
680 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- \
681 "$cur" ) )
682 return 0
683 ;;
684 id)
685 _bpftool_get_prog_ids
686 return 0
687 ;;
688 *)
689 if ! _bpftool_search_list "$ATTACH_TYPES"; then
690 COMPREPLY=( $( compgen -W "$ATTACH_TYPES" -- \
691 "$cur" ) )
692 elif [[ "$command" == "attach" ]]; then
693 # We have an attach type on the command line,
694 # but it is not the previous word, or
695 # "id|pinned|tag" (we already checked for
696 # that). This should only leave the case when
697 # we need attach flags for "attach" commamnd.
698 _bpftool_one_of_list "$ATTACH_FLAGS"
699 fi
700 return 0
701 ;;
702 esac
703 ;;
704 *)
705 [[ $prev == $object ]] && \
706 COMPREPLY=( $( compgen -W 'help attach detach \
707 show list tree' -- "$cur" ) )
708 ;;
709 esac
710 ;;
711 perf)
712 case $command in
713 *)
714 [[ $prev == $object ]] && \
715 COMPREPLY=( $( compgen -W 'help \
716 show list' -- "$cur" ) )
717 ;;
718 esac
719 ;;
720 net)
721 case $command in
722 *)
723 [[ $prev == $object ]] && \
724 COMPREPLY=( $( compgen -W 'help \
725 show list' -- "$cur" ) )
726 ;;
727 esac
728 ;;
729 feature)
730 case $command in
731 probe)
732 [[ $prev == "dev" ]] && _sysfs_get_netdevs && return 0
733 [[ $prev == "prefix" ]] && return 0
734 if _bpftool_search_list 'macros'; then
735 COMPREPLY+=( $( compgen -W 'prefix' -- "$cur" ) )
736 else
737 COMPREPLY+=( $( compgen -W 'macros' -- "$cur" ) )
738 fi
739 _bpftool_one_of_list 'kernel dev'
740 return 0
741 ;;
742 *)
743 [[ $prev == $object ]] && \
744 COMPREPLY=( $( compgen -W 'help probe' -- "$cur" ) )
745 ;;
746 esac
747 ;;
748 esac
749 } &&
750 complete -F _bpftool bpftool
751
752 # ex: ts=4 sw=4 et filetype=sh