| .. | .. |
|---|
| 1 | | -#!/usr/bin/python3 |
|---|
| 1 | +#!/usr/bin/env python3 |
|---|
| 2 | 2 | # SPDX-License-Identifier: GPL-2.0-only |
|---|
| 3 | 3 | # |
|---|
| 4 | | -# Copyright (C) 2018 Netronome Systems, Inc. |
|---|
| 4 | +# Copyright (C) 2018-2019 Netronome Systems, Inc. |
|---|
| 5 | 5 | |
|---|
| 6 | 6 | # In case user attempts to run with Python 2. |
|---|
| 7 | 7 | from __future__ import print_function |
|---|
| .. | .. |
|---|
| 39 | 39 | Break down helper function protocol into smaller chunks: return type, |
|---|
| 40 | 40 | name, distincts arguments. |
|---|
| 41 | 41 | """ |
|---|
| 42 | | - arg_re = re.compile('((const )?(struct )?(\w+|...))( (\**)(\w+))?$') |
|---|
| 42 | + arg_re = re.compile('((\w+ )*?(\w+|...))( (\**)(\w+))?$') |
|---|
| 43 | 43 | res = {} |
|---|
| 44 | 44 | proto_re = re.compile('(.+) (\**)(\w+)\(((([^,]+)(, )?){1,5})\)$') |
|---|
| 45 | 45 | |
|---|
| .. | .. |
|---|
| 54 | 54 | capture = arg_re.match(a) |
|---|
| 55 | 55 | res['args'].append({ |
|---|
| 56 | 56 | 'type' : capture.group(1), |
|---|
| 57 | | - 'star' : capture.group(6), |
|---|
| 58 | | - 'name' : capture.group(7) |
|---|
| 57 | + 'star' : capture.group(5), |
|---|
| 58 | + 'name' : capture.group(6) |
|---|
| 59 | 59 | }) |
|---|
| 60 | 60 | |
|---|
| 61 | 61 | return res |
|---|
| .. | .. |
|---|
| 158 | 158 | break |
|---|
| 159 | 159 | |
|---|
| 160 | 160 | self.reader.close() |
|---|
| 161 | | - print('Parsed description of %d helper function(s)' % len(self.helpers), |
|---|
| 162 | | - file=sys.stderr) |
|---|
| 163 | 161 | |
|---|
| 164 | 162 | ############################################################################### |
|---|
| 165 | 163 | |
|---|
| .. | .. |
|---|
| 320 | 318 | of eBPF maps are used with a given helper function. |
|---|
| 321 | 319 | * *kernel/bpf/* directory contains other files in which additional helpers are |
|---|
| 322 | 320 | defined (for cgroups, sockmaps, etc.). |
|---|
| 321 | +* The bpftool utility can be used to probe the availability of helper functions |
|---|
| 322 | + on the system (as well as supported program and map types, and a number of |
|---|
| 323 | + other parameters). To do so, run **bpftool feature probe** (see |
|---|
| 324 | + **bpftool-feature**\ (8) for details). Add the **unprivileged** keyword to |
|---|
| 325 | + list features available to unprivileged users. |
|---|
| 323 | 326 | |
|---|
| 324 | 327 | Compatibility between helper functions and program types can generally be found |
|---|
| 325 | 328 | in the files where helper functions are defined. Look for the **struct |
|---|
| .. | .. |
|---|
| 340 | 343 | ======== |
|---|
| 341 | 344 | |
|---|
| 342 | 345 | **bpf**\ (2), |
|---|
| 346 | +**bpftool**\ (8), |
|---|
| 343 | 347 | **cgroups**\ (7), |
|---|
| 344 | 348 | **ip**\ (8), |
|---|
| 345 | 349 | **perf_event_open**\ (2), |
|---|
| .. | .. |
|---|
| 391 | 395 | |
|---|
| 392 | 396 | print('') |
|---|
| 393 | 397 | |
|---|
| 398 | +class PrinterHelpers(Printer): |
|---|
| 399 | + """ |
|---|
| 400 | + A printer for dumping collected information about helpers as C header to |
|---|
| 401 | + be included from BPF program. |
|---|
| 402 | + @helpers: array of Helper objects to print to standard output |
|---|
| 403 | + """ |
|---|
| 404 | + |
|---|
| 405 | + type_fwds = [ |
|---|
| 406 | + 'struct bpf_fib_lookup', |
|---|
| 407 | + 'struct bpf_sk_lookup', |
|---|
| 408 | + 'struct bpf_perf_event_data', |
|---|
| 409 | + 'struct bpf_perf_event_value', |
|---|
| 410 | + 'struct bpf_pidns_info', |
|---|
| 411 | + 'struct bpf_redir_neigh', |
|---|
| 412 | + 'struct bpf_sock', |
|---|
| 413 | + 'struct bpf_sock_addr', |
|---|
| 414 | + 'struct bpf_sock_ops', |
|---|
| 415 | + 'struct bpf_sock_tuple', |
|---|
| 416 | + 'struct bpf_spin_lock', |
|---|
| 417 | + 'struct bpf_sysctl', |
|---|
| 418 | + 'struct bpf_tcp_sock', |
|---|
| 419 | + 'struct bpf_tunnel_key', |
|---|
| 420 | + 'struct bpf_xfrm_state', |
|---|
| 421 | + 'struct pt_regs', |
|---|
| 422 | + 'struct sk_reuseport_md', |
|---|
| 423 | + 'struct sockaddr', |
|---|
| 424 | + 'struct tcphdr', |
|---|
| 425 | + 'struct seq_file', |
|---|
| 426 | + 'struct tcp6_sock', |
|---|
| 427 | + 'struct tcp_sock', |
|---|
| 428 | + 'struct tcp_timewait_sock', |
|---|
| 429 | + 'struct tcp_request_sock', |
|---|
| 430 | + 'struct udp6_sock', |
|---|
| 431 | + 'struct task_struct', |
|---|
| 432 | + |
|---|
| 433 | + 'struct __sk_buff', |
|---|
| 434 | + 'struct sk_msg_md', |
|---|
| 435 | + 'struct xdp_md', |
|---|
| 436 | + 'struct path', |
|---|
| 437 | + 'struct btf_ptr', |
|---|
| 438 | + ] |
|---|
| 439 | + known_types = { |
|---|
| 440 | + '...', |
|---|
| 441 | + 'void', |
|---|
| 442 | + 'const void', |
|---|
| 443 | + 'char', |
|---|
| 444 | + 'const char', |
|---|
| 445 | + 'int', |
|---|
| 446 | + 'long', |
|---|
| 447 | + 'unsigned long', |
|---|
| 448 | + |
|---|
| 449 | + '__be16', |
|---|
| 450 | + '__be32', |
|---|
| 451 | + '__wsum', |
|---|
| 452 | + |
|---|
| 453 | + 'struct bpf_fib_lookup', |
|---|
| 454 | + 'struct bpf_perf_event_data', |
|---|
| 455 | + 'struct bpf_perf_event_value', |
|---|
| 456 | + 'struct bpf_pidns_info', |
|---|
| 457 | + 'struct bpf_redir_neigh', |
|---|
| 458 | + 'struct bpf_sk_lookup', |
|---|
| 459 | + 'struct bpf_sock', |
|---|
| 460 | + 'struct bpf_sock_addr', |
|---|
| 461 | + 'struct bpf_sock_ops', |
|---|
| 462 | + 'struct bpf_sock_tuple', |
|---|
| 463 | + 'struct bpf_spin_lock', |
|---|
| 464 | + 'struct bpf_sysctl', |
|---|
| 465 | + 'struct bpf_tcp_sock', |
|---|
| 466 | + 'struct bpf_tunnel_key', |
|---|
| 467 | + 'struct bpf_xfrm_state', |
|---|
| 468 | + 'struct pt_regs', |
|---|
| 469 | + 'struct sk_reuseport_md', |
|---|
| 470 | + 'struct sockaddr', |
|---|
| 471 | + 'struct tcphdr', |
|---|
| 472 | + 'struct seq_file', |
|---|
| 473 | + 'struct tcp6_sock', |
|---|
| 474 | + 'struct tcp_sock', |
|---|
| 475 | + 'struct tcp_timewait_sock', |
|---|
| 476 | + 'struct tcp_request_sock', |
|---|
| 477 | + 'struct udp6_sock', |
|---|
| 478 | + 'struct task_struct', |
|---|
| 479 | + 'struct path', |
|---|
| 480 | + 'struct btf_ptr', |
|---|
| 481 | + } |
|---|
| 482 | + mapped_types = { |
|---|
| 483 | + 'u8': '__u8', |
|---|
| 484 | + 'u16': '__u16', |
|---|
| 485 | + 'u32': '__u32', |
|---|
| 486 | + 'u64': '__u64', |
|---|
| 487 | + 's8': '__s8', |
|---|
| 488 | + 's16': '__s16', |
|---|
| 489 | + 's32': '__s32', |
|---|
| 490 | + 's64': '__s64', |
|---|
| 491 | + 'size_t': 'unsigned long', |
|---|
| 492 | + 'struct bpf_map': 'void', |
|---|
| 493 | + 'struct sk_buff': 'struct __sk_buff', |
|---|
| 494 | + 'const struct sk_buff': 'const struct __sk_buff', |
|---|
| 495 | + 'struct sk_msg_buff': 'struct sk_msg_md', |
|---|
| 496 | + 'struct xdp_buff': 'struct xdp_md', |
|---|
| 497 | + } |
|---|
| 498 | + # Helpers overloaded for different context types. |
|---|
| 499 | + overloaded_helpers = [ |
|---|
| 500 | + 'bpf_get_socket_cookie', |
|---|
| 501 | + 'bpf_sk_assign', |
|---|
| 502 | + ] |
|---|
| 503 | + |
|---|
| 504 | + def print_header(self): |
|---|
| 505 | + header = '''\ |
|---|
| 506 | +/* This is auto-generated file. See bpf_helpers_doc.py for details. */ |
|---|
| 507 | + |
|---|
| 508 | +/* Forward declarations of BPF structs */''' |
|---|
| 509 | + |
|---|
| 510 | + print(header) |
|---|
| 511 | + for fwd in self.type_fwds: |
|---|
| 512 | + print('%s;' % fwd) |
|---|
| 513 | + print('') |
|---|
| 514 | + |
|---|
| 515 | + def print_footer(self): |
|---|
| 516 | + footer = '' |
|---|
| 517 | + print(footer) |
|---|
| 518 | + |
|---|
| 519 | + def map_type(self, t): |
|---|
| 520 | + if t in self.known_types: |
|---|
| 521 | + return t |
|---|
| 522 | + if t in self.mapped_types: |
|---|
| 523 | + return self.mapped_types[t] |
|---|
| 524 | + print("Unrecognized type '%s', please add it to known types!" % t, |
|---|
| 525 | + file=sys.stderr) |
|---|
| 526 | + sys.exit(1) |
|---|
| 527 | + |
|---|
| 528 | + seen_helpers = set() |
|---|
| 529 | + |
|---|
| 530 | + def print_one(self, helper): |
|---|
| 531 | + proto = helper.proto_break_down() |
|---|
| 532 | + |
|---|
| 533 | + if proto['name'] in self.seen_helpers: |
|---|
| 534 | + return |
|---|
| 535 | + self.seen_helpers.add(proto['name']) |
|---|
| 536 | + |
|---|
| 537 | + print('/*') |
|---|
| 538 | + print(" * %s" % proto['name']) |
|---|
| 539 | + print(" *") |
|---|
| 540 | + if (helper.desc): |
|---|
| 541 | + # Do not strip all newline characters: formatted code at the end of |
|---|
| 542 | + # a section must be followed by a blank line. |
|---|
| 543 | + for line in re.sub('\n$', '', helper.desc, count=1).split('\n'): |
|---|
| 544 | + print(' *{}{}'.format(' \t' if line else '', line)) |
|---|
| 545 | + |
|---|
| 546 | + if (helper.ret): |
|---|
| 547 | + print(' *') |
|---|
| 548 | + print(' * Returns') |
|---|
| 549 | + for line in helper.ret.rstrip().split('\n'): |
|---|
| 550 | + print(' *{}{}'.format(' \t' if line else '', line)) |
|---|
| 551 | + |
|---|
| 552 | + print(' */') |
|---|
| 553 | + print('static %s %s(*%s)(' % (self.map_type(proto['ret_type']), |
|---|
| 554 | + proto['ret_star'], proto['name']), end='') |
|---|
| 555 | + comma = '' |
|---|
| 556 | + for i, a in enumerate(proto['args']): |
|---|
| 557 | + t = a['type'] |
|---|
| 558 | + n = a['name'] |
|---|
| 559 | + if proto['name'] in self.overloaded_helpers and i == 0: |
|---|
| 560 | + t = 'void' |
|---|
| 561 | + n = 'ctx' |
|---|
| 562 | + one_arg = '{}{}'.format(comma, self.map_type(t)) |
|---|
| 563 | + if n: |
|---|
| 564 | + if a['star']: |
|---|
| 565 | + one_arg += ' {}'.format(a['star']) |
|---|
| 566 | + else: |
|---|
| 567 | + one_arg += ' ' |
|---|
| 568 | + one_arg += '{}'.format(n) |
|---|
| 569 | + comma = ', ' |
|---|
| 570 | + print(one_arg, end='') |
|---|
| 571 | + |
|---|
| 572 | + print(') = (void *) %d;' % len(self.seen_helpers)) |
|---|
| 573 | + print('') |
|---|
| 574 | + |
|---|
| 394 | 575 | ############################################################################### |
|---|
| 395 | 576 | |
|---|
| 396 | 577 | # If script is launched from scripts/ from kernel tree and can access |
|---|
| .. | .. |
|---|
| 405 | 586 | The RST-formatted output produced can be turned into a manual page with the |
|---|
| 406 | 587 | rst2man utility. |
|---|
| 407 | 588 | """) |
|---|
| 589 | +argParser.add_argument('--header', action='store_true', |
|---|
| 590 | + help='generate C header file') |
|---|
| 408 | 591 | if (os.path.isfile(bpfh)): |
|---|
| 409 | 592 | argParser.add_argument('--filename', help='path to include/uapi/linux/bpf.h', |
|---|
| 410 | 593 | default=bpfh) |
|---|
| .. | .. |
|---|
| 417 | 600 | headerParser.run() |
|---|
| 418 | 601 | |
|---|
| 419 | 602 | # Print formatted output to standard output. |
|---|
| 420 | | -printer = PrinterRST(headerParser.helpers) |
|---|
| 603 | +if args.header: |
|---|
| 604 | + printer = PrinterHelpers(headerParser.helpers) |
|---|
| 605 | +else: |
|---|
| 606 | + printer = PrinterRST(headerParser.helpers) |
|---|
| 421 | 607 | printer.print_all() |
|---|