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