mirror of https://gitee.com/openkylin/linux.git
Merge branch 'bpf-dump-and-disasm-nfp-jit'
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>
This commit is contained in:
commit
cda18e9726
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)) {
|
||||
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
@ -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:
|
||||
|
|
|
@ -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>
|
||||
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue