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