forked from mirrors/linux
		
	scripts/bpf: teach bpf_helpers_doc.py to dump BPF helper definitions
Enhance scripts/bpf_helpers_doc.py to emit C header with BPF helper definitions (to be included from libbpf's bpf_helpers.h). Signed-off-by: Andrii Nakryiko <andriin@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
		
							parent
							
								
									5f0e541278
								
							
						
					
					
						commit
						7a387bed47
					
				
					 1 changed files with 154 additions and 1 deletions
				
			
		| 
						 | 
					@ -391,6 +391,154 @@ SEE ALSO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        print('')
 | 
					        print('')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PrinterHelpers(Printer):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    A printer for dumping collected information about helpers as C header to
 | 
				
			||||||
 | 
					    be included from BPF program.
 | 
				
			||||||
 | 
					    @helpers: array of Helper objects to print to standard output
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    type_fwds = [
 | 
				
			||||||
 | 
					            'struct bpf_fib_lookup',
 | 
				
			||||||
 | 
					            'struct bpf_perf_event_data',
 | 
				
			||||||
 | 
					            'struct bpf_perf_event_value',
 | 
				
			||||||
 | 
					            'struct bpf_sock',
 | 
				
			||||||
 | 
					            'struct bpf_sock_addr',
 | 
				
			||||||
 | 
					            'struct bpf_sock_ops',
 | 
				
			||||||
 | 
					            'struct bpf_sock_tuple',
 | 
				
			||||||
 | 
					            'struct bpf_spin_lock',
 | 
				
			||||||
 | 
					            'struct bpf_sysctl',
 | 
				
			||||||
 | 
					            'struct bpf_tcp_sock',
 | 
				
			||||||
 | 
					            'struct bpf_tunnel_key',
 | 
				
			||||||
 | 
					            'struct bpf_xfrm_state',
 | 
				
			||||||
 | 
					            'struct pt_regs',
 | 
				
			||||||
 | 
					            'struct sk_reuseport_md',
 | 
				
			||||||
 | 
					            'struct sockaddr',
 | 
				
			||||||
 | 
					            'struct tcphdr',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            'struct __sk_buff',
 | 
				
			||||||
 | 
					            'struct sk_msg_md',
 | 
				
			||||||
 | 
					            'struct xpd_md',
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					    known_types = {
 | 
				
			||||||
 | 
					            '...',
 | 
				
			||||||
 | 
					            'void',
 | 
				
			||||||
 | 
					            'const void',
 | 
				
			||||||
 | 
					            'char',
 | 
				
			||||||
 | 
					            'const char',
 | 
				
			||||||
 | 
					            'int',
 | 
				
			||||||
 | 
					            'long',
 | 
				
			||||||
 | 
					            'unsigned long',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            '__be16',
 | 
				
			||||||
 | 
					            '__be32',
 | 
				
			||||||
 | 
					            '__wsum',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            'struct bpf_fib_lookup',
 | 
				
			||||||
 | 
					            'struct bpf_perf_event_data',
 | 
				
			||||||
 | 
					            'struct bpf_perf_event_value',
 | 
				
			||||||
 | 
					            'struct bpf_sock',
 | 
				
			||||||
 | 
					            'struct bpf_sock_addr',
 | 
				
			||||||
 | 
					            'struct bpf_sock_ops',
 | 
				
			||||||
 | 
					            'struct bpf_sock_tuple',
 | 
				
			||||||
 | 
					            'struct bpf_spin_lock',
 | 
				
			||||||
 | 
					            'struct bpf_sysctl',
 | 
				
			||||||
 | 
					            'struct bpf_tcp_sock',
 | 
				
			||||||
 | 
					            'struct bpf_tunnel_key',
 | 
				
			||||||
 | 
					            'struct bpf_xfrm_state',
 | 
				
			||||||
 | 
					            'struct pt_regs',
 | 
				
			||||||
 | 
					            'struct sk_reuseport_md',
 | 
				
			||||||
 | 
					            'struct sockaddr',
 | 
				
			||||||
 | 
					            'struct tcphdr',
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    mapped_types = {
 | 
				
			||||||
 | 
					            'u8': '__u8',
 | 
				
			||||||
 | 
					            'u16': '__u16',
 | 
				
			||||||
 | 
					            'u32': '__u32',
 | 
				
			||||||
 | 
					            'u64': '__u64',
 | 
				
			||||||
 | 
					            's8': '__s8',
 | 
				
			||||||
 | 
					            's16': '__s16',
 | 
				
			||||||
 | 
					            's32': '__s32',
 | 
				
			||||||
 | 
					            's64': '__s64',
 | 
				
			||||||
 | 
					            'size_t': 'unsigned long',
 | 
				
			||||||
 | 
					            'struct bpf_map': 'void',
 | 
				
			||||||
 | 
					            'struct sk_buff': 'struct __sk_buff',
 | 
				
			||||||
 | 
					            'const struct sk_buff': 'const struct __sk_buff',
 | 
				
			||||||
 | 
					            'struct sk_msg_buff': 'struct sk_msg_md',
 | 
				
			||||||
 | 
					            'struct xdp_buff': 'struct xdp_md',
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def print_header(self):
 | 
				
			||||||
 | 
					        header = '''\
 | 
				
			||||||
 | 
					/* This is auto-generated file. See bpf_helpers_doc.py for details. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Forward declarations of BPF structs */'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        print(header)
 | 
				
			||||||
 | 
					        for fwd in self.type_fwds:
 | 
				
			||||||
 | 
					            print('%s;' % fwd)
 | 
				
			||||||
 | 
					        print('')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def print_footer(self):
 | 
				
			||||||
 | 
					        footer = ''
 | 
				
			||||||
 | 
					        print(footer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def map_type(self, t):
 | 
				
			||||||
 | 
					        if t in self.known_types:
 | 
				
			||||||
 | 
					            return t
 | 
				
			||||||
 | 
					        if t in self.mapped_types:
 | 
				
			||||||
 | 
					            return self.mapped_types[t]
 | 
				
			||||||
 | 
					        print("")
 | 
				
			||||||
 | 
					        print("Unrecognized type '%s', please add it to known types!" % t)
 | 
				
			||||||
 | 
					        sys.exit(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    seen_helpers = set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def print_one(self, helper):
 | 
				
			||||||
 | 
					        proto = helper.proto_break_down()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if proto['name'] in self.seen_helpers:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        self.seen_helpers.add(proto['name'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        print('/*')
 | 
				
			||||||
 | 
					        print(" * %s" % proto['name'])
 | 
				
			||||||
 | 
					        print(" *")
 | 
				
			||||||
 | 
					        if (helper.desc):
 | 
				
			||||||
 | 
					            # Do not strip all newline characters: formatted code at the end of
 | 
				
			||||||
 | 
					            # a section must be followed by a blank line.
 | 
				
			||||||
 | 
					            for line in re.sub('\n$', '', helper.desc, count=1).split('\n'):
 | 
				
			||||||
 | 
					                print(' *{}{}'.format(' \t' if line else '', line))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (helper.ret):
 | 
				
			||||||
 | 
					            print(' *')
 | 
				
			||||||
 | 
					            print(' * Returns')
 | 
				
			||||||
 | 
					            for line in helper.ret.rstrip().split('\n'):
 | 
				
			||||||
 | 
					                print(' *{}{}'.format(' \t' if line else '', line))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        print(' */')
 | 
				
			||||||
 | 
					        print('static %s %s(*%s)(' % (self.map_type(proto['ret_type']),
 | 
				
			||||||
 | 
					                                      proto['ret_star'], proto['name']), end='')
 | 
				
			||||||
 | 
					        comma = ''
 | 
				
			||||||
 | 
					        for i, a in enumerate(proto['args']):
 | 
				
			||||||
 | 
					            t = a['type']
 | 
				
			||||||
 | 
					            n = a['name']
 | 
				
			||||||
 | 
					            if proto['name'] == 'bpf_get_socket_cookie' and i == 0:
 | 
				
			||||||
 | 
					                    t = 'void'
 | 
				
			||||||
 | 
					                    n = 'ctx'
 | 
				
			||||||
 | 
					            one_arg = '{}{}'.format(comma, self.map_type(t))
 | 
				
			||||||
 | 
					            if n:
 | 
				
			||||||
 | 
					                if a['star']:
 | 
				
			||||||
 | 
					                    one_arg += ' {}'.format(a['star'])
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    one_arg += ' '
 | 
				
			||||||
 | 
					                one_arg += '{}'.format(n)
 | 
				
			||||||
 | 
					            comma = ', '
 | 
				
			||||||
 | 
					            print(one_arg, end='')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        print(') = (void *) %d;' % len(self.seen_helpers))
 | 
				
			||||||
 | 
					        print('')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
###############################################################################
 | 
					###############################################################################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# If script is launched from scripts/ from kernel tree and can access
 | 
					# If script is launched from scripts/ from kernel tree and can access
 | 
				
			||||||
| 
						 | 
					@ -405,6 +553,8 @@ Parse eBPF header file and generate documentation for eBPF helper functions.
 | 
				
			||||||
The RST-formatted output produced can be turned into a manual page with the
 | 
					The RST-formatted output produced can be turned into a manual page with the
 | 
				
			||||||
rst2man utility.
 | 
					rst2man utility.
 | 
				
			||||||
""")
 | 
					""")
 | 
				
			||||||
 | 
					argParser.add_argument('--header', action='store_true',
 | 
				
			||||||
 | 
					                       help='generate C header file')
 | 
				
			||||||
if (os.path.isfile(bpfh)):
 | 
					if (os.path.isfile(bpfh)):
 | 
				
			||||||
    argParser.add_argument('--filename', help='path to include/uapi/linux/bpf.h',
 | 
					    argParser.add_argument('--filename', help='path to include/uapi/linux/bpf.h',
 | 
				
			||||||
                           default=bpfh)
 | 
					                           default=bpfh)
 | 
				
			||||||
| 
						 | 
					@ -417,5 +567,8 @@ headerParser = HeaderParser(args.filename)
 | 
				
			||||||
headerParser.run()
 | 
					headerParser.run()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Print formatted output to standard output.
 | 
					# Print formatted output to standard output.
 | 
				
			||||||
 | 
					if args.header:
 | 
				
			||||||
 | 
					    printer = PrinterHelpers(headerParser.helpers)
 | 
				
			||||||
 | 
					else:
 | 
				
			||||||
    printer = PrinterRST(headerParser.helpers)
 | 
					    printer = PrinterRST(headerParser.helpers)
 | 
				
			||||||
printer.print_all()
 | 
					printer.print_all()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue