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;
|
struct nfp_prog *nfp_prog = prog->aux->offload->dev_priv;
|
||||||
unsigned int stack_size;
|
unsigned int stack_size;
|
||||||
unsigned int max_instr;
|
unsigned int max_instr;
|
||||||
|
int err;
|
||||||
|
|
||||||
stack_size = nn_readb(nn, NFP_NET_CFG_BPF_STACK_SZ) * 64;
|
stack_size = nn_readb(nn, NFP_NET_CFG_BPF_STACK_SZ) * 64;
|
||||||
if (prog->aux->stack_depth > stack_size) {
|
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)
|
if (!nfp_prog->prog)
|
||||||
return -ENOMEM;
|
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)
|
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;
|
struct list_head offloads;
|
||||||
bool dev_state;
|
bool dev_state;
|
||||||
const struct bpf_prog_offload_ops *dev_ops;
|
const struct bpf_prog_offload_ops *dev_ops;
|
||||||
|
void *jited_image;
|
||||||
|
u32 jited_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bpf_prog_aux {
|
struct bpf_prog_aux {
|
||||||
|
|
|
@ -230,9 +230,12 @@ int bpf_prog_offload_info_fill(struct bpf_prog_info *info,
|
||||||
.prog = prog,
|
.prog = prog,
|
||||||
.info = info,
|
.info = info,
|
||||||
};
|
};
|
||||||
|
struct bpf_prog_aux *aux = prog->aux;
|
||||||
struct inode *ns_inode;
|
struct inode *ns_inode;
|
||||||
struct path ns_path;
|
struct path ns_path;
|
||||||
|
char __user *uinsns;
|
||||||
void *res;
|
void *res;
|
||||||
|
u32 ulen;
|
||||||
|
|
||||||
res = ns_get_path_cb(&ns_path, bpf_prog_offload_info_fill_ns, &args);
|
res = ns_get_path_cb(&ns_path, bpf_prog_offload_info_fill_ns, &args);
|
||||||
if (IS_ERR(res)) {
|
if (IS_ERR(res)) {
|
||||||
|
@ -241,6 +244,26 @@ int bpf_prog_offload_info_fill(struct bpf_prog_info *info,
|
||||||
return PTR_ERR(res);
|
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;
|
ns_inode = ns_path.dentry->d_inode;
|
||||||
info->netns_dev = new_encode_dev(ns_inode->i_sb->s_dev);
|
info->netns_dev = new_encode_dev(ns_inode->i_sb->s_dev);
|
||||||
info->netns_ino = ns_inode->i_ino;
|
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;
|
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;
|
ulen = info.xlated_prog_len;
|
||||||
info.xlated_prog_len = bpf_prog_insn_size(prog);
|
info.xlated_prog_len = bpf_prog_insn_size(prog);
|
||||||
if (info.xlated_prog_len && ulen) {
|
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);
|
err = bpf_prog_offload_info_fill(&info, prog);
|
||||||
if (err)
|
if (err)
|
||||||
return 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:
|
done:
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
/* Author: Jakub Kicinski <kubakici@wp.pl> */
|
/* Author: Jakub Kicinski <kubakici@wp.pl> */
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <fts.h>
|
#include <fts.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <mntent.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);
|
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)
|
void print_dev_plain(__u32 ifindex, __u64 ns_dev, __u64 ns_inode)
|
||||||
{
|
{
|
||||||
char name[IF_NAMESIZE];
|
char name[IF_NAMESIZE];
|
||||||
|
|
|
@ -76,7 +76,8 @@ static int fprintf_json(void *out, const char *fmt, ...)
|
||||||
return 0;
|
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;
|
disassembler_ftype disassemble;
|
||||||
struct disassemble_info info;
|
struct disassemble_info info;
|
||||||
|
@ -100,6 +101,19 @@ void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes)
|
||||||
else
|
else
|
||||||
init_disassemble_info(&info, stdout,
|
init_disassemble_info(&info, stdout,
|
||||||
(fprintf_ftype) fprintf);
|
(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.arch = bfd_get_arch(bfdf);
|
||||||
info.mach = bfd_get_mach(bfdf);
|
info.mach = bfd_get_mach(bfdf);
|
||||||
info.buffer = image;
|
info.buffer = image;
|
||||||
|
|
|
@ -121,7 +121,10 @@ int do_cgroup(int argc, char **arg);
|
||||||
|
|
||||||
int prog_parse_fd(int *argc, char ***argv);
|
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);
|
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
|
#endif
|
||||||
|
|
|
@ -776,7 +776,17 @@ static int do_dump(int argc, char **argv)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (member_len == &info.jited_prog_len) {
|
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 {
|
} else {
|
||||||
kernel_syms_load(&dd);
|
kernel_syms_load(&dd);
|
||||||
if (json_output)
|
if (json_output)
|
||||||
|
|
Loading…
Reference in New Issue