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