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
8787 self.line = ''
8888 self.helpers = []
8989 self.commands = []
90+ self.desc_unique_helpers = set()
91+ self.define_unique_helpers = []
9092
9193 def parse_element(self):
9294 proto = self.parse_symbol()
@@ -193,19 +195,42 @@ class HeaderParser(object): · 100 unmodified lines
193195 except NoSyscallCommandFound:
194196 break
195197
196− def parse_helpers(self):
198+ def parse_desc_helpers(self):
197199 self.seek_to('* Start of BPF helper function descriptions:',
198200 'Could not find start of eBPF helper descriptions list')
199201 while True:
200202 try:
201203 helper = self.parse_helper()
202204 self.helpers.append(helper)
205+ proto = helper.proto_break_down()
206+ self.desc_unique_helpers.add(proto['name'])
203207 except NoHelperFound:
204208 break
205209
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+
206230 def run(self):
207231 self.parse_syscall()
208− self.parse_helpers()
232+ self.parse_desc_helpers()
233+ self.parse_define_helpers()
209234 self.reader.close()
210235
211236 ###############################################################################
@@ -295,6 +320,25 @@ class PrinterRST(Printer): · 83 unmodified lines
295320
296321 print('')
297322
323+def 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 = '''
333+The 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 += '''
339+The description for %s is not present or formatted correctly.
340+''' % (define_unique_helpers[nr_desc_unique_helpers])
341+ raise Exception(helper_exception)
298342
299343 class PrinterHelpersRST(PrinterRST):
300344 """
@@ -305,6 +349,7 @@ class PrinterHelpersRST(PrinterRST): · 4 unmodified lines
305349 """
306350 def __init__(self, parser):
307351 self.elements = parser.helpers
352+ helper_number_check(parser.desc_unique_helpers, parser.define_unique_helpers)
308353
309354 def print_header(self):
310355 header = '''\
@@ -509,6 +554,7 @@ class PrinterHelpers(Printer): · 198 unmodified lines
509554 """
510555 def __init__(self, parser):
511556 self.elements = parser.helpers
557+ helper_number_check(parser.desc_unique_helpers, parser.define_unique_helpers)
512558
513559 type_fwds = [
514560 'struct bpf_fib_lookup',