at v5.2-rc1 752 lines 28 kB view raw
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_prog_ids() 63{ 64 COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \ 65 command sed -n 's/.*"id": \(.*\),$/\1/p' )" -- "$cur" ) ) 66} 67 68_bpftool_get_prog_tags() 69{ 70 COMPREPLY+=( $( compgen -W "$( bpftool -jp prog 2>&1 | \ 71 command sed -n 's/.*"tag": "\(.*\)",$/\1/p' )" -- "$cur" ) ) 72} 73 74_bpftool_get_obj_map_names() 75{ 76 local obj 77 78 obj=$1 79 80 maps=$(objdump -j maps -t $obj 2>/dev/null | \ 81 command awk '/g . maps/ {print $NF}') 82 83 COMPREPLY+=( $( compgen -W "$maps" -- "$cur" ) ) 84} 85 86_bpftool_get_obj_map_idxs() 87{ 88 local obj 89 90 obj=$1 91 92 nmaps=$(objdump -j maps -t $obj 2>/dev/null | grep -c 'g . maps') 93 94 COMPREPLY+=( $( compgen -W "$(seq 0 $((nmaps - 1)))" -- "$cur" ) ) 95} 96 97_sysfs_get_netdevs() 98{ 99 COMPREPLY+=( $( compgen -W "$( ls /sys/class/net 2>/dev/null )" -- \ 100 "$cur" ) ) 101} 102 103# Retrieve type of the map that we are operating on. 104_bpftool_map_guess_map_type() 105{ 106 local keyword ref 107 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do 108 case "${words[$((idx-2))]}" in 109 lookup|update) 110 keyword=${words[$((idx-1))]} 111 ref=${words[$((idx))]} 112 ;; 113 push) 114 printf "stack" 115 return 0 116 ;; 117 enqueue) 118 printf "queue" 119 return 0 120 ;; 121 esac 122 done 123 [[ -z $ref ]] && return 0 124 125 local type 126 type=$(bpftool -jp map show $keyword $ref | \ 127 command sed -n 's/.*"type": "\(.*\)",$/\1/p') 128 [[ -n $type ]] && printf $type 129} 130 131_bpftool_map_update_get_id() 132{ 133 local command="$1" 134 135 # Is it the map to update, or a map to insert into the map to update? 136 # Search for "value" keyword. 137 local idx value 138 for (( idx=7; idx < ${#words[@]}-1; idx++ )); do 139 if [[ ${words[idx]} == "value" ]]; then 140 value=1 141 break 142 fi 143 done 144 if [[ $value -eq 0 ]]; then 145 case "$command" in 146 push) 147 _bpftool_get_map_ids_for_type stack 148 ;; 149 enqueue) 150 _bpftool_get_map_ids_for_type queue 151 ;; 152 *) 153 _bpftool_get_map_ids 154 ;; 155 esac 156 return 0 157 fi 158 159 # Id to complete is for a value. It can be either prog id or map id. This 160 # depends on the type of the map to update. 161 local type=$(_bpftool_map_guess_map_type) 162 case $type in 163 array_of_maps|hash_of_maps) 164 _bpftool_get_map_ids 165 return 0 166 ;; 167 prog_array) 168 _bpftool_get_prog_ids 169 return 0 170 ;; 171 *) 172 return 0 173 ;; 174 esac 175} 176 177_bpftool() 178{ 179 local cur prev words objword 180 _init_completion || return 181 182 # Deal with options 183 if [[ ${words[cword]} == -* ]]; then 184 local c='--version --json --pretty --bpffs --mapcompat' 185 COMPREPLY=( $( compgen -W "$c" -- "$cur" ) ) 186 return 0 187 fi 188 189 # Deal with simplest keywords 190 case $prev in 191 help|hex|opcodes|visual|linum) 192 return 0 193 ;; 194 tag) 195 _bpftool_get_prog_tags 196 return 0 197 ;; 198 file|pinned) 199 _filedir 200 return 0 201 ;; 202 batch) 203 COMPREPLY=( $( compgen -W 'file' -- "$cur" ) ) 204 return 0 205 ;; 206 esac 207 208 # Remove all options so completions don't have to deal with them. 209 local i 210 for (( i=1; i < ${#words[@]}; )); do 211 if [[ ${words[i]::1} == - ]]; then 212 words=( "${words[@]:0:i}" "${words[@]:i+1}" ) 213 [[ $i -le $cword ]] && cword=$(( cword - 1 )) 214 else 215 i=$(( ++i )) 216 fi 217 done 218 cur=${words[cword]} 219 prev=${words[cword - 1]} 220 pprev=${words[cword - 2]} 221 222 local object=${words[1]} command=${words[2]} 223 224 if [[ -z $object || $cword -eq 1 ]]; then 225 case $cur in 226 *) 227 COMPREPLY=( $( compgen -W "$( bpftool help 2>&1 | \ 228 command sed \ 229 -e '/OBJECT := /!d' \ 230 -e 's/.*{//' \ 231 -e 's/}.*//' \ 232 -e 's/|//g' )" -- "$cur" ) ) 233 COMPREPLY+=( $( compgen -W 'batch help' -- "$cur" ) ) 234 return 0 235 ;; 236 esac 237 fi 238 239 [[ $command == help ]] && return 0 240 241 # Completion depends on object and command in use 242 case $object in 243 prog) 244 # Complete id, only for subcommands that use prog (but no map) ids 245 case $command in 246 show|list|dump|pin) 247 case $prev in 248 id) 249 _bpftool_get_prog_ids 250 return 0 251 ;; 252 esac 253 ;; 254 esac 255 256 local PROG_TYPE='id pinned tag' 257 local MAP_TYPE='id pinned' 258 case $command in 259 show|list) 260 [[ $prev != "$command" ]] && return 0 261 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) ) 262 return 0 263 ;; 264 dump) 265 case $prev in 266 $command) 267 COMPREPLY+=( $( compgen -W "xlated jited" -- \ 268 "$cur" ) ) 269 return 0 270 ;; 271 xlated|jited) 272 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- \ 273 "$cur" ) ) 274 return 0 275 ;; 276 *) 277 _bpftool_once_attr 'file' 278 if _bpftool_search_list 'xlated'; then 279 COMPREPLY+=( $( compgen -W 'opcodes visual linum' -- \ 280 "$cur" ) ) 281 else 282 COMPREPLY+=( $( compgen -W 'opcodes linum' -- \ 283 "$cur" ) ) 284 fi 285 return 0 286 ;; 287 esac 288 ;; 289 pin) 290 if [[ $prev == "$command" ]]; then 291 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) ) 292 else 293 _filedir 294 fi 295 return 0 296 ;; 297 attach|detach) 298 case $cword in 299 3) 300 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) ) 301 return 0 302 ;; 303 4) 304 case $prev in 305 id) 306 _bpftool_get_prog_ids 307 ;; 308 pinned) 309 _filedir 310 ;; 311 esac 312 return 0 313 ;; 314 5) 315 COMPREPLY=( $( compgen -W 'msg_verdict stream_verdict \ 316 stream_parser flow_dissector' -- "$cur" ) ) 317 return 0 318 ;; 319 6) 320 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) ) 321 return 0 322 ;; 323 7) 324 case $prev in 325 id) 326 _bpftool_get_map_ids 327 ;; 328 pinned) 329 _filedir 330 ;; 331 esac 332 return 0 333 ;; 334 esac 335 ;; 336 load|loadall) 337 local obj 338 339 if [[ ${#words[@]} -lt 6 ]]; then 340 _filedir 341 return 0 342 fi 343 344 obj=${words[3]} 345 346 if [[ ${words[-4]} == "map" ]]; then 347 COMPREPLY=( $( compgen -W "id pinned" -- "$cur" ) ) 348 return 0 349 fi 350 if [[ ${words[-3]} == "map" ]]; then 351 if [[ ${words[-2]} == "idx" ]]; then 352 _bpftool_get_obj_map_idxs $obj 353 elif [[ ${words[-2]} == "name" ]]; then 354 _bpftool_get_obj_map_names $obj 355 fi 356 return 0 357 fi 358 if [[ ${words[-2]} == "map" ]]; then 359 COMPREPLY=( $( compgen -W "idx name" -- "$cur" ) ) 360 return 0 361 fi 362 363 case $prev in 364 type) 365 COMPREPLY=( $( compgen -W "socket kprobe \ 366 kretprobe classifier flow_dissector \ 367 action tracepoint raw_tracepoint \ 368 xdp perf_event cgroup/skb cgroup/sock \ 369 cgroup/dev lwt_in lwt_out lwt_xmit \ 370 lwt_seg6local sockops sk_skb sk_msg \ 371 lirc_mode2 cgroup/bind4 cgroup/bind6 \ 372 cgroup/connect4 cgroup/connect6 \ 373 cgroup/sendmsg4 cgroup/sendmsg6 \ 374 cgroup/post_bind4 cgroup/post_bind6 \ 375 cgroup/sysctl" -- \ 376 "$cur" ) ) 377 return 0 378 ;; 379 id) 380 _bpftool_get_map_ids 381 return 0 382 ;; 383 pinned|pinmaps) 384 _filedir 385 return 0 386 ;; 387 dev) 388 _sysfs_get_netdevs 389 return 0 390 ;; 391 *) 392 COMPREPLY=( $( compgen -W "map" -- "$cur" ) ) 393 _bpftool_once_attr 'type' 394 _bpftool_once_attr 'dev' 395 _bpftool_once_attr 'pinmaps' 396 return 0 397 ;; 398 esac 399 ;; 400 tracelog) 401 return 0 402 ;; 403 *) 404 [[ $prev == $object ]] && \ 405 COMPREPLY=( $( compgen -W 'dump help pin attach detach load \ 406 show list tracelog' -- "$cur" ) ) 407 ;; 408 esac 409 ;; 410 map) 411 local MAP_TYPE='id pinned' 412 case $command in 413 show|list|dump|peek|pop|dequeue) 414 case $prev in 415 $command) 416 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) ) 417 return 0 418 ;; 419 id) 420 case "$command" in 421 peek) 422 _bpftool_get_map_ids_for_type stack 423 _bpftool_get_map_ids_for_type queue 424 ;; 425 pop) 426 _bpftool_get_map_ids_for_type stack 427 ;; 428 dequeue) 429 _bpftool_get_map_ids_for_type queue 430 ;; 431 *) 432 _bpftool_get_map_ids 433 ;; 434 esac 435 return 0 436 ;; 437 *) 438 return 0 439 ;; 440 esac 441 ;; 442 create) 443 case $prev in 444 $command) 445 _filedir 446 return 0 447 ;; 448 type) 449 COMPREPLY=( $( compgen -W 'hash array prog_array \ 450 perf_event_array percpu_hash percpu_array \ 451 stack_trace cgroup_array lru_hash \ 452 lru_percpu_hash lpm_trie array_of_maps \ 453 hash_of_maps devmap sockmap cpumap xskmap \ 454 sockhash cgroup_storage reuseport_sockarray \ 455 percpu_cgroup_storage queue stack' -- \ 456 "$cur" ) ) 457 return 0 458 ;; 459 key|value|flags|name|entries) 460 return 0 461 ;; 462 dev) 463 _sysfs_get_netdevs 464 return 0 465 ;; 466 *) 467 _bpftool_once_attr 'type' 468 _bpftool_once_attr 'key' 469 _bpftool_once_attr 'value' 470 _bpftool_once_attr 'entries' 471 _bpftool_once_attr 'name' 472 _bpftool_once_attr 'flags' 473 _bpftool_once_attr 'dev' 474 return 0 475 ;; 476 esac 477 ;; 478 lookup|getnext|delete) 479 case $prev in 480 $command) 481 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) ) 482 return 0 483 ;; 484 id) 485 _bpftool_get_map_ids 486 return 0 487 ;; 488 key) 489 COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) ) 490 ;; 491 *) 492 case $(_bpftool_map_guess_map_type) in 493 queue|stack) 494 return 0 495 ;; 496 esac 497 498 _bpftool_once_attr 'key' 499 return 0 500 ;; 501 esac 502 ;; 503 update|push|enqueue) 504 case $prev in 505 $command) 506 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) ) 507 return 0 508 ;; 509 id) 510 _bpftool_map_update_get_id $command 511 return 0 512 ;; 513 key) 514 COMPREPLY+=( $( compgen -W 'hex' -- "$cur" ) ) 515 ;; 516 value) 517 # We can have bytes, or references to a prog or a 518 # map, depending on the type of the map to update. 519 case "$(_bpftool_map_guess_map_type)" in 520 array_of_maps|hash_of_maps) 521 local MAP_TYPE='id pinned' 522 COMPREPLY+=( $( compgen -W "$MAP_TYPE" \ 523 -- "$cur" ) ) 524 return 0 525 ;; 526 prog_array) 527 local PROG_TYPE='id pinned tag' 528 COMPREPLY+=( $( compgen -W "$PROG_TYPE" \ 529 -- "$cur" ) ) 530 return 0 531 ;; 532 *) 533 COMPREPLY+=( $( compgen -W 'hex' \ 534 -- "$cur" ) ) 535 return 0 536 ;; 537 esac 538 return 0 539 ;; 540 *) 541 case $(_bpftool_map_guess_map_type) in 542 queue|stack) 543 _bpftool_once_attr 'value' 544 return 0; 545 ;; 546 esac 547 548 _bpftool_once_attr 'key' 549 local UPDATE_FLAGS='any exist noexist' 550 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do 551 if [[ ${words[idx]} == 'value' ]]; then 552 # 'value' is present, but is not the last 553 # word i.e. we can now have UPDATE_FLAGS. 554 _bpftool_one_of_list "$UPDATE_FLAGS" 555 return 0 556 fi 557 done 558 for (( idx=3; idx < ${#words[@]}-1; idx++ )); do 559 if [[ ${words[idx]} == 'key' ]]; then 560 # 'key' is present, but is not the last 561 # word i.e. we can now have 'value'. 562 _bpftool_once_attr 'value' 563 return 0 564 fi 565 done 566 567 return 0 568 ;; 569 esac 570 ;; 571 pin) 572 if [[ $prev == "$command" ]]; then 573 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) ) 574 else 575 _filedir 576 fi 577 return 0 578 ;; 579 event_pipe) 580 case $prev in 581 $command) 582 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) ) 583 return 0 584 ;; 585 id) 586 _bpftool_get_map_ids_for_type perf_event_array 587 return 0 588 ;; 589 cpu) 590 return 0 591 ;; 592 index) 593 return 0 594 ;; 595 *) 596 _bpftool_once_attr 'cpu' 597 _bpftool_once_attr 'index' 598 return 0 599 ;; 600 esac 601 ;; 602 *) 603 [[ $prev == $object ]] && \ 604 COMPREPLY=( $( compgen -W 'delete dump getnext help \ 605 lookup pin event_pipe show list update create \ 606 peek push enqueue pop dequeue' -- \ 607 "$cur" ) ) 608 ;; 609 esac 610 ;; 611 btf) 612 local PROG_TYPE='id pinned tag' 613 local MAP_TYPE='id pinned' 614 case $command in 615 dump) 616 case $prev in 617 $command) 618 COMPREPLY+=( $( compgen -W "id map prog file" -- \ 619 "$cur" ) ) 620 return 0 621 ;; 622 prog) 623 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) ) 624 return 0 625 ;; 626 map) 627 COMPREPLY=( $( compgen -W "$MAP_TYPE" -- "$cur" ) ) 628 return 0 629 ;; 630 id) 631 case $pprev in 632 prog) 633 _bpftool_get_prog_ids 634 ;; 635 map) 636 _bpftool_get_map_ids 637 ;; 638 esac 639 return 0 640 ;; 641 *) 642 if [[ $cword == 6 ]] && [[ ${words[3]} == "map" ]]; then 643 COMPREPLY+=( $( compgen -W 'key value kv all' -- \ 644 "$cur" ) ) 645 fi 646 return 0 647 ;; 648 esac 649 ;; 650 *) 651 [[ $prev == $object ]] && \ 652 COMPREPLY=( $( compgen -W 'dump help' -- "$cur" ) ) 653 ;; 654 esac 655 ;; 656 cgroup) 657 case $command in 658 show|list) 659 _filedir 660 return 0 661 ;; 662 tree) 663 _filedir 664 return 0 665 ;; 666 attach|detach) 667 local ATTACH_TYPES='ingress egress sock_create sock_ops \ 668 device bind4 bind6 post_bind4 post_bind6 connect4 \ 669 connect6 sendmsg4 sendmsg6 sysctl' 670 local ATTACH_FLAGS='multi override' 671 local PROG_TYPE='id pinned tag' 672 case $prev in 673 $command) 674 _filedir 675 return 0 676 ;; 677 ingress|egress|sock_create|sock_ops|device|bind4|bind6|\ 678 post_bind4|post_bind6|connect4|connect6|sendmsg4|\ 679 sendmsg6|sysctl) 680 COMPREPLY=( $( compgen -W "$PROG_TYPE" -- \ 681 "$cur" ) ) 682 return 0 683 ;; 684 id) 685 _bpftool_get_prog_ids 686 return 0 687 ;; 688 *) 689 if ! _bpftool_search_list "$ATTACH_TYPES"; then 690 COMPREPLY=( $( compgen -W "$ATTACH_TYPES" -- \ 691 "$cur" ) ) 692 elif [[ "$command" == "attach" ]]; then 693 # We have an attach type on the command line, 694 # but it is not the previous word, or 695 # "id|pinned|tag" (we already checked for 696 # that). This should only leave the case when 697 # we need attach flags for "attach" commamnd. 698 _bpftool_one_of_list "$ATTACH_FLAGS" 699 fi 700 return 0 701 ;; 702 esac 703 ;; 704 *) 705 [[ $prev == $object ]] && \ 706 COMPREPLY=( $( compgen -W 'help attach detach \ 707 show list tree' -- "$cur" ) ) 708 ;; 709 esac 710 ;; 711 perf) 712 case $command in 713 *) 714 [[ $prev == $object ]] && \ 715 COMPREPLY=( $( compgen -W 'help \ 716 show list' -- "$cur" ) ) 717 ;; 718 esac 719 ;; 720 net) 721 case $command in 722 *) 723 [[ $prev == $object ]] && \ 724 COMPREPLY=( $( compgen -W 'help \ 725 show list' -- "$cur" ) ) 726 ;; 727 esac 728 ;; 729 feature) 730 case $command in 731 probe) 732 [[ $prev == "dev" ]] && _sysfs_get_netdevs && return 0 733 [[ $prev == "prefix" ]] && return 0 734 if _bpftool_search_list 'macros'; then 735 COMPREPLY+=( $( compgen -W 'prefix' -- "$cur" ) ) 736 else 737 COMPREPLY+=( $( compgen -W 'macros' -- "$cur" ) ) 738 fi 739 _bpftool_one_of_list 'kernel dev' 740 return 0 741 ;; 742 *) 743 [[ $prev == $object ]] && \ 744 COMPREPLY=( $( compgen -W 'help probe' -- "$cur" ) ) 745 ;; 746 esac 747 ;; 748 esac 749} && 750complete -F _bpftool bpftool 751 752# ex: ts=4 sw=4 et filetype=sh