xref: /linux/tools/bpf/bpftool/bash-completion/bpftool (revision ec2e0fb07d789976c601bec19ecced7a501c3705)
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
1242