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