~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/scripts/bpf_doc.py

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /scripts/bpf_doc.py (Version linux-6.11.5) and /scripts/bpf_doc.py (Version linux-6.9.12)


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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php