Skip to content

Commit

Permalink
Merge branch 'bpf-dump-and-disasm-nfp-jit'
Browse files Browse the repository at this point in the history
Jakub Kicinski says:

====================
Jiong says:

Currently bpftool could disassemble host jited image, for example x86_64,
using libbfd. However it couldn't disassemble offload jited image.

There are two reasons:

  1. bpf_obj_get_info_by_fd/struct bpf_prog_info couldn't get the address
     of jited image and image's length.

  2. Even after issue 1 resolved, bpftool couldn't figure out what is the
     offload arch from bpf_prog_info, therefore can't drive libbfd
     disassembler correctly.

  This patch set resolve issue 1 by introducing two new fields "jited_len"
and "jited_image" in bpf_dev_offload. These two fields serve as the generic
interface to communicate the jited image address and length for all offload
targets to higher level caller. For example, bpf_obj_get_info_by_fd could
use them to fill the userspace visible fields jited_prog_len and
jited_prog_insns.

  This patch set resolve issue 2 by getting bfd backend name through
"ifindex", i.e network interface index.

v1:
 - Deduct bfd arch name through ifindex, i.e network interface index.
   First, map ifindex to devname through ifindex_to_name_ns, then get
   pci id through /sys/class/dev/DEVNAME/device/vendor. (Daniel, Alexei)
====================

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
  • Loading branch information
Daniel Borkmann committed Jan 18, 2018
2 parents 4f7d585 + e659359 commit cda18e9
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 17 deletions.
10 changes: 9 additions & 1 deletion drivers/net/ethernet/netronome/nfp/bpf/offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ static int nfp_bpf_translate(struct nfp_net *nn, struct bpf_prog *prog)
struct nfp_prog *nfp_prog = prog->aux->offload->dev_priv;
unsigned int stack_size;
unsigned int max_instr;
int err;

stack_size = nn_readb(nn, NFP_NET_CFG_BPF_STACK_SZ) * 64;
if (prog->aux->stack_depth > stack_size) {
Expand All @@ -143,7 +144,14 @@ static int nfp_bpf_translate(struct nfp_net *nn, struct bpf_prog *prog)
if (!nfp_prog->prog)
return -ENOMEM;

return nfp_bpf_jit(nfp_prog);
err = nfp_bpf_jit(nfp_prog);
if (err)
return err;

prog->aux->offload->jited_len = nfp_prog->prog_len * sizeof(u64);
prog->aux->offload->jited_image = nfp_prog->prog;

return 0;
}

static int nfp_bpf_destroy(struct nfp_net *nn, struct bpf_prog *prog)
Expand Down
2 changes: 2 additions & 0 deletions include/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ struct bpf_prog_offload {
struct list_head offloads;
bool dev_state;
const struct bpf_prog_offload_ops *dev_ops;
void *jited_image;
u32 jited_len;
};

struct bpf_prog_aux {
Expand Down
23 changes: 23 additions & 0 deletions kernel/bpf/offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,9 +230,12 @@ int bpf_prog_offload_info_fill(struct bpf_prog_info *info,
.prog = prog,
.info = info,
};
struct bpf_prog_aux *aux = prog->aux;
struct inode *ns_inode;
struct path ns_path;
char __user *uinsns;
void *res;
u32 ulen;

res = ns_get_path_cb(&ns_path, bpf_prog_offload_info_fill_ns, &args);
if (IS_ERR(res)) {
Expand All @@ -241,6 +244,26 @@ int bpf_prog_offload_info_fill(struct bpf_prog_info *info,
return PTR_ERR(res);
}

down_read(&bpf_devs_lock);

if (!aux->offload) {
up_read(&bpf_devs_lock);
return -ENODEV;
}

ulen = info->jited_prog_len;
info->jited_prog_len = aux->offload->jited_len;
if (info->jited_prog_len & ulen) {
uinsns = u64_to_user_ptr(info->jited_prog_insns);
ulen = min_t(u32, info->jited_prog_len, ulen);
if (copy_to_user(uinsns, aux->offload->jited_image, ulen)) {
up_read(&bpf_devs_lock);
return -EFAULT;
}
}

up_read(&bpf_devs_lock);

ns_inode = ns_path.dentry->d_inode;
info->netns_dev = new_encode_dev(ns_inode->i_sb->s_dev);
info->netns_ino = ns_inode->i_ino;
Expand Down
31 changes: 18 additions & 13 deletions kernel/bpf/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -1724,19 +1724,6 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
goto done;
}

ulen = info.jited_prog_len;
info.jited_prog_len = prog->jited_len;
if (info.jited_prog_len && ulen) {
if (bpf_dump_raw_ok()) {
uinsns = u64_to_user_ptr(info.jited_prog_insns);
ulen = min_t(u32, info.jited_prog_len, ulen);
if (copy_to_user(uinsns, prog->bpf_func, ulen))
return -EFAULT;
} else {
info.jited_prog_insns = 0;
}
}

ulen = info.xlated_prog_len;
info.xlated_prog_len = bpf_prog_insn_size(prog);
if (info.xlated_prog_len && ulen) {
Expand All @@ -1762,6 +1749,24 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
err = bpf_prog_offload_info_fill(&info, prog);
if (err)
return err;
goto done;
}

/* NOTE: the following code is supposed to be skipped for offload.
* bpf_prog_offload_info_fill() is the place to fill similar fields
* for offload.
*/
ulen = info.jited_prog_len;
info.jited_prog_len = prog->jited_len;
if (info.jited_prog_len && ulen) {
if (bpf_dump_raw_ok()) {
uinsns = u64_to_user_ptr(info.jited_prog_insns);
ulen = min_t(u32, info.jited_prog_len, ulen);
if (copy_to_user(uinsns, prog->bpf_func, ulen))
return -EFAULT;
} else {
info.jited_prog_insns = 0;
}
}

done:
Expand Down
72 changes: 72 additions & 0 deletions tools/bpf/bpftool/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
/* Author: Jakub Kicinski <kubakici@wp.pl> */

#include <errno.h>
#include <fcntl.h>
#include <fts.h>
#include <libgen.h>
#include <mntent.h>
Expand Down Expand Up @@ -433,6 +434,77 @@ ifindex_to_name_ns(__u32 ifindex, __u32 ns_dev, __u32 ns_ino, char *buf)
return if_indextoname(ifindex, buf);
}

static int read_sysfs_hex_int(char *path)
{
char vendor_id_buf[8];
int len;
int fd;

fd = open(path, O_RDONLY);
if (fd < 0) {
p_err("Can't open %s: %s", path, strerror(errno));
return -1;
}

len = read(fd, vendor_id_buf, sizeof(vendor_id_buf));
close(fd);
if (len < 0) {
p_err("Can't read %s: %s", path, strerror(errno));
return -1;
}
if (len >= (int)sizeof(vendor_id_buf)) {
p_err("Value in %s too long", path);
return -1;
}

vendor_id_buf[len] = 0;

return strtol(vendor_id_buf, NULL, 0);
}

static int read_sysfs_netdev_hex_int(char *devname, const char *entry_name)
{
char full_path[64];

snprintf(full_path, sizeof(full_path), "/sys/class/net/%s/device/%s",
devname, entry_name);

return read_sysfs_hex_int(full_path);
}

const char *ifindex_to_bfd_name_ns(__u32 ifindex, __u64 ns_dev, __u64 ns_ino)
{
char devname[IF_NAMESIZE];
int vendor_id;
int device_id;

if (!ifindex_to_name_ns(ifindex, ns_dev, ns_ino, devname)) {
p_err("Can't get net device name for ifindex %d: %s", ifindex,
strerror(errno));
return NULL;
}

vendor_id = read_sysfs_netdev_hex_int(devname, "vendor");
if (vendor_id < 0) {
p_err("Can't get device vendor id for %s", devname);
return NULL;
}

switch (vendor_id) {
case 0x19ee:
device_id = read_sysfs_netdev_hex_int(devname, "device");
if (device_id != 0x4000 &&
device_id != 0x6000 &&
device_id != 0x6003)
p_info("Unknown NFP device ID, assuming it is NFP-6xxx arch");
return "NFP-6xxx";
default:
p_err("Can't get bfd arch name for device vendor id 0x%04x",
vendor_id);
return NULL;
}
}

void print_dev_plain(__u32 ifindex, __u64 ns_dev, __u64 ns_inode)
{
char name[IF_NAMESIZE];
Expand Down
16 changes: 15 additions & 1 deletion tools/bpf/bpftool/jit_disasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ static int fprintf_json(void *out, const char *fmt, ...)
return 0;
}

void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes)
void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
const char *arch)
{
disassembler_ftype disassemble;
struct disassemble_info info;
Expand All @@ -100,6 +101,19 @@ void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes)
else
init_disassemble_info(&info, stdout,
(fprintf_ftype) fprintf);

/* Update architecture info for offload. */
if (arch) {
const bfd_arch_info_type *inf = bfd_scan_arch(arch);

if (inf) {
bfdf->arch_info = inf;
} else {
p_err("No libfd support for %s", arch);
return;
}
}

info.arch = bfd_get_arch(bfdf);
info.mach = bfd_get_mach(bfdf);
info.buffer = image;
Expand Down
5 changes: 4 additions & 1 deletion tools/bpf/bpftool/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,10 @@ int do_cgroup(int argc, char **arg);

int prog_parse_fd(int *argc, char ***argv);

void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes);
void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
const char *arch);
void print_hex_data_json(uint8_t *data, size_t len);

const char *ifindex_to_bfd_name_ns(__u32 ifindex, __u64 ns_dev, __u64 ns_ino);

#endif
12 changes: 11 additions & 1 deletion tools/bpf/bpftool/prog.c
Original file line number Diff line number Diff line change
Expand Up @@ -776,7 +776,17 @@ static int do_dump(int argc, char **argv)
}
} else {
if (member_len == &info.jited_prog_len) {
disasm_print_insn(buf, *member_len, opcodes);
const char *name = NULL;

if (info.ifindex) {
name = ifindex_to_bfd_name_ns(info.ifindex,
info.netns_dev,
info.netns_ino);
if (!name)
goto err_free;
}

disasm_print_insn(buf, *member_len, opcodes, name);
} else {
kernel_syms_load(&dd);
if (json_output)
Expand Down

0 comments on commit cda18e9

Please sign in to comment.