.. | .. |
---|
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() |
---|