Blame view

scripts/bpf_doc.py 25 KB
3cd046f18   Scott Branden   scripts/bpf: Swit...
1
  #!/usr/bin/env python3
56a092c89   Quentin Monnet   bpf: add script a...
2
3
  # SPDX-License-Identifier: GPL-2.0-only
  #
748c7c821   Quentin Monnet   bpf: fix script f...
4
  # Copyright (C) 2018-2019 Netronome Systems, Inc.
923a932c9   Joe Stringer   scripts/bpf: Abst...
5
  # Copyright (C) 2021 Isovalent, Inc.
56a092c89   Quentin Monnet   bpf: add script a...
6
7
8
9
10
11
12
13
14
15
  
  # In case user attempts to run with Python 2.
  from __future__ import print_function
  
  import argparse
  import re
  import sys, os
  
  class NoHelperFound(BaseException):
      pass
a67882a22   Joe Stringer   scripts/bpf: Add ...
16
17
  class NoSyscallCommandFound(BaseException):
      pass
56a092c89   Quentin Monnet   bpf: add script a...
18
19
20
21
22
23
24
25
  class ParsingError(BaseException):
      def __init__(self, line='<line not provided>', reader=None):
          if reader:
              BaseException.__init__(self,
                                     'Error at file offset %d, parsing line: %s' %
                                     (reader.tell(), line))
          else:
              BaseException.__init__(self, 'Error parsing line: %s' % line)
a67882a22   Joe Stringer   scripts/bpf: Add ...
26
27
  
  class APIElement(object):
56a092c89   Quentin Monnet   bpf: add script a...
28
      """
a67882a22   Joe Stringer   scripts/bpf: Add ...
29
30
31
32
      An object representing the description of an aspect of the eBPF API.
      @proto: prototype of the API symbol
      @desc: textual description of the symbol
      @ret: (optional) description of any associated return value
56a092c89   Quentin Monnet   bpf: add script a...
33
34
35
36
37
      """
      def __init__(self, proto='', desc='', ret=''):
          self.proto = proto
          self.desc = desc
          self.ret = ret
a67882a22   Joe Stringer   scripts/bpf: Add ...
38
39
40
41
42
43
44
45
  
  class Helper(APIElement):
      """
      An object representing the description of an eBPF helper function.
      @proto: function prototype of the helper function
      @desc: textual description of the helper function
      @ret: description of the return value of the helper function
      """
56a092c89   Quentin Monnet   bpf: add script a...
46
47
48
49
50
      def proto_break_down(self):
          """
          Break down helper function protocol into smaller chunks: return type,
          name, distincts arguments.
          """
748c7c821   Quentin Monnet   bpf: fix script f...
51
          arg_re = re.compile('((\w+ )*?(\w+|...))( (\**)(\w+))?$')
56a092c89   Quentin Monnet   bpf: add script a...
52
          res = {}
6f96674db   Quentin Monnet   bpf: relax constr...
53
          proto_re = re.compile('(.+) (\**)(\w+)\(((([^,]+)(, )?){1,5})\)$')
56a092c89   Quentin Monnet   bpf: add script a...
54
55
56
57
58
59
60
61
62
63
64
65
  
          capture = proto_re.match(self.proto)
          res['ret_type'] = capture.group(1)
          res['ret_star'] = capture.group(2)
          res['name']     = capture.group(3)
          res['args'] = []
  
          args    = capture.group(4).split(', ')
          for a in args:
              capture = arg_re.match(a)
              res['args'].append({
                  'type' : capture.group(1),
748c7c821   Quentin Monnet   bpf: fix script f...
66
67
                  'star' : capture.group(5),
                  'name' : capture.group(6)
56a092c89   Quentin Monnet   bpf: add script a...
68
69
70
              })
  
          return res
a67882a22   Joe Stringer   scripts/bpf: Add ...
71

56a092c89   Quentin Monnet   bpf: add script a...
72
73
74
75
76
77
78
79
80
81
82
83
  class HeaderParser(object):
      """
      An object used to parse a file in order to extract the documentation of a
      list of eBPF helper functions. All the helpers that can be retrieved are
      stored as Helper object, in the self.helpers() array.
      @filename: name of file to parse, usually include/uapi/linux/bpf.h in the
                 kernel tree
      """
      def __init__(self, filename):
          self.reader = open(filename, 'r')
          self.line = ''
          self.helpers = []
a67882a22   Joe Stringer   scripts/bpf: Add ...
84
85
86
87
88
89
90
          self.commands = []
  
      def parse_element(self):
          proto    = self.parse_symbol()
          desc     = self.parse_desc()
          ret      = self.parse_ret()
          return APIElement(proto=proto, desc=desc, ret=ret)
56a092c89   Quentin Monnet   bpf: add script a...
91
92
93
94
95
96
  
      def parse_helper(self):
          proto    = self.parse_proto()
          desc     = self.parse_desc()
          ret      = self.parse_ret()
          return Helper(proto=proto, desc=desc, ret=ret)
a67882a22   Joe Stringer   scripts/bpf: Add ...
97
98
99
100
101
102
103
104
105
106
107
      def parse_symbol(self):
          p = re.compile(' \* ?(.+)$')
          capture = p.match(self.line)
          if not capture:
              raise NoSyscallCommandFound
          end_re = re.compile(' \* ?NOTES$')
          end = end_re.match(self.line)
          if end:
              raise NoSyscallCommandFound
          self.line = self.reader.readline()
          return capture.group(1)
56a092c89   Quentin Monnet   bpf: add script a...
108
109
110
111
112
113
114
115
      def parse_proto(self):
          # Argument can be of shape:
          #   - "void"
          #   - "type  name"
          #   - "type *name"
          #   - Same as above, with "const" and/or "struct" in front of type
          #   - "..." (undefined number of arguments, for bpf_trace_printk())
          # There is at least one term ("void"), and at most five arguments.
6f96674db   Quentin Monnet   bpf: relax constr...
116
          p = re.compile(' \* ?((.+) \**\w+\((((const )?(struct )?(\w+|\.\.\.)( \**\w+)?)(, )?){1,5}\))$')
56a092c89   Quentin Monnet   bpf: add script a...
117
118
119
120
121
122
123
          capture = p.match(self.line)
          if not capture:
              raise NoHelperFound
          self.line = self.reader.readline()
          return capture.group(1)
  
      def parse_desc(self):
eeacb7166   Quentin Monnet   bpf: change eBPF ...
124
          p = re.compile(' \* ?(?:\t| {5,8})Description$')
56a092c89   Quentin Monnet   bpf: add script a...
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
          capture = p.match(self.line)
          if not capture:
              # Helper can have empty description and we might be parsing another
              # attribute: return but do not consume.
              return ''
          # Description can be several lines, some of them possibly empty, and it
          # stops when another subsection title is met.
          desc = ''
          while True:
              self.line = self.reader.readline()
              if self.line == ' *
  ':
                  desc += '
  '
              else:
eeacb7166   Quentin Monnet   bpf: change eBPF ...
140
                  p = re.compile(' \* ?(?:\t| {5,8})(?:\t| {8})(.*)')
56a092c89   Quentin Monnet   bpf: add script a...
141
142
143
144
145
146
147
148
149
                  capture = p.match(self.line)
                  if capture:
                      desc += capture.group(1) + '
  '
                  else:
                      break
          return desc
  
      def parse_ret(self):
eeacb7166   Quentin Monnet   bpf: change eBPF ...
150
          p = re.compile(' \* ?(?:\t| {5,8})Return$')
56a092c89   Quentin Monnet   bpf: add script a...
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
          capture = p.match(self.line)
          if not capture:
              # Helper can have empty retval and we might be parsing another
              # attribute: return but do not consume.
              return ''
          # Return value description can be several lines, some of them possibly
          # empty, and it stops when another subsection title is met.
          ret = ''
          while True:
              self.line = self.reader.readline()
              if self.line == ' *
  ':
                  ret += '
  '
              else:
eeacb7166   Quentin Monnet   bpf: change eBPF ...
166
                  p = re.compile(' \* ?(?:\t| {5,8})(?:\t| {8})(.*)')
56a092c89   Quentin Monnet   bpf: add script a...
167
168
169
170
171
172
173
                  capture = p.match(self.line)
                  if capture:
                      ret += capture.group(1) + '
  '
                  else:
                      break
          return ret
a67882a22   Joe Stringer   scripts/bpf: Add ...
174
175
176
      def seek_to(self, target, help_message):
          self.reader.seek(0)
          offset = self.reader.read().find(target)
56a092c89   Quentin Monnet   bpf: add script a...
177
          if offset == -1:
a67882a22   Joe Stringer   scripts/bpf: Add ...
178
              raise Exception(help_message)
56a092c89   Quentin Monnet   bpf: add script a...
179
180
181
182
          self.reader.seek(offset)
          self.reader.readline()
          self.reader.readline()
          self.line = self.reader.readline()
a67882a22   Joe Stringer   scripts/bpf: Add ...
183
184
185
186
187
188
189
190
191
192
193
194
195
      def parse_syscall(self):
          self.seek_to('* DOC: eBPF Syscall Commands',
                       'Could not find start of eBPF syscall descriptions list')
          while True:
              try:
                  command = self.parse_element()
                  self.commands.append(command)
              except NoSyscallCommandFound:
                  break
  
      def parse_helpers(self):
          self.seek_to('* Start of BPF helper function descriptions:',
                       'Could not find start of eBPF helper descriptions list')
56a092c89   Quentin Monnet   bpf: add script a...
196
197
198
199
200
201
          while True:
              try:
                  helper = self.parse_helper()
                  self.helpers.append(helper)
              except NoHelperFound:
                  break
a67882a22   Joe Stringer   scripts/bpf: Add ...
202
203
204
      def run(self):
          self.parse_syscall()
          self.parse_helpers()
56a092c89   Quentin Monnet   bpf: add script a...
205
          self.reader.close()
56a092c89   Quentin Monnet   bpf: add script a...
206
207
208
209
210
211
212
  
  ###############################################################################
  
  class Printer(object):
      """
      A generic class for printers. Printers should be created with an array of
      Helper objects, and implement a way to print them in the desired fashion.
923a932c9   Joe Stringer   scripts/bpf: Abst...
213
      @parser: A HeaderParser with objects to print to standard output
56a092c89   Quentin Monnet   bpf: add script a...
214
      """
923a932c9   Joe Stringer   scripts/bpf: Abst...
215
216
217
      def __init__(self, parser):
          self.parser = parser
          self.elements = []
56a092c89   Quentin Monnet   bpf: add script a...
218
219
220
221
222
223
224
225
226
227
228
229
  
      def print_header(self):
          pass
  
      def print_footer(self):
          pass
  
      def print_one(self, helper):
          pass
  
      def print_all(self):
          self.print_header()
923a932c9   Joe Stringer   scripts/bpf: Abst...
230
231
          for elem in self.elements:
              self.print_one(elem)
56a092c89   Quentin Monnet   bpf: add script a...
232
          self.print_footer()
923a932c9   Joe Stringer   scripts/bpf: Abst...
233

56a092c89   Quentin Monnet   bpf: add script a...
234
235
  class PrinterRST(Printer):
      """
923a932c9   Joe Stringer   scripts/bpf: Abst...
236
237
238
239
      A generic class for printers that print ReStructured Text. Printers should
      be created with a HeaderParser object, and implement a way to print API
      elements in the desired fashion.
      @parser: A HeaderParser with objects to print to standard output
56a092c89   Quentin Monnet   bpf: add script a...
240
      """
923a932c9   Joe Stringer   scripts/bpf: Abst...
241
242
243
244
245
      def __init__(self, parser):
          self.parser = parser
  
      def print_license(self):
          license = '''\
56a092c89   Quentin Monnet   bpf: add script a...
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
  .. Copyright (C) All BPF authors and contributors from 2014 to present.
  .. See git log include/uapi/linux/bpf.h in kernel tree for details.
  .. 
  .. %%%LICENSE_START(VERBATIM)
  .. Permission is granted to make and distribute verbatim copies of this
  .. manual provided the copyright notice and this permission notice are
  .. preserved on all copies.
  .. 
  .. Permission is granted to copy and distribute modified versions of this
  .. manual under the conditions for verbatim copying, provided that the
  .. entire resulting derived work is distributed under the terms of a
  .. permission notice identical to this one.
  .. 
  .. Since the Linux kernel and libraries are constantly changing, this
  .. manual page may be incorrect or out-of-date.  The author(s) assume no
  .. responsibility for errors or omissions, or for damages resulting from
  .. the use of the information contained herein.  The author(s) may not
  .. have taken the same level of care in the production of this manual,
  .. which is licensed free of charge, as they might when working
  .. professionally.
  .. 
  .. Formatted or processed versions of this manual, if unaccompanied by
  .. the source, must acknowledge the copyright and authors of this work.
  .. %%%LICENSE_END
  .. 
  .. Please do not edit this file. It was generated from the documentation
  .. located in file include/uapi/linux/bpf.h of the Linux kernel sources
923a932c9   Joe Stringer   scripts/bpf: Abst...
273
  .. (helpers description), and from scripts/bpf_doc.py in the same
56a092c89   Quentin Monnet   bpf: add script a...
274
  .. repository (header and footer).
923a932c9   Joe Stringer   scripts/bpf: Abst...
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
  '''
          print(license)
  
      def print_elem(self, elem):
          if (elem.desc):
              print('\tDescription')
              # Do not strip all newline characters: formatted code at the end of
              # a section must be followed by a blank line.
              for line in re.sub('
  $', '', elem.desc, count=1).split('
  '):
                  print('{}{}'.format('\t\t' if line else '', line))
  
          if (elem.ret):
              print('\tReturn')
              for line in elem.ret.rstrip().split('
  '):
                  print('{}{}'.format('\t\t' if line else '', line))
  
          print('')
56a092c89   Quentin Monnet   bpf: add script a...
295

923a932c9   Joe Stringer   scripts/bpf: Abst...
296
297
298
299
300
301
302
303
304
305
306
307
308
  
  class PrinterHelpersRST(PrinterRST):
      """
      A printer for dumping collected information about helpers as a ReStructured
      Text page compatible with the rst2man program, which can be used to
      generate a manual page for the helpers.
      @parser: A HeaderParser with Helper objects to print to standard output
      """
      def __init__(self, parser):
          self.elements = parser.helpers
  
      def print_header(self):
          header = '''\
56a092c89   Quentin Monnet   bpf: add script a...
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
  ===========
  BPF-HELPERS
  ===========
  -------------------------------------------------------------------------------
  list of eBPF helper functions
  -------------------------------------------------------------------------------
  
  :Manual section: 7
  
  DESCRIPTION
  ===========
  
  The extended Berkeley Packet Filter (eBPF) subsystem consists in programs
  written in a pseudo-assembly language, then attached to one of the several
  kernel hooks and run in reaction of specific events. This framework differs
  from the older, "classic" BPF (or "cBPF") in several aspects, one of them being
  the ability to call special functions (or "helpers") from within a program.
  These functions are restricted to a white-list of helpers defined in the
  kernel.
  
  These helpers are used by eBPF programs to interact with the system, or with
  the context in which they work. For instance, they can be used to print
  debugging messages, to get the time since the system was booted, to interact
  with eBPF maps, or to manipulate network packets. Since there are several eBPF
  program types, and that they do not run in the same context, each program type
  can only call a subset of those helpers.
  
  Due to eBPF conventions, a helper can not have more than five arguments.
  
  Internally, eBPF programs call directly into the compiled helper functions
  without requiring any foreign-function interface. As a result, calling helpers
  introduces no overhead, thus offering excellent performance.
  
  This document is an attempt to list and document the helpers available to eBPF
  developers. They are sorted by chronological order (the oldest helpers in the
  kernel at the top).
  
  HELPERS
  =======
  '''
923a932c9   Joe Stringer   scripts/bpf: Abst...
349
          PrinterRST.print_license(self)
56a092c89   Quentin Monnet   bpf: add script a...
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
          print(header)
  
      def print_footer(self):
          footer = '''
  EXAMPLES
  ========
  
  Example usage for most of the eBPF helpers listed in this manual page are
  available within the Linux kernel sources, at the following locations:
  
  * *samples/bpf/*
  * *tools/testing/selftests/bpf/*
  
  LICENSE
  =======
  
  eBPF programs can have an associated license, passed along with the bytecode
  instructions to the kernel when the programs are loaded. The format for that
  string is identical to the one in use for kernel modules (Dual licenses, such
  as "Dual BSD/GPL", may be used). Some helper functions are only accessible to
  programs that are compatible with the GNU Privacy License (GPL).
  
  In order to use such helpers, the eBPF program must be loaded with the correct
  license string passed (via **attr**) to the **bpf**\ () system call, and this
  generally translates into the C source code of the program containing a line
  similar to the following:
  
  ::
  
  	char ____license[] __attribute__((section("license"), used)) = "GPL";
  
  IMPLEMENTATION
  ==============
  
  This manual page is an effort to document the existing eBPF helper functions.
  But as of this writing, the BPF sub-system is under heavy development. New eBPF
  program or map types are added, along with new helper functions. Some helpers
  are occasionally made available for additional program types. So in spite of
  the efforts of the community, this page might not be up-to-date. If you want to
  check by yourself what helper functions exist in your kernel, or what types of
  programs they can support, here are some files among the kernel tree that you
  may be interested in:
  
  * *include/uapi/linux/bpf.h* is the main BPF header. It contains the full list
    of all helper functions, as well as many other BPF definitions including most
    of the flags, structs or constants used by the helpers.
  * *net/core/filter.c* contains the definition of most network-related helper
    functions, and the list of program types from which they can be used.
  * *kernel/trace/bpf_trace.c* is the equivalent for most tracing program-related
    helpers.
  * *kernel/bpf/verifier.c* contains the functions used to check that valid types
    of eBPF maps are used with a given helper function.
  * *kernel/bpf/* directory contains other files in which additional helpers are
    defined (for cgroups, sockmaps, etc.).
ab8d78093   Quentin Monnet   bpf: Minor fixes ...
404
405
406
407
408
  * The bpftool utility can be used to probe the availability of helper functions
    on the system (as well as supported program and map types, and a number of
    other parameters). To do so, run **bpftool feature probe** (see
    **bpftool-feature**\ (8) for details). Add the **unprivileged** keyword to
    list features available to unprivileged users.
56a092c89   Quentin Monnet   bpf: add script a...
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
  
  Compatibility between helper functions and program types can generally be found
  in the files where helper functions are defined. Look for the **struct
  bpf_func_proto** objects and for functions returning them: these functions
  contain a list of helpers that a given program type can call. Note that the
  **default:** label of the **switch ... case** used to filter helpers can call
  other functions, themselves allowing access to additional helpers. The
  requirement for GPL license is also in those **struct bpf_func_proto**.
  
  Compatibility between helper functions and map types can be found in the
  **check_map_func_compatibility**\ () function in file *kernel/bpf/verifier.c*.
  
  Helper functions that invalidate the checks on **data** and **data_end**
  pointers for network processing are listed in function
  **bpf_helper_changes_pkt_data**\ () in file *net/core/filter.c*.
  
  SEE ALSO
  ========
  
  **bpf**\ (2),
ab8d78093   Quentin Monnet   bpf: Minor fixes ...
429
  **bpftool**\ (8),
56a092c89   Quentin Monnet   bpf: add script a...
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
  **cgroups**\ (7),
  **ip**\ (8),
  **perf_event_open**\ (2),
  **sendmsg**\ (2),
  **socket**\ (7),
  **tc-bpf**\ (8)'''
          print(footer)
  
      def print_proto(self, helper):
          """
          Format function protocol with bold and italics markers. This makes RST
          file less readable, but gives nice results in the manual page.
          """
          proto = helper.proto_break_down()
  
          print('**%s %s%s(' % (proto['ret_type'],
                                proto['ret_star'].replace('*', '\\*'),
                                proto['name']),
                end='')
  
          comma = ''
          for a in proto['args']:
              one_arg = '{}{}'.format(comma, a['type'])
              if a['name']:
                  if a['star']:
                      one_arg += ' {}**\ '.format(a['star'].replace('*', '\\*'))
                  else:
                      one_arg += '** '
                  one_arg += '*{}*\\ **'.format(a['name'])
              comma = ', '
              print(one_arg, end='')
  
          print(')**')
  
      def print_one(self, helper):
          self.print_proto(helper)
923a932c9   Joe Stringer   scripts/bpf: Abst...
466
          self.print_elem(helper)
56a092c89   Quentin Monnet   bpf: add script a...
467

56a092c89   Quentin Monnet   bpf: add script a...
468

a67882a22   Joe Stringer   scripts/bpf: Add ...
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
  class PrinterSyscallRST(PrinterRST):
      """
      A printer for dumping collected information about the syscall API as a
      ReStructured Text page compatible with the rst2man program, which can be
      used to generate a manual page for the syscall.
      @parser: A HeaderParser with APIElement objects to print to standard
               output
      """
      def __init__(self, parser):
          self.elements = parser.commands
  
      def print_header(self):
          header = '''\
  ===
  bpf
  ===
  -------------------------------------------------------------------------------
  Perform a command on an extended BPF object
  -------------------------------------------------------------------------------
  
  :Manual section: 2
  
  COMMANDS
  ========
  '''
          PrinterRST.print_license(self)
          print(header)
  
      def print_one(self, command):
          print('**%s**' % (command.proto))
          self.print_elem(command)
56a092c89   Quentin Monnet   bpf: add script a...
500

56a092c89   Quentin Monnet   bpf: add script a...
501

7a387bed4   Andrii Nakryiko   scripts/bpf: teac...
502
503
504
505
  class PrinterHelpers(Printer):
      """
      A printer for dumping collected information about helpers as C header to
      be included from BPF program.
923a932c9   Joe Stringer   scripts/bpf: Abst...
506
      @parser: A HeaderParser with Helper objects to print to standard output
7a387bed4   Andrii Nakryiko   scripts/bpf: teac...
507
      """
923a932c9   Joe Stringer   scripts/bpf: Abst...
508
509
      def __init__(self, parser):
          self.elements = parser.helpers
7a387bed4   Andrii Nakryiko   scripts/bpf: teac...
510
511
512
  
      type_fwds = [
              'struct bpf_fib_lookup',
e9ddbb770   Jakub Sitnicki   bpf: Introduce SK...
513
              'struct bpf_sk_lookup',
7a387bed4   Andrii Nakryiko   scripts/bpf: teac...
514
515
              'struct bpf_perf_event_data',
              'struct bpf_perf_event_value',
5996a587a   Carlos Neira   bpf_helpers_doc.p...
516
              'struct bpf_pidns_info',
821f5c901   Andrii Nakryiko   bpf: Add struct b...
517
              'struct bpf_redir_neigh',
7a387bed4   Andrii Nakryiko   scripts/bpf: teac...
518
519
520
521
522
523
524
525
526
              'struct bpf_sock',
              'struct bpf_sock_addr',
              'struct bpf_sock_ops',
              'struct bpf_sock_tuple',
              'struct bpf_spin_lock',
              'struct bpf_sysctl',
              'struct bpf_tcp_sock',
              'struct bpf_tunnel_key',
              'struct bpf_xfrm_state',
3f6719c7b   KP Singh   bpf: Add bpf_bprm...
527
              'struct linux_binprm',
7a387bed4   Andrii Nakryiko   scripts/bpf: teac...
528
529
530
531
              'struct pt_regs',
              'struct sk_reuseport_md',
              'struct sockaddr',
              'struct tcphdr',
492e639f0   Yonghong Song   bpf: Add bpf_seq_...
532
              'struct seq_file',
af7ec1383   Yonghong Song   bpf: Add bpf_skc_...
533
              'struct tcp6_sock',
478cfbdf5   Yonghong Song   bpf: Add bpf_skc_...
534
535
536
              'struct tcp_sock',
              'struct tcp_timewait_sock',
              'struct tcp_request_sock',
0d4fad3e5   Yonghong Song   bpf: Add bpf_skc_...
537
              'struct udp6_sock',
fa28dcb82   Song Liu   bpf: Introduce he...
538
              'struct task_struct',
7a387bed4   Andrii Nakryiko   scripts/bpf: teac...
539
540
541
  
              'struct __sk_buff',
              'struct sk_msg_md',
e0b68fb18   Andrii Nakryiko   scripts/bpf: Fix ...
542
              'struct xdp_md',
6e22ab9da   Jiri Olsa   bpf: Add d_path h...
543
              'struct path',
c4d0bfb45   Alan Maguire   bpf: Add bpf_snpr...
544
              'struct btf_ptr',
27672f0d2   KP Singh   bpf: Add a BPF he...
545
              'struct inode',
4f19cab76   Florent Revest   bpf: Add a bpf_so...
546
547
              'struct socket',
              'struct file',
b00628b1c   Alexei Starovoitov   bpf: Introduce bp...
548
              'struct bpf_timer',
7a387bed4   Andrii Nakryiko   scripts/bpf: teac...
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
      ]
      known_types = {
              '...',
              'void',
              'const void',
              'char',
              'const char',
              'int',
              'long',
              'unsigned long',
  
              '__be16',
              '__be32',
              '__wsum',
  
              'struct bpf_fib_lookup',
              'struct bpf_perf_event_data',
              'struct bpf_perf_event_value',
b4490c5c4   Carlos Neira   bpf: Added new he...
567
              'struct bpf_pidns_info',
ba452c9e9   Toke Høiland-Jørgensen   bpf: Fix bpf_redi...
568
              'struct bpf_redir_neigh',
e9ddbb770   Jakub Sitnicki   bpf: Introduce SK...
569
              'struct bpf_sk_lookup',
7a387bed4   Andrii Nakryiko   scripts/bpf: teac...
570
571
572
573
574
575
576
577
578
              'struct bpf_sock',
              'struct bpf_sock_addr',
              'struct bpf_sock_ops',
              'struct bpf_sock_tuple',
              'struct bpf_spin_lock',
              'struct bpf_sysctl',
              'struct bpf_tcp_sock',
              'struct bpf_tunnel_key',
              'struct bpf_xfrm_state',
3f6719c7b   KP Singh   bpf: Add bpf_bprm...
579
              'struct linux_binprm',
7a387bed4   Andrii Nakryiko   scripts/bpf: teac...
580
581
582
583
              'struct pt_regs',
              'struct sk_reuseport_md',
              'struct sockaddr',
              'struct tcphdr',
492e639f0   Yonghong Song   bpf: Add bpf_seq_...
584
              'struct seq_file',
af7ec1383   Yonghong Song   bpf: Add bpf_skc_...
585
              'struct tcp6_sock',
478cfbdf5   Yonghong Song   bpf: Add bpf_skc_...
586
587
588
              'struct tcp_sock',
              'struct tcp_timewait_sock',
              'struct tcp_request_sock',
0d4fad3e5   Yonghong Song   bpf: Add bpf_skc_...
589
              'struct udp6_sock',
fa28dcb82   Song Liu   bpf: Introduce he...
590
              'struct task_struct',
6e22ab9da   Jiri Olsa   bpf: Add d_path h...
591
              'struct path',
c4d0bfb45   Alan Maguire   bpf: Add bpf_snpr...
592
              'struct btf_ptr',
27672f0d2   KP Singh   bpf: Add a BPF he...
593
              'struct inode',
4f19cab76   Florent Revest   bpf: Add a bpf_so...
594
595
              'struct socket',
              'struct file',
b00628b1c   Alexei Starovoitov   bpf: Introduce bp...
596
              'struct bpf_timer',
7a387bed4   Andrii Nakryiko   scripts/bpf: teac...
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
      }
      mapped_types = {
              'u8': '__u8',
              'u16': '__u16',
              'u32': '__u32',
              'u64': '__u64',
              's8': '__s8',
              's16': '__s16',
              's32': '__s32',
              's64': '__s64',
              'size_t': 'unsigned long',
              'struct bpf_map': 'void',
              'struct sk_buff': 'struct __sk_buff',
              'const struct sk_buff': 'const struct __sk_buff',
              'struct sk_msg_buff': 'struct sk_msg_md',
              'struct xdp_buff': 'struct xdp_md',
      }
e9ddbb770   Jakub Sitnicki   bpf: Introduce SK...
614
615
616
617
618
      # Helpers overloaded for different context types.
      overloaded_helpers = [
          'bpf_get_socket_cookie',
          'bpf_sk_assign',
      ]
7a387bed4   Andrii Nakryiko   scripts/bpf: teac...
619
620
621
  
      def print_header(self):
          header = '''\
923a932c9   Joe Stringer   scripts/bpf: Abst...
622
  /* This is auto-generated file. See bpf_doc.py for details. */
7a387bed4   Andrii Nakryiko   scripts/bpf: teac...
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
  
  /* Forward declarations of BPF structs */'''
  
          print(header)
          for fwd in self.type_fwds:
              print('%s;' % fwd)
          print('')
  
      def print_footer(self):
          footer = ''
          print(footer)
  
      def map_type(self, t):
          if t in self.known_types:
              return t
          if t in self.mapped_types:
              return self.mapped_types[t]
ab81e203b   Jakub Sitnicki   scripts/bpf: Prin...
640
641
          print("Unrecognized type '%s', please add it to known types!" % t,
                file=sys.stderr)
7a387bed4   Andrii Nakryiko   scripts/bpf: teac...
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
          sys.exit(1)
  
      seen_helpers = set()
  
      def print_one(self, helper):
          proto = helper.proto_break_down()
  
          if proto['name'] in self.seen_helpers:
              return
          self.seen_helpers.add(proto['name'])
  
          print('/*')
          print(" * %s" % proto['name'])
          print(" *")
          if (helper.desc):
              # Do not strip all newline characters: formatted code at the end of
              # a section must be followed by a blank line.
              for line in re.sub('
  $', '', helper.desc, count=1).split('
  '):
                  print(' *{}{}'.format(' \t' if line else '', line))
  
          if (helper.ret):
              print(' *')
              print(' * Returns')
              for line in helper.ret.rstrip().split('
  '):
                  print(' *{}{}'.format(' \t' if line else '', line))
  
          print(' */')
          print('static %s %s(*%s)(' % (self.map_type(proto['ret_type']),
                                        proto['ret_star'], proto['name']), end='')
          comma = ''
          for i, a in enumerate(proto['args']):
              t = a['type']
              n = a['name']
e9ddbb770   Jakub Sitnicki   bpf: Introduce SK...
678
              if proto['name'] in self.overloaded_helpers and i == 0:
7a387bed4   Andrii Nakryiko   scripts/bpf: teac...
679
680
681
682
683
684
685
686
687
688
689
690
691
692
                      t = 'void'
                      n = 'ctx'
              one_arg = '{}{}'.format(comma, self.map_type(t))
              if n:
                  if a['star']:
                      one_arg += ' {}'.format(a['star'])
                  else:
                      one_arg += ' '
                  one_arg += '{}'.format(n)
              comma = ', '
              print(one_arg, end='')
  
          print(') = (void *) %d;' % len(self.seen_helpers))
          print('')
56a092c89   Quentin Monnet   bpf: add script a...
693
694
695
696
697
698
699
700
  ###############################################################################
  
  # If script is launched from scripts/ from kernel tree and can access
  # ../include/uapi/linux/bpf.h, use it as a default name for the file to parse,
  # otherwise the --filename argument will be required from the command line.
  script = os.path.abspath(sys.argv[0])
  linuxRoot = os.path.dirname(os.path.dirname(script))
  bpfh = os.path.join(linuxRoot, 'include/uapi/linux/bpf.h')
923a932c9   Joe Stringer   scripts/bpf: Abst...
701
702
  printers = {
          'helpers': PrinterHelpersRST,
a67882a22   Joe Stringer   scripts/bpf: Add ...
703
          'syscall': PrinterSyscallRST,
923a932c9   Joe Stringer   scripts/bpf: Abst...
704
  }
56a092c89   Quentin Monnet   bpf: add script a...
705
  argParser = argparse.ArgumentParser(description="""
923a932c9   Joe Stringer   scripts/bpf: Abst...
706
  Parse eBPF header file and generate documentation for the eBPF API.
56a092c89   Quentin Monnet   bpf: add script a...
707
708
709
  The RST-formatted output produced can be turned into a manual page with the
  rst2man utility.
  """)
7a387bed4   Andrii Nakryiko   scripts/bpf: teac...
710
711
  argParser.add_argument('--header', action='store_true',
                         help='generate C header file')
56a092c89   Quentin Monnet   bpf: add script a...
712
713
714
715
716
  if (os.path.isfile(bpfh)):
      argParser.add_argument('--filename', help='path to include/uapi/linux/bpf.h',
                             default=bpfh)
  else:
      argParser.add_argument('--filename', help='path to include/uapi/linux/bpf.h')
923a932c9   Joe Stringer   scripts/bpf: Abst...
717
718
  argParser.add_argument('target', nargs='?', default='helpers',
                         choices=printers.keys(), help='eBPF API target')
56a092c89   Quentin Monnet   bpf: add script a...
719
720
721
722
723
724
725
  args = argParser.parse_args()
  
  # Parse file.
  headerParser = HeaderParser(args.filename)
  headerParser.run()
  
  # Print formatted output to standard output.
7a387bed4   Andrii Nakryiko   scripts/bpf: teac...
726
  if args.header:
a67882a22   Joe Stringer   scripts/bpf: Add ...
727
728
      if args.target != 'helpers':
          raise NotImplementedError('Only helpers header generation is supported')
923a932c9   Joe Stringer   scripts/bpf: Abst...
729
      printer = PrinterHelpers(headerParser)
7a387bed4   Andrii Nakryiko   scripts/bpf: teac...
730
  else:
923a932c9   Joe Stringer   scripts/bpf: Abst...
731
      printer = printers[args.target](headerParser)
56a092c89   Quentin Monnet   bpf: add script a...
732
  printer.print_all()