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