2017-10-05 06:10:04 +03:00
/*
* Copyright ( C ) 2017 Netronome Systems , Inc .
*
* This software is dual licensed under the GNU General License Version 2 ,
* June 1991 as shown in the file COPYING in the top - level directory of this
* source tree or the BSD 2 - Clause License provided below . You have the
* option to license this software under the complete terms of either license .
*
* The BSD 2 - Clause License :
*
* Redistribution and use in source and binary forms , with or
* without modification , are permitted provided that the following
* conditions are met :
*
* 1. Redistributions of source code must retain the above
* copyright notice , this list of conditions and the following
* disclaimer .
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice , this list of conditions and the following
* disclaimer in the documentation and / or other materials
* provided with the distribution .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND ,
* EXPRESS OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY , FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN
* ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE .
*/
/* Author: Jakub Kicinski <kubakici@wp.pl> */
# include <errno.h>
tools: bpftool: show filenames of pinned objects
Added support to show filenames of pinned objects.
For example:
root@test# ./bpftool prog
3: tracepoint name tracepoint__irq tag f677a7dd722299a3
loaded_at Oct 26/11:39 uid 0
xlated 160B not jited memlock 4096B map_ids 4
pinned /sys/fs/bpf/softirq_prog
4: tracepoint name tracepoint__irq tag ea5dc530d00b92b6
loaded_at Oct 26/11:39 uid 0
xlated 392B not jited memlock 4096B map_ids 4,6
root@test# ./bpftool --json --pretty prog
[{
"id": 3,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "f677a7dd722299a3",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 160,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4
],
"pinned": ["/sys/fs/bpf/softirq_prog"
]
},{
"id": 4,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "ea5dc530d00b92b6",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 392,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4,6
],
"pinned": []
}
]
root@test# ./bpftool map
4: hash name start flags 0x0
key 4B value 16B max_entries 10240 memlock 1003520B
pinned /sys/fs/bpf/softirq_map1
5: hash name iptr flags 0x0
key 4B value 8B max_entries 10240 memlock 921600B
root@test# ./bpftool --json --pretty map
[{
"id": 4,
"type": "hash",
"name": "start",
"flags": 0,
"bytes_key": 4,
"bytes_value": 16,
"max_entries": 10240,
"bytes_memlock": 1003520,
"pinned": ["/sys/fs/bpf/softirq_map1"
]
},{
"id": 5,
"type": "hash",
"name": "iptr",
"flags": 0,
"bytes_key": 4,
"bytes_value": 8,
"max_entries": 10240,
"bytes_memlock": 921600,
"pinned": []
}
]
Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-08 07:55:48 +03:00
# include <fts.h>
2017-10-05 06:10:04 +03:00
# include <libgen.h>
tools: bpftool: show filenames of pinned objects
Added support to show filenames of pinned objects.
For example:
root@test# ./bpftool prog
3: tracepoint name tracepoint__irq tag f677a7dd722299a3
loaded_at Oct 26/11:39 uid 0
xlated 160B not jited memlock 4096B map_ids 4
pinned /sys/fs/bpf/softirq_prog
4: tracepoint name tracepoint__irq tag ea5dc530d00b92b6
loaded_at Oct 26/11:39 uid 0
xlated 392B not jited memlock 4096B map_ids 4,6
root@test# ./bpftool --json --pretty prog
[{
"id": 3,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "f677a7dd722299a3",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 160,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4
],
"pinned": ["/sys/fs/bpf/softirq_prog"
]
},{
"id": 4,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "ea5dc530d00b92b6",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 392,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4,6
],
"pinned": []
}
]
root@test# ./bpftool map
4: hash name start flags 0x0
key 4B value 16B max_entries 10240 memlock 1003520B
pinned /sys/fs/bpf/softirq_map1
5: hash name iptr flags 0x0
key 4B value 8B max_entries 10240 memlock 921600B
root@test# ./bpftool --json --pretty map
[{
"id": 4,
"type": "hash",
"name": "start",
"flags": 0,
"bytes_key": 4,
"bytes_value": 16,
"max_entries": 10240,
"bytes_memlock": 1003520,
"pinned": ["/sys/fs/bpf/softirq_map1"
]
},{
"id": 5,
"type": "hash",
"name": "iptr",
"flags": 0,
"bytes_key": 4,
"bytes_value": 8,
"max_entries": 10240,
"bytes_memlock": 921600,
"pinned": []
}
]
Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-08 07:55:48 +03:00
# include <mntent.h>
2017-10-05 06:10:04 +03:00
# include <stdbool.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <linux/limits.h>
# include <linux/magic.h>
2017-12-28 05:39:10 +03:00
# include <net/if.h>
2017-10-25 06:11:28 +03:00
# include <sys/mount.h>
2017-12-28 05:39:10 +03:00
# include <sys/stat.h>
2017-10-05 06:10:04 +03:00
# include <sys/types.h>
# include <sys/vfs.h>
# include <bpf.h>
# include "main.h"
2017-11-03 23:59:07 +03:00
void p_err ( const char * fmt , . . . )
{
va_list ap ;
va_start ( ap , fmt ) ;
if ( json_output ) {
jsonw_start_object ( json_wtr ) ;
jsonw_name ( json_wtr , " error " ) ;
jsonw_vprintf_enquote ( json_wtr , fmt , ap ) ;
jsonw_end_object ( json_wtr ) ;
} else {
fprintf ( stderr , " Error: " ) ;
vfprintf ( stderr , fmt , ap ) ;
fprintf ( stderr , " \n " ) ;
}
va_end ( ap ) ;
}
void p_info ( const char * fmt , . . . )
{
va_list ap ;
if ( json_output )
return ;
va_start ( ap , fmt ) ;
vfprintf ( stderr , fmt , ap ) ;
fprintf ( stderr , " \n " ) ;
va_end ( ap ) ;
}
2017-10-05 06:10:04 +03:00
static bool is_bpffs ( char * path )
{
struct statfs st_fs ;
if ( statfs ( path , & st_fs ) < 0 )
return false ;
return ( unsigned long ) st_fs . f_type = = BPF_FS_MAGIC ;
}
2017-10-25 06:11:28 +03:00
static int mnt_bpffs ( const char * target , char * buff , size_t bufflen )
{
bool bind_done = false ;
while ( mount ( " " , target , " none " , MS_PRIVATE | MS_REC , NULL ) ) {
if ( errno ! = EINVAL | | bind_done ) {
snprintf ( buff , bufflen ,
" mount --make-private %s failed: %s " ,
target , strerror ( errno ) ) ;
return - 1 ;
}
if ( mount ( target , target , " none " , MS_BIND , NULL ) ) {
snprintf ( buff , bufflen ,
" mount --bind %s %s failed: %s " ,
target , target , strerror ( errno ) ) ;
return - 1 ;
}
bind_done = true ;
}
if ( mount ( " bpf " , target , " bpf " , 0 , " mode=0700 " ) ) {
snprintf ( buff , bufflen , " mount -t bpf bpf %s failed: %s " ,
target , strerror ( errno ) ) ;
return - 1 ;
}
return 0 ;
}
2017-11-08 07:55:47 +03:00
int open_obj_pinned ( char * path )
2017-10-05 06:10:04 +03:00
{
int fd ;
fd = bpf_obj_get ( path ) ;
if ( fd < 0 ) {
2017-10-23 19:24:13 +03:00
p_err ( " bpf obj get (%s): %s " , path ,
errno = = EACCES & & ! is_bpffs ( dirname ( path ) ) ?
2017-10-05 06:10:04 +03:00
" directory not in bpf file system (bpffs) " :
strerror ( errno ) ) ;
return - 1 ;
}
2017-11-08 07:55:47 +03:00
return fd ;
}
int open_obj_pinned_any ( char * path , enum bpf_obj_type exp_type )
{
enum bpf_obj_type type ;
int fd ;
fd = open_obj_pinned ( path ) ;
if ( fd < 0 )
return - 1 ;
2017-10-05 06:10:04 +03:00
type = get_fd_type ( fd ) ;
if ( type < 0 ) {
close ( fd ) ;
return type ;
}
if ( type ! = exp_type ) {
2017-10-23 19:24:13 +03:00
p_err ( " incorrect object type: %s " , get_fd_type_name ( type ) ) ;
2017-10-05 06:10:04 +03:00
close ( fd ) ;
return - 1 ;
}
return fd ;
}
2017-12-13 18:18:53 +03:00
int do_pin_fd ( int fd , const char * name )
2017-10-05 06:10:04 +03:00
{
2017-10-25 06:11:28 +03:00
char err_str [ ERR_MAX_LEN ] ;
char * file ;
char * dir ;
2017-12-13 18:18:53 +03:00
int err = 0 ;
err = bpf_obj_pin ( fd , name ) ;
if ( ! err )
goto out ;
file = malloc ( strlen ( name ) + 1 ) ;
strcpy ( file , name ) ;
dir = dirname ( file ) ;
if ( errno ! = EPERM | | is_bpffs ( dir ) ) {
p_err ( " can't pin the object (%s): %s " , name , strerror ( errno ) ) ;
goto out_free ;
}
/* Attempt to mount bpffs, then retry pinning. */
err = mnt_bpffs ( dir , err_str , ERR_MAX_LEN ) ;
if ( ! err ) {
err = bpf_obj_pin ( fd , name ) ;
if ( err )
p_err ( " can't pin the object (%s): %s " , name ,
strerror ( errno ) ) ;
} else {
err_str [ ERR_MAX_LEN - 1 ] = ' \0 ' ;
p_err ( " can't mount BPF file system to pin the object (%s): %s " ,
name , err_str ) ;
}
out_free :
free ( file ) ;
out :
return err ;
}
int do_pin_any ( int argc , char * * argv , int ( * get_fd_by_id ) ( __u32 ) )
{
unsigned int id ;
char * endptr ;
2017-10-05 06:10:04 +03:00
int err ;
int fd ;
if ( ! is_prefix ( * argv , " id " ) ) {
2017-10-23 19:24:13 +03:00
p_err ( " expected 'id' got %s " , * argv ) ;
2017-10-05 06:10:04 +03:00
return - 1 ;
}
NEXT_ARG ( ) ;
id = strtoul ( * argv , & endptr , 0 ) ;
if ( * endptr ) {
2017-10-23 19:24:13 +03:00
p_err ( " can't parse %s as ID " , * argv ) ;
2017-10-05 06:10:04 +03:00
return - 1 ;
}
NEXT_ARG ( ) ;
if ( argc ! = 1 )
usage ( ) ;
fd = get_fd_by_id ( id ) ;
if ( fd < 0 ) {
2017-10-23 19:24:13 +03:00
p_err ( " can't get prog by id (%u): %s " , id , strerror ( errno ) ) ;
2017-10-05 06:10:04 +03:00
return - 1 ;
}
2017-12-13 18:18:53 +03:00
err = do_pin_fd ( fd , * argv ) ;
2017-10-05 06:10:04 +03:00
2017-10-25 06:11:28 +03:00
close ( fd ) ;
return err ;
2017-10-05 06:10:04 +03:00
}
const char * get_fd_type_name ( enum bpf_obj_type type )
{
static const char * const names [ ] = {
[ BPF_OBJ_UNKNOWN ] = " unknown " ,
[ BPF_OBJ_PROG ] = " prog " ,
[ BPF_OBJ_MAP ] = " map " ,
} ;
if ( type < 0 | | type > = ARRAY_SIZE ( names ) | | ! names [ type ] )
return names [ BPF_OBJ_UNKNOWN ] ;
return names [ type ] ;
}
int get_fd_type ( int fd )
{
char path [ PATH_MAX ] ;
char buf [ 512 ] ;
ssize_t n ;
snprintf ( path , sizeof ( path ) , " /proc/%d/fd/%d " , getpid ( ) , fd ) ;
n = readlink ( path , buf , sizeof ( buf ) ) ;
if ( n < 0 ) {
2017-10-23 19:24:13 +03:00
p_err ( " can't read link type: %s " , strerror ( errno ) ) ;
2017-10-05 06:10:04 +03:00
return - 1 ;
}
if ( n = = sizeof ( path ) ) {
2017-10-23 19:24:13 +03:00
p_err ( " can't read link type: path too long! " ) ;
2017-10-05 06:10:04 +03:00
return - 1 ;
}
if ( strstr ( buf , " bpf-map " ) )
return BPF_OBJ_MAP ;
else if ( strstr ( buf , " bpf-prog " ) )
return BPF_OBJ_PROG ;
return BPF_OBJ_UNKNOWN ;
}
char * get_fdinfo ( int fd , const char * key )
{
char path [ PATH_MAX ] ;
char * line = NULL ;
size_t line_n = 0 ;
ssize_t n ;
FILE * fdi ;
snprintf ( path , sizeof ( path ) , " /proc/%d/fdinfo/%d " , getpid ( ) , fd ) ;
fdi = fopen ( path , " r " ) ;
if ( ! fdi ) {
2017-10-23 19:24:13 +03:00
p_err ( " can't open fdinfo: %s " , strerror ( errno ) ) ;
2017-10-05 06:10:04 +03:00
return NULL ;
}
while ( ( n = getline ( & line , & line_n , fdi ) ) ) {
char * value ;
int len ;
if ( ! strstr ( line , key ) )
continue ;
fclose ( fdi ) ;
value = strchr ( line , ' \t ' ) ;
if ( ! value | | ! value [ 1 ] ) {
2017-10-23 19:24:13 +03:00
p_err ( " malformed fdinfo!? " ) ;
2017-10-05 06:10:04 +03:00
free ( line ) ;
return NULL ;
}
value + + ;
len = strlen ( value ) ;
memmove ( line , value , len ) ;
line [ len - 1 ] = ' \0 ' ;
return line ;
}
2017-10-23 19:24:13 +03:00
p_err ( " key '%s' not found in fdinfo " , key ) ;
2017-10-05 06:10:04 +03:00
free ( line ) ;
fclose ( fdi ) ;
return NULL ;
}
tools: bpftool: add JSON output for `bpftool prog dump xlated *` command
Add a new printing function to dump translated eBPF instructions as
JSON. As for plain output, opcodes are printed only on request (when
`opcodes` is provided on the command line).
The disassembled output is generated by the same code that is used by
the kernel verifier.
Example output:
$ bpftool --json --pretty prog dump xlated id 1
[{
"disasm": "(bf) r6 = r1"
},{
"disasm": "(61) r7 = *(u32 *)(r6 +16)"
},{
"disasm": "(95) exit"
}
]
$ bpftool --json --pretty prog dump xlated id 1 opcodes
[{
"disasm": "(bf) r6 = r1",
"opcodes": {
"code": "0xbf",
"src_reg": "0x1",
"dst_reg": "0x6",
"off": ["0x00","0x00"
],
"imm": ["0x00","0x00","0x00","0x00"
]
}
},{
"disasm": "(61) r7 = *(u32 *)(r6 +16)",
"opcodes": {
"code": "0x61",
"src_reg": "0x6",
"dst_reg": "0x7",
"off": ["0x10","0x00"
],
"imm": ["0x00","0x00","0x00","0x00"
]
}
},{
"disasm": "(95) exit",
"opcodes": {
"code": "0x95",
"src_reg": "0x0",
"dst_reg": "0x0",
"off": ["0x00","0x00"
],
"imm": ["0x00","0x00","0x00","0x00"
]
}
}
]
Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-10-23 19:24:10 +03:00
void print_hex_data_json ( uint8_t * data , size_t len )
{
unsigned int i ;
jsonw_start_array ( json_wtr ) ;
for ( i = 0 ; i < len ; i + + )
jsonw_printf ( json_wtr , " \" 0x%02hhx \" " , data [ i ] ) ;
jsonw_end_array ( json_wtr ) ;
}
tools: bpftool: show filenames of pinned objects
Added support to show filenames of pinned objects.
For example:
root@test# ./bpftool prog
3: tracepoint name tracepoint__irq tag f677a7dd722299a3
loaded_at Oct 26/11:39 uid 0
xlated 160B not jited memlock 4096B map_ids 4
pinned /sys/fs/bpf/softirq_prog
4: tracepoint name tracepoint__irq tag ea5dc530d00b92b6
loaded_at Oct 26/11:39 uid 0
xlated 392B not jited memlock 4096B map_ids 4,6
root@test# ./bpftool --json --pretty prog
[{
"id": 3,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "f677a7dd722299a3",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 160,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4
],
"pinned": ["/sys/fs/bpf/softirq_prog"
]
},{
"id": 4,
"type": "tracepoint",
"name": "tracepoint__irq",
"tag": "ea5dc530d00b92b6",
"loaded_at": "Oct 26/11:39",
"uid": 0,
"bytes_xlated": 392,
"jited": false,
"bytes_memlock": 4096,
"map_ids": [4,6
],
"pinned": []
}
]
root@test# ./bpftool map
4: hash name start flags 0x0
key 4B value 16B max_entries 10240 memlock 1003520B
pinned /sys/fs/bpf/softirq_map1
5: hash name iptr flags 0x0
key 4B value 8B max_entries 10240 memlock 921600B
root@test# ./bpftool --json --pretty map
[{
"id": 4,
"type": "hash",
"name": "start",
"flags": 0,
"bytes_key": 4,
"bytes_value": 16,
"max_entries": 10240,
"bytes_memlock": 1003520,
"pinned": ["/sys/fs/bpf/softirq_map1"
]
},{
"id": 5,
"type": "hash",
"name": "iptr",
"flags": 0,
"bytes_key": 4,
"bytes_value": 8,
"max_entries": 10240,
"bytes_memlock": 921600,
"pinned": []
}
]
Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-11-08 07:55:48 +03:00
int build_pinned_obj_table ( struct pinned_obj_table * tab ,
enum bpf_obj_type type )
{
struct bpf_prog_info pinned_info = { } ;
struct pinned_obj * obj_node = NULL ;
__u32 len = sizeof ( pinned_info ) ;
struct mntent * mntent = NULL ;
enum bpf_obj_type objtype ;
FILE * mntfile = NULL ;
FTSENT * ftse = NULL ;
FTS * fts = NULL ;
int fd , err ;
mntfile = setmntent ( " /proc/mounts " , " r " ) ;
if ( ! mntfile )
return - 1 ;
while ( ( mntent = getmntent ( mntfile ) ) ) {
char * path [ ] = { mntent - > mnt_dir , NULL } ;
if ( strncmp ( mntent - > mnt_type , " bpf " , 3 ) ! = 0 )
continue ;
fts = fts_open ( path , 0 , NULL ) ;
if ( ! fts )
continue ;
while ( ( ftse = fts_read ( fts ) ) ) {
if ( ! ( ftse - > fts_info & FTS_F ) )
continue ;
fd = open_obj_pinned ( ftse - > fts_path ) ;
if ( fd < 0 )
continue ;
objtype = get_fd_type ( fd ) ;
if ( objtype ! = type ) {
close ( fd ) ;
continue ;
}
memset ( & pinned_info , 0 , sizeof ( pinned_info ) ) ;
err = bpf_obj_get_info_by_fd ( fd , & pinned_info , & len ) ;
if ( err ) {
close ( fd ) ;
continue ;
}
obj_node = malloc ( sizeof ( * obj_node ) ) ;
if ( ! obj_node ) {
close ( fd ) ;
fts_close ( fts ) ;
fclose ( mntfile ) ;
return - 1 ;
}
memset ( obj_node , 0 , sizeof ( * obj_node ) ) ;
obj_node - > id = pinned_info . id ;
obj_node - > path = strdup ( ftse - > fts_path ) ;
hash_add ( tab - > table , & obj_node - > hash , obj_node - > id ) ;
close ( fd ) ;
}
fts_close ( fts ) ;
}
fclose ( mntfile ) ;
return 0 ;
}
void delete_pinned_obj_table ( struct pinned_obj_table * tab )
{
struct pinned_obj * obj ;
struct hlist_node * tmp ;
unsigned int bkt ;
hash_for_each_safe ( tab - > table , bkt , tmp , obj , hash ) {
hash_del ( & obj - > hash ) ;
free ( obj - > path ) ;
free ( obj ) ;
}
}
2017-12-28 05:39:10 +03:00
static char *
ifindex_to_name_ns ( __u32 ifindex , __u32 ns_dev , __u32 ns_ino , char * buf )
{
struct stat st ;
int err ;
err = stat ( " /proc/self/ns/net " , & st ) ;
if ( err ) {
p_err ( " Can't stat /proc/self: %s " , strerror ( errno ) ) ;
return NULL ;
}
if ( st . st_dev ! = ns_dev | | st . st_ino ! = ns_ino )
return NULL ;
return if_indextoname ( ifindex , buf ) ;
}
void print_dev_plain ( __u32 ifindex , __u64 ns_dev , __u64 ns_inode )
{
char name [ IF_NAMESIZE ] ;
if ( ! ifindex )
return ;
printf ( " dev " ) ;
if ( ifindex_to_name_ns ( ifindex , ns_dev , ns_inode , name ) )
printf ( " %s " , name ) ;
else
printf ( " ifindex %u ns_dev %llu ns_ino %llu " ,
ifindex , ns_dev , ns_inode ) ;
}
void print_dev_json ( __u32 ifindex , __u64 ns_dev , __u64 ns_inode )
{
char name [ IF_NAMESIZE ] ;
if ( ! ifindex )
return ;
jsonw_name ( json_wtr , " dev " ) ;
jsonw_start_object ( json_wtr ) ;
jsonw_uint_field ( json_wtr , " ifindex " , ifindex ) ;
jsonw_uint_field ( json_wtr , " ns_dev " , ns_dev ) ;
jsonw_uint_field ( json_wtr , " ns_inode " , ns_inode ) ;
if ( ifindex_to_name_ns ( ifindex , ns_dev , ns_inode , name ) )
jsonw_string_field ( json_wtr , " ifname " , name ) ;
jsonw_end_object ( json_wtr ) ;
}