History

bpf/scripts: Raise an exception if the correct number of helpers are not generated

Currently bpf_helper_defs.h and the bpf helpers man page are auto-generated using function documentation present in bpf.h. If the documentation for the helper is missing or doesn't follow a specific format for e.g. if a function is documented as: * long bpf_kallsyms_lookup_name( const char *name, int name_sz, int flags, u64 *res ) instead of * long bpf_kallsyms_lookup_name(const char *name, int name_sz, int flags, u64 *res) (notice the extra space at the start and end of function arguments) then that helper is not dumped in the auto-generated header and results in an invalid call during eBPF runtime, even if all the code specific to the helper is correct. This patch checks the number of functions documented within the header file with those present as part of #define __BPF_FUNC_MAPPER and raises an Exception if they don't match. It is not needed with the currently documented upstream functions, but can help in debugging when developing new helpers when there might be missing or misformatted documentation.

Usama Arif committed 4 years ago

Commit 71a3cdf1 parent 86c7eca1 file · +48 −2Browse files

Unified · Split

scripts/bpf_doc.py+48−2
@@ -87,6 +87,8 @@ class HeaderParser(object): · 86 unmodified lines
87 self.line = ''87 self.line = ''
88 self.helpers = []88 self.helpers = []
89 self.commands = []89 self.commands = []
90 self.desc_unique_helpers = set()
91 self.define_unique_helpers = []
90 92
91 def parse_element(self):93 def parse_element(self):
92 proto = self.parse_symbol()94 proto = self.parse_symbol()
@@ -193,19 +195,42 @@ class HeaderParser(object): · 100 unmodified lines
193 except NoSyscallCommandFound:195 except NoSyscallCommandFound:
194 break196 break
195 197
196 def parse_helpers(self):198 def parse_desc_helpers(self):
197 self.seek_to('* Start of BPF helper function descriptions:',199 self.seek_to('* Start of BPF helper function descriptions:',
198 'Could not find start of eBPF helper descriptions list')200 'Could not find start of eBPF helper descriptions list')
199 while True:201 while True:
200 try:202 try:
201 helper = self.parse_helper()203 helper = self.parse_helper()
202 self.helpers.append(helper)204 self.helpers.append(helper)
205 proto = helper.proto_break_down()
206 self.desc_unique_helpers.add(proto['name'])
203 except NoHelperFound:207 except NoHelperFound:
204 break208 break
205 209
210 def parse_define_helpers(self):
211 # Parse the number of FN(...) in #define __BPF_FUNC_MAPPER to compare
212 # later with the number of unique function names present in description.
213 # Note: seek_to(..) discards the first line below the target search text,
214 # resulting in FN(unspec) being skipped and not added to self.define_unique_helpers.
215 self.seek_to('#define __BPF_FUNC_MAPPER(FN)',
216 'Could not find start of eBPF helper definition list')
217 # Searches for either one or more FN(\w+) defines or a backslash for newline
218 p = re.compile('\s*(FN\(\w+\))+|\\\\')
219 fn_defines_str = ''
220 while True:
221 capture = p.match(self.line)
222 if capture:
223 fn_defines_str += self.line
224 else:
225 break
226 self.line = self.reader.readline()
227 # Find the number of occurences of FN(\w+)
228 self.define_unique_helpers = re.findall('FN\(\w+\)', fn_defines_str)
229
206 def run(self):230 def run(self):
207 self.parse_syscall()231 self.parse_syscall()
208 self.parse_helpers()232 self.parse_desc_helpers()
233 self.parse_define_helpers()
209 self.reader.close()234 self.reader.close()
210 235
211###############################################################################236###############################################################################
@@ -295,6 +320,25 @@ class PrinterRST(Printer): · 83 unmodified lines
295 320
296 print('')321 print('')
297 322
323def helper_number_check(desc_unique_helpers, define_unique_helpers):
324 """
325 Checks the number of functions documented within the header file
326 with those present as part of #define __BPF_FUNC_MAPPER and raise an
327 Exception if they don't match.
328 """
329 nr_desc_unique_helpers = len(desc_unique_helpers)
330 nr_define_unique_helpers = len(define_unique_helpers)
331 if nr_desc_unique_helpers != nr_define_unique_helpers:
332 helper_exception = '''
333The number of unique helpers in description (%d) doesn\'t match the number of unique helpers defined in __BPF_FUNC_MAPPER (%d)
334''' % (nr_desc_unique_helpers, nr_define_unique_helpers)
335 if nr_desc_unique_helpers < nr_define_unique_helpers:
336 # Function description is parsed until no helper is found (which can be due to
337 # misformatting). Hence, only print the first missing/misformatted function.
338 helper_exception += '''
339The description for %s is not present or formatted correctly.
340''' % (define_unique_helpers[nr_desc_unique_helpers])
341 raise Exception(helper_exception)
298 342
299class PrinterHelpersRST(PrinterRST):343class PrinterHelpersRST(PrinterRST):
300 """344 """
@@ -305,6 +349,7 @@ class PrinterHelpersRST(PrinterRST): · 4 unmodified lines
305 """349 """
306 def __init__(self, parser):350 def __init__(self, parser):
307 self.elements = parser.helpers351 self.elements = parser.helpers
352 helper_number_check(parser.desc_unique_helpers, parser.define_unique_helpers)
308 353
309 def print_header(self):354 def print_header(self):
310 header = '''\355 header = '''\
@@ -509,6 +554,7 @@ class PrinterHelpers(Printer): · 198 unmodified lines
509 """554 """
510 def __init__(self, parser):555 def __init__(self, parser):
511 self.elements = parser.helpers556 self.elements = parser.helpers
557 helper_number_check(parser.desc_unique_helpers, parser.define_unique_helpers)
512 558
513 type_fwds = [559 type_fwds = [
514 'struct bpf_fib_lookup',560 'struct bpf_fib_lookup',