1*4882a593Smuzhiyun#!/usr/bin/env python3 2*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun# Copyright (C) 2018-2019 Netronome Systems, Inc. 5*4882a593Smuzhiyun 6*4882a593Smuzhiyun# In case user attempts to run with Python 2. 7*4882a593Smuzhiyunfrom __future__ import print_function 8*4882a593Smuzhiyun 9*4882a593Smuzhiyunimport argparse 10*4882a593Smuzhiyunimport re 11*4882a593Smuzhiyunimport sys, os 12*4882a593Smuzhiyun 13*4882a593Smuzhiyunclass NoHelperFound(BaseException): 14*4882a593Smuzhiyun pass 15*4882a593Smuzhiyun 16*4882a593Smuzhiyunclass ParsingError(BaseException): 17*4882a593Smuzhiyun def __init__(self, line='<line not provided>', reader=None): 18*4882a593Smuzhiyun if reader: 19*4882a593Smuzhiyun BaseException.__init__(self, 20*4882a593Smuzhiyun 'Error at file offset %d, parsing line: %s' % 21*4882a593Smuzhiyun (reader.tell(), line)) 22*4882a593Smuzhiyun else: 23*4882a593Smuzhiyun BaseException.__init__(self, 'Error parsing line: %s' % line) 24*4882a593Smuzhiyun 25*4882a593Smuzhiyunclass Helper(object): 26*4882a593Smuzhiyun """ 27*4882a593Smuzhiyun An object representing the description of an eBPF helper function. 28*4882a593Smuzhiyun @proto: function prototype of the helper function 29*4882a593Smuzhiyun @desc: textual description of the helper function 30*4882a593Smuzhiyun @ret: description of the return value of the helper function 31*4882a593Smuzhiyun """ 32*4882a593Smuzhiyun def __init__(self, proto='', desc='', ret=''): 33*4882a593Smuzhiyun self.proto = proto 34*4882a593Smuzhiyun self.desc = desc 35*4882a593Smuzhiyun self.ret = ret 36*4882a593Smuzhiyun 37*4882a593Smuzhiyun def proto_break_down(self): 38*4882a593Smuzhiyun """ 39*4882a593Smuzhiyun Break down helper function protocol into smaller chunks: return type, 40*4882a593Smuzhiyun name, distincts arguments. 41*4882a593Smuzhiyun """ 42*4882a593Smuzhiyun arg_re = re.compile('((\w+ )*?(\w+|...))( (\**)(\w+))?$') 43*4882a593Smuzhiyun res = {} 44*4882a593Smuzhiyun proto_re = re.compile('(.+) (\**)(\w+)\(((([^,]+)(, )?){1,5})\)$') 45*4882a593Smuzhiyun 46*4882a593Smuzhiyun capture = proto_re.match(self.proto) 47*4882a593Smuzhiyun res['ret_type'] = capture.group(1) 48*4882a593Smuzhiyun res['ret_star'] = capture.group(2) 49*4882a593Smuzhiyun res['name'] = capture.group(3) 50*4882a593Smuzhiyun res['args'] = [] 51*4882a593Smuzhiyun 52*4882a593Smuzhiyun args = capture.group(4).split(', ') 53*4882a593Smuzhiyun for a in args: 54*4882a593Smuzhiyun capture = arg_re.match(a) 55*4882a593Smuzhiyun res['args'].append({ 56*4882a593Smuzhiyun 'type' : capture.group(1), 57*4882a593Smuzhiyun 'star' : capture.group(5), 58*4882a593Smuzhiyun 'name' : capture.group(6) 59*4882a593Smuzhiyun }) 60*4882a593Smuzhiyun 61*4882a593Smuzhiyun return res 62*4882a593Smuzhiyun 63*4882a593Smuzhiyunclass HeaderParser(object): 64*4882a593Smuzhiyun """ 65*4882a593Smuzhiyun An object used to parse a file in order to extract the documentation of a 66*4882a593Smuzhiyun list of eBPF helper functions. All the helpers that can be retrieved are 67*4882a593Smuzhiyun stored as Helper object, in the self.helpers() array. 68*4882a593Smuzhiyun @filename: name of file to parse, usually include/uapi/linux/bpf.h in the 69*4882a593Smuzhiyun kernel tree 70*4882a593Smuzhiyun """ 71*4882a593Smuzhiyun def __init__(self, filename): 72*4882a593Smuzhiyun self.reader = open(filename, 'r') 73*4882a593Smuzhiyun self.line = '' 74*4882a593Smuzhiyun self.helpers = [] 75*4882a593Smuzhiyun 76*4882a593Smuzhiyun def parse_helper(self): 77*4882a593Smuzhiyun proto = self.parse_proto() 78*4882a593Smuzhiyun desc = self.parse_desc() 79*4882a593Smuzhiyun ret = self.parse_ret() 80*4882a593Smuzhiyun return Helper(proto=proto, desc=desc, ret=ret) 81*4882a593Smuzhiyun 82*4882a593Smuzhiyun def parse_proto(self): 83*4882a593Smuzhiyun # Argument can be of shape: 84*4882a593Smuzhiyun # - "void" 85*4882a593Smuzhiyun # - "type name" 86*4882a593Smuzhiyun # - "type *name" 87*4882a593Smuzhiyun # - Same as above, with "const" and/or "struct" in front of type 88*4882a593Smuzhiyun # - "..." (undefined number of arguments, for bpf_trace_printk()) 89*4882a593Smuzhiyun # There is at least one term ("void"), and at most five arguments. 90*4882a593Smuzhiyun p = re.compile(' \* ?((.+) \**\w+\((((const )?(struct )?(\w+|\.\.\.)( \**\w+)?)(, )?){1,5}\))$') 91*4882a593Smuzhiyun capture = p.match(self.line) 92*4882a593Smuzhiyun if not capture: 93*4882a593Smuzhiyun raise NoHelperFound 94*4882a593Smuzhiyun self.line = self.reader.readline() 95*4882a593Smuzhiyun return capture.group(1) 96*4882a593Smuzhiyun 97*4882a593Smuzhiyun def parse_desc(self): 98*4882a593Smuzhiyun p = re.compile(' \* ?(?:\t| {5,8})Description$') 99*4882a593Smuzhiyun capture = p.match(self.line) 100*4882a593Smuzhiyun if not capture: 101*4882a593Smuzhiyun # Helper can have empty description and we might be parsing another 102*4882a593Smuzhiyun # attribute: return but do not consume. 103*4882a593Smuzhiyun return '' 104*4882a593Smuzhiyun # Description can be several lines, some of them possibly empty, and it 105*4882a593Smuzhiyun # stops when another subsection title is met. 106*4882a593Smuzhiyun desc = '' 107*4882a593Smuzhiyun while True: 108*4882a593Smuzhiyun self.line = self.reader.readline() 109*4882a593Smuzhiyun if self.line == ' *\n': 110*4882a593Smuzhiyun desc += '\n' 111*4882a593Smuzhiyun else: 112*4882a593Smuzhiyun p = re.compile(' \* ?(?:\t| {5,8})(?:\t| {8})(.*)') 113*4882a593Smuzhiyun capture = p.match(self.line) 114*4882a593Smuzhiyun if capture: 115*4882a593Smuzhiyun desc += capture.group(1) + '\n' 116*4882a593Smuzhiyun else: 117*4882a593Smuzhiyun break 118*4882a593Smuzhiyun return desc 119*4882a593Smuzhiyun 120*4882a593Smuzhiyun def parse_ret(self): 121*4882a593Smuzhiyun p = re.compile(' \* ?(?:\t| {5,8})Return$') 122*4882a593Smuzhiyun capture = p.match(self.line) 123*4882a593Smuzhiyun if not capture: 124*4882a593Smuzhiyun # Helper can have empty retval and we might be parsing another 125*4882a593Smuzhiyun # attribute: return but do not consume. 126*4882a593Smuzhiyun return '' 127*4882a593Smuzhiyun # Return value description can be several lines, some of them possibly 128*4882a593Smuzhiyun # empty, and it stops when another subsection title is met. 129*4882a593Smuzhiyun ret = '' 130*4882a593Smuzhiyun while True: 131*4882a593Smuzhiyun self.line = self.reader.readline() 132*4882a593Smuzhiyun if self.line == ' *\n': 133*4882a593Smuzhiyun ret += '\n' 134*4882a593Smuzhiyun else: 135*4882a593Smuzhiyun p = re.compile(' \* ?(?:\t| {5,8})(?:\t| {8})(.*)') 136*4882a593Smuzhiyun capture = p.match(self.line) 137*4882a593Smuzhiyun if capture: 138*4882a593Smuzhiyun ret += capture.group(1) + '\n' 139*4882a593Smuzhiyun else: 140*4882a593Smuzhiyun break 141*4882a593Smuzhiyun return ret 142*4882a593Smuzhiyun 143*4882a593Smuzhiyun def run(self): 144*4882a593Smuzhiyun # Advance to start of helper function descriptions. 145*4882a593Smuzhiyun offset = self.reader.read().find('* Start of BPF helper function descriptions:') 146*4882a593Smuzhiyun if offset == -1: 147*4882a593Smuzhiyun raise Exception('Could not find start of eBPF helper descriptions list') 148*4882a593Smuzhiyun self.reader.seek(offset) 149*4882a593Smuzhiyun self.reader.readline() 150*4882a593Smuzhiyun self.reader.readline() 151*4882a593Smuzhiyun self.line = self.reader.readline() 152*4882a593Smuzhiyun 153*4882a593Smuzhiyun while True: 154*4882a593Smuzhiyun try: 155*4882a593Smuzhiyun helper = self.parse_helper() 156*4882a593Smuzhiyun self.helpers.append(helper) 157*4882a593Smuzhiyun except NoHelperFound: 158*4882a593Smuzhiyun break 159*4882a593Smuzhiyun 160*4882a593Smuzhiyun self.reader.close() 161*4882a593Smuzhiyun 162*4882a593Smuzhiyun############################################################################### 163*4882a593Smuzhiyun 164*4882a593Smuzhiyunclass Printer(object): 165*4882a593Smuzhiyun """ 166*4882a593Smuzhiyun A generic class for printers. Printers should be created with an array of 167*4882a593Smuzhiyun Helper objects, and implement a way to print them in the desired fashion. 168*4882a593Smuzhiyun @helpers: array of Helper objects to print to standard output 169*4882a593Smuzhiyun """ 170*4882a593Smuzhiyun def __init__(self, helpers): 171*4882a593Smuzhiyun self.helpers = helpers 172*4882a593Smuzhiyun 173*4882a593Smuzhiyun def print_header(self): 174*4882a593Smuzhiyun pass 175*4882a593Smuzhiyun 176*4882a593Smuzhiyun def print_footer(self): 177*4882a593Smuzhiyun pass 178*4882a593Smuzhiyun 179*4882a593Smuzhiyun def print_one(self, helper): 180*4882a593Smuzhiyun pass 181*4882a593Smuzhiyun 182*4882a593Smuzhiyun def print_all(self): 183*4882a593Smuzhiyun self.print_header() 184*4882a593Smuzhiyun for helper in self.helpers: 185*4882a593Smuzhiyun self.print_one(helper) 186*4882a593Smuzhiyun self.print_footer() 187*4882a593Smuzhiyun 188*4882a593Smuzhiyunclass PrinterRST(Printer): 189*4882a593Smuzhiyun """ 190*4882a593Smuzhiyun A printer for dumping collected information about helpers as a ReStructured 191*4882a593Smuzhiyun Text page compatible with the rst2man program, which can be used to 192*4882a593Smuzhiyun generate a manual page for the helpers. 193*4882a593Smuzhiyun @helpers: array of Helper objects to print to standard output 194*4882a593Smuzhiyun """ 195*4882a593Smuzhiyun def print_header(self): 196*4882a593Smuzhiyun header = '''\ 197*4882a593Smuzhiyun.. Copyright (C) All BPF authors and contributors from 2014 to present. 198*4882a593Smuzhiyun.. See git log include/uapi/linux/bpf.h in kernel tree for details. 199*4882a593Smuzhiyun.. 200*4882a593Smuzhiyun.. %%%LICENSE_START(VERBATIM) 201*4882a593Smuzhiyun.. Permission is granted to make and distribute verbatim copies of this 202*4882a593Smuzhiyun.. manual provided the copyright notice and this permission notice are 203*4882a593Smuzhiyun.. preserved on all copies. 204*4882a593Smuzhiyun.. 205*4882a593Smuzhiyun.. Permission is granted to copy and distribute modified versions of this 206*4882a593Smuzhiyun.. manual under the conditions for verbatim copying, provided that the 207*4882a593Smuzhiyun.. entire resulting derived work is distributed under the terms of a 208*4882a593Smuzhiyun.. permission notice identical to this one. 209*4882a593Smuzhiyun.. 210*4882a593Smuzhiyun.. Since the Linux kernel and libraries are constantly changing, this 211*4882a593Smuzhiyun.. manual page may be incorrect or out-of-date. The author(s) assume no 212*4882a593Smuzhiyun.. responsibility for errors or omissions, or for damages resulting from 213*4882a593Smuzhiyun.. the use of the information contained herein. The author(s) may not 214*4882a593Smuzhiyun.. have taken the same level of care in the production of this manual, 215*4882a593Smuzhiyun.. which is licensed free of charge, as they might when working 216*4882a593Smuzhiyun.. professionally. 217*4882a593Smuzhiyun.. 218*4882a593Smuzhiyun.. Formatted or processed versions of this manual, if unaccompanied by 219*4882a593Smuzhiyun.. the source, must acknowledge the copyright and authors of this work. 220*4882a593Smuzhiyun.. %%%LICENSE_END 221*4882a593Smuzhiyun.. 222*4882a593Smuzhiyun.. Please do not edit this file. It was generated from the documentation 223*4882a593Smuzhiyun.. located in file include/uapi/linux/bpf.h of the Linux kernel sources 224*4882a593Smuzhiyun.. (helpers description), and from scripts/bpf_helpers_doc.py in the same 225*4882a593Smuzhiyun.. repository (header and footer). 226*4882a593Smuzhiyun 227*4882a593Smuzhiyun=========== 228*4882a593SmuzhiyunBPF-HELPERS 229*4882a593Smuzhiyun=========== 230*4882a593Smuzhiyun------------------------------------------------------------------------------- 231*4882a593Smuzhiyunlist of eBPF helper functions 232*4882a593Smuzhiyun------------------------------------------------------------------------------- 233*4882a593Smuzhiyun 234*4882a593Smuzhiyun:Manual section: 7 235*4882a593Smuzhiyun 236*4882a593SmuzhiyunDESCRIPTION 237*4882a593Smuzhiyun=========== 238*4882a593Smuzhiyun 239*4882a593SmuzhiyunThe extended Berkeley Packet Filter (eBPF) subsystem consists in programs 240*4882a593Smuzhiyunwritten in a pseudo-assembly language, then attached to one of the several 241*4882a593Smuzhiyunkernel hooks and run in reaction of specific events. This framework differs 242*4882a593Smuzhiyunfrom the older, "classic" BPF (or "cBPF") in several aspects, one of them being 243*4882a593Smuzhiyunthe ability to call special functions (or "helpers") from within a program. 244*4882a593SmuzhiyunThese functions are restricted to a white-list of helpers defined in the 245*4882a593Smuzhiyunkernel. 246*4882a593Smuzhiyun 247*4882a593SmuzhiyunThese helpers are used by eBPF programs to interact with the system, or with 248*4882a593Smuzhiyunthe context in which they work. For instance, they can be used to print 249*4882a593Smuzhiyundebugging messages, to get the time since the system was booted, to interact 250*4882a593Smuzhiyunwith eBPF maps, or to manipulate network packets. Since there are several eBPF 251*4882a593Smuzhiyunprogram types, and that they do not run in the same context, each program type 252*4882a593Smuzhiyuncan only call a subset of those helpers. 253*4882a593Smuzhiyun 254*4882a593SmuzhiyunDue to eBPF conventions, a helper can not have more than five arguments. 255*4882a593Smuzhiyun 256*4882a593SmuzhiyunInternally, eBPF programs call directly into the compiled helper functions 257*4882a593Smuzhiyunwithout requiring any foreign-function interface. As a result, calling helpers 258*4882a593Smuzhiyunintroduces no overhead, thus offering excellent performance. 259*4882a593Smuzhiyun 260*4882a593SmuzhiyunThis document is an attempt to list and document the helpers available to eBPF 261*4882a593Smuzhiyundevelopers. They are sorted by chronological order (the oldest helpers in the 262*4882a593Smuzhiyunkernel at the top). 263*4882a593Smuzhiyun 264*4882a593SmuzhiyunHELPERS 265*4882a593Smuzhiyun======= 266*4882a593Smuzhiyun''' 267*4882a593Smuzhiyun print(header) 268*4882a593Smuzhiyun 269*4882a593Smuzhiyun def print_footer(self): 270*4882a593Smuzhiyun footer = ''' 271*4882a593SmuzhiyunEXAMPLES 272*4882a593Smuzhiyun======== 273*4882a593Smuzhiyun 274*4882a593SmuzhiyunExample usage for most of the eBPF helpers listed in this manual page are 275*4882a593Smuzhiyunavailable within the Linux kernel sources, at the following locations: 276*4882a593Smuzhiyun 277*4882a593Smuzhiyun* *samples/bpf/* 278*4882a593Smuzhiyun* *tools/testing/selftests/bpf/* 279*4882a593Smuzhiyun 280*4882a593SmuzhiyunLICENSE 281*4882a593Smuzhiyun======= 282*4882a593Smuzhiyun 283*4882a593SmuzhiyuneBPF programs can have an associated license, passed along with the bytecode 284*4882a593Smuzhiyuninstructions to the kernel when the programs are loaded. The format for that 285*4882a593Smuzhiyunstring is identical to the one in use for kernel modules (Dual licenses, such 286*4882a593Smuzhiyunas "Dual BSD/GPL", may be used). Some helper functions are only accessible to 287*4882a593Smuzhiyunprograms that are compatible with the GNU Privacy License (GPL). 288*4882a593Smuzhiyun 289*4882a593SmuzhiyunIn order to use such helpers, the eBPF program must be loaded with the correct 290*4882a593Smuzhiyunlicense string passed (via **attr**) to the **bpf**\ () system call, and this 291*4882a593Smuzhiyungenerally translates into the C source code of the program containing a line 292*4882a593Smuzhiyunsimilar to the following: 293*4882a593Smuzhiyun 294*4882a593Smuzhiyun:: 295*4882a593Smuzhiyun 296*4882a593Smuzhiyun char ____license[] __attribute__((section("license"), used)) = "GPL"; 297*4882a593Smuzhiyun 298*4882a593SmuzhiyunIMPLEMENTATION 299*4882a593Smuzhiyun============== 300*4882a593Smuzhiyun 301*4882a593SmuzhiyunThis manual page is an effort to document the existing eBPF helper functions. 302*4882a593SmuzhiyunBut as of this writing, the BPF sub-system is under heavy development. New eBPF 303*4882a593Smuzhiyunprogram or map types are added, along with new helper functions. Some helpers 304*4882a593Smuzhiyunare occasionally made available for additional program types. So in spite of 305*4882a593Smuzhiyunthe efforts of the community, this page might not be up-to-date. If you want to 306*4882a593Smuzhiyuncheck by yourself what helper functions exist in your kernel, or what types of 307*4882a593Smuzhiyunprograms they can support, here are some files among the kernel tree that you 308*4882a593Smuzhiyunmay be interested in: 309*4882a593Smuzhiyun 310*4882a593Smuzhiyun* *include/uapi/linux/bpf.h* is the main BPF header. It contains the full list 311*4882a593Smuzhiyun of all helper functions, as well as many other BPF definitions including most 312*4882a593Smuzhiyun of the flags, structs or constants used by the helpers. 313*4882a593Smuzhiyun* *net/core/filter.c* contains the definition of most network-related helper 314*4882a593Smuzhiyun functions, and the list of program types from which they can be used. 315*4882a593Smuzhiyun* *kernel/trace/bpf_trace.c* is the equivalent for most tracing program-related 316*4882a593Smuzhiyun helpers. 317*4882a593Smuzhiyun* *kernel/bpf/verifier.c* contains the functions used to check that valid types 318*4882a593Smuzhiyun of eBPF maps are used with a given helper function. 319*4882a593Smuzhiyun* *kernel/bpf/* directory contains other files in which additional helpers are 320*4882a593Smuzhiyun defined (for cgroups, sockmaps, etc.). 321*4882a593Smuzhiyun* The bpftool utility can be used to probe the availability of helper functions 322*4882a593Smuzhiyun on the system (as well as supported program and map types, and a number of 323*4882a593Smuzhiyun other parameters). To do so, run **bpftool feature probe** (see 324*4882a593Smuzhiyun **bpftool-feature**\ (8) for details). Add the **unprivileged** keyword to 325*4882a593Smuzhiyun list features available to unprivileged users. 326*4882a593Smuzhiyun 327*4882a593SmuzhiyunCompatibility between helper functions and program types can generally be found 328*4882a593Smuzhiyunin the files where helper functions are defined. Look for the **struct 329*4882a593Smuzhiyunbpf_func_proto** objects and for functions returning them: these functions 330*4882a593Smuzhiyuncontain a list of helpers that a given program type can call. Note that the 331*4882a593Smuzhiyun**default:** label of the **switch ... case** used to filter helpers can call 332*4882a593Smuzhiyunother functions, themselves allowing access to additional helpers. The 333*4882a593Smuzhiyunrequirement for GPL license is also in those **struct bpf_func_proto**. 334*4882a593Smuzhiyun 335*4882a593SmuzhiyunCompatibility between helper functions and map types can be found in the 336*4882a593Smuzhiyun**check_map_func_compatibility**\ () function in file *kernel/bpf/verifier.c*. 337*4882a593Smuzhiyun 338*4882a593SmuzhiyunHelper functions that invalidate the checks on **data** and **data_end** 339*4882a593Smuzhiyunpointers for network processing are listed in function 340*4882a593Smuzhiyun**bpf_helper_changes_pkt_data**\ () in file *net/core/filter.c*. 341*4882a593Smuzhiyun 342*4882a593SmuzhiyunSEE ALSO 343*4882a593Smuzhiyun======== 344*4882a593Smuzhiyun 345*4882a593Smuzhiyun**bpf**\ (2), 346*4882a593Smuzhiyun**bpftool**\ (8), 347*4882a593Smuzhiyun**cgroups**\ (7), 348*4882a593Smuzhiyun**ip**\ (8), 349*4882a593Smuzhiyun**perf_event_open**\ (2), 350*4882a593Smuzhiyun**sendmsg**\ (2), 351*4882a593Smuzhiyun**socket**\ (7), 352*4882a593Smuzhiyun**tc-bpf**\ (8)''' 353*4882a593Smuzhiyun print(footer) 354*4882a593Smuzhiyun 355*4882a593Smuzhiyun def print_proto(self, helper): 356*4882a593Smuzhiyun """ 357*4882a593Smuzhiyun Format function protocol with bold and italics markers. This makes RST 358*4882a593Smuzhiyun file less readable, but gives nice results in the manual page. 359*4882a593Smuzhiyun """ 360*4882a593Smuzhiyun proto = helper.proto_break_down() 361*4882a593Smuzhiyun 362*4882a593Smuzhiyun print('**%s %s%s(' % (proto['ret_type'], 363*4882a593Smuzhiyun proto['ret_star'].replace('*', '\\*'), 364*4882a593Smuzhiyun proto['name']), 365*4882a593Smuzhiyun end='') 366*4882a593Smuzhiyun 367*4882a593Smuzhiyun comma = '' 368*4882a593Smuzhiyun for a in proto['args']: 369*4882a593Smuzhiyun one_arg = '{}{}'.format(comma, a['type']) 370*4882a593Smuzhiyun if a['name']: 371*4882a593Smuzhiyun if a['star']: 372*4882a593Smuzhiyun one_arg += ' {}**\ '.format(a['star'].replace('*', '\\*')) 373*4882a593Smuzhiyun else: 374*4882a593Smuzhiyun one_arg += '** ' 375*4882a593Smuzhiyun one_arg += '*{}*\\ **'.format(a['name']) 376*4882a593Smuzhiyun comma = ', ' 377*4882a593Smuzhiyun print(one_arg, end='') 378*4882a593Smuzhiyun 379*4882a593Smuzhiyun print(')**') 380*4882a593Smuzhiyun 381*4882a593Smuzhiyun def print_one(self, helper): 382*4882a593Smuzhiyun self.print_proto(helper) 383*4882a593Smuzhiyun 384*4882a593Smuzhiyun if (helper.desc): 385*4882a593Smuzhiyun print('\tDescription') 386*4882a593Smuzhiyun # Do not strip all newline characters: formatted code at the end of 387*4882a593Smuzhiyun # a section must be followed by a blank line. 388*4882a593Smuzhiyun for line in re.sub('\n$', '', helper.desc, count=1).split('\n'): 389*4882a593Smuzhiyun print('{}{}'.format('\t\t' if line else '', line)) 390*4882a593Smuzhiyun 391*4882a593Smuzhiyun if (helper.ret): 392*4882a593Smuzhiyun print('\tReturn') 393*4882a593Smuzhiyun for line in helper.ret.rstrip().split('\n'): 394*4882a593Smuzhiyun print('{}{}'.format('\t\t' if line else '', line)) 395*4882a593Smuzhiyun 396*4882a593Smuzhiyun print('') 397*4882a593Smuzhiyun 398*4882a593Smuzhiyunclass PrinterHelpers(Printer): 399*4882a593Smuzhiyun """ 400*4882a593Smuzhiyun A printer for dumping collected information about helpers as C header to 401*4882a593Smuzhiyun be included from BPF program. 402*4882a593Smuzhiyun @helpers: array of Helper objects to print to standard output 403*4882a593Smuzhiyun """ 404*4882a593Smuzhiyun 405*4882a593Smuzhiyun type_fwds = [ 406*4882a593Smuzhiyun 'struct bpf_fib_lookup', 407*4882a593Smuzhiyun 'struct bpf_sk_lookup', 408*4882a593Smuzhiyun 'struct bpf_perf_event_data', 409*4882a593Smuzhiyun 'struct bpf_perf_event_value', 410*4882a593Smuzhiyun 'struct bpf_pidns_info', 411*4882a593Smuzhiyun 'struct bpf_redir_neigh', 412*4882a593Smuzhiyun 'struct bpf_sock', 413*4882a593Smuzhiyun 'struct bpf_sock_addr', 414*4882a593Smuzhiyun 'struct bpf_sock_ops', 415*4882a593Smuzhiyun 'struct bpf_sock_tuple', 416*4882a593Smuzhiyun 'struct bpf_spin_lock', 417*4882a593Smuzhiyun 'struct bpf_sysctl', 418*4882a593Smuzhiyun 'struct bpf_tcp_sock', 419*4882a593Smuzhiyun 'struct bpf_tunnel_key', 420*4882a593Smuzhiyun 'struct bpf_xfrm_state', 421*4882a593Smuzhiyun 'struct pt_regs', 422*4882a593Smuzhiyun 'struct sk_reuseport_md', 423*4882a593Smuzhiyun 'struct sockaddr', 424*4882a593Smuzhiyun 'struct tcphdr', 425*4882a593Smuzhiyun 'struct seq_file', 426*4882a593Smuzhiyun 'struct tcp6_sock', 427*4882a593Smuzhiyun 'struct tcp_sock', 428*4882a593Smuzhiyun 'struct tcp_timewait_sock', 429*4882a593Smuzhiyun 'struct tcp_request_sock', 430*4882a593Smuzhiyun 'struct udp6_sock', 431*4882a593Smuzhiyun 'struct task_struct', 432*4882a593Smuzhiyun 433*4882a593Smuzhiyun 'struct __sk_buff', 434*4882a593Smuzhiyun 'struct sk_msg_md', 435*4882a593Smuzhiyun 'struct xdp_md', 436*4882a593Smuzhiyun 'struct path', 437*4882a593Smuzhiyun 'struct btf_ptr', 438*4882a593Smuzhiyun ] 439*4882a593Smuzhiyun known_types = { 440*4882a593Smuzhiyun '...', 441*4882a593Smuzhiyun 'void', 442*4882a593Smuzhiyun 'const void', 443*4882a593Smuzhiyun 'char', 444*4882a593Smuzhiyun 'const char', 445*4882a593Smuzhiyun 'int', 446*4882a593Smuzhiyun 'long', 447*4882a593Smuzhiyun 'unsigned long', 448*4882a593Smuzhiyun 449*4882a593Smuzhiyun '__be16', 450*4882a593Smuzhiyun '__be32', 451*4882a593Smuzhiyun '__wsum', 452*4882a593Smuzhiyun 453*4882a593Smuzhiyun 'struct bpf_fib_lookup', 454*4882a593Smuzhiyun 'struct bpf_perf_event_data', 455*4882a593Smuzhiyun 'struct bpf_perf_event_value', 456*4882a593Smuzhiyun 'struct bpf_pidns_info', 457*4882a593Smuzhiyun 'struct bpf_redir_neigh', 458*4882a593Smuzhiyun 'struct bpf_sk_lookup', 459*4882a593Smuzhiyun 'struct bpf_sock', 460*4882a593Smuzhiyun 'struct bpf_sock_addr', 461*4882a593Smuzhiyun 'struct bpf_sock_ops', 462*4882a593Smuzhiyun 'struct bpf_sock_tuple', 463*4882a593Smuzhiyun 'struct bpf_spin_lock', 464*4882a593Smuzhiyun 'struct bpf_sysctl', 465*4882a593Smuzhiyun 'struct bpf_tcp_sock', 466*4882a593Smuzhiyun 'struct bpf_tunnel_key', 467*4882a593Smuzhiyun 'struct bpf_xfrm_state', 468*4882a593Smuzhiyun 'struct pt_regs', 469*4882a593Smuzhiyun 'struct sk_reuseport_md', 470*4882a593Smuzhiyun 'struct sockaddr', 471*4882a593Smuzhiyun 'struct tcphdr', 472*4882a593Smuzhiyun 'struct seq_file', 473*4882a593Smuzhiyun 'struct tcp6_sock', 474*4882a593Smuzhiyun 'struct tcp_sock', 475*4882a593Smuzhiyun 'struct tcp_timewait_sock', 476*4882a593Smuzhiyun 'struct tcp_request_sock', 477*4882a593Smuzhiyun 'struct udp6_sock', 478*4882a593Smuzhiyun 'struct task_struct', 479*4882a593Smuzhiyun 'struct path', 480*4882a593Smuzhiyun 'struct btf_ptr', 481*4882a593Smuzhiyun } 482*4882a593Smuzhiyun mapped_types = { 483*4882a593Smuzhiyun 'u8': '__u8', 484*4882a593Smuzhiyun 'u16': '__u16', 485*4882a593Smuzhiyun 'u32': '__u32', 486*4882a593Smuzhiyun 'u64': '__u64', 487*4882a593Smuzhiyun 's8': '__s8', 488*4882a593Smuzhiyun 's16': '__s16', 489*4882a593Smuzhiyun 's32': '__s32', 490*4882a593Smuzhiyun 's64': '__s64', 491*4882a593Smuzhiyun 'size_t': 'unsigned long', 492*4882a593Smuzhiyun 'struct bpf_map': 'void', 493*4882a593Smuzhiyun 'struct sk_buff': 'struct __sk_buff', 494*4882a593Smuzhiyun 'const struct sk_buff': 'const struct __sk_buff', 495*4882a593Smuzhiyun 'struct sk_msg_buff': 'struct sk_msg_md', 496*4882a593Smuzhiyun 'struct xdp_buff': 'struct xdp_md', 497*4882a593Smuzhiyun } 498*4882a593Smuzhiyun # Helpers overloaded for different context types. 499*4882a593Smuzhiyun overloaded_helpers = [ 500*4882a593Smuzhiyun 'bpf_get_socket_cookie', 501*4882a593Smuzhiyun 'bpf_sk_assign', 502*4882a593Smuzhiyun ] 503*4882a593Smuzhiyun 504*4882a593Smuzhiyun def print_header(self): 505*4882a593Smuzhiyun header = '''\ 506*4882a593Smuzhiyun/* This is auto-generated file. See bpf_helpers_doc.py for details. */ 507*4882a593Smuzhiyun 508*4882a593Smuzhiyun/* Forward declarations of BPF structs */''' 509*4882a593Smuzhiyun 510*4882a593Smuzhiyun print(header) 511*4882a593Smuzhiyun for fwd in self.type_fwds: 512*4882a593Smuzhiyun print('%s;' % fwd) 513*4882a593Smuzhiyun print('') 514*4882a593Smuzhiyun 515*4882a593Smuzhiyun def print_footer(self): 516*4882a593Smuzhiyun footer = '' 517*4882a593Smuzhiyun print(footer) 518*4882a593Smuzhiyun 519*4882a593Smuzhiyun def map_type(self, t): 520*4882a593Smuzhiyun if t in self.known_types: 521*4882a593Smuzhiyun return t 522*4882a593Smuzhiyun if t in self.mapped_types: 523*4882a593Smuzhiyun return self.mapped_types[t] 524*4882a593Smuzhiyun print("Unrecognized type '%s', please add it to known types!" % t, 525*4882a593Smuzhiyun file=sys.stderr) 526*4882a593Smuzhiyun sys.exit(1) 527*4882a593Smuzhiyun 528*4882a593Smuzhiyun seen_helpers = set() 529*4882a593Smuzhiyun 530*4882a593Smuzhiyun def print_one(self, helper): 531*4882a593Smuzhiyun proto = helper.proto_break_down() 532*4882a593Smuzhiyun 533*4882a593Smuzhiyun if proto['name'] in self.seen_helpers: 534*4882a593Smuzhiyun return 535*4882a593Smuzhiyun self.seen_helpers.add(proto['name']) 536*4882a593Smuzhiyun 537*4882a593Smuzhiyun print('/*') 538*4882a593Smuzhiyun print(" * %s" % proto['name']) 539*4882a593Smuzhiyun print(" *") 540*4882a593Smuzhiyun if (helper.desc): 541*4882a593Smuzhiyun # Do not strip all newline characters: formatted code at the end of 542*4882a593Smuzhiyun # a section must be followed by a blank line. 543*4882a593Smuzhiyun for line in re.sub('\n$', '', helper.desc, count=1).split('\n'): 544*4882a593Smuzhiyun print(' *{}{}'.format(' \t' if line else '', line)) 545*4882a593Smuzhiyun 546*4882a593Smuzhiyun if (helper.ret): 547*4882a593Smuzhiyun print(' *') 548*4882a593Smuzhiyun print(' * Returns') 549*4882a593Smuzhiyun for line in helper.ret.rstrip().split('\n'): 550*4882a593Smuzhiyun print(' *{}{}'.format(' \t' if line else '', line)) 551*4882a593Smuzhiyun 552*4882a593Smuzhiyun print(' */') 553*4882a593Smuzhiyun print('static %s %s(*%s)(' % (self.map_type(proto['ret_type']), 554*4882a593Smuzhiyun proto['ret_star'], proto['name']), end='') 555*4882a593Smuzhiyun comma = '' 556*4882a593Smuzhiyun for i, a in enumerate(proto['args']): 557*4882a593Smuzhiyun t = a['type'] 558*4882a593Smuzhiyun n = a['name'] 559*4882a593Smuzhiyun if proto['name'] in self.overloaded_helpers and i == 0: 560*4882a593Smuzhiyun t = 'void' 561*4882a593Smuzhiyun n = 'ctx' 562*4882a593Smuzhiyun one_arg = '{}{}'.format(comma, self.map_type(t)) 563*4882a593Smuzhiyun if n: 564*4882a593Smuzhiyun if a['star']: 565*4882a593Smuzhiyun one_arg += ' {}'.format(a['star']) 566*4882a593Smuzhiyun else: 567*4882a593Smuzhiyun one_arg += ' ' 568*4882a593Smuzhiyun one_arg += '{}'.format(n) 569*4882a593Smuzhiyun comma = ', ' 570*4882a593Smuzhiyun print(one_arg, end='') 571*4882a593Smuzhiyun 572*4882a593Smuzhiyun print(') = (void *) %d;' % len(self.seen_helpers)) 573*4882a593Smuzhiyun print('') 574*4882a593Smuzhiyun 575*4882a593Smuzhiyun############################################################################### 576*4882a593Smuzhiyun 577*4882a593Smuzhiyun# If script is launched from scripts/ from kernel tree and can access 578*4882a593Smuzhiyun# ../include/uapi/linux/bpf.h, use it as a default name for the file to parse, 579*4882a593Smuzhiyun# otherwise the --filename argument will be required from the command line. 580*4882a593Smuzhiyunscript = os.path.abspath(sys.argv[0]) 581*4882a593SmuzhiyunlinuxRoot = os.path.dirname(os.path.dirname(script)) 582*4882a593Smuzhiyunbpfh = os.path.join(linuxRoot, 'include/uapi/linux/bpf.h') 583*4882a593Smuzhiyun 584*4882a593SmuzhiyunargParser = argparse.ArgumentParser(description=""" 585*4882a593SmuzhiyunParse eBPF header file and generate documentation for eBPF helper functions. 586*4882a593SmuzhiyunThe RST-formatted output produced can be turned into a manual page with the 587*4882a593Smuzhiyunrst2man utility. 588*4882a593Smuzhiyun""") 589*4882a593SmuzhiyunargParser.add_argument('--header', action='store_true', 590*4882a593Smuzhiyun help='generate C header file') 591*4882a593Smuzhiyunif (os.path.isfile(bpfh)): 592*4882a593Smuzhiyun argParser.add_argument('--filename', help='path to include/uapi/linux/bpf.h', 593*4882a593Smuzhiyun default=bpfh) 594*4882a593Smuzhiyunelse: 595*4882a593Smuzhiyun argParser.add_argument('--filename', help='path to include/uapi/linux/bpf.h') 596*4882a593Smuzhiyunargs = argParser.parse_args() 597*4882a593Smuzhiyun 598*4882a593Smuzhiyun# Parse file. 599*4882a593SmuzhiyunheaderParser = HeaderParser(args.filename) 600*4882a593SmuzhiyunheaderParser.run() 601*4882a593Smuzhiyun 602*4882a593Smuzhiyun# Print formatted output to standard output. 603*4882a593Smuzhiyunif args.header: 604*4882a593Smuzhiyun printer = PrinterHelpers(headerParser.helpers) 605*4882a593Smuzhiyunelse: 606*4882a593Smuzhiyun printer = PrinterRST(headerParser.helpers) 607*4882a593Smuzhiyunprinter.print_all() 608