Commit 4b54db13 authored by David S. Miller's avatar David S. Miller

Merge branch 'bpftool'

Jakub Kicinski says:

====================
tools: add bpftool

This set adds bpftool to the tools/ directory.  The first
patch renames tools/net to tools/bpf, the second one adds
the new code, while the third adds simple documentation.

v4:
 - rename docs *.txt -> *.rst (Jesper).
v3:
 - address Alexei's comments about output and docs.
v2:
 - report names, map ids, load time, uid;
 - add docs/man pages;
 - general cleanups & fixes.
====================
Acked-by: default avatarDavid Ahern <dsahern@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c331501c ff69c21a
...@@ -2725,7 +2725,7 @@ F: net/core/filter.c ...@@ -2725,7 +2725,7 @@ F: net/core/filter.c
F: net/sched/act_bpf.c F: net/sched/act_bpf.c
F: net/sched/cls_bpf.c F: net/sched/cls_bpf.c
F: samples/bpf/ F: samples/bpf/
F: tools/net/bpf* F: tools/bpf/
F: tools/testing/selftests/bpf/ F: tools/testing/selftests/bpf/
BROADCOM B44 10/100 ETHERNET DRIVER BROADCOM B44 10/100 ETHERNET DRIVER
...@@ -9416,7 +9416,6 @@ F: include/uapi/linux/in.h ...@@ -9416,7 +9416,6 @@ F: include/uapi/linux/in.h
F: include/uapi/linux/net.h F: include/uapi/linux/net.h
F: include/uapi/linux/netdevice.h F: include/uapi/linux/netdevice.h
F: include/uapi/linux/net_namespace.h F: include/uapi/linux/net_namespace.h
F: tools/net/
F: tools/testing/selftests/net/ F: tools/testing/selftests/net/
F: lib/random32.c F: lib/random32.c
......
...@@ -19,7 +19,7 @@ help: ...@@ -19,7 +19,7 @@ help:
@echo ' kvm_stat - top-like utility for displaying kvm statistics' @echo ' kvm_stat - top-like utility for displaying kvm statistics'
@echo ' leds - LEDs tools' @echo ' leds - LEDs tools'
@echo ' liblockdep - user-space wrapper for kernel locking-validator' @echo ' liblockdep - user-space wrapper for kernel locking-validator'
@echo ' net - misc networking tools' @echo ' bpf - misc BPF tools'
@echo ' perf - Linux performance measurement and analysis tool' @echo ' perf - Linux performance measurement and analysis tool'
@echo ' selftests - various kernel selftests' @echo ' selftests - various kernel selftests'
@echo ' spi - spi tools' @echo ' spi - spi tools'
...@@ -57,7 +57,7 @@ acpi: FORCE ...@@ -57,7 +57,7 @@ acpi: FORCE
cpupower: FORCE cpupower: FORCE
$(call descend,power/$@) $(call descend,power/$@)
cgroup firewire hv guest spi usb virtio vm net iio gpio objtool leds: FORCE cgroup firewire hv guest spi usb virtio vm bpf iio gpio objtool leds: FORCE
$(call descend,$@) $(call descend,$@)
liblockdep: FORCE liblockdep: FORCE
...@@ -91,7 +91,7 @@ kvm_stat: FORCE ...@@ -91,7 +91,7 @@ kvm_stat: FORCE
all: acpi cgroup cpupower gpio hv firewire liblockdep \ all: acpi cgroup cpupower gpio hv firewire liblockdep \
perf selftests spi turbostat usb \ perf selftests spi turbostat usb \
virtio vm net x86_energy_perf_policy \ virtio vm bpf x86_energy_perf_policy \
tmon freefall iio objtool kvm_stat tmon freefall iio objtool kvm_stat
acpi_install: acpi_install:
...@@ -100,7 +100,7 @@ acpi_install: ...@@ -100,7 +100,7 @@ acpi_install:
cpupower_install: cpupower_install:
$(call descend,power/$(@:_install=),install) $(call descend,power/$(@:_install=),install)
cgroup_install firewire_install gpio_install hv_install iio_install perf_install spi_install usb_install virtio_install vm_install net_install objtool_install: cgroup_install firewire_install gpio_install hv_install iio_install perf_install spi_install usb_install virtio_install vm_install bpf_install objtool_install:
$(call descend,$(@:_install=),install) $(call descend,$(@:_install=),install)
liblockdep_install: liblockdep_install:
...@@ -124,7 +124,7 @@ kvm_stat_install: ...@@ -124,7 +124,7 @@ kvm_stat_install:
install: acpi_install cgroup_install cpupower_install gpio_install \ install: acpi_install cgroup_install cpupower_install gpio_install \
hv_install firewire_install iio_install liblockdep_install \ hv_install firewire_install iio_install liblockdep_install \
perf_install selftests_install turbostat_install usb_install \ perf_install selftests_install turbostat_install usb_install \
virtio_install vm_install net_install x86_energy_perf_policy_install \ virtio_install vm_install bpf_install x86_energy_perf_policy_install \
tmon_install freefall_install objtool_install kvm_stat_install tmon_install freefall_install objtool_install kvm_stat_install
acpi_clean: acpi_clean:
...@@ -133,7 +133,7 @@ acpi_clean: ...@@ -133,7 +133,7 @@ acpi_clean:
cpupower_clean: cpupower_clean:
$(call descend,power/cpupower,clean) $(call descend,power/cpupower,clean)
cgroup_clean hv_clean firewire_clean spi_clean usb_clean virtio_clean vm_clean net_clean iio_clean gpio_clean objtool_clean leds_clean: cgroup_clean hv_clean firewire_clean spi_clean usb_clean virtio_clean vm_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean:
$(call descend,$(@:_clean=),clean) $(call descend,$(@:_clean=),clean)
liblockdep_clean: liblockdep_clean:
...@@ -169,7 +169,7 @@ build_clean: ...@@ -169,7 +169,7 @@ build_clean:
clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean \ clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean \
perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \ perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \
vm_clean net_clean iio_clean x86_energy_perf_policy_clean tmon_clean \ vm_clean bpf_clean iio_clean x86_energy_perf_policy_clean tmon_clean \
freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \ freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \
gpio_clean objtool_clean leds_clean gpio_clean objtool_clean leds_clean
......
...@@ -3,6 +3,7 @@ prefix = /usr ...@@ -3,6 +3,7 @@ prefix = /usr
CC = gcc CC = gcc
LEX = flex LEX = flex
YACC = bison YACC = bison
MAKE = make
CFLAGS += -Wall -O2 CFLAGS += -Wall -O2
CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include
...@@ -13,7 +14,7 @@ CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include ...@@ -13,7 +14,7 @@ CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include
%.lex.c: %.l %.lex.c: %.l
$(LEX) -o $@ $< $(LEX) -o $@ $<
all : bpf_jit_disasm bpf_dbg bpf_asm all: bpf_jit_disasm bpf_dbg bpf_asm bpftool
bpf_jit_disasm : CFLAGS += -DPACKAGE='bpf_jit_disasm' bpf_jit_disasm : CFLAGS += -DPACKAGE='bpf_jit_disasm'
bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl
...@@ -26,10 +27,21 @@ bpf_asm : LDLIBS = ...@@ -26,10 +27,21 @@ bpf_asm : LDLIBS =
bpf_asm : bpf_asm.o bpf_exp.yacc.o bpf_exp.lex.o bpf_asm : bpf_asm.o bpf_exp.yacc.o bpf_exp.lex.o
bpf_exp.lex.o : bpf_exp.yacc.c bpf_exp.lex.o : bpf_exp.yacc.c
clean : clean: bpftool_clean
rm -rf *.o bpf_jit_disasm bpf_dbg bpf_asm bpf_exp.yacc.* bpf_exp.lex.* rm -rf *.o bpf_jit_disasm bpf_dbg bpf_asm bpf_exp.yacc.* bpf_exp.lex.*
install : install: bpftool_install
install bpf_jit_disasm $(prefix)/bin/bpf_jit_disasm install bpf_jit_disasm $(prefix)/bin/bpf_jit_disasm
install bpf_dbg $(prefix)/bin/bpf_dbg install bpf_dbg $(prefix)/bin/bpf_dbg
install bpf_asm $(prefix)/bin/bpf_asm install bpf_asm $(prefix)/bin/bpf_asm
bpftool:
$(MAKE) -C bpftool
bpftool_install:
$(MAKE) -C bpftool install
bpftool_clean:
$(MAKE) -C bpftool clean
.PHONY: bpftool FORCE
include ../../../scripts/Makefile.include
include ../../../scripts/utilities.mak
INSTALL ?= install
RM ?= rm -f
# Make the path relative to DESTDIR, not prefix
ifndef DESTDIR
prefix?=$(HOME)
endif
mandir ?= $(prefix)/share/man
man8dir = $(mandir)/man8
MAN8_RST = $(wildcard *.rst)
_DOC_MAN8 = $(patsubst %.rst,%.8,$(MAN8_RST))
DOC_MAN8 = $(addprefix $(OUTPUT),$(_DOC_MAN8))
man: man8
man8: $(DOC_MAN8)
$(OUTPUT)%.8: %.rst
rst2man $< > $@
clean:
$(call QUIET_CLEAN, Documentation) $(RM) $(DOC_MAN8)
install: man
$(call QUIET_INSTALL, Documentation-man) \
$(INSTALL) -d -m 755 $(DESTDIR)$(man8dir); \
$(INSTALL) -m 644 $(DOC_MAN8) $(DESTDIR)$(man8dir);
.PHONY: man man8 clean install
.DEFAULT_GOAL := man
================
bpftool-map
================
-------------------------------------------------------------------------------
tool for inspection and simple manipulation of eBPF maps
-------------------------------------------------------------------------------
:Manual section: 8
SYNOPSIS
========
**bpftool** **map** *COMMAND*
*COMMANDS* :=
{ show | dump | update | lookup | getnext | delete | pin | help }
MAP COMMANDS
=============
| **bpftool** map show [*MAP*]
| **bpftool** map dump *MAP*
| **bpftool** map update *MAP* key *BYTES* value *VALUE* [*UPDATE_FLAGS*]
| **bpftool** map lookup *MAP* key *BYTES*
| **bpftool** map getnext *MAP* [key *BYTES*]
| **bpftool** map delete *MAP* key *BYTES*
| **bpftool** map pin *MAP* *FILE*
| **bpftool** map help
|
| *MAP* := { id MAP_ID | pinned FILE }
| *VALUE* := { BYTES | MAP | PROGRAM }
| *UPDATE_FLAGS* := { any | exist | noexist }
DESCRIPTION
===========
**bpftool map show** [*MAP*]
Show information about loaded maps. If *MAP* is specified
show information only about given map, otherwise list all
maps currently loaded on the system.
Output will start with map ID followed by map type and
zero or more named attributes (depending on kernel version).
**bpftool map dump** *MAP*
Dump all entries in a given *MAP*.
**bpftool map update** *MAP* **key** *BYTES* **value** *VALUE* [*UPDATE_FLAGS*]
Update map entry for a given *KEY*.
*UPDATE_FLAGS* can be one of: **any** update existing entry
or add if doesn't exit; **exist** update only if entry already
exists; **noexist** update only if entry doesn't exist.
**bpftool map lookup** *MAP* **key** *BYTES*
Lookup **key** in the map.
**bpftool map getnext** *MAP* [**key** *BYTES*]
Get next key. If *key* is not specified, get first key.
**bpftool map delete** *MAP* **key** *BYTES*
Remove entry from the map.
**bpftool map pin** *MAP* *FILE*
Pin map *MAP* as *FILE*.
Note: *FILE* must be located in *bpffs* mount.
**bpftool map help**
Print short help message.
EXAMPLES
========
**# bpftool map show**
::
10: hash name some_map flags 0x0
key 4B value 8B max_entries 2048 memlock 167936B
**# bpftool map update id 10 key 13 00 07 00 value 02 00 00 00 01 02 03 04**
**# bpftool map lookup id 10 key 0 1 2 3**
::
key: 00 01 02 03 value: 00 01 02 03 04 05 06 07
**# bpftool map dump id 10**
::
key: 00 01 02 03 value: 00 01 02 03 04 05 06 07
key: 0d 00 07 00 value: 02 00 00 00 01 02 03 04
Found 2 elements
**# bpftool map getnext id 10 key 0 1 2 3**
::
key:
00 01 02 03
next key:
0d 00 07 00
|
| **# mount -t bpf none /sys/fs/bpf/**
| **# bpftool map pin id 10 /sys/fs/bpf/map**
| **# bpftool map del pinned /sys/fs/bpf/map key 13 00 07 00**
SEE ALSO
========
**bpftool**\ (8), **bpftool-prog**\ (8)
================
bpftool-prog
================
-------------------------------------------------------------------------------
tool for inspection and simple manipulation of eBPF progs
-------------------------------------------------------------------------------
:Manual section: 8
SYNOPSIS
========
| **bpftool** prog show [*PROG*]
| **bpftool** prog dump xlated *PROG* file *FILE*
| **bpftool** prog dump jited *PROG* [file *FILE*] [opcodes]
| **bpftool** prog pin *PROG* *FILE*
| **bpftool** prog help
|
| *PROG* := { id *PROG_ID* | pinned *FILE* | tag *PROG_TAG* }
DESCRIPTION
===========
**bpftool prog show** [*PROG*]
Show information about loaded programs. If *PROG* is
specified show information only about given program, otherwise
list all programs currently loaded on the system.
Output will start with program ID followed by program type and
zero or more named attributes (depending on kernel version).
**bpftool prog dump xlated** *PROG* **file** *FILE*
Dump eBPF instructions of the program from the kernel to a
file.
**bpftool prog dump jited** *PROG* [**file** *FILE*] [**opcodes**]
Dump jited image (host machine code) of the program.
If *FILE* is specified image will be written to a file,
otherwise it will be disassembled and printed to stdout.
**opcodes** controls if raw opcodes will be printed.
**bpftool prog pin** *PROG* *FILE*
Pin program *PROG* as *FILE*.
Note: *FILE* must be located in *bpffs* mount.
**bpftool prog help**
Print short help message.
EXAMPLES
========
**# bpftool prog show**
::
10: xdp name some_prog tag 00:5a:3d:21:23:62:0c:8b
loaded_at Sep 29/20:11 uid 0
xlated 528B jited 370B memlock 4096B map_ids 10
|
| **# bpftool prog dump xlated id 10 file /tmp/t**
| **# ls -l /tmp/t**
| -rw------- 1 root root 560 Jul 22 01:42 /tmp/t
|
| **# bpftool prog dum jited pinned /sys/fs/bpf/prog**
::
push %rbp
mov %rsp,%rbp
sub $0x228,%rsp
sub $0x28,%rbp
mov %rbx,0x0(%rbp)
SEE ALSO
========
**bpftool**\ (8), **bpftool-map**\ (8)
================
BPFTOOL
================
-------------------------------------------------------------------------------
tool for inspection and simple manipulation of eBPF programs and maps
-------------------------------------------------------------------------------
:Manual section: 8
SYNOPSIS
========
**bpftool** *OBJECT* { *COMMAND* | help }
**bpftool** batch file *FILE*
*OBJECT* := { **map** | **program** }
*MAP-COMMANDS* :=
{ show | dump | update | lookup | getnext | delete | pin | help }
*PROG-COMMANDS* := { show | dump jited | dump xlated | pin | help }
DESCRIPTION
===========
*bpftool* allows for inspection and simple modification of BPF objects
on the system.
Note that format of the output of all tools is not guaranteed to be
stable and should not be depended upon.
SEE ALSO
========
**bpftool-map**\ (8), **bpftool-prog**\ (8)
include ../../scripts/Makefile.include
include ../../scripts/utilities.mak
ifeq ($(srctree),)
srctree := $(patsubst %/,%,$(dir $(CURDIR)))
srctree := $(patsubst %/,%,$(dir $(srctree)))
srctree := $(patsubst %/,%,$(dir $(srctree)))
#$(info Determined 'srctree' to be $(srctree))
endif
ifneq ($(objtree),)
#$(info Determined 'objtree' to be $(objtree))
endif
ifneq ($(OUTPUT),)
#$(info Determined 'OUTPUT' to be $(OUTPUT))
# Adding $(OUTPUT) as a directory to look for source files,
# because use generated output files as sources dependency
# for flex/bison parsers.
VPATH += $(OUTPUT)
export VPATH
endif
ifeq ($(V),1)
Q =
else
Q = @
endif
BPF_DIR = $(srctree)/tools/lib/bpf/
ifneq ($(OUTPUT),)
BPF_PATH=$(OUTPUT)
else
BPF_PATH=$(BPF_DIR)
endif
LIBBPF = $(BPF_PATH)libbpf.a
$(LIBBPF): FORCE
$(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(OUTPUT) $(OUTPUT)libbpf.a FEATURES_DUMP=$(FEATURE_DUMP_EXPORT)
$(LIBBPF)-clean:
$(call QUIET_CLEAN, libbpf)
$(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(OUTPUT) clean >/dev/null
prefix = /usr
CC = gcc
CFLAGS += -O2
CFLAGS += -W -Wall -Wextra -Wno-unused-parameter -Wshadow
CFLAGS += -D__EXPORTED_HEADERS__ -I$(srctree)/tools/include/uapi -I$(srctree)/tools/include -I$(srctree)/tools/lib/bpf
LIBS = -lelf -lbfd -lopcodes $(LIBBPF)
include $(wildcard *.d)
all: $(OUTPUT)bpftool
SRCS=$(wildcard *.c)
OBJS=$(patsubst %.c,$(OUTPUT)%.o,$(SRCS))
$(OUTPUT)bpftool: $(OBJS) $(LIBBPF)
$(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
$(OUTPUT)%.o: %.c
$(QUIET_CC)$(COMPILE.c) -MMD -o $@ $<
clean: $(LIBBPF)-clean
$(call QUIET_CLEAN, bpftool)
$(Q)rm -rf $(OUTPUT)bpftool $(OUTPUT)*.o $(OUTPUT)*.d
install:
install $(OUTPUT)bpftool $(prefix)/sbin/bpftool
doc:
$(Q)$(MAKE) -C Documentation/
doc-install:
$(Q)$(MAKE) -C Documentation/ install
FORCE:
.PHONY: all clean FORCE
.DEFAULT_GOAL := all
/*
* 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>
#include <libgen.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <linux/limits.h>
#include <linux/magic.h>
#include <sys/types.h>
#include <sys/vfs.h>
#include <bpf.h>
#include "main.h"
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;
}
int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type)
{
enum bpf_obj_type type;
int fd;
fd = bpf_obj_get(path);
if (fd < 0) {
err("bpf obj get (%s): %s\n", path,
errno == EACCES && !is_bpffs(dirname(path)) ?
"directory not in bpf file system (bpffs)" :
strerror(errno));
return -1;
}
type = get_fd_type(fd);
if (type < 0) {
close(fd);
return type;
}
if (type != exp_type) {
err("incorrect object type: %s\n", get_fd_type_name(type));
close(fd);
return -1;
}
return fd;
}
int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32))
{
unsigned int id;
char *endptr;
int err;
int fd;
if (!is_prefix(*argv, "id")) {
err("expected 'id' got %s\n", *argv);
return -1;
}
NEXT_ARG();
id = strtoul(*argv, &endptr, 0);
if (*endptr) {
err("can't parse %s as ID\n", *argv);
return -1;
}
NEXT_ARG();
if (argc != 1)
usage();
fd = get_fd_by_id(id);
if (fd < 0) {
err("can't get prog by id (%u): %s\n", id, strerror(errno));
return -1;
}
err = bpf_obj_pin(fd, *argv);
close(fd);
if (err) {
err("can't pin the object (%s): %s\n", *argv,
errno == EACCES && !is_bpffs(dirname(*argv)) ?
"directory not in bpf file system (bpffs)" :
strerror(errno));
return -1;
}
return 0;
}
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) {
err("can't read link type: %s\n", strerror(errno));
return -1;
}
if (n == sizeof(path)) {
err("can't read link type: path too long!\n");
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) {
err("can't open fdinfo: %s\n", strerror(errno));
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]) {
err("malformed fdinfo!?\n");
free(line);
return NULL;
}
value++;
len = strlen(value);
memmove(line, value, len);
line[len - 1] = '\0';
return line;
}
err("key '%s' not found in fdinfo\n", key);
free(line);
fclose(fdi);
return NULL;
}
/*
* Based on:
*
* Minimal BPF JIT image disassembler
*
* Disassembles BPF JIT compiler emitted opcodes back to asm insn's for
* debugging or verification purposes.
*
* Copyright 2013 Daniel Borkmann <daniel@iogearbox.net>
* Licensed under the GNU General Public License, version 2.0 (GPLv2)
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <bfd.h>
#include <dis-asm.h>
#include <sys/types.h>
#include <sys/stat.h>
static void get_exec_path(char *tpath, size_t size)
{
ssize_t len;
char *path;
snprintf(tpath, size, "/proc/%d/exe", (int) getpid());
tpath[size - 1] = 0;
path = strdup(tpath);
assert(path);
len = readlink(path, tpath, size - 1);
assert(len > 0);
tpath[len] = 0;
free(path);
}
void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes)
{
disassembler_ftype disassemble;
struct disassemble_info info;
int count, i, pc = 0;
char tpath[256];
bfd *bfdf;
if (!len)
return;
memset(tpath, 0, sizeof(tpath));
get_exec_path(tpath, sizeof(tpath));
bfdf = bfd_openr(tpath, NULL);
assert(bfdf);
assert(bfd_check_format(bfdf, bfd_object));
init_disassemble_info(&info, stdout, (fprintf_ftype) fprintf);
info.arch = bfd_get_arch(bfdf);
info.mach = bfd_get_mach(bfdf);
info.buffer = image;
info.buffer_length = len;
disassemble_init_for_target(&info);
disassemble = disassembler(bfdf);
assert(disassemble);
do {
printf("%4x:\t", pc);
count = disassemble(pc, &info);
if (opcodes) {
printf("\n\t");
for (i = 0; i < count; ++i)
printf("%02x ", (uint8_t) image[pc + i]);
}
printf("\n");
pc += count;
} while (count > 0 && pc < len);
bfd_close(bfdf);
}
/*
* 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 <bfd.h>
#include <ctype.h>
#include <errno.h>
#include <linux/bpf.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <bpf.h>
#include "main.h"
const char *bin_name;
static int last_argc;
static char **last_argv;
static int (*last_do_help)(int argc, char **argv);
void usage(void)
{
last_do_help(last_argc - 1, last_argv + 1);
exit(-1);
}
static int do_help(int argc, char **argv)
{
fprintf(stderr,
"Usage: %s OBJECT { COMMAND | help }\n"
" %s batch file FILE\n"
"\n"
" OBJECT := { prog | map }\n",
bin_name, bin_name);
return 0;
}
int cmd_select(const struct cmd *cmds, int argc, char **argv,
int (*help)(int argc, char **argv))
{
unsigned int i;
last_argc = argc;
last_argv = argv;
last_do_help = help;
if (argc < 1 && cmds[0].func)
return cmds[0].func(argc, argv);
for (i = 0; cmds[i].func; i++)
if (is_prefix(*argv, cmds[i].cmd))
return cmds[i].func(argc - 1, argv + 1);
help(argc - 1, argv + 1);
return -1;
}
bool is_prefix(const char *pfx, const char *str)
{
if (!pfx)
return false;
if (strlen(str) < strlen(pfx))
return false;
return !memcmp(str, pfx, strlen(pfx));
}
void print_hex(void *arg, unsigned int n, const char *sep)
{
unsigned char *data = arg;
unsigned int i;
for (i = 0; i < n; i++) {
const char *pfx = "";
if (!i)
/* nothing */;
else if (!(i % 16))
printf("\n");
else if (!(i % 8))
printf(" ");
else
pfx = sep;
printf("%s%02hhx", i ? pfx : "", data[i]);
}
}
static int do_batch(int argc, char **argv);
static const struct cmd cmds[] = {
{ "help", do_help },
{ "batch", do_batch },
{ "prog", do_prog },
{ "map", do_map },
{ 0 }
};
static int do_batch(int argc, char **argv)
{
unsigned int lines = 0;
char *n_argv[4096];
char buf[65536];
int n_argc;
FILE *fp;
int err;
if (argc < 2) {
err("too few parameters for batch\n");
return -1;
} else if (!is_prefix(*argv, "file")) {
err("expected 'file', got: %s\n", *argv);
return -1;
} else if (argc > 2) {
err("too many parameters for batch\n");
return -1;
}
NEXT_ARG();
fp = fopen(*argv, "r");
if (!fp) {
err("Can't open file (%s): %s\n", *argv, strerror(errno));
return -1;
}
while (fgets(buf, sizeof(buf), fp)) {
if (strlen(buf) == sizeof(buf) - 1) {
errno = E2BIG;
break;
}
n_argc = 0;
n_argv[n_argc] = strtok(buf, " \t\n");
while (n_argv[n_argc]) {
n_argc++;
if (n_argc == ARRAY_SIZE(n_argv)) {
err("line %d has too many arguments, skip\n",
lines);
n_argc = 0;
break;
}
n_argv[n_argc] = strtok(NULL, " \t\n");
}
if (!n_argc)
continue;
err = cmd_select(cmds, n_argc, n_argv, do_help);
if (err)
goto err_close;
lines++;
}
if (errno && errno != ENOENT) {
perror("reading batch file failed");
err = -1;
} else {
info("processed %d lines\n", lines);
err = 0;
}
err_close:
fclose(fp);
return err;
}
int main(int argc, char **argv)
{
bin_name = argv[0];
NEXT_ARG();
bfd_init();
return cmd_select(cmds, argc, argv, do_help);
}
/*
* 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> */
#ifndef __BPF_TOOL_H
#define __BPF_TOOL_H
#include <stdbool.h>
#include <stdio.h>
#include <linux/bpf.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define err(msg...) fprintf(stderr, "Error: " msg)
#define warn(msg...) fprintf(stderr, "Warning: " msg)
#define info(msg...) fprintf(stderr, msg)
#define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr))
#define min(a, b) \
({ typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _b : _a; })
#define max(a, b) \
({ typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _b : _a; })
#define NEXT_ARG() ({ argc--; argv++; if (argc < 0) usage(); })
#define NEXT_ARGP() ({ (*argc)--; (*argv)++; if (*argc < 0) usage(); })
#define BAD_ARG() ({ err("what is '%s'?\n", *argv); -1; })
#define BPF_TAG_FMT "%02hhx:%02hhx:%02hhx:%02hhx:" \
"%02hhx:%02hhx:%02hhx:%02hhx"
#define HELP_SPEC_PROGRAM \
"PROG := { id PROG_ID | pinned FILE | tag PROG_TAG }"
enum bpf_obj_type {
BPF_OBJ_UNKNOWN,
BPF_OBJ_PROG,
BPF_OBJ_MAP,
};
extern const char *bin_name;
bool is_prefix(const char *pfx, const char *str);
void print_hex(void *arg, unsigned int n, const char *sep);
void usage(void) __attribute__((noreturn));
struct cmd {
const char *cmd;
int (*func)(int argc, char **argv);
};
int cmd_select(const struct cmd *cmds, int argc, char **argv,
int (*help)(int argc, char **argv));
int get_fd_type(int fd);
const char *get_fd_type_name(enum bpf_obj_type type);
char *get_fdinfo(int fd, const char *key);
int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type);
int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32));
int do_prog(int argc, char **arg);
int do_map(int argc, char **arg);
int prog_parse_fd(int *argc, char ***argv);
void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes);
#endif
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment