1#!/usr/bin/env python3 2# SPDX-License-Identifier: GPL-2.0-only 3# 4# Copyright (C) 2018-2019 Netronome Systems, Inc. 5# Copyright (C) 2021 Isovalent, Inc. 6 7# In case user attempts to run with Python 2. 8from __future__ import print_function 9 10import argparse 11import re 12import sys, os 13 14class NoHelperFound(BaseException): 15 pass 16 17class NoSyscallCommandFound(BaseException): 18 pass 19 20class ParsingError(BaseException): 21 def __init__(self, line='<line not provided>', reader=None): 22 if reader: 23 BaseException.__init__(self, 24 'Error at file offset %d, parsing line: %s' % 25 (reader.tell(), line)) 26 else: 27 BaseException.__init__(self, 'Error parsing line: %s' % line) 28 29 30class APIElement(object): 31 """ 32 An object representing the description of an aspect of the eBPF API. 33 @proto: prototype of the API symbol 34 @desc: textual description of the symbol 35 @ret: (optional) description of any associated return value 36 """ 37 def __init__(self, proto='', desc='', ret=''): 38 self.proto = proto 39 self.desc = desc 40 self.ret = ret 41 42 43class Helper(APIElement): 44 """ 45 An object representing the description of an eBPF helper function. 46 @proto: function prototype of the helper function 47 @desc: textual description of the helper function 48 @ret: description of the return value of the helper function 49 """ 50 def proto_break_down(self): 51 """ 52 Break down helper function protocol into smaller chunks: return type, 53 name, distincts arguments. 54 """ 55 arg_re = re.compile('((\w+ )*?(\w+|...))( (\**)(\w+))?$') 56 res = {} 57 proto_re = re.compile('(.+) (\**)(\w+)\(((([^,]+)(, )?){1,5})\)$') 58 59 capture = proto_re.match(self.proto) 60 res['ret_type'] = capture.group(1) 61 res['ret_star'] = capture.group(2) 62 res['name'] = capture.group(3) 63 res['args'] = [] 64 65 args = capture.group(4).split(', ') 66 for a in args: 67 capture = arg_re.match(a) 68 res['args'].append({ 69 'type' : capture.group(1), 70 'star' : capture.group(5), 71 'name' : capture.group(6) 72 }) 73 74 return res 75 76 77class HeaderParser(object): 78 """ 79 An object used to parse a file in order to extract the documentation of a 80 list of eBPF helper functions. All the helpers that can be retrieved are 81 stored as Helper object, in the self.helpers() array. 82 @filename: name of file to parse, usually include/uapi/linux/bpf.h in the 83 kernel tree 84 """ 85 def __init__(self, filename): 86 self.reader = open(filename, 'r') 87 self.line = '' 88 self.helpers = [] 89 self.commands = [] 90 self.desc_unique_helpers = set() 91 self.define_unique_helpers = [] 92 93 def parse_element(self): 94 proto = self.parse_symbol() 95 desc = self.parse_desc() 96 ret = self.parse_ret() 97 return APIElement(proto=proto, desc=desc, ret=ret) 98 99 def parse_helper(self): 100 proto = self.parse_proto() 101 desc = self.parse_desc() 102 ret = self.parse_ret() 103 return Helper(proto=proto, desc=desc, ret=ret) 104 105 def parse_symbol(self): 106 p = re.compile(' \* ?(.+)$') 107 capture = p.match(self.line) 108 if not capture: 109 raise NoSyscallCommandFound 110 end_re = re.compile(' \* ?NOTES$') 111 end = end_re.match(self.line) 112 if end: 113 raise NoSyscallCommandFound 114 self.line = self.reader.readline() 115 return capture.group(1) 116 117 def parse_proto(self): 118 # Argument can be of shape: 119 # - "void" 120 # - "type name" 121 # - "type *name" 122 # - Same as above, with "const" and/or "struct" in front of type 123 # - "..." (undefined number of arguments, for bpf_trace_printk()) 124 # There is at least one term ("void"), and at most five arguments. 125 p = re.compile(' \* ?((.+) \**\w+\((((const )?(struct )?(\w+|\.\.\.)( \**\w+)?)(, )?){1,5}\))$') 126 capture = p.match(self.line) 127 if not capture: 128 raise NoHelperFound 129 self.line = self.reader.readline() 130 return capture.group(1) 131 132 def parse_desc(self): 133 p = re.compile(' \* ?(?:\t| {5,8})Description$') 134 capture = p.match(self.line) 135 if not capture: 136 # Helper can have empty description and we might be parsing another 137 # attribute: return but do not consume. 138 return '' 139 # Description can be several lines, some of them possibly empty, and it 140 # stops when another subsection title is met. 141 desc = '' 142 while True: 143 self.line = self.reader.readline() 144 if self.line == ' *\n': 145 desc += '\n' 146 else: 147 p = re.compile(' \* ?(?:\t| {5,8})(?:\t| {8})(.*)') 148 capture = p.match(self.line) 149 if capture: 150 desc += capture.group(1) + '\n' 151 else: 152 break 153 return desc 154 155 def parse_ret(self): 156 p = re.compile(' \* ?(?:\t| {5,8})Return$') 157 capture = p.match(self.line) 158 if not capture: 159 # Helper can have empty retval and we might be parsing another 160 # attribute: return but do not consume. 161 return '' 162 # Return value description can be several lines, some of them possibly 163 # empty, and it stops when another subsection title is met. 164 ret = '' 165 while True: 166 self.line = self.reader.readline() 167 if self.line == ' *\n': 168 ret += '\n' 169 else: 170 p = re.compile(' \* ?(?:\t| {5,8})(?:\t| {8})(.*)') 171 capture = p.match(self.line) 172 if capture: 173 ret += capture.group(1) + '\n' 174 else: 175 break 176 return ret 177 178 def seek_to(self, target, help_message): 179 self.reader.seek(0) 180 offset = self.reader.read().find(target) 181 if offset == -1: 182 raise Exception(help_message) 183 self.reader.seek(offset) 184 self.reader.readline() 185 self.reader.readline() 186 self.line = self.reader.readline() 187 188 def parse_syscall(self): 189 self.seek_to('* DOC: eBPF Syscall Commands', 190 'Could not find start of eBPF syscall descriptions list') 191 while True: 192 try: 193 command = self.parse_element() 194 self.commands.append(command) 195 except NoSyscallCommandFound: 196 break 197 198 def parse_desc_helpers(self): 199 self.seek_to('* Start of BPF helper function descriptions:', 200 'Could not find start of eBPF helper descriptions list') 201 while True: 202 try: 203 helper = self.parse_helper() 204 self.helpers.append(helper) 205 proto = helper.proto_break_down() 206 self.desc_unique_helpers.add(proto['name']) 207 except NoHelperFound: 208 break 209 210 def parse_define_helpers(self): 211 # Parse the number of FN(...) in #define __BPF_FUNC_MAPPER to compare 212 # later with the number of unique function names present in description. 213 # Note: seek_to(..) discards the first line below the target search text, 214 # resulting in FN(unspec) being skipped and not added to self.define_unique_helpers. 215 self.seek_to('#define __BPF_FUNC_MAPPER(FN)', 216 'Could not find start of eBPF helper definition list') 217 # Searches for either one or more FN(\w+) defines or a backslash for newline 218 p = re.compile('\s*(FN\(\w+\))+|\\\\') 219 fn_defines_str = '' 220 while True: 221 capture = p.match(self.line) 222 if capture: 223 fn_defines_str += self.line 224 else: 225 break 226 self.line = self.reader.readline() 227 # Find the number of occurences of FN(\w+) 228 self.define_unique_helpers = re.findall('FN\(\w+\)', fn_defines_str) 229 230 def run(self): 231 self.parse_syscall() 232 self.parse_desc_helpers() 233 self.parse_define_helpers() 234 self.reader.close() 235 236############################################################################### 237 238class Printer(object): 239 """ 240 A generic class for printers. Printers should be created with an array of 241 Helper objects, and implement a way to print them in the desired fashion. 242 @parser: A HeaderParser with objects to print to standard output 243 """ 244 def __init__(self, parser): 245 self.parser = parser 246 self.elements = [] 247 248 def print_header(self): 249 pass 250 251 def print_footer(self): 252 pass 253 254 def print_one(self, helper): 255 pass 256 257 def print_all(self): 258 self.print_header() 259 for elem in self.elements: 260 self.print_one(elem) 261 self.print_footer() 262 263 264class PrinterRST(Printer): 265 """ 266 A generic class for printers that print ReStructured Text. Printers should 267 be created with a HeaderParser object, and implement a way to print API 268 elements in the desired fashion. 269 @parser: A HeaderParser with objects to print to standard output 270 """ 271 def __init__(self, parser): 272 self.parser = parser 273 274 def print_license(self): 275 license = '''\ 276.. Copyright (C) All BPF authors and contributors from 2014 to present. 277.. See git log include/uapi/linux/bpf.h in kernel tree for details. 278.. 279.. %%%LICENSE_START(VERBATIM) 280.. Permission is granted to make and distribute verbatim copies of this 281.. manual provided the copyright notice and this permission notice are 282.. preserved on all copies. 283.. 284.. Permission is granted to copy and distribute modified versions of this 285.. manual under the conditions for verbatim copying, provided that the 286.. entire resulting derived work is distributed under the terms of a 287.. permission notice identical to this one. 288.. 289.. Since the Linux kernel and libraries are constantly changing, this 290.. manual page may be incorrect or out-of-date. The author(s) assume no 291.. responsibility for errors or omissions, or for damages resulting from 292.. the use of the information contained herein. The author(s) may not 293.. have taken the same level of care in the production of this manual, 294.. which is licensed free of charge, as they might when working 295.. professionally. 296.. 297.. Formatted or processed versions of this manual, if unaccompanied by 298.. the source, must acknowledge the copyright and authors of this work. 299.. %%%LICENSE_END 300.. 301.. Please do not edit this file. It was generated from the documentation 302.. located in file include/uapi/linux/bpf.h of the Linux kernel sources 303.. (helpers description), and from scripts/bpf_doc.py in the same 304.. repository (header and footer). 305''' 306 print(license) 307 308 def print_elem(self, elem): 309 if (elem.desc): 310 print('\tDescription') 311 # Do not strip all newline characters: formatted code at the end of 312 # a section must be followed by a blank line. 313 for line in re.sub('\n$', '', elem.desc, count=1).split('\n'): 314 print('{}{}'.format('\t\t' if line else '', line)) 315 316 if (elem.ret): 317 print('\tReturn') 318 for line in elem.ret.rstrip().split('\n'): 319 print('{}{}'.format('\t\t' if line else '', line)) 320 321 print('') 322 323def helper_number_check(desc_unique_helpers, define_unique_helpers): 324 """ 325 Checks the number of functions documented within the header file 326 with those present as part of #define __BPF_FUNC_MAPPER and raise an 327 Exception if they don't match. 328 """ 329 nr_desc_unique_helpers = len(desc_unique_helpers) 330 nr_define_unique_helpers = len(define_unique_helpers) 331 if nr_desc_unique_helpers != nr_define_unique_helpers: 332 helper_exception = ''' 333The number of unique helpers in description (%d) doesn\'t match the number of unique helpers defined in __BPF_FUNC_MAPPER (%d) 334''' % (nr_desc_unique_helpers, nr_define_unique_helpers) 335 if nr_desc_unique_helpers < nr_define_unique_helpers: 336 # Function description is parsed until no helper is found (which can be due to 337 # misformatting). Hence, only print the first missing/misformatted function. 338 helper_exception += ''' 339The description for %s is not present or formatted correctly. 340''' % (define_unique_helpers[nr_desc_unique_helpers]) 341 raise Exception(helper_exception) 342 343class PrinterHelpersRST(PrinterRST): 344 """ 345 A printer for dumping collected information about helpers as a ReStructured 346 Text page compatible with the rst2man program, which can be used to 347 generate a manual page for the helpers. 348 @parser: A HeaderParser with Helper objects to print to standard output 349 """ 350 def __init__(self, parser): 351 self.elements = parser.helpers 352 helper_number_check(parser.desc_unique_helpers, parser.define_unique_helpers) 353 354 def print_header(self): 355 header = '''\ 356=========== 357BPF-HELPERS 358=========== 359------------------------------------------------------------------------------- 360list of eBPF helper functions 361------------------------------------------------------------------------------- 362 363:Manual section: 7 364 365DESCRIPTION 366=========== 367 368The extended Berkeley Packet Filter (eBPF) subsystem consists in programs 369written in a pseudo-assembly language, then attached to one of the several 370kernel hooks and run in reaction of specific events. This framework differs 371from the older, "classic" BPF (or "cBPF") in several aspects, one of them being 372the ability to call special functions (or "helpers") from within a program. 373These functions are restricted to a white-list of helpers defined in the 374kernel. 375 376These helpers are used by eBPF programs to interact with the system, or with 377the context in which they work. For instance, they can be used to print 378debugging messages, to get the time since the system was booted, to interact 379with eBPF maps, or to manipulate network packets. Since there are several eBPF 380program types, and that they do not run in the same context, each program type 381can only call a subset of those helpers. 382 383Due to eBPF conventions, a helper can not have more than five arguments. 384 385Internally, eBPF programs call directly into the compiled helper functions 386without requiring any foreign-function interface. As a result, calling helpers 387introduces no overhead, thus offering excellent performance. 388 389This document is an attempt to list and document the helpers available to eBPF 390developers. They are sorted by chronological order (the oldest helpers in the 391kernel at the top). 392 393HELPERS 394======= 395''' 396 PrinterRST.print_license(self) 397 print(header) 398 399 def print_footer(self): 400 footer = ''' 401EXAMPLES 402======== 403 404Example usage for most of the eBPF helpers listed in this manual page are 405available within the Linux kernel sources, at the following locations: 406 407* *samples/bpf/* 408* *tools/testing/selftests/bpf/* 409 410LICENSE 411======= 412 413eBPF programs can have an associated license, passed along with the bytecode 414instructions to the kernel when the programs are loaded. The format for that 415string is identical to the one in use for kernel modules (Dual licenses, such 416as "Dual BSD/GPL", may be used). Some helper functions are only accessible to 417programs that are compatible with the GNU Privacy License (GPL). 418 419In order to use such helpers, the eBPF program must be loaded with the correct 420license string passed (via **attr**) to the **bpf**\ () system call, and this 421generally translates into the C source code of the program containing a line 422similar to the following: 423 424:: 425 426 char ____license[] __attribute__((section("license"), used)) = "GPL"; 427 428IMPLEMENTATION 429============== 430 431This manual page is an effort to document the existing eBPF helper functions. 432But as of this writing, the BPF sub-system is under heavy development. New eBPF 433program or map types are added, along with new helper functions. Some helpers 434are occasionally made available for additional program types. So in spite of 435the efforts of the community, this page might not be up-to-date. If you want to 436check by yourself what helper functions exist in your kernel, or what types of 437programs they can support, here are some files among the kernel tree that you 438may be interested in: 439 440* *include/uapi/linux/bpf.h* is the main BPF header. It contains the full list 441 of all helper functions, as well as many other BPF definitions including most 442 of the flags, structs or constants used by the helpers. 443* *net/core/filter.c* contains the definition of most network-related helper 444 functions, and the list of program types from which they can be used. 445* *kernel/trace/bpf_trace.c* is the equivalent for most tracing program-related 446 helpers. 447* *kernel/bpf/verifier.c* contains the functions used to check that valid types 448 of eBPF maps are used with a given helper function. 449* *kernel/bpf/* directory contains other files in which additional helpers are 450 defined (for cgroups, sockmaps, etc.). 451* The bpftool utility can be used to probe the availability of helper functions 452 on the system (as well as supported program and map types, and a number of 453 other parameters). To do so, run **bpftool feature probe** (see 454 **bpftool-feature**\ (8) for details). Add the **unprivileged** keyword to 455 list features available to unprivileged users. 456 457Compatibility between helper functions and program types can generally be found 458in the files where helper functions are defined. Look for the **struct 459bpf_func_proto** objects and for functions returning them: these functions 460contain a list of helpers that a given program type can call. Note that the 461**default:** label of the **switch ... case** used to filter helpers can call 462other functions, themselves allowing access to additional helpers. The 463requirement for GPL license is also in those **struct bpf_func_proto**. 464 465Compatibility between helper functions and map types can be found in the 466**check_map_func_compatibility**\ () function in file *kernel/bpf/verifier.c*. 467 468Helper functions that invalidate the checks on **data** and **data_end** 469pointers for network processing are listed in function 470**bpf_helper_changes_pkt_data**\ () in file *net/core/filter.c*. 471 472SEE ALSO 473======== 474 475**bpf**\ (2), 476**bpftool**\ (8), 477**cgroups**\ (7), 478**ip**\ (8), 479**perf_event_open**\ (2), 480**sendmsg**\ (2), 481**socket**\ (7), 482**tc-bpf**\ (8)''' 483 print(footer) 484 485 def print_proto(self, helper): 486 """ 487 Format function protocol with bold and italics markers. This makes RST 488 file less readable, but gives nice results in the manual page. 489 """ 490 proto = helper.proto_break_down() 491 492 print('**%s %s%s(' % (proto['ret_type'], 493 proto['ret_star'].replace('*', '\\*'), 494 proto['name']), 495 end='') 496 497 comma = '' 498 for a in proto['args']: 499 one_arg = '{}{}'.format(comma, a['type']) 500 if a['name']: 501 if a['star']: 502 one_arg += ' {}**\ '.format(a['star'].replace('*', '\\*')) 503 else: 504 one_arg += '** ' 505 one_arg += '*{}*\\ **'.format(a['name']) 506 comma = ', ' 507 print(one_arg, end='') 508 509 print(')**') 510 511 def print_one(self, helper): 512 self.print_proto(helper) 513 self.print_elem(helper) 514 515 516class PrinterSyscallRST(PrinterRST): 517 """ 518 A printer for dumping collected information about the syscall API as a 519 ReStructured Text page compatible with the rst2man program, which can be 520 used to generate a manual page for the syscall. 521 @parser: A HeaderParser with APIElement objects to print to standard 522 output 523 """ 524 def __init__(self, parser): 525 self.elements = parser.commands 526 527 def print_header(self): 528 header = '''\ 529=== 530bpf 531=== 532------------------------------------------------------------------------------- 533Perform a command on an extended BPF object 534------------------------------------------------------------------------------- 535 536:Manual section: 2 537 538COMMANDS 539======== 540''' 541 PrinterRST.print_license(self) 542 print(header) 543 544 def print_one(self, command): 545 print('**%s**' % (command.proto)) 546 self.print_elem(command) 547 548 549class PrinterHelpers(Printer): 550 """ 551 A printer for dumping collected information about helpers as C header to 552 be included from BPF program. 553 @parser: A HeaderParser with Helper objects to print to standard output 554 """ 555 def __init__(self, parser): 556 self.elements = parser.helpers 557 helper_number_check(parser.desc_unique_helpers, parser.define_unique_helpers) 558 559 type_fwds = [ 560 'struct bpf_fib_lookup', 561 'struct bpf_sk_lookup', 562 'struct bpf_perf_event_data', 563 'struct bpf_perf_event_value', 564 'struct bpf_pidns_info', 565 'struct bpf_redir_neigh', 566 'struct bpf_sock', 567 'struct bpf_sock_addr', 568 'struct bpf_sock_ops', 569 'struct bpf_sock_tuple', 570 'struct bpf_spin_lock', 571 'struct bpf_sysctl', 572 'struct bpf_tcp_sock', 573 'struct bpf_tunnel_key', 574 'struct bpf_xfrm_state', 575 'struct linux_binprm', 576 'struct pt_regs', 577 'struct sk_reuseport_md', 578 'struct sockaddr', 579 'struct tcphdr', 580 'struct seq_file', 581 'struct tcp6_sock', 582 'struct tcp_sock', 583 'struct tcp_timewait_sock', 584 'struct tcp_request_sock', 585 'struct udp6_sock', 586 'struct unix_sock', 587 'struct task_struct', 588 589 'struct __sk_buff', 590 'struct sk_msg_md', 591 'struct xdp_md', 592 'struct path', 593 'struct btf_ptr', 594 'struct inode', 595 'struct socket', 596 'struct file', 597 'struct bpf_timer', 598 ] 599 known_types = { 600 '...', 601 'void', 602 'const void', 603 'char', 604 'const char', 605 'int', 606 'long', 607 'unsigned long', 608 609 '__be16', 610 '__be32', 611 '__wsum', 612 613 'struct bpf_fib_lookup', 614 'struct bpf_perf_event_data', 615 'struct bpf_perf_event_value', 616 'struct bpf_pidns_info', 617 'struct bpf_redir_neigh', 618 'struct bpf_sk_lookup', 619 'struct bpf_sock', 620 'struct bpf_sock_addr', 621 'struct bpf_sock_ops', 622 'struct bpf_sock_tuple', 623 'struct bpf_spin_lock', 624 'struct bpf_sysctl', 625 'struct bpf_tcp_sock', 626 'struct bpf_tunnel_key', 627 'struct bpf_xfrm_state', 628 'struct linux_binprm', 629 'struct pt_regs', 630 'struct sk_reuseport_md', 631 'struct sockaddr', 632 'struct tcphdr', 633 'struct seq_file', 634 'struct tcp6_sock', 635 'struct tcp_sock', 636 'struct tcp_timewait_sock', 637 'struct tcp_request_sock', 638 'struct udp6_sock', 639 'struct unix_sock', 640 'struct task_struct', 641 'struct path', 642 'struct btf_ptr', 643 'struct inode', 644 'struct socket', 645 'struct file', 646 'struct bpf_timer', 647 } 648 mapped_types = { 649 'u8': '__u8', 650 'u16': '__u16', 651 'u32': '__u32', 652 'u64': '__u64', 653 's8': '__s8', 654 's16': '__s16', 655 's32': '__s32', 656 's64': '__s64', 657 'size_t': 'unsigned long', 658 'struct bpf_map': 'void', 659 'struct sk_buff': 'struct __sk_buff', 660 'const struct sk_buff': 'const struct __sk_buff', 661 'struct sk_msg_buff': 'struct sk_msg_md', 662 'struct xdp_buff': 'struct xdp_md', 663 } 664 # Helpers overloaded for different context types. 665 overloaded_helpers = [ 666 'bpf_get_socket_cookie', 667 'bpf_sk_assign', 668 ] 669 670 def print_header(self): 671 header = '''\ 672/* This is auto-generated file. See bpf_doc.py for details. */ 673 674/* Forward declarations of BPF structs */''' 675 676 print(header) 677 for fwd in self.type_fwds: 678 print('%s;' % fwd) 679 print('') 680 681 def print_footer(self): 682 footer = '' 683 print(footer) 684 685 def map_type(self, t): 686 if t in self.known_types: 687 return t 688 if t in self.mapped_types: 689 return self.mapped_types[t] 690 print("Unrecognized type '%s', please add it to known types!" % t, 691 file=sys.stderr) 692 sys.exit(1) 693 694 seen_helpers = set() 695 696 def print_one(self, helper): 697 proto = helper.proto_break_down() 698 699 if proto['name'] in self.seen_helpers: 700 return 701 self.seen_helpers.add(proto['name']) 702 703 print('/*') 704 print(" * %s" % proto['name']) 705 print(" *") 706 if (helper.desc): 707 # Do not strip all newline characters: formatted code at the end of 708 # a section must be followed by a blank line. 709 for line in re.sub('\n$', '', helper.desc, count=1).split('\n'): 710 print(' *{}{}'.format(' \t' if line else '', line)) 711 712 if (helper.ret): 713 print(' *') 714 print(' * Returns') 715 for line in helper.ret.rstrip().split('\n'): 716 print(' *{}{}'.format(' \t' if line else '', line)) 717 718 print(' */') 719 print('static %s %s(*%s)(' % (self.map_type(proto['ret_type']), 720 proto['ret_star'], proto['name']), end='') 721 comma = '' 722 for i, a in enumerate(proto['args']): 723 t = a['type'] 724 n = a['name'] 725 if proto['name'] in self.overloaded_helpers and i == 0: 726 t = 'void' 727 n = 'ctx' 728 one_arg = '{}{}'.format(comma, self.map_type(t)) 729 if n: 730 if a['star']: 731 one_arg += ' {}'.format(a['star']) 732 else: 733 one_arg += ' ' 734 one_arg += '{}'.format(n) 735 comma = ', ' 736 print(one_arg, end='') 737 738 print(') = (void *) %d;' % len(self.seen_helpers)) 739 print('') 740 741############################################################################### 742 743# If script is launched from scripts/ from kernel tree and can access 744# ../include/uapi/linux/bpf.h, use it as a default name for the file to parse, 745# otherwise the --filename argument will be required from the command line. 746script = os.path.abspath(sys.argv[0]) 747linuxRoot = os.path.dirname(os.path.dirname(script)) 748bpfh = os.path.join(linuxRoot, 'include/uapi/linux/bpf.h') 749 750printers = { 751 'helpers': PrinterHelpersRST, 752 'syscall': PrinterSyscallRST, 753} 754 755argParser = argparse.ArgumentParser(description=""" 756Parse eBPF header file and generate documentation for the eBPF API. 757The RST-formatted output produced can be turned into a manual page with the 758rst2man utility. 759""") 760argParser.add_argument('--header', action='store_true', 761 help='generate C header file') 762if (os.path.isfile(bpfh)): 763 argParser.add_argument('--filename', help='path to include/uapi/linux/bpf.h', 764 default=bpfh) 765else: 766 argParser.add_argument('--filename', help='path to include/uapi/linux/bpf.h') 767argParser.add_argument('target', nargs='?', default='helpers', 768 choices=printers.keys(), help='eBPF API target') 769args = argParser.parse_args() 770 771# Parse file. 772headerParser = HeaderParser(args.filename) 773headerParser.run() 774 775# Print formatted output to standard output. 776if args.header: 777 if args.target != 'helpers': 778 raise NotImplementedError('Only helpers header generation is supported') 779 printer = PrinterHelpers(headerParser) 780else: 781 printer = printers[args.target](headerParser) 782printer.print_all() 783