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