Skip to content

Commit

Permalink
bpf/scripts: Raise an exception if the correct number of helpers are …
Browse files Browse the repository at this point in the history
…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.

Signed-off-by: Usama Arif <usama.arif@bytedance.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Reviewed-by: Quentin Monnet <quentin@isovalent.com>
Acked-by: Song Liu <songliubraving@fb.com>
Link: https://lore.kernel.org/bpf/20220112114953.722380-1-usama.arif@bytedance.com
  • Loading branch information
uarif1 authored and anakryiko committed Jan 15, 2022
1 parent 86c7eca commit 71a3cdf
Showing 1 changed file with 48 additions and 2 deletions.
50 changes: 48 additions & 2 deletions scripts/bpf_doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ def __init__(self, filename):
self.line = ''
self.helpers = []
self.commands = []
self.desc_unique_helpers = set()
self.define_unique_helpers = []

def parse_element(self):
proto = self.parse_symbol()
Expand Down Expand Up @@ -193,19 +195,42 @@ def parse_syscall(self):
except NoSyscallCommandFound:
break

def parse_helpers(self):
def parse_desc_helpers(self):
self.seek_to('* Start of BPF helper function descriptions:',
'Could not find start of eBPF helper descriptions list')
while True:
try:
helper = self.parse_helper()
self.helpers.append(helper)
proto = helper.proto_break_down()
self.desc_unique_helpers.add(proto['name'])
except NoHelperFound:
break

def parse_define_helpers(self):
# Parse the number of FN(...) in #define __BPF_FUNC_MAPPER to compare
# later with the number of unique function names present in description.
# Note: seek_to(..) discards the first line below the target search text,
# resulting in FN(unspec) being skipped and not added to self.define_unique_helpers.
self.seek_to('#define __BPF_FUNC_MAPPER(FN)',
'Could not find start of eBPF helper definition list')
# Searches for either one or more FN(\w+) defines or a backslash for newline
p = re.compile('\s*(FN\(\w+\))+|\\\\')
fn_defines_str = ''
while True:
capture = p.match(self.line)
if capture:
fn_defines_str += self.line
else:
break
self.line = self.reader.readline()
# Find the number of occurences of FN(\w+)
self.define_unique_helpers = re.findall('FN\(\w+\)', fn_defines_str)

def run(self):
self.parse_syscall()
self.parse_helpers()
self.parse_desc_helpers()
self.parse_define_helpers()
self.reader.close()

###############################################################################
Expand Down Expand Up @@ -295,6 +320,25 @@ def print_elem(self, elem):

print('')

def helper_number_check(desc_unique_helpers, define_unique_helpers):
"""
Checks the number of functions documented within the header file
with those present as part of #define __BPF_FUNC_MAPPER and raise an
Exception if they don't match.
"""
nr_desc_unique_helpers = len(desc_unique_helpers)
nr_define_unique_helpers = len(define_unique_helpers)
if nr_desc_unique_helpers != nr_define_unique_helpers:
helper_exception = '''
The number of unique helpers in description (%d) doesn\'t match the number of unique helpers defined in __BPF_FUNC_MAPPER (%d)
''' % (nr_desc_unique_helpers, nr_define_unique_helpers)
if nr_desc_unique_helpers < nr_define_unique_helpers:
# Function description is parsed until no helper is found (which can be due to
# misformatting). Hence, only print the first missing/misformatted function.
helper_exception += '''
The description for %s is not present or formatted correctly.
''' % (define_unique_helpers[nr_desc_unique_helpers])
raise Exception(helper_exception)

class PrinterHelpersRST(PrinterRST):
"""
Expand All @@ -305,6 +349,7 @@ class PrinterHelpersRST(PrinterRST):
"""
def __init__(self, parser):
self.elements = parser.helpers
helper_number_check(parser.desc_unique_helpers, parser.define_unique_helpers)

def print_header(self):
header = '''\
Expand Down Expand Up @@ -509,6 +554,7 @@ class PrinterHelpers(Printer):
"""
def __init__(self, parser):
self.elements = parser.helpers
helper_number_check(parser.desc_unique_helpers, parser.define_unique_helpers)

type_fwds = [
'struct bpf_fib_lookup',
Expand Down

0 comments on commit 71a3cdf

Please sign in to comment.