Back to home page

OSCL-LXR

 
 

    


0001 #!/usr/bin/env python3
0002 # SPDX-License-Identifier: GPL-2.0-only
0003 #
0004 # Copyright (C) 2018-2019 Netronome Systems, Inc.
0005 # Copyright (C) 2021 Isovalent, Inc.
0006 
0007 # In case user attempts to run with Python 2.
0008 from __future__ import print_function
0009 
0010 import argparse
0011 import re
0012 import sys, os
0013 
0014 class NoHelperFound(BaseException):
0015     pass
0016 
0017 class NoSyscallCommandFound(BaseException):
0018     pass
0019 
0020 class ParsingError(BaseException):
0021     def __init__(self, line='<line not provided>', reader=None):
0022         if reader:
0023             BaseException.__init__(self,
0024                                    'Error at file offset %d, parsing line: %s' %
0025                                    (reader.tell(), line))
0026         else:
0027             BaseException.__init__(self, 'Error parsing line: %s' % line)
0028 
0029 
0030 class APIElement(object):
0031     """
0032     An object representing the description of an aspect of the eBPF API.
0033     @proto: prototype of the API symbol
0034     @desc: textual description of the symbol
0035     @ret: (optional) description of any associated return value
0036     """
0037     def __init__(self, proto='', desc='', ret=''):
0038         self.proto = proto
0039         self.desc = desc
0040         self.ret = ret
0041 
0042 
0043 class Helper(APIElement):
0044     """
0045     An object representing the description of an eBPF helper function.
0046     @proto: function prototype of the helper function
0047     @desc: textual description of the helper function
0048     @ret: description of the return value of the helper function
0049     """
0050     def proto_break_down(self):
0051         """
0052         Break down helper function protocol into smaller chunks: return type,
0053         name, distincts arguments.
0054         """
0055         arg_re = re.compile('((\w+ )*?(\w+|...))( (\**)(\w+))?$')
0056         res = {}
0057         proto_re = re.compile('(.+) (\**)(\w+)\(((([^,]+)(, )?){1,5})\)$')
0058 
0059         capture = proto_re.match(self.proto)
0060         res['ret_type'] = capture.group(1)
0061         res['ret_star'] = capture.group(2)
0062         res['name']     = capture.group(3)
0063         res['args'] = []
0064 
0065         args    = capture.group(4).split(', ')
0066         for a in args:
0067             capture = arg_re.match(a)
0068             res['args'].append({
0069                 'type' : capture.group(1),
0070                 'star' : capture.group(5),
0071                 'name' : capture.group(6)
0072             })
0073 
0074         return res
0075 
0076 
0077 class HeaderParser(object):
0078     """
0079     An object used to parse a file in order to extract the documentation of a
0080     list of eBPF helper functions. All the helpers that can be retrieved are
0081     stored as Helper object, in the self.helpers() array.
0082     @filename: name of file to parse, usually include/uapi/linux/bpf.h in the
0083                kernel tree
0084     """
0085     def __init__(self, filename):
0086         self.reader = open(filename, 'r')
0087         self.line = ''
0088         self.helpers = []
0089         self.commands = []
0090         self.desc_unique_helpers = set()
0091         self.define_unique_helpers = []
0092         self.desc_syscalls = []
0093         self.enum_syscalls = []
0094 
0095     def parse_element(self):
0096         proto    = self.parse_symbol()
0097         desc     = self.parse_desc(proto)
0098         ret      = self.parse_ret(proto)
0099         return APIElement(proto=proto, desc=desc, ret=ret)
0100 
0101     def parse_helper(self):
0102         proto    = self.parse_proto()
0103         desc     = self.parse_desc(proto)
0104         ret      = self.parse_ret(proto)
0105         return Helper(proto=proto, desc=desc, ret=ret)
0106 
0107     def parse_symbol(self):
0108         p = re.compile(' \* ?(BPF\w+)$')
0109         capture = p.match(self.line)
0110         if not capture:
0111             raise NoSyscallCommandFound
0112         end_re = re.compile(' \* ?NOTES$')
0113         end = end_re.match(self.line)
0114         if end:
0115             raise NoSyscallCommandFound
0116         self.line = self.reader.readline()
0117         return capture.group(1)
0118 
0119     def parse_proto(self):
0120         # Argument can be of shape:
0121         #   - "void"
0122         #   - "type  name"
0123         #   - "type *name"
0124         #   - Same as above, with "const" and/or "struct" in front of type
0125         #   - "..." (undefined number of arguments, for bpf_trace_printk())
0126         # There is at least one term ("void"), and at most five arguments.
0127         p = re.compile(' \* ?((.+) \**\w+\((((const )?(struct )?(\w+|\.\.\.)( \**\w+)?)(, )?){1,5}\))$')
0128         capture = p.match(self.line)
0129         if not capture:
0130             raise NoHelperFound
0131         self.line = self.reader.readline()
0132         return capture.group(1)
0133 
0134     def parse_desc(self, proto):
0135         p = re.compile(' \* ?(?:\t| {5,8})Description$')
0136         capture = p.match(self.line)
0137         if not capture:
0138             raise Exception("No description section found for " + proto)
0139         # Description can be several lines, some of them possibly empty, and it
0140         # stops when another subsection title is met.
0141         desc = ''
0142         desc_present = False
0143         while True:
0144             self.line = self.reader.readline()
0145             if self.line == ' *\n':
0146                 desc += '\n'
0147             else:
0148                 p = re.compile(' \* ?(?:\t| {5,8})(?:\t| {8})(.*)')
0149                 capture = p.match(self.line)
0150                 if capture:
0151                     desc_present = True
0152                     desc += capture.group(1) + '\n'
0153                 else:
0154                     break
0155 
0156         if not desc_present:
0157             raise Exception("No description found for " + proto)
0158         return desc
0159 
0160     def parse_ret(self, proto):
0161         p = re.compile(' \* ?(?:\t| {5,8})Return$')
0162         capture = p.match(self.line)
0163         if not capture:
0164             raise Exception("No return section found for " + proto)
0165         # Return value description can be several lines, some of them possibly
0166         # empty, and it stops when another subsection title is met.
0167         ret = ''
0168         ret_present = False
0169         while True:
0170             self.line = self.reader.readline()
0171             if self.line == ' *\n':
0172                 ret += '\n'
0173             else:
0174                 p = re.compile(' \* ?(?:\t| {5,8})(?:\t| {8})(.*)')
0175                 capture = p.match(self.line)
0176                 if capture:
0177                     ret_present = True
0178                     ret += capture.group(1) + '\n'
0179                 else:
0180                     break
0181 
0182         if not ret_present:
0183             raise Exception("No return found for " + proto)
0184         return ret
0185 
0186     def seek_to(self, target, help_message, discard_lines = 1):
0187         self.reader.seek(0)
0188         offset = self.reader.read().find(target)
0189         if offset == -1:
0190             raise Exception(help_message)
0191         self.reader.seek(offset)
0192         self.reader.readline()
0193         for _ in range(discard_lines):
0194             self.reader.readline()
0195         self.line = self.reader.readline()
0196 
0197     def parse_desc_syscall(self):
0198         self.seek_to('* DOC: eBPF Syscall Commands',
0199                      'Could not find start of eBPF syscall descriptions list')
0200         while True:
0201             try:
0202                 command = self.parse_element()
0203                 self.commands.append(command)
0204                 self.desc_syscalls.append(command.proto)
0205 
0206             except NoSyscallCommandFound:
0207                 break
0208 
0209     def parse_enum_syscall(self):
0210         self.seek_to('enum bpf_cmd {',
0211                      'Could not find start of bpf_cmd enum', 0)
0212         # Searches for either one or more BPF\w+ enums
0213         bpf_p = re.compile('\s*(BPF\w+)+')
0214         # Searches for an enum entry assigned to another entry,
0215         # for e.g. BPF_PROG_RUN = BPF_PROG_TEST_RUN, which is
0216         # not documented hence should be skipped in check to
0217         # determine if the right number of syscalls are documented
0218         assign_p = re.compile('\s*(BPF\w+)\s*=\s*(BPF\w+)')
0219         bpf_cmd_str = ''
0220         while True:
0221             capture = assign_p.match(self.line)
0222             if capture:
0223                 # Skip line if an enum entry is assigned to another entry
0224                 self.line = self.reader.readline()
0225                 continue
0226             capture = bpf_p.match(self.line)
0227             if capture:
0228                 bpf_cmd_str += self.line
0229             else:
0230                 break
0231             self.line = self.reader.readline()
0232         # Find the number of occurences of BPF\w+
0233         self.enum_syscalls = re.findall('(BPF\w+)+', bpf_cmd_str)
0234 
0235     def parse_desc_helpers(self):
0236         self.seek_to('* Start of BPF helper function descriptions:',
0237                      'Could not find start of eBPF helper descriptions list')
0238         while True:
0239             try:
0240                 helper = self.parse_helper()
0241                 self.helpers.append(helper)
0242                 proto = helper.proto_break_down()
0243                 self.desc_unique_helpers.add(proto['name'])
0244             except NoHelperFound:
0245                 break
0246 
0247     def parse_define_helpers(self):
0248         # Parse the number of FN(...) in #define __BPF_FUNC_MAPPER to compare
0249         # later with the number of unique function names present in description.
0250         # Note: seek_to(..) discards the first line below the target search text,
0251         # resulting in FN(unspec) being skipped and not added to self.define_unique_helpers.
0252         self.seek_to('#define __BPF_FUNC_MAPPER(FN)',
0253                      'Could not find start of eBPF helper definition list')
0254         # Searches for either one or more FN(\w+) defines or a backslash for newline
0255         p = re.compile('\s*(FN\(\w+\))+|\\\\')
0256         fn_defines_str = ''
0257         while True:
0258             capture = p.match(self.line)
0259             if capture:
0260                 fn_defines_str += self.line
0261             else:
0262                 break
0263             self.line = self.reader.readline()
0264         # Find the number of occurences of FN(\w+)
0265         self.define_unique_helpers = re.findall('FN\(\w+\)', fn_defines_str)
0266 
0267     def run(self):
0268         self.parse_desc_syscall()
0269         self.parse_enum_syscall()
0270         self.parse_desc_helpers()
0271         self.parse_define_helpers()
0272         self.reader.close()
0273 
0274 ###############################################################################
0275 
0276 class Printer(object):
0277     """
0278     A generic class for printers. Printers should be created with an array of
0279     Helper objects, and implement a way to print them in the desired fashion.
0280     @parser: A HeaderParser with objects to print to standard output
0281     """
0282     def __init__(self, parser):
0283         self.parser = parser
0284         self.elements = []
0285 
0286     def print_header(self):
0287         pass
0288 
0289     def print_footer(self):
0290         pass
0291 
0292     def print_one(self, helper):
0293         pass
0294 
0295     def print_all(self):
0296         self.print_header()
0297         for elem in self.elements:
0298             self.print_one(elem)
0299         self.print_footer()
0300 
0301     def elem_number_check(self, desc_unique_elem, define_unique_elem, type, instance):
0302         """
0303         Checks the number of helpers/syscalls documented within the header file
0304         description with those defined as part of enum/macro and raise an
0305         Exception if they don't match.
0306         """
0307         nr_desc_unique_elem = len(desc_unique_elem)
0308         nr_define_unique_elem = len(define_unique_elem)
0309         if nr_desc_unique_elem != nr_define_unique_elem:
0310             exception_msg = '''
0311 The number of unique %s in description (%d) doesn\'t match the number of unique %s defined in %s (%d)
0312 ''' % (type, nr_desc_unique_elem, type, instance, nr_define_unique_elem)
0313             if nr_desc_unique_elem < nr_define_unique_elem:
0314                 # Function description is parsed until no helper is found (which can be due to
0315                 # misformatting). Hence, only print the first missing/misformatted helper/enum.
0316                 exception_msg += '''
0317 The description for %s is not present or formatted correctly.
0318 ''' % (define_unique_elem[nr_desc_unique_elem])
0319             raise Exception(exception_msg)
0320 
0321 class PrinterRST(Printer):
0322     """
0323     A generic class for printers that print ReStructured Text. Printers should
0324     be created with a HeaderParser object, and implement a way to print API
0325     elements in the desired fashion.
0326     @parser: A HeaderParser with objects to print to standard output
0327     """
0328     def __init__(self, parser):
0329         self.parser = parser
0330 
0331     def print_license(self):
0332         license = '''\
0333 .. Copyright (C) All BPF authors and contributors from 2014 to present.
0334 .. See git log include/uapi/linux/bpf.h in kernel tree for details.
0335 .. 
0336 .. SPDX-License-Identifier:  Linux-man-pages-copyleft
0337 .. 
0338 .. Please do not edit this file. It was generated from the documentation
0339 .. located in file include/uapi/linux/bpf.h of the Linux kernel sources
0340 .. (helpers description), and from scripts/bpf_doc.py in the same
0341 .. repository (header and footer).
0342 '''
0343         print(license)
0344 
0345     def print_elem(self, elem):
0346         if (elem.desc):
0347             print('\tDescription')
0348             # Do not strip all newline characters: formatted code at the end of
0349             # a section must be followed by a blank line.
0350             for line in re.sub('\n$', '', elem.desc, count=1).split('\n'):
0351                 print('{}{}'.format('\t\t' if line else '', line))
0352 
0353         if (elem.ret):
0354             print('\tReturn')
0355             for line in elem.ret.rstrip().split('\n'):
0356                 print('{}{}'.format('\t\t' if line else '', line))
0357 
0358         print('')
0359 
0360 class PrinterHelpersRST(PrinterRST):
0361     """
0362     A printer for dumping collected information about helpers as a ReStructured
0363     Text page compatible with the rst2man program, which can be used to
0364     generate a manual page for the helpers.
0365     @parser: A HeaderParser with Helper objects to print to standard output
0366     """
0367     def __init__(self, parser):
0368         self.elements = parser.helpers
0369         self.elem_number_check(parser.desc_unique_helpers, parser.define_unique_helpers, 'helper', '__BPF_FUNC_MAPPER')
0370 
0371     def print_header(self):
0372         header = '''\
0373 ===========
0374 BPF-HELPERS
0375 ===========
0376 -------------------------------------------------------------------------------
0377 list of eBPF helper functions
0378 -------------------------------------------------------------------------------
0379 
0380 :Manual section: 7
0381 
0382 DESCRIPTION
0383 ===========
0384 
0385 The extended Berkeley Packet Filter (eBPF) subsystem consists in programs
0386 written in a pseudo-assembly language, then attached to one of the several
0387 kernel hooks and run in reaction of specific events. This framework differs
0388 from the older, "classic" BPF (or "cBPF") in several aspects, one of them being
0389 the ability to call special functions (or "helpers") from within a program.
0390 These functions are restricted to a white-list of helpers defined in the
0391 kernel.
0392 
0393 These helpers are used by eBPF programs to interact with the system, or with
0394 the context in which they work. For instance, they can be used to print
0395 debugging messages, to get the time since the system was booted, to interact
0396 with eBPF maps, or to manipulate network packets. Since there are several eBPF
0397 program types, and that they do not run in the same context, each program type
0398 can only call a subset of those helpers.
0399 
0400 Due to eBPF conventions, a helper can not have more than five arguments.
0401 
0402 Internally, eBPF programs call directly into the compiled helper functions
0403 without requiring any foreign-function interface. As a result, calling helpers
0404 introduces no overhead, thus offering excellent performance.
0405 
0406 This document is an attempt to list and document the helpers available to eBPF
0407 developers. They are sorted by chronological order (the oldest helpers in the
0408 kernel at the top).
0409 
0410 HELPERS
0411 =======
0412 '''
0413         PrinterRST.print_license(self)
0414         print(header)
0415 
0416     def print_footer(self):
0417         footer = '''
0418 EXAMPLES
0419 ========
0420 
0421 Example usage for most of the eBPF helpers listed in this manual page are
0422 available within the Linux kernel sources, at the following locations:
0423 
0424 * *samples/bpf/*
0425 * *tools/testing/selftests/bpf/*
0426 
0427 LICENSE
0428 =======
0429 
0430 eBPF programs can have an associated license, passed along with the bytecode
0431 instructions to the kernel when the programs are loaded. The format for that
0432 string is identical to the one in use for kernel modules (Dual licenses, such
0433 as "Dual BSD/GPL", may be used). Some helper functions are only accessible to
0434 programs that are compatible with the GNU Privacy License (GPL).
0435 
0436 In order to use such helpers, the eBPF program must be loaded with the correct
0437 license string passed (via **attr**) to the **bpf**\ () system call, and this
0438 generally translates into the C source code of the program containing a line
0439 similar to the following:
0440 
0441 ::
0442 
0443     char ____license[] __attribute__((section("license"), used)) = "GPL";
0444 
0445 IMPLEMENTATION
0446 ==============
0447 
0448 This manual page is an effort to document the existing eBPF helper functions.
0449 But as of this writing, the BPF sub-system is under heavy development. New eBPF
0450 program or map types are added, along with new helper functions. Some helpers
0451 are occasionally made available for additional program types. So in spite of
0452 the efforts of the community, this page might not be up-to-date. If you want to
0453 check by yourself what helper functions exist in your kernel, or what types of
0454 programs they can support, here are some files among the kernel tree that you
0455 may be interested in:
0456 
0457 * *include/uapi/linux/bpf.h* is the main BPF header. It contains the full list
0458   of all helper functions, as well as many other BPF definitions including most
0459   of the flags, structs or constants used by the helpers.
0460 * *net/core/filter.c* contains the definition of most network-related helper
0461   functions, and the list of program types from which they can be used.
0462 * *kernel/trace/bpf_trace.c* is the equivalent for most tracing program-related
0463   helpers.
0464 * *kernel/bpf/verifier.c* contains the functions used to check that valid types
0465   of eBPF maps are used with a given helper function.
0466 * *kernel/bpf/* directory contains other files in which additional helpers are
0467   defined (for cgroups, sockmaps, etc.).
0468 * The bpftool utility can be used to probe the availability of helper functions
0469   on the system (as well as supported program and map types, and a number of
0470   other parameters). To do so, run **bpftool feature probe** (see
0471   **bpftool-feature**\ (8) for details). Add the **unprivileged** keyword to
0472   list features available to unprivileged users.
0473 
0474 Compatibility between helper functions and program types can generally be found
0475 in the files where helper functions are defined. Look for the **struct
0476 bpf_func_proto** objects and for functions returning them: these functions
0477 contain a list of helpers that a given program type can call. Note that the
0478 **default:** label of the **switch ... case** used to filter helpers can call
0479 other functions, themselves allowing access to additional helpers. The
0480 requirement for GPL license is also in those **struct bpf_func_proto**.
0481 
0482 Compatibility between helper functions and map types can be found in the
0483 **check_map_func_compatibility**\ () function in file *kernel/bpf/verifier.c*.
0484 
0485 Helper functions that invalidate the checks on **data** and **data_end**
0486 pointers for network processing are listed in function
0487 **bpf_helper_changes_pkt_data**\ () in file *net/core/filter.c*.
0488 
0489 SEE ALSO
0490 ========
0491 
0492 **bpf**\ (2),
0493 **bpftool**\ (8),
0494 **cgroups**\ (7),
0495 **ip**\ (8),
0496 **perf_event_open**\ (2),
0497 **sendmsg**\ (2),
0498 **socket**\ (7),
0499 **tc-bpf**\ (8)'''
0500         print(footer)
0501 
0502     def print_proto(self, helper):
0503         """
0504         Format function protocol with bold and italics markers. This makes RST
0505         file less readable, but gives nice results in the manual page.
0506         """
0507         proto = helper.proto_break_down()
0508 
0509         print('**%s %s%s(' % (proto['ret_type'],
0510                               proto['ret_star'].replace('*', '\\*'),
0511                               proto['name']),
0512               end='')
0513 
0514         comma = ''
0515         for a in proto['args']:
0516             one_arg = '{}{}'.format(comma, a['type'])
0517             if a['name']:
0518                 if a['star']:
0519                     one_arg += ' {}**\ '.format(a['star'].replace('*', '\\*'))
0520                 else:
0521                     one_arg += '** '
0522                 one_arg += '*{}*\\ **'.format(a['name'])
0523             comma = ', '
0524             print(one_arg, end='')
0525 
0526         print(')**')
0527 
0528     def print_one(self, helper):
0529         self.print_proto(helper)
0530         self.print_elem(helper)
0531 
0532 
0533 class PrinterSyscallRST(PrinterRST):
0534     """
0535     A printer for dumping collected information about the syscall API as a
0536     ReStructured Text page compatible with the rst2man program, which can be
0537     used to generate a manual page for the syscall.
0538     @parser: A HeaderParser with APIElement objects to print to standard
0539              output
0540     """
0541     def __init__(self, parser):
0542         self.elements = parser.commands
0543         self.elem_number_check(parser.desc_syscalls, parser.enum_syscalls, 'syscall', 'bpf_cmd')
0544 
0545     def print_header(self):
0546         header = '''\
0547 ===
0548 bpf
0549 ===
0550 -------------------------------------------------------------------------------
0551 Perform a command on an extended BPF object
0552 -------------------------------------------------------------------------------
0553 
0554 :Manual section: 2
0555 
0556 COMMANDS
0557 ========
0558 '''
0559         PrinterRST.print_license(self)
0560         print(header)
0561 
0562     def print_one(self, command):
0563         print('**%s**' % (command.proto))
0564         self.print_elem(command)
0565 
0566 
0567 class PrinterHelpers(Printer):
0568     """
0569     A printer for dumping collected information about helpers as C header to
0570     be included from BPF program.
0571     @parser: A HeaderParser with Helper objects to print to standard output
0572     """
0573     def __init__(self, parser):
0574         self.elements = parser.helpers
0575         self.elem_number_check(parser.desc_unique_helpers, parser.define_unique_helpers, 'helper', '__BPF_FUNC_MAPPER')
0576 
0577     type_fwds = [
0578             'struct bpf_fib_lookup',
0579             'struct bpf_sk_lookup',
0580             'struct bpf_perf_event_data',
0581             'struct bpf_perf_event_value',
0582             'struct bpf_pidns_info',
0583             'struct bpf_redir_neigh',
0584             'struct bpf_sock',
0585             'struct bpf_sock_addr',
0586             'struct bpf_sock_ops',
0587             'struct bpf_sock_tuple',
0588             'struct bpf_spin_lock',
0589             'struct bpf_sysctl',
0590             'struct bpf_tcp_sock',
0591             'struct bpf_tunnel_key',
0592             'struct bpf_xfrm_state',
0593             'struct linux_binprm',
0594             'struct pt_regs',
0595             'struct sk_reuseport_md',
0596             'struct sockaddr',
0597             'struct tcphdr',
0598             'struct seq_file',
0599             'struct tcp6_sock',
0600             'struct tcp_sock',
0601             'struct tcp_timewait_sock',
0602             'struct tcp_request_sock',
0603             'struct udp6_sock',
0604             'struct unix_sock',
0605             'struct task_struct',
0606 
0607             'struct __sk_buff',
0608             'struct sk_msg_md',
0609             'struct xdp_md',
0610             'struct path',
0611             'struct btf_ptr',
0612             'struct inode',
0613             'struct socket',
0614             'struct file',
0615             'struct bpf_timer',
0616             'struct mptcp_sock',
0617             'struct bpf_dynptr',
0618             'struct iphdr',
0619             'struct ipv6hdr',
0620     ]
0621     known_types = {
0622             '...',
0623             'void',
0624             'const void',
0625             'char',
0626             'const char',
0627             'int',
0628             'long',
0629             'unsigned long',
0630 
0631             '__be16',
0632             '__be32',
0633             '__wsum',
0634 
0635             'struct bpf_fib_lookup',
0636             'struct bpf_perf_event_data',
0637             'struct bpf_perf_event_value',
0638             'struct bpf_pidns_info',
0639             'struct bpf_redir_neigh',
0640             'struct bpf_sk_lookup',
0641             'struct bpf_sock',
0642             'struct bpf_sock_addr',
0643             'struct bpf_sock_ops',
0644             'struct bpf_sock_tuple',
0645             'struct bpf_spin_lock',
0646             'struct bpf_sysctl',
0647             'struct bpf_tcp_sock',
0648             'struct bpf_tunnel_key',
0649             'struct bpf_xfrm_state',
0650             'struct linux_binprm',
0651             'struct pt_regs',
0652             'struct sk_reuseport_md',
0653             'struct sockaddr',
0654             'struct tcphdr',
0655             'struct seq_file',
0656             'struct tcp6_sock',
0657             'struct tcp_sock',
0658             'struct tcp_timewait_sock',
0659             'struct tcp_request_sock',
0660             'struct udp6_sock',
0661             'struct unix_sock',
0662             'struct task_struct',
0663             'struct path',
0664             'struct btf_ptr',
0665             'struct inode',
0666             'struct socket',
0667             'struct file',
0668             'struct bpf_timer',
0669             'struct mptcp_sock',
0670             'struct bpf_dynptr',
0671             'struct iphdr',
0672             'struct ipv6hdr',
0673     }
0674     mapped_types = {
0675             'u8': '__u8',
0676             'u16': '__u16',
0677             'u32': '__u32',
0678             'u64': '__u64',
0679             's8': '__s8',
0680             's16': '__s16',
0681             's32': '__s32',
0682             's64': '__s64',
0683             'size_t': 'unsigned long',
0684             'struct bpf_map': 'void',
0685             'struct sk_buff': 'struct __sk_buff',
0686             'const struct sk_buff': 'const struct __sk_buff',
0687             'struct sk_msg_buff': 'struct sk_msg_md',
0688             'struct xdp_buff': 'struct xdp_md',
0689     }
0690     # Helpers overloaded for different context types.
0691     overloaded_helpers = [
0692         'bpf_get_socket_cookie',
0693         'bpf_sk_assign',
0694     ]
0695 
0696     def print_header(self):
0697         header = '''\
0698 /* This is auto-generated file. See bpf_doc.py for details. */
0699 
0700 /* Forward declarations of BPF structs */'''
0701 
0702         print(header)
0703         for fwd in self.type_fwds:
0704             print('%s;' % fwd)
0705         print('')
0706 
0707     def print_footer(self):
0708         footer = ''
0709         print(footer)
0710 
0711     def map_type(self, t):
0712         if t in self.known_types:
0713             return t
0714         if t in self.mapped_types:
0715             return self.mapped_types[t]
0716         print("Unrecognized type '%s', please add it to known types!" % t,
0717               file=sys.stderr)
0718         sys.exit(1)
0719 
0720     seen_helpers = set()
0721 
0722     def print_one(self, helper):
0723         proto = helper.proto_break_down()
0724 
0725         if proto['name'] in self.seen_helpers:
0726             return
0727         self.seen_helpers.add(proto['name'])
0728 
0729         print('/*')
0730         print(" * %s" % proto['name'])
0731         print(" *")
0732         if (helper.desc):
0733             # Do not strip all newline characters: formatted code at the end of
0734             # a section must be followed by a blank line.
0735             for line in re.sub('\n$', '', helper.desc, count=1).split('\n'):
0736                 print(' *{}{}'.format(' \t' if line else '', line))
0737 
0738         if (helper.ret):
0739             print(' *')
0740             print(' * Returns')
0741             for line in helper.ret.rstrip().split('\n'):
0742                 print(' *{}{}'.format(' \t' if line else '', line))
0743 
0744         print(' */')
0745         print('static %s %s(*%s)(' % (self.map_type(proto['ret_type']),
0746                                       proto['ret_star'], proto['name']), end='')
0747         comma = ''
0748         for i, a in enumerate(proto['args']):
0749             t = a['type']
0750             n = a['name']
0751             if proto['name'] in self.overloaded_helpers and i == 0:
0752                     t = 'void'
0753                     n = 'ctx'
0754             one_arg = '{}{}'.format(comma, self.map_type(t))
0755             if n:
0756                 if a['star']:
0757                     one_arg += ' {}'.format(a['star'])
0758                 else:
0759                     one_arg += ' '
0760                 one_arg += '{}'.format(n)
0761             comma = ', '
0762             print(one_arg, end='')
0763 
0764         print(') = (void *) %d;' % len(self.seen_helpers))
0765         print('')
0766 
0767 ###############################################################################
0768 
0769 # If script is launched from scripts/ from kernel tree and can access
0770 # ../include/uapi/linux/bpf.h, use it as a default name for the file to parse,
0771 # otherwise the --filename argument will be required from the command line.
0772 script = os.path.abspath(sys.argv[0])
0773 linuxRoot = os.path.dirname(os.path.dirname(script))
0774 bpfh = os.path.join(linuxRoot, 'include/uapi/linux/bpf.h')
0775 
0776 printers = {
0777         'helpers': PrinterHelpersRST,
0778         'syscall': PrinterSyscallRST,
0779 }
0780 
0781 argParser = argparse.ArgumentParser(description="""
0782 Parse eBPF header file and generate documentation for the eBPF API.
0783 The RST-formatted output produced can be turned into a manual page with the
0784 rst2man utility.
0785 """)
0786 argParser.add_argument('--header', action='store_true',
0787                        help='generate C header file')
0788 if (os.path.isfile(bpfh)):
0789     argParser.add_argument('--filename', help='path to include/uapi/linux/bpf.h',
0790                            default=bpfh)
0791 else:
0792     argParser.add_argument('--filename', help='path to include/uapi/linux/bpf.h')
0793 argParser.add_argument('target', nargs='?', default='helpers',
0794                        choices=printers.keys(), help='eBPF API target')
0795 args = argParser.parse_args()
0796 
0797 # Parse file.
0798 headerParser = HeaderParser(args.filename)
0799 headerParser.run()
0800 
0801 # Print formatted output to standard output.
0802 if args.header:
0803     if args.target != 'helpers':
0804         raise NotImplementedError('Only helpers header generation is supported')
0805     printer = PrinterHelpers(headerParser)
0806 else:
0807     printer = printers[args.target](headerParser)
0808 printer.print_all()