1923a932cSJoe Stringer#!/usr/bin/env python3 2923a932cSJoe Stringer# SPDX-License-Identifier: GPL-2.0-only 3923a932cSJoe Stringer# 4923a932cSJoe Stringer# Copyright (C) 2018-2019 Netronome Systems, Inc. 5923a932cSJoe Stringer# Copyright (C) 2021 Isovalent, Inc. 6923a932cSJoe Stringer 7923a932cSJoe Stringer# In case user attempts to run with Python 2. 8923a932cSJoe Stringerfrom __future__ import print_function 9923a932cSJoe Stringer 10923a932cSJoe Stringerimport argparse 11923a932cSJoe Stringerimport re 12923a932cSJoe Stringerimport sys, os 13fd0a38f9SQuentin Monnetimport subprocess 14fd0a38f9SQuentin Monnet 1592ec1cc3SQuentin MonnethelpersDocStart = 'Start of BPF helper function descriptions:' 16923a932cSJoe Stringer 17923a932cSJoe Stringerclass NoHelperFound(BaseException): 18923a932cSJoe Stringer pass 19923a932cSJoe Stringer 20a67882a2SJoe Stringerclass NoSyscallCommandFound(BaseException): 21a67882a2SJoe Stringer pass 22a67882a2SJoe Stringer 23923a932cSJoe Stringerclass ParsingError(BaseException): 24923a932cSJoe Stringer def __init__(self, line='<line not provided>', reader=None): 25923a932cSJoe Stringer if reader: 26923a932cSJoe Stringer BaseException.__init__(self, 27923a932cSJoe Stringer 'Error at file offset %d, parsing line: %s' % 28923a932cSJoe Stringer (reader.tell(), line)) 29923a932cSJoe Stringer else: 30923a932cSJoe Stringer BaseException.__init__(self, 'Error parsing line: %s' % line) 31923a932cSJoe Stringer 32a67882a2SJoe Stringer 33a67882a2SJoe Stringerclass APIElement(object): 34923a932cSJoe Stringer """ 35a67882a2SJoe Stringer An object representing the description of an aspect of the eBPF API. 36a67882a2SJoe Stringer @proto: prototype of the API symbol 37a67882a2SJoe Stringer @desc: textual description of the symbol 38a67882a2SJoe Stringer @ret: (optional) description of any associated return value 39923a932cSJoe Stringer """ 40923a932cSJoe Stringer def __init__(self, proto='', desc='', ret=''): 41923a932cSJoe Stringer self.proto = proto 42923a932cSJoe Stringer self.desc = desc 43923a932cSJoe Stringer self.ret = ret 44923a932cSJoe Stringer 45a67882a2SJoe Stringer 46a67882a2SJoe Stringerclass Helper(APIElement): 47a67882a2SJoe Stringer """ 48a67882a2SJoe Stringer An object representing the description of an eBPF helper function. 49a67882a2SJoe Stringer @proto: function prototype of the helper function 50a67882a2SJoe Stringer @desc: textual description of the helper function 51a67882a2SJoe Stringer @ret: description of the return value of the helper function 52a67882a2SJoe Stringer """ 530a0d55efSEyal Birger def __init__(self, *args, **kwargs): 540a0d55efSEyal Birger super().__init__(*args, **kwargs) 550a0d55efSEyal Birger self.enum_val = None 560a0d55efSEyal Birger 57923a932cSJoe Stringer def proto_break_down(self): 58923a932cSJoe Stringer """ 59923a932cSJoe Stringer Break down helper function protocol into smaller chunks: return type, 60923a932cSJoe Stringer name, distincts arguments. 61923a932cSJoe Stringer """ 62121fd33bSVishal Chourasia arg_re = re.compile(r'((\w+ )*?(\w+|...))( (\**)(\w+))?$') 63923a932cSJoe Stringer res = {} 64121fd33bSVishal Chourasia proto_re = re.compile(r'(.+) (\**)(\w+)\(((([^,]+)(, )?){1,5})\)$') 65923a932cSJoe Stringer 66923a932cSJoe Stringer capture = proto_re.match(self.proto) 67923a932cSJoe Stringer res['ret_type'] = capture.group(1) 68923a932cSJoe Stringer res['ret_star'] = capture.group(2) 69923a932cSJoe Stringer res['name'] = capture.group(3) 70923a932cSJoe Stringer res['args'] = [] 71923a932cSJoe Stringer 72923a932cSJoe Stringer args = capture.group(4).split(', ') 73923a932cSJoe Stringer for a in args: 74923a932cSJoe Stringer capture = arg_re.match(a) 75923a932cSJoe Stringer res['args'].append({ 76923a932cSJoe Stringer 'type' : capture.group(1), 77923a932cSJoe Stringer 'star' : capture.group(5), 78923a932cSJoe Stringer 'name' : capture.group(6) 79923a932cSJoe Stringer }) 80923a932cSJoe Stringer 81923a932cSJoe Stringer return res 82923a932cSJoe Stringer 83a67882a2SJoe Stringer 84923a932cSJoe Stringerclass HeaderParser(object): 85923a932cSJoe Stringer """ 86923a932cSJoe Stringer An object used to parse a file in order to extract the documentation of a 87923a932cSJoe Stringer list of eBPF helper functions. All the helpers that can be retrieved are 88923a932cSJoe Stringer stored as Helper object, in the self.helpers() array. 89923a932cSJoe Stringer @filename: name of file to parse, usually include/uapi/linux/bpf.h in the 90923a932cSJoe Stringer kernel tree 91923a932cSJoe Stringer """ 92923a932cSJoe Stringer def __init__(self, filename): 93923a932cSJoe Stringer self.reader = open(filename, 'r') 94923a932cSJoe Stringer self.line = '' 95923a932cSJoe Stringer self.helpers = [] 96a67882a2SJoe Stringer self.commands = [] 9771a3cdf8SUsama Arif self.desc_unique_helpers = set() 9871a3cdf8SUsama Arif self.define_unique_helpers = [] 990a0d55efSEyal Birger self.helper_enum_vals = {} 100ce3e44a0SAndrii Nakryiko self.helper_enum_pos = {} 1010ba3929eSUsama Arif self.desc_syscalls = [] 1020ba3929eSUsama Arif self.enum_syscalls = [] 103a67882a2SJoe Stringer 104a67882a2SJoe Stringer def parse_element(self): 105a67882a2SJoe Stringer proto = self.parse_symbol() 106f1f3f67fSUsama Arif desc = self.parse_desc(proto) 107f1f3f67fSUsama Arif ret = self.parse_ret(proto) 108a67882a2SJoe Stringer return APIElement(proto=proto, desc=desc, ret=ret) 109923a932cSJoe Stringer 110923a932cSJoe Stringer def parse_helper(self): 111923a932cSJoe Stringer proto = self.parse_proto() 112f1f3f67fSUsama Arif desc = self.parse_desc(proto) 113f1f3f67fSUsama Arif ret = self.parse_ret(proto) 114923a932cSJoe Stringer return Helper(proto=proto, desc=desc, ret=ret) 115923a932cSJoe Stringer 116a67882a2SJoe Stringer def parse_symbol(self): 117121fd33bSVishal Chourasia p = re.compile(r' \* ?(BPF\w+)$') 118a67882a2SJoe Stringer capture = p.match(self.line) 119a67882a2SJoe Stringer if not capture: 120a67882a2SJoe Stringer raise NoSyscallCommandFound 121121fd33bSVishal Chourasia end_re = re.compile(r' \* ?NOTES$') 122a67882a2SJoe Stringer end = end_re.match(self.line) 123a67882a2SJoe Stringer if end: 124a67882a2SJoe Stringer raise NoSyscallCommandFound 125a67882a2SJoe Stringer self.line = self.reader.readline() 126a67882a2SJoe Stringer return capture.group(1) 127a67882a2SJoe Stringer 128923a932cSJoe Stringer def parse_proto(self): 129923a932cSJoe Stringer # Argument can be of shape: 130923a932cSJoe Stringer # - "void" 131923a932cSJoe Stringer # - "type name" 132923a932cSJoe Stringer # - "type *name" 133923a932cSJoe Stringer # - Same as above, with "const" and/or "struct" in front of type 134923a932cSJoe Stringer # - "..." (undefined number of arguments, for bpf_trace_printk()) 135923a932cSJoe Stringer # There is at least one term ("void"), and at most five arguments. 136121fd33bSVishal Chourasia p = re.compile(r' \* ?((.+) \**\w+\((((const )?(struct )?(\w+|\.\.\.)( \**\w+)?)(, )?){1,5}\))$') 137923a932cSJoe Stringer capture = p.match(self.line) 138923a932cSJoe Stringer if not capture: 139923a932cSJoe Stringer raise NoHelperFound 140923a932cSJoe Stringer self.line = self.reader.readline() 141923a932cSJoe Stringer return capture.group(1) 142923a932cSJoe Stringer 143f1f3f67fSUsama Arif def parse_desc(self, proto): 144121fd33bSVishal Chourasia p = re.compile(r' \* ?(?:\t| {5,8})Description$') 145923a932cSJoe Stringer capture = p.match(self.line) 146923a932cSJoe Stringer if not capture: 147f1f3f67fSUsama Arif raise Exception("No description section found for " + proto) 148923a932cSJoe Stringer # Description can be several lines, some of them possibly empty, and it 149923a932cSJoe Stringer # stops when another subsection title is met. 150923a932cSJoe Stringer desc = '' 151f1f3f67fSUsama Arif desc_present = False 152923a932cSJoe Stringer while True: 153923a932cSJoe Stringer self.line = self.reader.readline() 154923a932cSJoe Stringer if self.line == ' *\n': 155923a932cSJoe Stringer desc += '\n' 156923a932cSJoe Stringer else: 157121fd33bSVishal Chourasia p = re.compile(r' \* ?(?:\t| {5,8})(?:\t| {8})(.*)') 158923a932cSJoe Stringer capture = p.match(self.line) 159923a932cSJoe Stringer if capture: 160f1f3f67fSUsama Arif desc_present = True 161923a932cSJoe Stringer desc += capture.group(1) + '\n' 162923a932cSJoe Stringer else: 163923a932cSJoe Stringer break 164f1f3f67fSUsama Arif 165f1f3f67fSUsama Arif if not desc_present: 166f1f3f67fSUsama Arif raise Exception("No description found for " + proto) 167923a932cSJoe Stringer return desc 168923a932cSJoe Stringer 169f1f3f67fSUsama Arif def parse_ret(self, proto): 170121fd33bSVishal Chourasia p = re.compile(r' \* ?(?:\t| {5,8})Return$') 171923a932cSJoe Stringer capture = p.match(self.line) 172923a932cSJoe Stringer if not capture: 173f1f3f67fSUsama Arif raise Exception("No return section found for " + proto) 174923a932cSJoe Stringer # Return value description can be several lines, some of them possibly 175923a932cSJoe Stringer # empty, and it stops when another subsection title is met. 176923a932cSJoe Stringer ret = '' 177f1f3f67fSUsama Arif ret_present = False 178923a932cSJoe Stringer while True: 179923a932cSJoe Stringer self.line = self.reader.readline() 180923a932cSJoe Stringer if self.line == ' *\n': 181923a932cSJoe Stringer ret += '\n' 182923a932cSJoe Stringer else: 183121fd33bSVishal Chourasia p = re.compile(r' \* ?(?:\t| {5,8})(?:\t| {8})(.*)') 184923a932cSJoe Stringer capture = p.match(self.line) 185923a932cSJoe Stringer if capture: 186f1f3f67fSUsama Arif ret_present = True 187923a932cSJoe Stringer ret += capture.group(1) + '\n' 188923a932cSJoe Stringer else: 189923a932cSJoe Stringer break 190f1f3f67fSUsama Arif 191f1f3f67fSUsama Arif if not ret_present: 192f1f3f67fSUsama Arif raise Exception("No return found for " + proto) 193923a932cSJoe Stringer return ret 194923a932cSJoe Stringer 1950ba3929eSUsama Arif def seek_to(self, target, help_message, discard_lines = 1): 196a67882a2SJoe Stringer self.reader.seek(0) 197a67882a2SJoe Stringer offset = self.reader.read().find(target) 198923a932cSJoe Stringer if offset == -1: 199a67882a2SJoe Stringer raise Exception(help_message) 200923a932cSJoe Stringer self.reader.seek(offset) 201923a932cSJoe Stringer self.reader.readline() 2020ba3929eSUsama Arif for _ in range(discard_lines): 203923a932cSJoe Stringer self.reader.readline() 204923a932cSJoe Stringer self.line = self.reader.readline() 205923a932cSJoe Stringer 2060ba3929eSUsama Arif def parse_desc_syscall(self): 207a67882a2SJoe Stringer self.seek_to('* DOC: eBPF Syscall Commands', 208a67882a2SJoe Stringer 'Could not find start of eBPF syscall descriptions list') 209a67882a2SJoe Stringer while True: 210a67882a2SJoe Stringer try: 211a67882a2SJoe Stringer command = self.parse_element() 212a67882a2SJoe Stringer self.commands.append(command) 2130ba3929eSUsama Arif self.desc_syscalls.append(command.proto) 2140ba3929eSUsama Arif 215a67882a2SJoe Stringer except NoSyscallCommandFound: 216a67882a2SJoe Stringer break 217a67882a2SJoe Stringer 2180ba3929eSUsama Arif def parse_enum_syscall(self): 2190ba3929eSUsama Arif self.seek_to('enum bpf_cmd {', 2200ba3929eSUsama Arif 'Could not find start of bpf_cmd enum', 0) 2210ba3929eSUsama Arif # Searches for either one or more BPF\w+ enums 222121fd33bSVishal Chourasia bpf_p = re.compile(r'\s*(BPF\w+)+') 2230ba3929eSUsama Arif # Searches for an enum entry assigned to another entry, 2240ba3929eSUsama Arif # for e.g. BPF_PROG_RUN = BPF_PROG_TEST_RUN, which is 2250ba3929eSUsama Arif # not documented hence should be skipped in check to 2260ba3929eSUsama Arif # determine if the right number of syscalls are documented 227121fd33bSVishal Chourasia assign_p = re.compile(r'\s*(BPF\w+)\s*=\s*(BPF\w+)') 2280ba3929eSUsama Arif bpf_cmd_str = '' 2290ba3929eSUsama Arif while True: 2300ba3929eSUsama Arif capture = assign_p.match(self.line) 2310ba3929eSUsama Arif if capture: 2320ba3929eSUsama Arif # Skip line if an enum entry is assigned to another entry 2330ba3929eSUsama Arif self.line = self.reader.readline() 2340ba3929eSUsama Arif continue 2350ba3929eSUsama Arif capture = bpf_p.match(self.line) 2360ba3929eSUsama Arif if capture: 2370ba3929eSUsama Arif bpf_cmd_str += self.line 2380ba3929eSUsama Arif else: 2390ba3929eSUsama Arif break 2400ba3929eSUsama Arif self.line = self.reader.readline() 2410ba3929eSUsama Arif # Find the number of occurences of BPF\w+ 242121fd33bSVishal Chourasia self.enum_syscalls = re.findall(r'(BPF\w+)+', bpf_cmd_str) 2430ba3929eSUsama Arif 24471a3cdf8SUsama Arif def parse_desc_helpers(self): 24592ec1cc3SQuentin Monnet self.seek_to(helpersDocStart, 246a67882a2SJoe Stringer 'Could not find start of eBPF helper descriptions list') 247923a932cSJoe Stringer while True: 248923a932cSJoe Stringer try: 249923a932cSJoe Stringer helper = self.parse_helper() 250923a932cSJoe Stringer self.helpers.append(helper) 25171a3cdf8SUsama Arif proto = helper.proto_break_down() 25271a3cdf8SUsama Arif self.desc_unique_helpers.add(proto['name']) 253923a932cSJoe Stringer except NoHelperFound: 254923a932cSJoe Stringer break 255923a932cSJoe Stringer 25671a3cdf8SUsama Arif def parse_define_helpers(self): 2578a76145aSAndrii Nakryiko # Parse FN(...) in #define ___BPF_FUNC_MAPPER to compare later with the 2580a0d55efSEyal Birger # number of unique function names present in description and use the 2590a0d55efSEyal Birger # correct enumeration value. 26071a3cdf8SUsama Arif # Note: seek_to(..) discards the first line below the target search text, 2618a76145aSAndrii Nakryiko # resulting in FN(unspec, 0, ##ctx) being skipped and not added to 2628a76145aSAndrii Nakryiko # self.define_unique_helpers. 2638a76145aSAndrii Nakryiko self.seek_to('#define ___BPF_FUNC_MAPPER(FN, ctx...)', 26471a3cdf8SUsama Arif 'Could not find start of eBPF helper definition list') 2650a0d55efSEyal Birger # Searches for one FN(\w+) define or a backslash for newline 266121fd33bSVishal Chourasia p = re.compile(r'\s*FN\((\w+), (\d+), ##ctx\)|\\\\') 26771a3cdf8SUsama Arif fn_defines_str = '' 268ce3e44a0SAndrii Nakryiko i = 0 26971a3cdf8SUsama Arif while True: 27071a3cdf8SUsama Arif capture = p.match(self.line) 27171a3cdf8SUsama Arif if capture: 27271a3cdf8SUsama Arif fn_defines_str += self.line 273ce3e44a0SAndrii Nakryiko helper_name = capture.expand(r'bpf_\1') 2745fbea423SMichal Suchanek self.helper_enum_vals[helper_name] = int(capture.group(2)) 275ce3e44a0SAndrii Nakryiko self.helper_enum_pos[helper_name] = i 276ce3e44a0SAndrii Nakryiko i += 1 27771a3cdf8SUsama Arif else: 27871a3cdf8SUsama Arif break 27971a3cdf8SUsama Arif self.line = self.reader.readline() 28071a3cdf8SUsama Arif # Find the number of occurences of FN(\w+) 281121fd33bSVishal Chourasia self.define_unique_helpers = re.findall(r'FN\(\w+, \d+, ##ctx\)', fn_defines_str) 28271a3cdf8SUsama Arif 283ce3e44a0SAndrii Nakryiko def validate_helpers(self): 284ce3e44a0SAndrii Nakryiko last_helper = '' 2850a0d55efSEyal Birger seen_helpers = set() 286ce3e44a0SAndrii Nakryiko seen_enum_vals = set() 287ce3e44a0SAndrii Nakryiko i = 0 2880a0d55efSEyal Birger for helper in self.helpers: 2890a0d55efSEyal Birger proto = helper.proto_break_down() 2900a0d55efSEyal Birger name = proto['name'] 2910a0d55efSEyal Birger try: 2920a0d55efSEyal Birger enum_val = self.helper_enum_vals[name] 293ce3e44a0SAndrii Nakryiko enum_pos = self.helper_enum_pos[name] 2940a0d55efSEyal Birger except KeyError: 2950a0d55efSEyal Birger raise Exception("Helper %s is missing from enum bpf_func_id" % name) 2960a0d55efSEyal Birger 297ce3e44a0SAndrii Nakryiko if name in seen_helpers: 298ce3e44a0SAndrii Nakryiko if last_helper != name: 299ce3e44a0SAndrii Nakryiko raise Exception("Helper %s has multiple descriptions which are not grouped together" % name) 300ce3e44a0SAndrii Nakryiko continue 301ce3e44a0SAndrii Nakryiko 3020a0d55efSEyal Birger # Enforce current practice of having the descriptions ordered 3030a0d55efSEyal Birger # by enum value. 304ce3e44a0SAndrii Nakryiko if enum_pos != i: 305ce3e44a0SAndrii Nakryiko 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)) 306ce3e44a0SAndrii Nakryiko if enum_val in seen_enum_vals: 307ce3e44a0SAndrii Nakryiko raise Exception("Helper %s has duplicated value %d" % (name, enum_val)) 308ce3e44a0SAndrii Nakryiko 3090a0d55efSEyal Birger seen_helpers.add(name) 310ce3e44a0SAndrii Nakryiko last_helper = name 311ce3e44a0SAndrii Nakryiko seen_enum_vals.add(enum_val) 3120a0d55efSEyal Birger 3130a0d55efSEyal Birger helper.enum_val = enum_val 314ce3e44a0SAndrii Nakryiko i += 1 3150a0d55efSEyal Birger 316a67882a2SJoe Stringer def run(self): 3170ba3929eSUsama Arif self.parse_desc_syscall() 3180ba3929eSUsama Arif self.parse_enum_syscall() 31971a3cdf8SUsama Arif self.parse_desc_helpers() 32071a3cdf8SUsama Arif self.parse_define_helpers() 321ce3e44a0SAndrii Nakryiko self.validate_helpers() 322923a932cSJoe Stringer self.reader.close() 323923a932cSJoe Stringer 324923a932cSJoe Stringer############################################################################### 325923a932cSJoe Stringer 326923a932cSJoe Stringerclass Printer(object): 327923a932cSJoe Stringer """ 328923a932cSJoe Stringer A generic class for printers. Printers should be created with an array of 329923a932cSJoe Stringer Helper objects, and implement a way to print them in the desired fashion. 330923a932cSJoe Stringer @parser: A HeaderParser with objects to print to standard output 331923a932cSJoe Stringer """ 332923a932cSJoe Stringer def __init__(self, parser): 333923a932cSJoe Stringer self.parser = parser 334923a932cSJoe Stringer self.elements = [] 335923a932cSJoe Stringer 336923a932cSJoe Stringer def print_header(self): 337923a932cSJoe Stringer pass 338923a932cSJoe Stringer 339923a932cSJoe Stringer def print_footer(self): 340923a932cSJoe Stringer pass 341923a932cSJoe Stringer 342923a932cSJoe Stringer def print_one(self, helper): 343923a932cSJoe Stringer pass 344923a932cSJoe Stringer 345923a932cSJoe Stringer def print_all(self): 346923a932cSJoe Stringer self.print_header() 347923a932cSJoe Stringer for elem in self.elements: 348923a932cSJoe Stringer self.print_one(elem) 349923a932cSJoe Stringer self.print_footer() 350923a932cSJoe Stringer 3510ba3929eSUsama Arif def elem_number_check(self, desc_unique_elem, define_unique_elem, type, instance): 3520ba3929eSUsama Arif """ 3530ba3929eSUsama Arif Checks the number of helpers/syscalls documented within the header file 3540ba3929eSUsama Arif description with those defined as part of enum/macro and raise an 3550ba3929eSUsama Arif Exception if they don't match. 3560ba3929eSUsama Arif """ 3570ba3929eSUsama Arif nr_desc_unique_elem = len(desc_unique_elem) 3580ba3929eSUsama Arif nr_define_unique_elem = len(define_unique_elem) 3590ba3929eSUsama Arif if nr_desc_unique_elem != nr_define_unique_elem: 3600ba3929eSUsama Arif exception_msg = ''' 3610ba3929eSUsama ArifThe number of unique %s in description (%d) doesn\'t match the number of unique %s defined in %s (%d) 3620ba3929eSUsama Arif''' % (type, nr_desc_unique_elem, type, instance, nr_define_unique_elem) 3630ba3929eSUsama Arif if nr_desc_unique_elem < nr_define_unique_elem: 3640ba3929eSUsama Arif # Function description is parsed until no helper is found (which can be due to 3650ba3929eSUsama Arif # misformatting). Hence, only print the first missing/misformatted helper/enum. 3660ba3929eSUsama Arif exception_msg += ''' 3670ba3929eSUsama ArifThe description for %s is not present or formatted correctly. 3680ba3929eSUsama Arif''' % (define_unique_elem[nr_desc_unique_elem]) 3690ba3929eSUsama Arif raise Exception(exception_msg) 370923a932cSJoe Stringer 371923a932cSJoe Stringerclass PrinterRST(Printer): 372923a932cSJoe Stringer """ 373923a932cSJoe Stringer A generic class for printers that print ReStructured Text. Printers should 374923a932cSJoe Stringer be created with a HeaderParser object, and implement a way to print API 375923a932cSJoe Stringer elements in the desired fashion. 376923a932cSJoe Stringer @parser: A HeaderParser with objects to print to standard output 377923a932cSJoe Stringer """ 378923a932cSJoe Stringer def __init__(self, parser): 379923a932cSJoe Stringer self.parser = parser 380923a932cSJoe Stringer 381923a932cSJoe Stringer def print_license(self): 382923a932cSJoe Stringer license = '''\ 383923a932cSJoe Stringer.. Copyright (C) All BPF authors and contributors from 2014 to present. 384923a932cSJoe Stringer.. See git log include/uapi/linux/bpf.h in kernel tree for details. 385923a932cSJoe Stringer.. 3865cb62b75SAlejandro Colomar.. SPDX-License-Identifier: Linux-man-pages-copyleft 387923a932cSJoe Stringer.. 388923a932cSJoe Stringer.. Please do not edit this file. It was generated from the documentation 389923a932cSJoe Stringer.. located in file include/uapi/linux/bpf.h of the Linux kernel sources 390923a932cSJoe Stringer.. (helpers description), and from scripts/bpf_doc.py in the same 391923a932cSJoe Stringer.. repository (header and footer). 392923a932cSJoe Stringer''' 393923a932cSJoe Stringer print(license) 394923a932cSJoe Stringer 395923a932cSJoe Stringer def print_elem(self, elem): 396923a932cSJoe Stringer if (elem.desc): 397923a932cSJoe Stringer print('\tDescription') 398923a932cSJoe Stringer # Do not strip all newline characters: formatted code at the end of 399923a932cSJoe Stringer # a section must be followed by a blank line. 400923a932cSJoe Stringer for line in re.sub('\n$', '', elem.desc, count=1).split('\n'): 401923a932cSJoe Stringer print('{}{}'.format('\t\t' if line else '', line)) 402923a932cSJoe Stringer 403923a932cSJoe Stringer if (elem.ret): 404923a932cSJoe Stringer print('\tReturn') 405923a932cSJoe Stringer for line in elem.ret.rstrip().split('\n'): 406923a932cSJoe Stringer print('{}{}'.format('\t\t' if line else '', line)) 407923a932cSJoe Stringer 408923a932cSJoe Stringer print('') 409923a932cSJoe Stringer 410fd0a38f9SQuentin Monnet def get_kernel_version(self): 411fd0a38f9SQuentin Monnet try: 412fd0a38f9SQuentin Monnet version = subprocess.run(['git', 'describe'], cwd=linuxRoot, 413fd0a38f9SQuentin Monnet capture_output=True, check=True) 414fd0a38f9SQuentin Monnet version = version.stdout.decode().rstrip() 415fd0a38f9SQuentin Monnet except: 416fd0a38f9SQuentin Monnet try: 417*54d38a5cSHangbin Liu version = subprocess.run(['make', '-s', '--no-print-directory', 'kernelversion'], 418*54d38a5cSHangbin Liu cwd=linuxRoot, capture_output=True, check=True) 419fd0a38f9SQuentin Monnet version = version.stdout.decode().rstrip() 420fd0a38f9SQuentin Monnet except: 421fd0a38f9SQuentin Monnet return 'Linux' 422fd0a38f9SQuentin Monnet return 'Linux {version}'.format(version=version) 423fd0a38f9SQuentin Monnet 42492ec1cc3SQuentin Monnet def get_last_doc_update(self, delimiter): 42592ec1cc3SQuentin Monnet try: 42692ec1cc3SQuentin Monnet cmd = ['git', 'log', '-1', '--pretty=format:%cs', '--no-patch', 42792ec1cc3SQuentin Monnet '-L', 428121fd33bSVishal Chourasia '/{}/,/\\*\\//:include/uapi/linux/bpf.h'.format(delimiter)] 42992ec1cc3SQuentin Monnet date = subprocess.run(cmd, cwd=linuxRoot, 43092ec1cc3SQuentin Monnet capture_output=True, check=True) 43192ec1cc3SQuentin Monnet return date.stdout.decode().rstrip() 43292ec1cc3SQuentin Monnet except: 43392ec1cc3SQuentin Monnet return '' 43492ec1cc3SQuentin Monnet 435923a932cSJoe Stringerclass PrinterHelpersRST(PrinterRST): 436923a932cSJoe Stringer """ 437923a932cSJoe Stringer A printer for dumping collected information about helpers as a ReStructured 438923a932cSJoe Stringer Text page compatible with the rst2man program, which can be used to 439923a932cSJoe Stringer generate a manual page for the helpers. 440923a932cSJoe Stringer @parser: A HeaderParser with Helper objects to print to standard output 441923a932cSJoe Stringer """ 442923a932cSJoe Stringer def __init__(self, parser): 443923a932cSJoe Stringer self.elements = parser.helpers 4448a76145aSAndrii Nakryiko self.elem_number_check(parser.desc_unique_helpers, parser.define_unique_helpers, 'helper', '___BPF_FUNC_MAPPER') 445923a932cSJoe Stringer 446923a932cSJoe Stringer def print_header(self): 447923a932cSJoe Stringer header = '''\ 448923a932cSJoe Stringer=========== 449923a932cSJoe StringerBPF-HELPERS 450923a932cSJoe Stringer=========== 451923a932cSJoe Stringer------------------------------------------------------------------------------- 452923a932cSJoe Stringerlist of eBPF helper functions 453923a932cSJoe Stringer------------------------------------------------------------------------------- 454923a932cSJoe Stringer 455923a932cSJoe Stringer:Manual section: 7 456fd0a38f9SQuentin Monnet:Version: {version} 45792ec1cc3SQuentin Monnet{date_field}{date} 458923a932cSJoe Stringer 459923a932cSJoe StringerDESCRIPTION 460923a932cSJoe Stringer=========== 461923a932cSJoe Stringer 462923a932cSJoe StringerThe extended Berkeley Packet Filter (eBPF) subsystem consists in programs 463923a932cSJoe Stringerwritten in a pseudo-assembly language, then attached to one of the several 464923a932cSJoe Stringerkernel hooks and run in reaction of specific events. This framework differs 465923a932cSJoe Stringerfrom the older, "classic" BPF (or "cBPF") in several aspects, one of them being 466923a932cSJoe Stringerthe ability to call special functions (or "helpers") from within a program. 467923a932cSJoe StringerThese functions are restricted to a white-list of helpers defined in the 468923a932cSJoe Stringerkernel. 469923a932cSJoe Stringer 470923a932cSJoe StringerThese helpers are used by eBPF programs to interact with the system, or with 471923a932cSJoe Stringerthe context in which they work. For instance, they can be used to print 472923a932cSJoe Stringerdebugging messages, to get the time since the system was booted, to interact 473923a932cSJoe Stringerwith eBPF maps, or to manipulate network packets. Since there are several eBPF 474923a932cSJoe Stringerprogram types, and that they do not run in the same context, each program type 475923a932cSJoe Stringercan only call a subset of those helpers. 476923a932cSJoe Stringer 477923a932cSJoe StringerDue to eBPF conventions, a helper can not have more than five arguments. 478923a932cSJoe Stringer 479923a932cSJoe StringerInternally, eBPF programs call directly into the compiled helper functions 480923a932cSJoe Stringerwithout requiring any foreign-function interface. As a result, calling helpers 481923a932cSJoe Stringerintroduces no overhead, thus offering excellent performance. 482923a932cSJoe Stringer 483923a932cSJoe StringerThis document is an attempt to list and document the helpers available to eBPF 484923a932cSJoe Stringerdevelopers. They are sorted by chronological order (the oldest helpers in the 485923a932cSJoe Stringerkernel at the top). 486923a932cSJoe Stringer 487923a932cSJoe StringerHELPERS 488923a932cSJoe Stringer======= 489923a932cSJoe Stringer''' 490fd0a38f9SQuentin Monnet kernelVersion = self.get_kernel_version() 49192ec1cc3SQuentin Monnet lastUpdate = self.get_last_doc_update(helpersDocStart) 492fd0a38f9SQuentin Monnet 493923a932cSJoe Stringer PrinterRST.print_license(self) 49492ec1cc3SQuentin Monnet print(header.format(version=kernelVersion, 49592ec1cc3SQuentin Monnet date_field = ':Date: ' if lastUpdate else '', 49692ec1cc3SQuentin Monnet date=lastUpdate)) 497923a932cSJoe Stringer 498923a932cSJoe Stringer def print_footer(self): 499923a932cSJoe Stringer footer = ''' 500923a932cSJoe StringerEXAMPLES 501923a932cSJoe Stringer======== 502923a932cSJoe Stringer 503923a932cSJoe StringerExample usage for most of the eBPF helpers listed in this manual page are 504923a932cSJoe Stringeravailable within the Linux kernel sources, at the following locations: 505923a932cSJoe Stringer 506923a932cSJoe Stringer* *samples/bpf/* 507923a932cSJoe Stringer* *tools/testing/selftests/bpf/* 508923a932cSJoe Stringer 509923a932cSJoe StringerLICENSE 510923a932cSJoe Stringer======= 511923a932cSJoe Stringer 512923a932cSJoe StringereBPF programs can have an associated license, passed along with the bytecode 513923a932cSJoe Stringerinstructions to the kernel when the programs are loaded. The format for that 514923a932cSJoe Stringerstring is identical to the one in use for kernel modules (Dual licenses, such 515923a932cSJoe Stringeras "Dual BSD/GPL", may be used). Some helper functions are only accessible to 516239b85a9SGianmarco Lusvardiprograms that are compatible with the GNU General Public License (GNU GPL). 517923a932cSJoe Stringer 518923a932cSJoe StringerIn order to use such helpers, the eBPF program must be loaded with the correct 519121fd33bSVishal Chourasialicense string passed (via **attr**) to the **bpf**\\ () system call, and this 520923a932cSJoe Stringergenerally translates into the C source code of the program containing a line 521923a932cSJoe Stringersimilar to the following: 522923a932cSJoe Stringer 523923a932cSJoe Stringer:: 524923a932cSJoe Stringer 525923a932cSJoe Stringer char ____license[] __attribute__((section("license"), used)) = "GPL"; 526923a932cSJoe Stringer 527923a932cSJoe StringerIMPLEMENTATION 528923a932cSJoe Stringer============== 529923a932cSJoe Stringer 530923a932cSJoe StringerThis manual page is an effort to document the existing eBPF helper functions. 531923a932cSJoe StringerBut as of this writing, the BPF sub-system is under heavy development. New eBPF 532923a932cSJoe Stringerprogram or map types are added, along with new helper functions. Some helpers 533923a932cSJoe Stringerare occasionally made available for additional program types. So in spite of 534923a932cSJoe Stringerthe efforts of the community, this page might not be up-to-date. If you want to 535923a932cSJoe Stringercheck by yourself what helper functions exist in your kernel, or what types of 536923a932cSJoe Stringerprograms they can support, here are some files among the kernel tree that you 537923a932cSJoe Stringermay be interested in: 538923a932cSJoe Stringer 539923a932cSJoe Stringer* *include/uapi/linux/bpf.h* is the main BPF header. It contains the full list 540923a932cSJoe Stringer of all helper functions, as well as many other BPF definitions including most 541923a932cSJoe Stringer of the flags, structs or constants used by the helpers. 542923a932cSJoe Stringer* *net/core/filter.c* contains the definition of most network-related helper 543923a932cSJoe Stringer functions, and the list of program types from which they can be used. 544923a932cSJoe Stringer* *kernel/trace/bpf_trace.c* is the equivalent for most tracing program-related 545923a932cSJoe Stringer helpers. 546923a932cSJoe Stringer* *kernel/bpf/verifier.c* contains the functions used to check that valid types 547923a932cSJoe Stringer of eBPF maps are used with a given helper function. 548923a932cSJoe Stringer* *kernel/bpf/* directory contains other files in which additional helpers are 549923a932cSJoe Stringer defined (for cgroups, sockmaps, etc.). 550923a932cSJoe Stringer* The bpftool utility can be used to probe the availability of helper functions 551923a932cSJoe Stringer on the system (as well as supported program and map types, and a number of 552923a932cSJoe Stringer other parameters). To do so, run **bpftool feature probe** (see 553121fd33bSVishal Chourasia **bpftool-feature**\\ (8) for details). Add the **unprivileged** keyword to 554923a932cSJoe Stringer list features available to unprivileged users. 555923a932cSJoe Stringer 556923a932cSJoe StringerCompatibility between helper functions and program types can generally be found 557923a932cSJoe Stringerin the files where helper functions are defined. Look for the **struct 558923a932cSJoe Stringerbpf_func_proto** objects and for functions returning them: these functions 559923a932cSJoe Stringercontain a list of helpers that a given program type can call. Note that the 560923a932cSJoe Stringer**default:** label of the **switch ... case** used to filter helpers can call 561923a932cSJoe Stringerother functions, themselves allowing access to additional helpers. The 562923a932cSJoe Stringerrequirement for GPL license is also in those **struct bpf_func_proto**. 563923a932cSJoe Stringer 564923a932cSJoe StringerCompatibility between helper functions and map types can be found in the 565121fd33bSVishal Chourasia**check_map_func_compatibility**\\ () function in file *kernel/bpf/verifier.c*. 566923a932cSJoe Stringer 567923a932cSJoe StringerHelper functions that invalidate the checks on **data** and **data_end** 568923a932cSJoe Stringerpointers for network processing are listed in function 569121fd33bSVishal Chourasia**bpf_helper_changes_pkt_data**\\ () in file *net/core/filter.c*. 570923a932cSJoe Stringer 571923a932cSJoe StringerSEE ALSO 572923a932cSJoe Stringer======== 573923a932cSJoe Stringer 574121fd33bSVishal Chourasia**bpf**\\ (2), 575121fd33bSVishal Chourasia**bpftool**\\ (8), 576121fd33bSVishal Chourasia**cgroups**\\ (7), 577121fd33bSVishal Chourasia**ip**\\ (8), 578121fd33bSVishal Chourasia**perf_event_open**\\ (2), 579121fd33bSVishal Chourasia**sendmsg**\\ (2), 580121fd33bSVishal Chourasia**socket**\\ (7), 581121fd33bSVishal Chourasia**tc-bpf**\\ (8)''' 582923a932cSJoe Stringer print(footer) 583923a932cSJoe Stringer 584923a932cSJoe Stringer def print_proto(self, helper): 585923a932cSJoe Stringer """ 586923a932cSJoe Stringer Format function protocol with bold and italics markers. This makes RST 587923a932cSJoe Stringer file less readable, but gives nice results in the manual page. 588923a932cSJoe Stringer """ 589923a932cSJoe Stringer proto = helper.proto_break_down() 590923a932cSJoe Stringer 591923a932cSJoe Stringer print('**%s %s%s(' % (proto['ret_type'], 592923a932cSJoe Stringer proto['ret_star'].replace('*', '\\*'), 593923a932cSJoe Stringer proto['name']), 594923a932cSJoe Stringer end='') 595923a932cSJoe Stringer 596923a932cSJoe Stringer comma = '' 597923a932cSJoe Stringer for a in proto['args']: 598923a932cSJoe Stringer one_arg = '{}{}'.format(comma, a['type']) 599923a932cSJoe Stringer if a['name']: 600923a932cSJoe Stringer if a['star']: 601121fd33bSVishal Chourasia one_arg += ' {}**\\ '.format(a['star'].replace('*', '\\*')) 602923a932cSJoe Stringer else: 603923a932cSJoe Stringer one_arg += '** ' 604923a932cSJoe Stringer one_arg += '*{}*\\ **'.format(a['name']) 605923a932cSJoe Stringer comma = ', ' 606923a932cSJoe Stringer print(one_arg, end='') 607923a932cSJoe Stringer 608923a932cSJoe Stringer print(')**') 609923a932cSJoe Stringer 610923a932cSJoe Stringer def print_one(self, helper): 611923a932cSJoe Stringer self.print_proto(helper) 612923a932cSJoe Stringer self.print_elem(helper) 613923a932cSJoe Stringer 614923a932cSJoe Stringer 615a67882a2SJoe Stringerclass PrinterSyscallRST(PrinterRST): 616a67882a2SJoe Stringer """ 617a67882a2SJoe Stringer A printer for dumping collected information about the syscall API as a 618a67882a2SJoe Stringer ReStructured Text page compatible with the rst2man program, which can be 619a67882a2SJoe Stringer used to generate a manual page for the syscall. 620a67882a2SJoe Stringer @parser: A HeaderParser with APIElement objects to print to standard 621a67882a2SJoe Stringer output 622a67882a2SJoe Stringer """ 623a67882a2SJoe Stringer def __init__(self, parser): 624a67882a2SJoe Stringer self.elements = parser.commands 6250ba3929eSUsama Arif self.elem_number_check(parser.desc_syscalls, parser.enum_syscalls, 'syscall', 'bpf_cmd') 626a67882a2SJoe Stringer 627a67882a2SJoe Stringer def print_header(self): 628a67882a2SJoe Stringer header = '''\ 629a67882a2SJoe Stringer=== 630a67882a2SJoe Stringerbpf 631a67882a2SJoe Stringer=== 632a67882a2SJoe Stringer------------------------------------------------------------------------------- 633a67882a2SJoe StringerPerform a command on an extended BPF object 634a67882a2SJoe Stringer------------------------------------------------------------------------------- 635a67882a2SJoe Stringer 636a67882a2SJoe Stringer:Manual section: 2 637a67882a2SJoe Stringer 638a67882a2SJoe StringerCOMMANDS 639a67882a2SJoe Stringer======== 640a67882a2SJoe Stringer''' 641a67882a2SJoe Stringer PrinterRST.print_license(self) 642a67882a2SJoe Stringer print(header) 643a67882a2SJoe Stringer 644a67882a2SJoe Stringer def print_one(self, command): 645a67882a2SJoe Stringer print('**%s**' % (command.proto)) 646a67882a2SJoe Stringer self.print_elem(command) 647923a932cSJoe Stringer 648923a932cSJoe Stringer 649923a932cSJoe Stringerclass PrinterHelpers(Printer): 650923a932cSJoe Stringer """ 651923a932cSJoe Stringer A printer for dumping collected information about helpers as C header to 652923a932cSJoe Stringer be included from BPF program. 653923a932cSJoe Stringer @parser: A HeaderParser with Helper objects to print to standard output 654923a932cSJoe Stringer """ 655923a932cSJoe Stringer def __init__(self, parser): 656923a932cSJoe Stringer self.elements = parser.helpers 6578a76145aSAndrii Nakryiko self.elem_number_check(parser.desc_unique_helpers, parser.define_unique_helpers, 'helper', '___BPF_FUNC_MAPPER') 658923a932cSJoe Stringer 659923a932cSJoe Stringer type_fwds = [ 660923a932cSJoe Stringer 'struct bpf_fib_lookup', 661923a932cSJoe Stringer 'struct bpf_sk_lookup', 662923a932cSJoe Stringer 'struct bpf_perf_event_data', 663923a932cSJoe Stringer 'struct bpf_perf_event_value', 664923a932cSJoe Stringer 'struct bpf_pidns_info', 665923a932cSJoe Stringer 'struct bpf_redir_neigh', 666923a932cSJoe Stringer 'struct bpf_sock', 667923a932cSJoe Stringer 'struct bpf_sock_addr', 668923a932cSJoe Stringer 'struct bpf_sock_ops', 669923a932cSJoe Stringer 'struct bpf_sock_tuple', 670923a932cSJoe Stringer 'struct bpf_spin_lock', 671923a932cSJoe Stringer 'struct bpf_sysctl', 672923a932cSJoe Stringer 'struct bpf_tcp_sock', 673923a932cSJoe Stringer 'struct bpf_tunnel_key', 674923a932cSJoe Stringer 'struct bpf_xfrm_state', 675923a932cSJoe Stringer 'struct linux_binprm', 676923a932cSJoe Stringer 'struct pt_regs', 677923a932cSJoe Stringer 'struct sk_reuseport_md', 678923a932cSJoe Stringer 'struct sockaddr', 679923a932cSJoe Stringer 'struct tcphdr', 680923a932cSJoe Stringer 'struct seq_file', 681923a932cSJoe Stringer 'struct tcp6_sock', 682923a932cSJoe Stringer 'struct tcp_sock', 683923a932cSJoe Stringer 'struct tcp_timewait_sock', 684923a932cSJoe Stringer 'struct tcp_request_sock', 685923a932cSJoe Stringer 'struct udp6_sock', 6869eeb3aa3SHengqi Chen 'struct unix_sock', 687923a932cSJoe Stringer 'struct task_struct', 688c4bcfb38SYonghong Song 'struct cgroup', 689923a932cSJoe Stringer 690923a932cSJoe Stringer 'struct __sk_buff', 691923a932cSJoe Stringer 'struct sk_msg_md', 692923a932cSJoe Stringer 'struct xdp_md', 693923a932cSJoe Stringer 'struct path', 694923a932cSJoe Stringer 'struct btf_ptr', 695923a932cSJoe Stringer 'struct inode', 696923a932cSJoe Stringer 'struct socket', 697923a932cSJoe Stringer 'struct file', 698b00628b1SAlexei Starovoitov 'struct bpf_timer', 6993bc253c2SGeliang Tang 'struct mptcp_sock', 70097e03f52SJoanne Koong 'struct bpf_dynptr', 70133bf9885SMaxim Mikityanskiy 'struct iphdr', 70233bf9885SMaxim Mikityanskiy 'struct ipv6hdr', 703923a932cSJoe Stringer ] 704923a932cSJoe Stringer known_types = { 705923a932cSJoe Stringer '...', 706923a932cSJoe Stringer 'void', 707923a932cSJoe Stringer 'const void', 708923a932cSJoe Stringer 'char', 709923a932cSJoe Stringer 'const char', 710923a932cSJoe Stringer 'int', 711923a932cSJoe Stringer 'long', 712923a932cSJoe Stringer 'unsigned long', 713923a932cSJoe Stringer 714923a932cSJoe Stringer '__be16', 715923a932cSJoe Stringer '__be32', 716923a932cSJoe Stringer '__wsum', 717923a932cSJoe Stringer 718923a932cSJoe Stringer 'struct bpf_fib_lookup', 719923a932cSJoe Stringer 'struct bpf_perf_event_data', 720923a932cSJoe Stringer 'struct bpf_perf_event_value', 721923a932cSJoe Stringer 'struct bpf_pidns_info', 722923a932cSJoe Stringer 'struct bpf_redir_neigh', 723923a932cSJoe Stringer 'struct bpf_sk_lookup', 724923a932cSJoe Stringer 'struct bpf_sock', 725923a932cSJoe Stringer 'struct bpf_sock_addr', 726923a932cSJoe Stringer 'struct bpf_sock_ops', 727923a932cSJoe Stringer 'struct bpf_sock_tuple', 728923a932cSJoe Stringer 'struct bpf_spin_lock', 729923a932cSJoe Stringer 'struct bpf_sysctl', 730923a932cSJoe Stringer 'struct bpf_tcp_sock', 731923a932cSJoe Stringer 'struct bpf_tunnel_key', 732923a932cSJoe Stringer 'struct bpf_xfrm_state', 733923a932cSJoe Stringer 'struct linux_binprm', 734923a932cSJoe Stringer 'struct pt_regs', 735923a932cSJoe Stringer 'struct sk_reuseport_md', 736923a932cSJoe Stringer 'struct sockaddr', 737923a932cSJoe Stringer 'struct tcphdr', 738923a932cSJoe Stringer 'struct seq_file', 739923a932cSJoe Stringer 'struct tcp6_sock', 740923a932cSJoe Stringer 'struct tcp_sock', 741923a932cSJoe Stringer 'struct tcp_timewait_sock', 742923a932cSJoe Stringer 'struct tcp_request_sock', 743923a932cSJoe Stringer 'struct udp6_sock', 7449eeb3aa3SHengqi Chen 'struct unix_sock', 745923a932cSJoe Stringer 'struct task_struct', 746c4bcfb38SYonghong Song 'struct cgroup', 747923a932cSJoe Stringer 'struct path', 748923a932cSJoe Stringer 'struct btf_ptr', 749923a932cSJoe Stringer 'struct inode', 750923a932cSJoe Stringer 'struct socket', 751923a932cSJoe Stringer 'struct file', 752b00628b1SAlexei Starovoitov 'struct bpf_timer', 7533bc253c2SGeliang Tang 'struct mptcp_sock', 75497e03f52SJoanne Koong 'struct bpf_dynptr', 75527060531SKumar Kartikeya Dwivedi 'const struct bpf_dynptr', 75633bf9885SMaxim Mikityanskiy 'struct iphdr', 75733bf9885SMaxim Mikityanskiy 'struct ipv6hdr', 758923a932cSJoe Stringer } 759923a932cSJoe Stringer mapped_types = { 760923a932cSJoe Stringer 'u8': '__u8', 761923a932cSJoe Stringer 'u16': '__u16', 762923a932cSJoe Stringer 'u32': '__u32', 763923a932cSJoe Stringer 'u64': '__u64', 764923a932cSJoe Stringer 's8': '__s8', 765923a932cSJoe Stringer 's16': '__s16', 766923a932cSJoe Stringer 's32': '__s32', 767923a932cSJoe Stringer 's64': '__s64', 768923a932cSJoe Stringer 'size_t': 'unsigned long', 769923a932cSJoe Stringer 'struct bpf_map': 'void', 770923a932cSJoe Stringer 'struct sk_buff': 'struct __sk_buff', 771923a932cSJoe Stringer 'const struct sk_buff': 'const struct __sk_buff', 772923a932cSJoe Stringer 'struct sk_msg_buff': 'struct sk_msg_md', 773923a932cSJoe Stringer 'struct xdp_buff': 'struct xdp_md', 774923a932cSJoe Stringer } 775923a932cSJoe Stringer # Helpers overloaded for different context types. 776923a932cSJoe Stringer overloaded_helpers = [ 777923a932cSJoe Stringer 'bpf_get_socket_cookie', 778923a932cSJoe Stringer 'bpf_sk_assign', 779923a932cSJoe Stringer ] 780923a932cSJoe Stringer 781923a932cSJoe Stringer def print_header(self): 782923a932cSJoe Stringer header = '''\ 783923a932cSJoe Stringer/* This is auto-generated file. See bpf_doc.py for details. */ 784923a932cSJoe Stringer 785923a932cSJoe Stringer/* Forward declarations of BPF structs */''' 786923a932cSJoe Stringer 787923a932cSJoe Stringer print(header) 788923a932cSJoe Stringer for fwd in self.type_fwds: 789923a932cSJoe Stringer print('%s;' % fwd) 790923a932cSJoe Stringer print('') 791923a932cSJoe Stringer 792923a932cSJoe Stringer def print_footer(self): 793923a932cSJoe Stringer footer = '' 794923a932cSJoe Stringer print(footer) 795923a932cSJoe Stringer 796923a932cSJoe Stringer def map_type(self, t): 797923a932cSJoe Stringer if t in self.known_types: 798923a932cSJoe Stringer return t 799923a932cSJoe Stringer if t in self.mapped_types: 800923a932cSJoe Stringer return self.mapped_types[t] 801923a932cSJoe Stringer print("Unrecognized type '%s', please add it to known types!" % t, 802923a932cSJoe Stringer file=sys.stderr) 803923a932cSJoe Stringer sys.exit(1) 804923a932cSJoe Stringer 805923a932cSJoe Stringer seen_helpers = set() 806923a932cSJoe Stringer 807923a932cSJoe Stringer def print_one(self, helper): 808923a932cSJoe Stringer proto = helper.proto_break_down() 809923a932cSJoe Stringer 810923a932cSJoe Stringer if proto['name'] in self.seen_helpers: 811923a932cSJoe Stringer return 812923a932cSJoe Stringer self.seen_helpers.add(proto['name']) 813923a932cSJoe Stringer 814923a932cSJoe Stringer print('/*') 815923a932cSJoe Stringer print(" * %s" % proto['name']) 816923a932cSJoe Stringer print(" *") 817923a932cSJoe Stringer if (helper.desc): 818923a932cSJoe Stringer # Do not strip all newline characters: formatted code at the end of 819923a932cSJoe Stringer # a section must be followed by a blank line. 820923a932cSJoe Stringer for line in re.sub('\n$', '', helper.desc, count=1).split('\n'): 821923a932cSJoe Stringer print(' *{}{}'.format(' \t' if line else '', line)) 822923a932cSJoe Stringer 823923a932cSJoe Stringer if (helper.ret): 824923a932cSJoe Stringer print(' *') 825923a932cSJoe Stringer print(' * Returns') 826923a932cSJoe Stringer for line in helper.ret.rstrip().split('\n'): 827923a932cSJoe Stringer print(' *{}{}'.format(' \t' if line else '', line)) 828923a932cSJoe Stringer 829923a932cSJoe Stringer print(' */') 830923a932cSJoe Stringer print('static %s %s(*%s)(' % (self.map_type(proto['ret_type']), 831923a932cSJoe Stringer proto['ret_star'], proto['name']), end='') 832923a932cSJoe Stringer comma = '' 833923a932cSJoe Stringer for i, a in enumerate(proto['args']): 834923a932cSJoe Stringer t = a['type'] 835923a932cSJoe Stringer n = a['name'] 836923a932cSJoe Stringer if proto['name'] in self.overloaded_helpers and i == 0: 837923a932cSJoe Stringer t = 'void' 838923a932cSJoe Stringer n = 'ctx' 839923a932cSJoe Stringer one_arg = '{}{}'.format(comma, self.map_type(t)) 840923a932cSJoe Stringer if n: 841923a932cSJoe Stringer if a['star']: 842923a932cSJoe Stringer one_arg += ' {}'.format(a['star']) 843923a932cSJoe Stringer else: 844923a932cSJoe Stringer one_arg += ' ' 845923a932cSJoe Stringer one_arg += '{}'.format(n) 846923a932cSJoe Stringer comma = ', ' 847923a932cSJoe Stringer print(one_arg, end='') 848923a932cSJoe Stringer 8490a0d55efSEyal Birger print(') = (void *) %d;' % helper.enum_val) 850923a932cSJoe Stringer print('') 851923a932cSJoe Stringer 852923a932cSJoe Stringer############################################################################### 853923a932cSJoe Stringer 854923a932cSJoe Stringer# If script is launched from scripts/ from kernel tree and can access 855923a932cSJoe Stringer# ../include/uapi/linux/bpf.h, use it as a default name for the file to parse, 856923a932cSJoe Stringer# otherwise the --filename argument will be required from the command line. 857923a932cSJoe Stringerscript = os.path.abspath(sys.argv[0]) 858923a932cSJoe StringerlinuxRoot = os.path.dirname(os.path.dirname(script)) 859923a932cSJoe Stringerbpfh = os.path.join(linuxRoot, 'include/uapi/linux/bpf.h') 860923a932cSJoe Stringer 861923a932cSJoe Stringerprinters = { 862923a932cSJoe Stringer 'helpers': PrinterHelpersRST, 863a67882a2SJoe Stringer 'syscall': PrinterSyscallRST, 864923a932cSJoe Stringer} 865923a932cSJoe Stringer 866923a932cSJoe StringerargParser = argparse.ArgumentParser(description=""" 867923a932cSJoe StringerParse eBPF header file and generate documentation for the eBPF API. 868923a932cSJoe StringerThe RST-formatted output produced can be turned into a manual page with the 869923a932cSJoe Stringerrst2man utility. 870923a932cSJoe Stringer""") 871923a932cSJoe StringerargParser.add_argument('--header', action='store_true', 872923a932cSJoe Stringer help='generate C header file') 873923a932cSJoe Stringerif (os.path.isfile(bpfh)): 874923a932cSJoe Stringer argParser.add_argument('--filename', help='path to include/uapi/linux/bpf.h', 875923a932cSJoe Stringer default=bpfh) 876923a932cSJoe Stringerelse: 877923a932cSJoe Stringer argParser.add_argument('--filename', help='path to include/uapi/linux/bpf.h') 878923a932cSJoe StringerargParser.add_argument('target', nargs='?', default='helpers', 879923a932cSJoe Stringer choices=printers.keys(), help='eBPF API target') 880923a932cSJoe Stringerargs = argParser.parse_args() 881923a932cSJoe Stringer 882923a932cSJoe Stringer# Parse file. 883923a932cSJoe StringerheaderParser = HeaderParser(args.filename) 884923a932cSJoe StringerheaderParser.run() 885923a932cSJoe Stringer 886923a932cSJoe Stringer# Print formatted output to standard output. 887923a932cSJoe Stringerif args.header: 888a67882a2SJoe Stringer if args.target != 'helpers': 889a67882a2SJoe Stringer raise NotImplementedError('Only helpers header generation is supported') 890923a932cSJoe Stringer printer = PrinterHelpers(headerParser) 891923a932cSJoe Stringerelse: 892923a932cSJoe Stringer printer = printers[args.target](headerParser) 893923a932cSJoe Stringerprinter.print_all() 894