* [PATCH v4 perf,bpf 09/15] perf, bpf: save btf information as headers to perf.data
From: Song Liu @ 2019-02-26 0:20 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu
In-Reply-To: <20190226002019.3748539-1-songliubraving@fb.com>
This patch enables perf-record to save btf information as headers to
perf.data A new header type HEADER_BPF_BTF is introduced for this data.
Signed-off-by: Song Liu <songliubraving@fb.com>
---
| 108 ++++++++++++++++++++++++++++++++++++++-
| 1 +
2 files changed, 108 insertions(+), 1 deletion(-)
--git a/tools/perf/util/header.c b/tools/perf/util/header.c
index c89dce7942d1..ce5402101468 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1127,6 +1127,45 @@ static int write_bpf_prog_info(struct feat_fd *ff,
return ret;
}
+static int write_bpf_btf(struct feat_fd *ff,
+ struct perf_evlist *evlist __maybe_unused)
+{
+ struct perf_env *env = &ff->ph->env;
+ struct rb_root *root;
+ struct rb_node *next;
+ u32 count = 0;
+ int ret;
+
+ down_read(&env->bpf_progs.lock);
+
+ root = &env->bpf_progs.btfs;
+ next = rb_first(root);
+ while (next) {
+ ++count;
+ next = rb_next(next);
+ }
+
+ ret = do_write(ff, &count, sizeof(count));
+
+ if (ret < 0)
+ goto out;
+
+ next = rb_first(root);
+ while (next) {
+ struct btf_node *node;
+
+ node = rb_entry(next, struct btf_node, rb_node);
+ next = rb_next(&node->rb_node);
+ ret = do_write(ff, &node->id,
+ sizeof(u32) * 2 + node->data_size);
+ if (ret < 0)
+ goto out;
+ }
+out:
+ up_read(&env->bpf_progs.lock);
+ return ret;
+}
+
static int cpu_cache_level__sort(const void *a, const void *b)
{
struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a;
@@ -1630,6 +1669,28 @@ static void print_bpf_prog_info(struct feat_fd *ff, FILE *fp)
up_read(&env->bpf_progs.lock);
}
+static void print_bpf_btf(struct feat_fd *ff, FILE *fp)
+{
+ struct perf_env *env = &ff->ph->env;
+ struct rb_root *root;
+ struct rb_node *next;
+
+ down_read(&env->bpf_progs.lock);
+
+ root = &env->bpf_progs.btfs;
+ next = rb_first(root);
+
+ while (next) {
+ struct btf_node *node;
+
+ node = rb_entry(next, struct btf_node, rb_node);
+ next = rb_next(&node->rb_node);
+ fprintf(fp, "# btf info of id %u\n", node->id);
+ }
+
+ up_read(&env->bpf_progs.lock);
+}
+
static void free_event_desc(struct perf_evsel *events)
{
struct perf_evsel *evsel;
@@ -2732,6 +2793,50 @@ static int process_bpf_prog_info(struct feat_fd *ff,
return err;
}
+static int process_bpf_btf(struct feat_fd *ff, void *data __maybe_unused)
+{
+ struct perf_env *env = &ff->ph->env;
+ u32 count, i;
+
+ if (do_read_u32(ff, &count))
+ return -1;
+
+ down_write(&env->bpf_progs.lock);
+
+ for (i = 0; i < count; ++i) {
+ struct btf_node *node;
+ u32 id, data_size;
+
+ if (do_read_u32(ff, &id))
+ return -1;
+ if (do_read_u32(ff, &data_size))
+ return -1;
+
+ node = malloc(sizeof(struct btf_node) + data_size);
+ if (!node)
+ return -1;
+
+ node->id = id;
+ node->data_size = data_size;
+
+ if (__do_read(ff, node->data, data_size)) {
+ free(node);
+ return -1;
+ }
+
+ /* endian mismatch, drop the btf, continue */
+ if (ff->ph->needs_swap) {
+ free(node);
+ continue;
+ }
+
+ perf_env__insert_btf(env, node);
+ }
+
+ up_write(&env->bpf_progs.lock);
+ return 0;
+}
+
struct feature_ops {
int (*write)(struct feat_fd *ff, struct perf_evlist *evlist);
void (*print)(struct feat_fd *ff, FILE *fp);
@@ -2792,7 +2897,8 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
FEAT_OPR(SAMPLE_TIME, sample_time, false),
FEAT_OPR(MEM_TOPOLOGY, mem_topology, true),
FEAT_OPR(CLOCKID, clockid, false),
- FEAT_OPR(BPF_PROG_INFO, bpf_prog_info, false)
+ FEAT_OPR(BPF_PROG_INFO, bpf_prog_info, false),
+ FEAT_OPR(BPF_BTF, bpf_btf, false)
};
struct header_print_data {
--git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 0785c91b4c3a..9e7d931f7c0d 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -40,6 +40,7 @@ enum {
HEADER_MEM_TOPOLOGY,
HEADER_CLOCKID,
HEADER_BPF_PROG_INFO,
+ HEADER_BPF_BTF,
HEADER_LAST_FEATURE,
HEADER_FEAT_BITS = 256,
};
--
2.17.1
^ permalink raw reply related
* [PATCH v4 perf,bpf 13/15] perf, bpf: process PERF_BPF_EVENT_PROG_LOAD for annotation
From: Song Liu @ 2019-02-26 0:20 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu
In-Reply-To: <20190226002019.3748539-1-songliubraving@fb.com>
This patch adds processing of PERF_BPF_EVENT_PROG_LOAD, which sets proper
DSO type/id/etc of memory regions mapped to BPF programs to
DSO_BINARY_TYPE__BPF_PROG_INFO
Signed-off-by: Song Liu <songliubraving@fb.com>
---
tools/perf/util/bpf-event.c | 53 +++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index 370b830f2433..048ef00371ad 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -25,12 +25,65 @@ static int snprintf_hex(char *buf, size_t size, unsigned char *data, size_t len)
return ret;
}
+static int machine__process_bpf_event_load(struct machine *machine __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused)
+{
+ struct bpf_prog_info_linear *info_linear;
+ struct bpf_prog_info_node *info_node;
+ struct perf_env *env = machine->env;
+ int id = event->bpf_event.id;
+ unsigned int i;
+
+ /* perf-record, no need to handle bpf-event */
+ if (env == NULL)
+ return 0;
+
+ info_node = perf_env__find_bpf_prog_info(env, id);
+ if (!info_node)
+ return 0;
+ info_linear = info_node->info_linear;
+
+ for (i = 0; i < info_linear->info.nr_jited_ksyms; i++) {
+ u64 *addrs = (u64 *)(info_linear->info.jited_ksyms);
+ u64 addr = addrs[i];
+ struct map *map;
+
+ map = map_groups__find(&machine->kmaps, addr);
+
+ if (map) {
+ map->dso->binary_type = DSO_BINARY_TYPE__BPF_PROG_INFO;
+ map->dso->bpf_prog.id = id;
+ map->dso->bpf_prog.sub_id = i;
+ map->dso->bpf_prog.env = env;
+ }
+ }
+ return 0;
+}
+
int machine__process_bpf_event(struct machine *machine __maybe_unused,
union perf_event *event,
struct perf_sample *sample __maybe_unused)
{
if (dump_trace)
perf_event__fprintf_bpf_event(event, stdout);
+
+ switch (event->bpf_event.type) {
+ case PERF_BPF_EVENT_PROG_LOAD:
+ return machine__process_bpf_event_load(machine, event, sample);
+
+ case PERF_BPF_EVENT_PROG_UNLOAD:
+ /*
+ * Do not free bpf_prog_info and btf of the program here,
+ * as annotation still need them. They will be freed at
+ * the end of the session.
+ */
+ break;
+ default:
+ pr_debug("unexpected bpf_event type of %d\n",
+ event->bpf_event.type);
+ break;
+ }
return 0;
}
--
2.17.1
^ permalink raw reply related
* [PATCH v4 perf,bpf 12/15] perf, bpf: enable annotation of bpf program
From: Song Liu @ 2019-02-26 0:20 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu
In-Reply-To: <20190226002019.3748539-1-songliubraving@fb.com>
This patch enables the annotation of bpf program.
A new dso type DSO_BINARY_TYPE__BPF_PROG_INFO is introduced to for BPF
programs. In symbol__disassemble(), DSO_BINARY_TYPE__BPF_PROG_INFO dso
calls into a new function symbol__disassemble_bpf(), where annotation
line information is filled based bpf_prog_info and btf saved in given
perf_env.
symbol__disassemble_bpf() uses libbfd to disassemble bpf programs.
Signed-off-by: Song Liu <songliubraving@fb.com>
---
tools/build/Makefile.feature | 6 +-
tools/perf/Makefile.config | 4 +
tools/perf/util/annotate.c | 149 ++++++++++++++++++++++++++++++++++-
tools/perf/util/dso.c | 1 +
tools/perf/util/dso.h | 33 +++++---
| 7 +-
tools/perf/util/symbol.c | 1 +
tools/perf/util/util.c | 10 +++
tools/perf/util/util.h | 2 +
9 files changed, 193 insertions(+), 20 deletions(-)
diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index 5467c6bf9ceb..4f35e9ff1e00 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -71,7 +71,8 @@ FEATURE_TESTS_BASIC := \
sdt \
setns \
libopencsd \
- libaio
+ libaio \
+ disassembler-four-args
# FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list
# of all feature tests
@@ -118,7 +119,8 @@ FEATURE_DISPLAY ?= \
lzma \
get_cpuid \
bpf \
- libaio
+ libaio \
+ disassembler-four-args
# Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features.
# If in the future we need per-feature checks/flags for features not
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index e0bafbc273af..ab223239f1fb 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -796,6 +796,10 @@ ifdef HAVE_KVM_STAT_SUPPORT
CFLAGS += -DHAVE_KVM_STAT_SUPPORT
endif
+ifeq ($(feature-disassembler-four-args), 1)
+ CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE
+endif
+
ifeq (${IS_64_BIT}, 1)
ifndef NO_PERF_READ_VDSO32
$(call feature_check,compile-32)
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 70de8f6b3aee..716fdb07f45e 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -9,6 +9,10 @@
#include <errno.h>
#include <inttypes.h>
+#include <bpf/bpf.h>
+#include <bpf/btf.h>
+#include <bpf/libbpf.h>
+#include <linux/btf.h>
#include "util.h"
#include "ui/ui.h"
#include "sort.h"
@@ -22,6 +26,7 @@
#include "annotate.h"
#include "evsel.h"
#include "evlist.h"
+#include "bpf-event.h"
#include "block-range.h"
#include "string2.h"
#include "arch/common.h"
@@ -29,6 +34,9 @@
#include <pthread.h>
#include <linux/bitops.h>
#include <linux/kernel.h>
+#include <bfd.h>
+#include <dis-asm.h>
+#include <bpf/libbpf.h>
/* FIXME: For the HE_COLORSET */
#include "ui/browser.h"
@@ -1672,6 +1680,143 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil
return 0;
}
+static int symbol__disassemble_bpf(struct symbol *sym,
+ struct annotate_args *args)
+{
+ struct annotation *notes = symbol__annotation(sym);
+ struct annotation_options *opts = args->options;
+ struct bpf_prog_info_linear *info_linear;
+ struct bpf_prog_linfo *prog_linfo = NULL;
+ struct bpf_prog_info_node *info_node;
+ int len = sym->end - sym->start;
+ disassembler_ftype disassemble;
+ struct map *map = args->ms.map;
+ struct disassemble_info info;
+ struct dso *dso = map->dso;
+ int pc = 0, count, sub_id;
+ struct btf *btf = NULL;
+ char tpath[PATH_MAX];
+ size_t buf_size;
+ int nr_skip = 0;
+ int ret = -1;
+ char *buf;
+ bfd *bfdf;
+ FILE *s;
+
+ if (dso->binary_type != DSO_BINARY_TYPE__BPF_PROG_INFO)
+ return -1;
+
+ pr_debug("%s: handling sym %s addr %lx len %lx\n", __func__,
+ sym->name, sym->start, sym->end - sym->start);
+
+ 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));
+
+ s = open_memstream(&buf, &buf_size);
+ if (!s)
+ goto out;
+ init_disassemble_info(&info, s,
+ (fprintf_ftype) fprintf);
+
+ info.arch = bfd_get_arch(bfdf);
+ info.mach = bfd_get_mach(bfdf);
+
+ info_node = perf_env__find_bpf_prog_info(dso->bpf_prog.env,
+ dso->bpf_prog.id);
+ if (!info_node)
+ goto out;
+ info_linear = info_node->info_linear;
+ sub_id = dso->bpf_prog.sub_id;
+
+ info.buffer = (void *)(info_linear->info.jited_prog_insns);
+ info.buffer_length = info_linear->info.jited_prog_len;
+
+ if (info_linear->info.nr_line_info)
+ prog_linfo = bpf_prog_linfo__new(&info_linear->info);
+
+ if (info_linear->info.btf_id) {
+ struct btf_node *node;
+
+ node = perf_env__find_btf(dso->bpf_prog.env,
+ info_linear->info.btf_id);
+ if (node)
+ btf = btf__new((__u8 *)(node->data),
+ node->data_size);
+ }
+
+ disassemble_init_for_target(&info);
+
+#ifdef DISASM_FOUR_ARGS_SIGNATURE
+ disassemble = disassembler(info.arch,
+ bfd_big_endian(bfdf),
+ info.mach,
+ bfdf);
+#else
+ disassemble = disassembler(bfdf);
+#endif
+ assert(disassemble);
+
+ fflush(s);
+ do {
+ const struct bpf_line_info *linfo = NULL;
+ struct disasm_line *dl;
+ size_t prev_buf_size;
+ const char *srcline;
+ u64 addr;
+
+ addr = pc + ((u64 *)(info_linear->info.jited_ksyms))[sub_id];
+ count = disassemble(pc, &info);
+
+ if (prog_linfo)
+ linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
+ addr, sub_id,
+ nr_skip);
+
+ if (linfo && btf) {
+ srcline = btf__name_by_offset(btf, linfo->line_off);
+ nr_skip++;
+ } else
+ srcline = NULL;
+
+ fprintf(s, "\n");
+ prev_buf_size = buf_size;
+ fflush(s);
+
+ if (!opts->hide_src_code && srcline) {
+ args->offset = -1;
+ args->line = strdup(srcline);
+ args->line_nr = 0;
+ args->ms.sym = sym;
+ dl = disasm_line__new(args);
+ if (dl)
+ annotation_line__add(&dl->al,
+ ¬es->src->source);
+ }
+
+ args->offset = pc;
+ args->line = buf + prev_buf_size;
+ args->line_nr = 0;
+ args->ms.sym = sym;
+ dl = disasm_line__new(args);
+ if (dl)
+ annotation_line__add(&dl->al, ¬es->src->source);
+
+ pc += count;
+ } while (count > 0 && pc < len);
+
+ ret = 0;
+out:
+ free(prog_linfo);
+ free(btf);
+ fclose(s);
+ bfd_close(bfdf);
+ return ret;
+}
+
static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
{
struct annotation_options *opts = args->options;
@@ -1699,7 +1844,9 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
pr_debug("annotating [%p] %30s : [%p] %30s\n",
dso, dso->long_name, sym, sym->name);
- if (dso__is_kcore(dso)) {
+ if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) {
+ return symbol__disassemble_bpf(sym, args);
+ } else if (dso__is_kcore(dso)) {
kce.kcore_filename = symfs_filename;
kce.addr = map__rip_2objdump(map, sym->start);
kce.offs = sym->start;
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 62c8cf622607..1798192bf0f9 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -181,6 +181,7 @@ int dso__read_binary_type_filename(const struct dso *dso,
case DSO_BINARY_TYPE__KALLSYMS:
case DSO_BINARY_TYPE__GUEST_KALLSYMS:
case DSO_BINARY_TYPE__JAVA_JIT:
+ case DSO_BINARY_TYPE__BPF_PROG_INFO:
case DSO_BINARY_TYPE__NOT_FOUND:
ret = -1;
break;
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index 8c8a7abe809d..f20d319463f1 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -14,6 +14,8 @@
#include "namespaces.h"
#include "build-id.h"
+struct perf_env;
+
enum dso_binary_type {
DSO_BINARY_TYPE__KALLSYMS = 0,
DSO_BINARY_TYPE__GUEST_KALLSYMS,
@@ -34,6 +36,7 @@ enum dso_binary_type {
DSO_BINARY_TYPE__KCORE,
DSO_BINARY_TYPE__GUEST_KCORE,
DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
+ DSO_BINARY_TYPE__BPF_PROG_INFO,
DSO_BINARY_TYPE__NOT_FOUND,
};
@@ -177,17 +180,25 @@ struct dso {
struct auxtrace_cache *auxtrace_cache;
int comp;
- /* dso data file */
- struct {
- struct rb_root cache;
- int fd;
- int status;
- u32 status_seen;
- size_t file_size;
- struct list_head open_entry;
- u64 debug_frame_offset;
- u64 eh_frame_hdr_offset;
- } data;
+ union {
+ /* dso data file */
+ struct {
+ struct rb_root cache;
+ int fd;
+ int status;
+ u32 status_seen;
+ size_t file_size;
+ struct list_head open_entry;
+ u64 debug_frame_offset;
+ u64 eh_frame_hdr_offset;
+ } data;
+ /* bpf prog information */
+ struct {
+ u32 id;
+ u32 sub_id;
+ struct perf_env *env;
+ } bpf_prog;
+ };
union { /* Tool specific area */
void *priv;
--git a/tools/perf/util/header.c b/tools/perf/util/header.c
index ce5402101468..c39e107ac5b8 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -533,12 +533,7 @@ static int write_cmdline(struct feat_fd *ff,
int i, ret;
/* actual path to perf binary */
- ret = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
- if (ret <= 0)
- return -1;
-
- /* readlink() does not add null termination */
- buf[ret] = '\0';
+ get_exec_path(buf, sizeof(buf));
/* account for binary path */
n = perf_env.nr_cmdline + 1;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 48efad6d0f90..33ae59e89da2 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1441,6 +1441,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO:
return true;
+ case DSO_BINARY_TYPE__BPF_PROG_INFO:
case DSO_BINARY_TYPE__NOT_FOUND:
default:
return false;
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 093352e93d50..0bc9ec69f38a 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -506,3 +506,13 @@ const char *perf_tip(const char *dirpath)
return tip;
}
+
+void get_exec_path(char *tpath, size_t size)
+{
+ const char *path = "/proc/self/exe";
+ ssize_t len;
+
+ len = readlink(path, tpath, size - 1);
+ assert(len > 0);
+ tpath[len] = 0;
+}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index ece040b799f6..8d0a88eb8685 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -76,6 +76,8 @@ extern bool perf_singlethreaded;
void perf_set_singlethreaded(void);
void perf_set_multithreaded(void);
+void get_exec_path(char *tpath, size_t size);
+
#ifndef O_CLOEXEC
#ifdef __sparc__
#define O_CLOEXEC 0x400000
--
2.17.1
^ permalink raw reply related
* [PATCH v4 perf,bpf 10/15] perf-top: add option --no-bpf-event
From: Song Liu @ 2019-02-26 0:20 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu
In-Reply-To: <20190226002019.3748539-1-songliubraving@fb.com>
bpf events should be tracked by default for perf-top. This patch makes it
on by default, and adds option to disable bpf events.
Signed-off-by: Song Liu <songliubraving@fb.com>
---
tools/perf/builtin-top.c | 3 +++
tools/perf/util/top.h | 1 +
2 files changed, 4 insertions(+)
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 27d8d42e0a4d..ccdf5689452f 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1492,6 +1492,7 @@ int cmd_top(int argc, const char **argv)
"Display raw encoding of assembly instructions (default)"),
OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
"Enable kernel symbol demangling"),
+ OPT_BOOLEAN(0, "no-bpf-event", &top.no_bpf_event, "do not record bpf events"),
OPT_STRING(0, "objdump", &top.annotation_opts.objdump_path, "path",
"objdump binary to use for disassembly and annotations"),
OPT_STRING('M', "disassembler-style", &top.annotation_opts.disassembler_style, "disassembler style",
@@ -1651,6 +1652,8 @@ int cmd_top(int argc, const char **argv)
signal(SIGWINCH, winch_sig);
}
+ top.record_opts.bpf_event = !top.no_bpf_event;
+
status = __cmd_top(&top);
out_delete_evlist:
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index 19f95eaf75c8..862a37bd27ea 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -32,6 +32,7 @@ struct perf_top {
bool use_tui, use_stdio;
bool vmlinux_warned;
bool dump_symtab;
+ bool no_bpf_event;
struct hist_entry *sym_filter_entry;
struct perf_evsel *sym_evsel;
struct perf_session *session;
--
2.17.1
^ permalink raw reply related
* [PATCH net] netfilter: bridge: Don't sabotage nf_hook calls for an l3mdev slave
From: David Ahern @ 2019-02-26 0:21 UTC (permalink / raw)
To: pablo; +Cc: netdev, netfilter-devel, David Ahern
From: David Ahern <dsahern@gmail.com>
Followup to a173f066c7cf ("netfilter: bridge: Don't sabotage nf_hook
calls from an l3mdev"). Some packets (e.g., ndisc) do not have the skb
device flipped to the l3mdev (e.g., VRF) device. Update ip_sabotage_in
to not drop packets for slave devices too. Currently, neighbor
solicitation packets for 'dev -> bridge (addr) -> vrf' setups are getting
dropped. This patch enables IPv6 communications for bridges with an
address that are enslaved to a VRF.
Fixes: 73e20b761acf ("net: vrf: Add support for PREROUTING rules on vrf device")
Signed-off-by: David Ahern <dsahern@gmail.com>
---
net/bridge/br_netfilter_hooks.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c
index c93c35bb73dd..8ab222babc98 100644
--- a/net/bridge/br_netfilter_hooks.c
+++ b/net/bridge/br_netfilter_hooks.c
@@ -831,7 +831,8 @@ static unsigned int ip_sabotage_in(void *priv,
struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
if (nf_bridge && !nf_bridge->in_prerouting &&
- !netif_is_l3_master(skb->dev)) {
+ !netif_is_l3_master(skb->dev) &&
+ !netif_is_l3_slave(skb->dev)) {
state->okfn(state->net, state->sk, skb);
return NF_STOLEN;
}
--
2.11.0
^ permalink raw reply related
* [PATCH v4 perf,bpf 11/15] perf: add -lopcodes to feature-libbfd
From: Song Liu @ 2019-02-26 0:20 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu
In-Reply-To: <20190226002019.3748539-1-songliubraving@fb.com>
Both libbfd and libopcodes are distributed with binutil-dev/devel. When
libbfd presents, it is OK to assume libopcodes also presents. This has
been a safe assumption for bpftool.
This patch adds -lopcodes to perf/Makefile.config. libopcodes will be
used in the next commit for bpf annotation.
Signed-off-by: Song Liu <songliubraving@fb.com>
---
tools/perf/Makefile.config | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index b441c88cafa1..e0bafbc273af 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -701,7 +701,7 @@ else
endif
ifeq ($(feature-libbfd), 1)
- EXTLIBS += -lbfd
+ EXTLIBS += -lbfd -lopcodes
else
# we are on a system that requires -liberty and (maybe) -lz
# to link against -lbfd; test each case individually here
--
2.17.1
^ permalink raw reply related
* [PATCH v4 perf,bpf 15/15] perf, bpf: save information about short living bpf programs
From: Song Liu @ 2019-02-26 0:20 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu
In-Reply-To: <20190226002019.3748539-1-songliubraving@fb.com>
This patch adds and side band event to capture bpf_prog_info and btf of
short living bpf programs.
Signed-off-by: Song Liu <songliubraving@fb.com>
---
tools/perf/builtin-record.c | 3 ++
tools/perf/builtin-top.c | 3 ++
tools/perf/util/bpf-event.c | 66 +++++++++++++++++++++++++++++++++++++
tools/perf/util/bpf-event.h | 18 ++++++++++
tools/perf/util/evlist.c | 5 +++
5 files changed, 95 insertions(+)
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index d10c1d5a9e89..ce26d37c2871 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1207,6 +1207,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
goto out_child;
}
+ if (opts->bpf_event)
+ bpf_event__add_polling_event();
+
poll_args.env = &session->header.env;
poll_args.done = &done;
perf_evlist__start_polling_thread(&rec->opts.target, &poll_args);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index f41545445917..851c4dcce66f 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1655,6 +1655,9 @@ int cmd_top(int argc, const char **argv)
top.record_opts.bpf_event = !top.no_bpf_event;
+ if (top.record_opts.bpf_event)
+ bpf_event__add_polling_event();
+
poll_args.env = &perf_env;
poll_args.done = &done;
perf_evlist__start_polling_thread(target, &poll_args);
diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index 048ef00371ad..664906237ffb 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -12,6 +12,7 @@
#include "machine.h"
#include "env.h"
#include "session.h"
+#include "evlist.h"
#define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr))
@@ -332,3 +333,68 @@ int perf_event__synthesize_bpf_events(struct perf_session *session,
free(event);
return err;
}
+
+void perf_env__add_bpf_info(struct perf_env *env, u32 id)
+{
+ struct bpf_prog_info_linear *info_linear;
+ struct bpf_prog_info_node *info_node;
+ struct btf *btf = NULL;
+ u64 arrays;
+ u32 btf_id;
+ int fd;
+
+ fd = bpf_prog_get_fd_by_id(id);
+ if (fd < 0)
+ return;
+
+ arrays = 1UL << BPF_PROG_INFO_JITED_KSYMS;
+ arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS;
+ arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO;
+ arrays |= 1UL << BPF_PROG_INFO_PROG_TAGS;
+ arrays |= 1UL << BPF_PROG_INFO_JITED_INSNS;
+ arrays |= 1UL << BPF_PROG_INFO_LINE_INFO;
+ arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO;
+
+ info_linear = bpf_program__get_prog_info_linear(fd, arrays);
+ if (IS_ERR_OR_NULL(info_linear)) {
+ pr_debug("%s: failed to get BPF program info. aborting\n", __func__);
+ goto out;
+ }
+
+ btf_id = info_linear->info.btf_id;
+
+ info_node = malloc(sizeof(struct bpf_prog_info_node));
+ if (info_node) {
+ info_node->info_linear = info_linear;
+ perf_env__insert_bpf_prog_info(env, info_node);
+ } else
+ free(info_linear);
+
+ if (btf_id == 0)
+ goto out;
+
+ if (btf__get_from_id(btf_id, &btf)) {
+ pr_debug("%s: failed to get BTF of id %u, aborting\n",
+ __func__, btf_id);
+ goto out;
+ }
+ perf_env__fetch_btf(env, btf_id, btf);
+
+out:
+ free(btf);
+ close(fd);
+}
+
+int bpf_event__add_polling_event(void)
+{
+ struct perf_event_attr attr = {
+ .type = PERF_TYPE_SOFTWARE,
+ .config = PERF_COUNT_SW_DUMMY,
+ .watermark = 1,
+ .bpf_event = 1,
+ .wakeup_watermark = 1,
+ .size = sizeof(attr), /* to capture ABI version */
+ };
+
+ return perf_evlist__new_side_band_event(&attr);
+}
diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h
index b9ec394dc7c7..03a6f018e219 100644
--- a/tools/perf/util/bpf-event.h
+++ b/tools/perf/util/bpf-event.h
@@ -4,12 +4,17 @@
#include <linux/compiler.h>
#include <linux/rbtree.h>
+#include <pthread.h>
+#include <api/fd/array.h>
#include "event.h"
struct machine;
union perf_event;
+struct perf_env;
struct perf_sample;
struct record_opts;
+struct evlist;
+struct target;
struct bpf_prog_info_node {
struct bpf_prog_info_linear *info_linear;
@@ -31,6 +36,9 @@ int perf_event__synthesize_bpf_events(struct perf_session *session,
perf_event__handler_t process,
struct machine *machine,
struct record_opts *opts);
+int bpf_event__add_polling_event(void);
+void perf_env__add_bpf_info(struct perf_env *env, u32 id);
+
#else
static inline int machine__process_bpf_event(struct machine *machine __maybe_unused,
union perf_event *event __maybe_unused,
@@ -46,5 +54,15 @@ static inline int perf_event__synthesize_bpf_events(struct perf_session *session
{
return 0;
}
+
+static inline int bpf_event__add_polling_event(void)
+{
+ return 0;
+}
+
+void perf_env__add_bpf_info(struct perf_env *env __maybe_unused,
+ u32 id __maybe_unused)
+{
+}
#endif // HAVE_LIBBPF_SUPPORT
#endif
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 61b87c8111e6..58ac42878c0a 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1886,6 +1886,11 @@ static void *perf_evlist__poll_thread(void *arg)
pr_debug("processing vip event of type %d\n",
event->header.type);
switch (event->header.type) {
+ case PERF_RECORD_BPF_EVENT:
+ if (event->bpf_event.type != PERF_BPF_EVENT_PROG_LOAD)
+ break;
+ perf_env__add_bpf_info(args->env, event->bpf_event.id);
+ break;
default:
break;
}
--
2.17.1
^ permalink raw reply related
* [PATCH v4 perf,bpf 14/15] perf: introduce side band thread
From: Song Liu @ 2019-02-26 0:20 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu
In-Reply-To: <20190226002019.3748539-1-songliubraving@fb.com>
This patch introduces side band thread that captures extended information
for events like PERF_RECORD_BPF_EVENT.
This new thread uses its own evlist that uses ring buffer with very low
watermark for lower latency. In the next patch, we uses this thread to
handle PERF_RECORD_BPF_EVENT.
Signed-off-by: Song Liu <songliubraving@fb.com>
---
tools/perf/builtin-record.c | 7 +++
tools/perf/builtin-top.c | 7 +++
tools/perf/util/evlist.c | 100 ++++++++++++++++++++++++++++++++++++
tools/perf/util/evlist.h | 13 +++++
4 files changed, 127 insertions(+)
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 2355e0a9eda0..d10c1d5a9e89 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1106,6 +1106,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
struct perf_data *data = &rec->data;
struct perf_session *session;
bool disabled = false, draining = false;
+ struct perf_evlist_sb_poll_args poll_args;
int fd;
atexit(record__sig_exit);
@@ -1206,6 +1207,10 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
goto out_child;
}
+ poll_args.env = &session->header.env;
+ poll_args.done = &done;
+ perf_evlist__start_polling_thread(&rec->opts.target, &poll_args);
+
err = record__synthesize(rec, false);
if (err < 0)
goto out_child;
@@ -1456,6 +1461,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
out_delete_session:
perf_session__delete(session);
+
+ perf_evlist__stop_polling_thread();
return status;
}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index ccdf5689452f..f41545445917 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1524,6 +1524,7 @@ int cmd_top(int argc, const char **argv)
"number of thread to run event synthesize"),
OPT_END()
};
+ struct perf_evlist_sb_poll_args poll_args;
const char * const top_usage[] = {
"perf top [<options>]",
NULL
@@ -1654,8 +1655,14 @@ int cmd_top(int argc, const char **argv)
top.record_opts.bpf_event = !top.no_bpf_event;
+ poll_args.env = &perf_env;
+ poll_args.done = &done;
+ perf_evlist__start_polling_thread(target, &poll_args);
+
status = __cmd_top(&top);
+ perf_evlist__stop_polling_thread();
+
out_delete_evlist:
perf_evlist__delete(top.evlist);
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 8c902276d4b4..61b87c8111e6 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -19,6 +19,7 @@
#include "debug.h"
#include "units.h"
#include "asm/bug.h"
+#include "bpf-event.h"
#include <signal.h>
#include <unistd.h>
@@ -1841,3 +1842,102 @@ struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list,
}
return leader;
}
+
+static struct perf_evlist *sb_evlist;
+pthread_t poll_thread;
+
+int perf_evlist__new_side_band_event(struct perf_event_attr *attr)
+{
+ struct perf_evsel *evsel;
+
+ if (!sb_evlist)
+ sb_evlist = perf_evlist__new();
+
+ if (!sb_evlist)
+ return -1;
+
+ evsel = perf_evsel__new_idx(attr, sb_evlist->nr_entries);
+ if (!evsel)
+ goto out_err;
+
+ perf_evlist__add(sb_evlist, evsel);
+ return 0;
+
+out_err:
+ perf_evlist__delete(sb_evlist);
+ return -1;
+}
+
+static void *perf_evlist__poll_thread(void *arg)
+{
+ struct perf_evlist_sb_poll_args *args = arg;
+ int i;
+
+ while (!*(args->done)) {
+ perf_evlist__poll(sb_evlist, 1000);
+
+ for (i = 0; i < sb_evlist->nr_mmaps; i++) {
+ struct perf_mmap *map = &sb_evlist->mmap[i];
+ union perf_event *event;
+
+ if (perf_mmap__read_init(map))
+ continue;
+ while ((event = perf_mmap__read_event(map)) != NULL) {
+ pr_debug("processing vip event of type %d\n",
+ event->header.type);
+ switch (event->header.type) {
+ default:
+ break;
+ }
+ perf_mmap__consume(map);
+ }
+ perf_mmap__read_done(map);
+ }
+ }
+ return NULL;
+}
+
+int perf_evlist__start_polling_thread(struct target *target,
+ struct perf_evlist_sb_poll_args *args)
+{
+ struct perf_evsel *counter;
+
+ if (sb_evlist == NULL)
+ return 0;
+
+ if (perf_evlist__create_maps(sb_evlist, target))
+ goto out_delete_evlist;
+
+ evlist__for_each_entry(sb_evlist, counter) {
+ if (perf_evsel__open(counter, sb_evlist->cpus,
+ sb_evlist->threads) < 0)
+ goto out_delete_evlist;
+ }
+
+ if (perf_evlist__mmap(sb_evlist, UINT_MAX))
+ goto out_delete_evlist;
+
+ evlist__for_each_entry(sb_evlist, counter) {
+ if (perf_evsel__enable(counter))
+ goto out_delete_evlist;
+ }
+
+ if (pthread_create(&poll_thread, NULL, perf_evlist__poll_thread, args))
+ goto out_delete_evlist;
+
+ return 0;
+
+out_delete_evlist:
+ perf_evlist__delete(sb_evlist);
+ sb_evlist = NULL;
+ return -1;
+}
+
+void perf_evlist__stop_polling_thread(void)
+{
+ if (!sb_evlist)
+ return;
+ pthread_join(poll_thread, NULL);
+ perf_evlist__exit(sb_evlist);
+ sb_evlist = NULL;
+}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 868294491194..4182e50659e0 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -58,6 +58,12 @@ struct perf_evsel_str_handler {
void *handler;
};
+struct perf_evlist_sb_poll_args {
+ struct perf_env *env;
+
+ volatile int *done;
+};
+
struct perf_evlist *perf_evlist__new(void);
struct perf_evlist *perf_evlist__new_default(void);
struct perf_evlist *perf_evlist__new_dummy(void);
@@ -84,6 +90,13 @@ int __perf_evlist__add_default_attrs(struct perf_evlist *evlist,
int perf_evlist__add_dummy(struct perf_evlist *evlist);
+int perf_evlist__new_side_band_event(struct perf_event_attr *attr);
+
+int perf_evlist__start_polling_thread(struct target *target,
+ struct perf_evlist_sb_poll_args *args);
+
+void perf_evlist__stop_polling_thread(void);
+
int perf_evlist__add_newtp(struct perf_evlist *evlist,
const char *sys, const char *name, void *handler);
--
2.17.1
^ permalink raw reply related
* [PATCH v4 perf,bpf 03/15] bpf: bpftool: use bpf_program__get_prog_info_linear() in prog.c:do_dump()
From: Song Liu @ 2019-02-26 0:20 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu
In-Reply-To: <20190226002019.3748539-1-songliubraving@fb.com>
This patches uses bpf_program__get_prog_info_linear() to simplify the
logic in prog.c do_dump().
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Song Liu <songliubraving@fb.com>
---
tools/bpf/bpftool/prog.c | 266 +++++++++------------------------------
1 file changed, 59 insertions(+), 207 deletions(-)
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index 0640e9bc0ada..206b820df7c2 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -393,41 +393,31 @@ static int do_show(int argc, char **argv)
static int do_dump(int argc, char **argv)
{
- unsigned int finfo_rec_size, linfo_rec_size, jited_linfo_rec_size;
- void *func_info = NULL, *linfo = NULL, *jited_linfo = NULL;
- unsigned int nr_finfo, nr_linfo = 0, nr_jited_linfo = 0;
+ struct bpf_prog_info_linear *info_linear;
struct bpf_prog_linfo *prog_linfo = NULL;
- unsigned long *func_ksyms = NULL;
- struct bpf_prog_info info = {};
- unsigned int *func_lens = NULL;
+ enum {DUMP_JITED, DUMP_XLATED} mode;
const char *disasm_opt = NULL;
- unsigned int nr_func_ksyms;
- unsigned int nr_func_lens;
+ struct bpf_prog_info *info;
struct dump_data dd = {};
- __u32 len = sizeof(info);
+ void *func_info = NULL;
struct btf *btf = NULL;
- unsigned int buf_size;
char *filepath = NULL;
bool opcodes = false;
bool visual = false;
char func_sig[1024];
unsigned char *buf;
bool linum = false;
- __u32 *member_len;
- __u64 *member_ptr;
+ __u32 member_len;
+ __u64 arrays;
ssize_t n;
- int err;
int fd;
if (is_prefix(*argv, "jited")) {
if (disasm_init())
return -1;
-
- member_len = &info.jited_prog_len;
- member_ptr = &info.jited_prog_insns;
+ mode = DUMP_JITED;
} else if (is_prefix(*argv, "xlated")) {
- member_len = &info.xlated_prog_len;
- member_ptr = &info.xlated_prog_insns;
+ mode = DUMP_XLATED;
} else {
p_err("expected 'xlated' or 'jited', got: %s", *argv);
return -1;
@@ -466,175 +456,50 @@ static int do_dump(int argc, char **argv)
return -1;
}
- err = bpf_obj_get_info_by_fd(fd, &info, &len);
- if (err) {
- p_err("can't get prog info: %s", strerror(errno));
- return -1;
- }
-
- if (!*member_len) {
- p_info("no instructions returned");
- close(fd);
- return 0;
- }
+ if (mode == DUMP_JITED)
+ arrays = 1UL << BPF_PROG_INFO_JITED_INSNS;
+ else
+ arrays = 1UL << BPF_PROG_INFO_XLATED_INSNS;
- buf_size = *member_len;
+ arrays |= 1UL << BPF_PROG_INFO_JITED_KSYMS;
+ arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS;
+ arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO;
+ arrays |= 1UL << BPF_PROG_INFO_LINE_INFO;
+ arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO;
- buf = malloc(buf_size);
- if (!buf) {
- p_err("mem alloc failed");
- close(fd);
+ info_linear = bpf_program__get_prog_info_linear(fd, arrays);
+ close(fd);
+ if (IS_ERR_OR_NULL(info_linear)) {
+ p_err("can't get prog info: %s", strerror(errno));
return -1;
}
- nr_func_ksyms = info.nr_jited_ksyms;
- if (nr_func_ksyms) {
- func_ksyms = malloc(nr_func_ksyms * sizeof(__u64));
- if (!func_ksyms) {
- p_err("mem alloc failed");
- close(fd);
- goto err_free;
- }
- }
-
- nr_func_lens = info.nr_jited_func_lens;
- if (nr_func_lens) {
- func_lens = malloc(nr_func_lens * sizeof(__u32));
- if (!func_lens) {
- p_err("mem alloc failed");
- close(fd);
+ info = &info_linear->info;
+ if (mode == DUMP_JITED) {
+ if (info->jited_prog_len == 0) {
+ p_info("no instructions returned");
goto err_free;
}
- }
-
- nr_finfo = info.nr_func_info;
- finfo_rec_size = info.func_info_rec_size;
- if (nr_finfo && finfo_rec_size) {
- func_info = malloc(nr_finfo * finfo_rec_size);
- if (!func_info) {
- p_err("mem alloc failed");
- close(fd);
+ buf = (unsigned char *)(info->jited_prog_insns);
+ member_len = info->jited_prog_len;
+ } else { /* DUMP_XLATED */
+ if (info->xlated_prog_len == 0) {
+ p_err("error retrieving insn dump: kernel.kptr_restrict set?");
goto err_free;
}
+ buf = (unsigned char *)info->xlated_prog_insns;
+ member_len = info->xlated_prog_len;
}
- linfo_rec_size = info.line_info_rec_size;
- if (info.nr_line_info && linfo_rec_size && info.btf_id) {
- nr_linfo = info.nr_line_info;
- linfo = malloc(nr_linfo * linfo_rec_size);
- if (!linfo) {
- p_err("mem alloc failed");
- close(fd);
- goto err_free;
- }
- }
-
- jited_linfo_rec_size = info.jited_line_info_rec_size;
- if (info.nr_jited_line_info &&
- jited_linfo_rec_size &&
- info.nr_jited_ksyms &&
- info.nr_jited_func_lens &&
- info.btf_id) {
- nr_jited_linfo = info.nr_jited_line_info;
- jited_linfo = malloc(nr_jited_linfo * jited_linfo_rec_size);
- if (!jited_linfo) {
- p_err("mem alloc failed");
- close(fd);
- goto err_free;
- }
- }
-
- memset(&info, 0, sizeof(info));
-
- *member_ptr = ptr_to_u64(buf);
- *member_len = buf_size;
- info.jited_ksyms = ptr_to_u64(func_ksyms);
- info.nr_jited_ksyms = nr_func_ksyms;
- info.jited_func_lens = ptr_to_u64(func_lens);
- info.nr_jited_func_lens = nr_func_lens;
- info.nr_func_info = nr_finfo;
- info.func_info_rec_size = finfo_rec_size;
- info.func_info = ptr_to_u64(func_info);
- info.nr_line_info = nr_linfo;
- info.line_info_rec_size = linfo_rec_size;
- info.line_info = ptr_to_u64(linfo);
- info.nr_jited_line_info = nr_jited_linfo;
- info.jited_line_info_rec_size = jited_linfo_rec_size;
- info.jited_line_info = ptr_to_u64(jited_linfo);
-
- err = bpf_obj_get_info_by_fd(fd, &info, &len);
- close(fd);
- if (err) {
- p_err("can't get prog info: %s", strerror(errno));
- goto err_free;
- }
-
- if (*member_len > buf_size) {
- p_err("too many instructions returned");
- goto err_free;
- }
-
- if (info.nr_jited_ksyms > nr_func_ksyms) {
- p_err("too many addresses returned");
- goto err_free;
- }
-
- if (info.nr_jited_func_lens > nr_func_lens) {
- p_err("too many values returned");
- goto err_free;
- }
-
- if (info.nr_func_info != nr_finfo) {
- p_err("incorrect nr_func_info %d vs. expected %d",
- info.nr_func_info, nr_finfo);
- goto err_free;
- }
-
- if (info.func_info_rec_size != finfo_rec_size) {
- p_err("incorrect func_info_rec_size %d vs. expected %d",
- info.func_info_rec_size, finfo_rec_size);
- goto err_free;
- }
-
- if (linfo && info.nr_line_info != nr_linfo) {
- p_err("incorrect nr_line_info %u vs. expected %u",
- info.nr_line_info, nr_linfo);
- goto err_free;
- }
-
- if (info.line_info_rec_size != linfo_rec_size) {
- p_err("incorrect line_info_rec_size %u vs. expected %u",
- info.line_info_rec_size, linfo_rec_size);
- goto err_free;
- }
-
- if (jited_linfo && info.nr_jited_line_info != nr_jited_linfo) {
- p_err("incorrect nr_jited_line_info %u vs. expected %u",
- info.nr_jited_line_info, nr_jited_linfo);
- goto err_free;
- }
-
- if (info.jited_line_info_rec_size != jited_linfo_rec_size) {
- p_err("incorrect jited_line_info_rec_size %u vs. expected %u",
- info.jited_line_info_rec_size, jited_linfo_rec_size);
- goto err_free;
- }
-
- if ((member_len == &info.jited_prog_len &&
- info.jited_prog_insns == 0) ||
- (member_len == &info.xlated_prog_len &&
- info.xlated_prog_insns == 0)) {
- p_err("error retrieving insn dump: kernel.kptr_restrict set?");
- goto err_free;
- }
-
- if (info.btf_id && btf__get_from_id(info.btf_id, &btf)) {
+ if (info->btf_id && btf__get_from_id(info->btf_id, &btf)) {
p_err("failed to get btf");
goto err_free;
}
- if (nr_linfo) {
- prog_linfo = bpf_prog_linfo__new(&info);
+ func_info = (void *)info->func_info;
+
+ if (info->nr_line_info) {
+ prog_linfo = bpf_prog_linfo__new(info);
if (!prog_linfo)
p_info("error in processing bpf_line_info. continue without it.");
}
@@ -647,9 +512,9 @@ static int do_dump(int argc, char **argv)
goto err_free;
}
- n = write(fd, buf, *member_len);
+ n = write(fd, buf, member_len);
close(fd);
- if (n != *member_len) {
+ if (n != member_len) {
p_err("error writing output file: %s",
n < 0 ? strerror(errno) : "short write");
goto err_free;
@@ -657,19 +522,19 @@ static int do_dump(int argc, char **argv)
if (json_output)
jsonw_null(json_wtr);
- } else if (member_len == &info.jited_prog_len) {
+ } else if (mode == DUMP_JITED) {
const char *name = NULL;
- if (info.ifindex) {
- name = ifindex_to_bfd_params(info.ifindex,
- info.netns_dev,
- info.netns_ino,
+ if (info->ifindex) {
+ name = ifindex_to_bfd_params(info->ifindex,
+ info->netns_dev,
+ info->netns_ino,
&disasm_opt);
if (!name)
goto err_free;
}
- if (info.nr_jited_func_lens && info.jited_func_lens) {
+ if (info->nr_jited_func_lens && info->jited_func_lens) {
struct kernel_sym *sym = NULL;
struct bpf_func_info *record;
char sym_name[SYM_MAX_NAME];
@@ -677,17 +542,16 @@ static int do_dump(int argc, char **argv)
__u64 *ksyms = NULL;
__u32 *lens;
__u32 i;
-
- if (info.nr_jited_ksyms) {
+ if (info->nr_jited_ksyms) {
kernel_syms_load(&dd);
- ksyms = (__u64 *) info.jited_ksyms;
+ ksyms = (__u64 *) info->jited_ksyms;
}
if (json_output)
jsonw_start_array(json_wtr);
- lens = (__u32 *) info.jited_func_lens;
- for (i = 0; i < info.nr_jited_func_lens; i++) {
+ lens = (__u32 *) info->jited_func_lens;
+ for (i = 0; i < info->nr_jited_func_lens; i++) {
if (ksyms) {
sym = kernel_syms_search(&dd, ksyms[i]);
if (sym)
@@ -699,7 +563,7 @@ static int do_dump(int argc, char **argv)
}
if (func_info) {
- record = func_info + i * finfo_rec_size;
+ record = func_info + i * info->func_info_rec_size;
btf_dumper_type_only(btf, record->type_id,
func_sig,
sizeof(func_sig));
@@ -736,49 +600,37 @@ static int do_dump(int argc, char **argv)
if (json_output)
jsonw_end_array(json_wtr);
} else {
- disasm_print_insn(buf, *member_len, opcodes, name,
+ disasm_print_insn(buf, member_len, opcodes, name,
disasm_opt, btf, NULL, 0, 0, false);
}
} else if (visual) {
if (json_output)
jsonw_null(json_wtr);
else
- dump_xlated_cfg(buf, *member_len);
+ dump_xlated_cfg(buf, member_len);
} else {
kernel_syms_load(&dd);
- dd.nr_jited_ksyms = info.nr_jited_ksyms;
- dd.jited_ksyms = (__u64 *) info.jited_ksyms;
+ dd.nr_jited_ksyms = info->nr_jited_ksyms;
+ dd.jited_ksyms = (__u64 *) info->jited_ksyms;
dd.btf = btf;
dd.func_info = func_info;
- dd.finfo_rec_size = finfo_rec_size;
+ dd.finfo_rec_size = info->func_info_rec_size;
dd.prog_linfo = prog_linfo;
if (json_output)
- dump_xlated_json(&dd, buf, *member_len, opcodes,
+ dump_xlated_json(&dd, buf, member_len, opcodes,
linum);
else
- dump_xlated_plain(&dd, buf, *member_len, opcodes,
+ dump_xlated_plain(&dd, buf, member_len, opcodes,
linum);
kernel_syms_destroy(&dd);
}
- free(buf);
- free(func_ksyms);
- free(func_lens);
- free(func_info);
- free(linfo);
- free(jited_linfo);
- bpf_prog_linfo__free(prog_linfo);
+ free(info_linear);
return 0;
err_free:
- free(buf);
- free(func_ksyms);
- free(func_lens);
- free(func_info);
- free(linfo);
- free(jited_linfo);
- bpf_prog_linfo__free(prog_linfo);
+ free(info_linear);
return -1;
}
--
2.17.1
^ permalink raw reply related
* [PATCH v4 perf,bpf 02/15] bpf: libbpf: introduce bpf_program__get_prog_info_linear()
From: Song Liu @ 2019-02-26 0:20 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu
In-Reply-To: <20190226002019.3748539-1-songliubraving@fb.com>
Currently, bpf_prog_info includes 9 arrays. The user has the option to
fetch any combination of these arrays. However, this requires a lot of
handling of these arrays. This work becomes more tricky when we need to
store bpf_prog_info to a file, because these arrays are allocated
independently.
This patch introduces struct bpf_prog_info_linear, which stores arrays
of bpf_prog_info in continues memory. Helper functions are introduced
to unify the work to get different information of bpf_prog_info.
Specifically, bpf_program__get_prog_info_linear() allows the user to
select which arrays to fetch, and handles details for the user.
Plesae see the comments before enum bpf_prog_info_array for more details
and examples.
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Song Liu <songliubraving@fb.com>
---
tools/lib/bpf/libbpf.c | 251 +++++++++++++++++++++++++++++++++++++++
tools/lib/bpf/libbpf.h | 63 ++++++++++
tools/lib/bpf/libbpf.map | 3 +
3 files changed, 317 insertions(+)
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index b38dcbe7460a..fa12729de283 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -112,6 +112,11 @@ void libbpf_print(enum libbpf_print_level level, const char *format, ...)
# define LIBBPF_ELF_C_READ_MMAP ELF_C_READ
#endif
+static inline __u64 ptr_to_u64(const void *ptr)
+{
+ return (__u64) (unsigned long) ptr;
+}
+
struct bpf_capabilities {
/* v4.14: kernel support for program & map names. */
__u32 name:1;
@@ -2997,3 +3002,249 @@ bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size,
ring_buffer_write_tail(header, data_tail);
return ret;
}
+
+struct bpf_prog_info_array_desc {
+ int array_offset; /* e.g. offset of jited_prog_insns */
+ int count_offset; /* e.g. offset of jited_prog_len */
+ int size_offset; /* > 0: offset of rec size,
+ * < 0: fix size of -size_offset
+ */
+};
+
+static struct bpf_prog_info_array_desc bpf_prog_info_array_desc[] = {
+ [BPF_PROG_INFO_JITED_INSNS] = {
+ offsetof(struct bpf_prog_info, jited_prog_insns),
+ offsetof(struct bpf_prog_info, jited_prog_len),
+ -1,
+ },
+ [BPF_PROG_INFO_XLATED_INSNS] = {
+ offsetof(struct bpf_prog_info, xlated_prog_insns),
+ offsetof(struct bpf_prog_info, xlated_prog_len),
+ -1,
+ },
+ [BPF_PROG_INFO_MAP_IDS] = {
+ offsetof(struct bpf_prog_info, map_ids),
+ offsetof(struct bpf_prog_info, nr_map_ids),
+ -(int)sizeof(__u32),
+ },
+ [BPF_PROG_INFO_JITED_KSYMS] = {
+ offsetof(struct bpf_prog_info, jited_ksyms),
+ offsetof(struct bpf_prog_info, nr_jited_ksyms),
+ -(int)sizeof(__u64),
+ },
+ [BPF_PROG_INFO_JITED_FUNC_LENS] = {
+ offsetof(struct bpf_prog_info, jited_func_lens),
+ offsetof(struct bpf_prog_info, nr_jited_func_lens),
+ -(int)sizeof(__u32),
+ },
+ [BPF_PROG_INFO_FUNC_INFO] = {
+ offsetof(struct bpf_prog_info, func_info),
+ offsetof(struct bpf_prog_info, nr_func_info),
+ offsetof(struct bpf_prog_info, func_info_rec_size),
+ },
+ [BPF_PROG_INFO_LINE_INFO] = {
+ offsetof(struct bpf_prog_info, line_info),
+ offsetof(struct bpf_prog_info, nr_line_info),
+ offsetof(struct bpf_prog_info, line_info_rec_size),
+ },
+ [BPF_PROG_INFO_JITED_LINE_INFO] = {
+ offsetof(struct bpf_prog_info, jited_line_info),
+ offsetof(struct bpf_prog_info, nr_jited_line_info),
+ offsetof(struct bpf_prog_info, jited_line_info_rec_size),
+ },
+ [BPF_PROG_INFO_PROG_TAGS] = {
+ offsetof(struct bpf_prog_info, prog_tags),
+ offsetof(struct bpf_prog_info, nr_prog_tags),
+ -(int)sizeof(__u8) * BPF_TAG_SIZE,
+ },
+
+};
+
+static __u32 bpf_prog_info_read_offset_u32(struct bpf_prog_info *info, int offset)
+{
+ __u32 *array = (__u32 *)info;
+
+ if (offset >= 0)
+ return array[offset / sizeof(__u32)];
+ return -(int)offset;
+}
+
+static __u64 bpf_prog_info_read_offset_u64(struct bpf_prog_info *info, int offset)
+{
+ __u64 *array = (__u64 *)info;
+
+ if (offset >= 0)
+ return array[offset / sizeof(__u64)];
+ return -(int)offset;
+}
+
+static void bpf_prog_info_set_offset_u32(struct bpf_prog_info *info, int offset,
+ __u32 val)
+{
+ __u32 *array = (__u32 *)info;
+
+ if (offset >= 0)
+ array[offset / sizeof(__u32)] = val;
+}
+
+static void bpf_prog_info_set_offset_u64(struct bpf_prog_info *info, int offset,
+ __u64 val)
+{
+ __u64 *array = (__u64 *)info;
+
+ if (offset >= 0)
+ array[offset / sizeof(__u64)] = val;
+}
+
+struct bpf_prog_info_linear *
+bpf_program__get_prog_info_linear(int fd, __u64 arrays)
+{
+ struct bpf_prog_info_linear *info_linear;
+ struct bpf_prog_info info = {};
+ __u32 info_len = sizeof(info);
+ __u32 data_len = 0;
+ int i, err;
+ void *ptr;
+
+ if (arrays >> BPF_PROG_INFO_LAST_ARRAY)
+ return ERR_PTR(-EINVAL);
+
+ /* step 1: get array dimensions */
+ err = bpf_obj_get_info_by_fd(fd, &info, &info_len);
+ if (err) {
+ pr_debug("can't get prog info: %s", strerror(errno));
+ return ERR_PTR(-EFAULT);
+ }
+
+ /* step 2: calculate total size of all arrays */
+ for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
+ bool include_array = (arrays & (1UL << i)) > 0;
+ struct bpf_prog_info_array_desc *desc;
+ __u32 count, size;
+
+ desc = bpf_prog_info_array_desc + i;
+
+ /* kernel is too old to support this field */
+ if (info_len < desc->array_offset + sizeof(__u32) ||
+ info_len < desc->count_offset + sizeof(__u32) ||
+ (desc->size_offset > 0 && info_len < desc->size_offset))
+ include_array = false;
+
+ if (!include_array) {
+ arrays &= ~(1UL << i); /* clear the bit */
+ continue;
+ }
+
+ count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
+ size = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
+
+ data_len += count * size;
+ }
+
+ /* step 3: allocate continuous memory */
+ data_len = roundup(data_len, sizeof(__u64));
+ info_linear = malloc(sizeof(struct bpf_prog_info_linear) + data_len);
+ if (!info_linear)
+ return ERR_PTR(-ENOMEM);
+
+ /* step 4: fill data to info_linear->info */
+ info_linear->arrays = arrays;
+ memset(&info_linear->info, 0, sizeof(info));
+ ptr = info_linear->data;
+
+ for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
+ struct bpf_prog_info_array_desc *desc;
+ __u32 count, size;
+
+ if ((arrays & (1UL << i)) == 0)
+ continue;
+
+ desc = bpf_prog_info_array_desc + i;
+ count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
+ size = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
+ bpf_prog_info_set_offset_u32(&info_linear->info,
+ desc->count_offset, count);
+ bpf_prog_info_set_offset_u32(&info_linear->info,
+ desc->size_offset, size);
+ bpf_prog_info_set_offset_u64(&info_linear->info,
+ desc->array_offset,
+ ptr_to_u64(ptr));
+ ptr += count * size;
+ }
+
+ /* step 5: call syscall again to get required arrays */
+ err = bpf_obj_get_info_by_fd(fd, &info_linear->info, &info_len);
+ if (err) {
+ pr_debug("can't get prog info: %s", strerror(errno));
+ free(info_linear);
+ return ERR_PTR(-EFAULT);
+ }
+
+ /* step 6: verify the data */
+ for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
+ struct bpf_prog_info_array_desc *desc;
+ __u32 v1, v2;
+
+ if ((arrays & (1UL << i)) == 0)
+ continue;
+
+ desc = bpf_prog_info_array_desc + i;
+ v1 = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
+ v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
+ desc->count_offset);
+ if (v1 != v2)
+ pr_warning("%s: mismatch in element count\n", __func__);
+
+ v1 = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
+ v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
+ desc->size_offset);
+ if (v1 != v2)
+ pr_warning("%s: mismatch in rec size\n", __func__);
+ }
+
+ /* step 7: update info_len and data_len */
+ info_linear->info_len = sizeof(struct bpf_prog_info);
+ info_linear->data_len = data_len;
+
+ return info_linear;
+}
+
+void bpf_program__bpil_addr_to_offs(struct bpf_prog_info_linear *info_linear)
+{
+ int i;
+
+ for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
+ struct bpf_prog_info_array_desc *desc;
+ __u64 addr, offs;
+
+ if ((info_linear->arrays & (1UL << i)) == 0)
+ continue;
+
+ desc = bpf_prog_info_array_desc + i;
+ addr = bpf_prog_info_read_offset_u64(&info_linear->info,
+ desc->array_offset);
+ offs = addr - ptr_to_u64(info_linear->data);
+ bpf_prog_info_set_offset_u64(&info_linear->info,
+ desc->array_offset, offs);
+ }
+}
+
+void bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear)
+{
+ int i;
+
+ for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
+ struct bpf_prog_info_array_desc *desc;
+ __u64 addr, offs;
+
+ if ((info_linear->arrays & (1UL << i)) == 0)
+ continue;
+
+ desc = bpf_prog_info_array_desc + i;
+ offs = bpf_prog_info_read_offset_u64(&info_linear->info,
+ desc->array_offset);
+ addr = offs + ptr_to_u64(info_linear->data);
+ bpf_prog_info_set_offset_u64(&info_linear->info,
+ desc->array_offset, addr);
+ }
+}
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 6c0168f8bba5..809275c47bb5 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -376,6 +376,69 @@ LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex);
LIBBPF_API bool bpf_probe_helper(enum bpf_func_id id,
enum bpf_prog_type prog_type, __u32 ifindex);
+/*
+ * Get bpf_prog_info in continuous memory
+ *
+ * struct bpf_prog_info has multiple arrays. The user has option to choose
+ * arrays to fetch from kernel. The following APIs provide uniform way to
+ * fetch these data. All arrays in bpf_prog_info are stored in singile
+ * continuous memory region. This makes it easy to store the info in a
+ * file.
+ *
+ * Before writing bpf_prog_info_linear to files, it is necessary to
+ * translate pointers bpf_prog_info to offsets. Helper functions
+ * bpf_program__bpil_addr_to_offs() and bpf_program__bpil_offs_to_addr()
+ * are introduced to switch between pointers and offsets.
+ *
+ * Examples:
+ * # To fetch map_ids and prog_tags:
+ * __u64 arrays = (1UL << BPF_PROG_INFO_MAP_IDS) |
+ * (1UL << BPF_PROG_INFO_PROG_TAGS);
+ * struct bpf_prog_info_linear *info_linear =
+ * bpf_program__get_prog_info_linear(fd, arrays);
+ *
+ * # To save data in file
+ * bpf_program__bpil_addr_to_offs(info_linear);
+ * write(f, info_linear, sizeof(*info_linear) + info_linear->data_len);
+ *
+ * # To read data from file
+ * read(f, info_linear, <proper_size>);
+ * bpf_program__bpil_offs_to_addr(info_linear);
+ */
+enum bpf_prog_info_array {
+ BPF_PROG_INFO_FIRST_ARRAY = 0,
+ BPF_PROG_INFO_JITED_INSNS = 0,
+ BPF_PROG_INFO_XLATED_INSNS,
+ BPF_PROG_INFO_MAP_IDS,
+ BPF_PROG_INFO_JITED_KSYMS,
+ BPF_PROG_INFO_JITED_FUNC_LENS,
+ BPF_PROG_INFO_FUNC_INFO,
+ BPF_PROG_INFO_LINE_INFO,
+ BPF_PROG_INFO_JITED_LINE_INFO,
+ BPF_PROG_INFO_PROG_TAGS,
+ BPF_PROG_INFO_LAST_ARRAY,
+};
+
+struct bpf_prog_info_linear {
+ /* size of struct bpf_prog_info, when the tool is compiled */
+ __u32 info_len;
+ /* total bytes allocated for data, round up to 8 bytes */
+ __u32 data_len;
+ /* which arrays are included in data */
+ __u64 arrays;
+ struct bpf_prog_info info;
+ __u8 data[];
+};
+
+LIBBPF_API struct bpf_prog_info_linear *
+bpf_program__get_prog_info_linear(int fd, __u64 arrays);
+
+LIBBPF_API void
+bpf_program__bpil_addr_to_offs(struct bpf_prog_info_linear *info_linear);
+
+LIBBPF_API void
+bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear);
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index 99dfa710c818..24616162447e 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -147,4 +147,7 @@ LIBBPF_0.0.2 {
btf_ext__new;
btf_ext__reloc_func_info;
btf_ext__reloc_line_info;
+ bpf_program__get_prog_info_linear;
+ bpf_program__bpil_addr_to_offs;
+ bpf_program__bpil_offs_to_addr;
} LIBBPF_0.0.1;
--
2.17.1
^ permalink raw reply related
* [PATCH v4 perf,bpf 07/15] perf, bpf: save bpf_prog_info information as headers to perf.data
From: Song Liu @ 2019-02-26 0:20 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu
In-Reply-To: <20190226002019.3748539-1-songliubraving@fb.com>
This patch enables perf-record to save bpf_prog_info information as
headers to perf.data. A new header type HEADER_BPF_PROG_INFO is
introduced for this data.
Signed-off-by: Song Liu <songliubraving@fb.com>
---
| 143 ++++++++++++++++++++++++++++++++++++++-
| 1 +
2 files changed, 143 insertions(+), 1 deletion(-)
--git a/tools/perf/util/header.c b/tools/perf/util/header.c
index dec6d218c31c..c89dce7942d1 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -18,6 +18,7 @@
#include <sys/utsname.h>
#include <linux/time64.h>
#include <dirent.h>
+#include <bpf/libbpf.h>
#include "evlist.h"
#include "evsel.h"
@@ -39,6 +40,7 @@
#include "tool.h"
#include "time-utils.h"
#include "units.h"
+#include "bpf-event.h"
#include "sane_ctype.h"
@@ -1080,6 +1082,51 @@ static int write_clockid(struct feat_fd *ff,
sizeof(ff->ph->env.clockid_res_ns));
}
+static int write_bpf_prog_info(struct feat_fd *ff,
+ struct perf_evlist *evlist __maybe_unused)
+{
+ struct perf_env *env = &ff->ph->env;
+ struct rb_root *root;
+ struct rb_node *next;
+ u32 count = 0;
+ int ret;
+
+ down_read(&env->bpf_progs.lock);
+
+ root = &env->bpf_progs.prog_infos;
+ next = rb_first(root);
+ while (next) {
+ ++count;
+ next = rb_next(next);
+ }
+
+ ret = do_write(ff, &count, sizeof(count));
+
+ if (ret < 0)
+ goto out;
+
+ next = rb_first(root);
+ while (next) {
+ struct bpf_prog_info_node *node;
+ size_t len;
+
+ node = rb_entry(next, struct bpf_prog_info_node, rb_node);
+ next = rb_next(&node->rb_node);
+ len = sizeof(struct bpf_prog_info_linear) +
+ node->info_linear->data_len;
+
+ /* before writing to file, translate address to offset */
+ bpf_program__bpil_addr_to_offs(node->info_linear);
+ ret = do_write(ff, node->info_linear, len);
+ bpf_program__bpil_offs_to_addr(node->info_linear);
+ if (ret < 0)
+ goto out;
+ }
+out:
+ up_read(&env->bpf_progs.lock);
+ return ret;
+}
+
static int cpu_cache_level__sort(const void *a, const void *b)
{
struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a;
@@ -1560,6 +1607,29 @@ static void print_clockid(struct feat_fd *ff, FILE *fp)
ff->ph->env.clockid_res_ns * 1000);
}
+static void print_bpf_prog_info(struct feat_fd *ff, FILE *fp)
+{
+ struct perf_env *env = &ff->ph->env;
+ struct rb_root *root;
+ struct rb_node *next;
+
+ down_read(&env->bpf_progs.lock);
+
+ root = &env->bpf_progs.prog_infos;
+ next = rb_first(root);
+
+ while (next) {
+ struct bpf_prog_info_node *node;
+
+ node = rb_entry(next, struct bpf_prog_info_node, rb_node);
+ next = rb_next(&node->rb_node);
+ fprintf(fp, "# bpf_prog_info of id %u\n",
+ node->info_linear->info.id);
+ }
+
+ up_read(&env->bpf_progs.lock);
+}
+
static void free_event_desc(struct perf_evsel *events)
{
struct perf_evsel *evsel;
@@ -2592,6 +2662,76 @@ static int process_clockid(struct feat_fd *ff,
return 0;
}
+static int process_bpf_prog_info(struct feat_fd *ff,
+ void *data __maybe_unused)
+{
+ struct bpf_prog_info_linear *info_linear;
+ struct bpf_prog_info_node *info_node;
+ struct perf_env *env = &ff->ph->env;
+ u32 count, i;
+ int err = -1;
+
+ if (do_read_u32(ff, &count))
+ return -1;
+
+ down_write(&env->bpf_progs.lock);
+
+ for (i = 0; i < count; ++i) {
+ u32 info_len, data_len;
+
+ info_linear = NULL;
+ info_node = NULL;
+ if (do_read_u32(ff, &info_len))
+ goto out;
+ if (do_read_u32(ff, &data_len))
+ goto out;
+
+ if (info_len > sizeof(struct bpf_prog_info)) {
+ pr_warning("detected invalid bpf_prog_info\n");
+ goto out;
+ }
+
+ info_linear = malloc(sizeof(struct bpf_prog_info_linear) +
+ data_len);
+ if (!info_linear)
+ goto out;
+ info_linear->info_len = sizeof(struct bpf_prog_info);
+ info_linear->data_len = data_len;
+ if (do_read_u64(ff, (u64 *)(&info_linear->arrays)))
+ goto out;
+ if (__do_read(ff, &info_linear->info, info_len))
+ goto out;
+ if (info_len < sizeof(struct bpf_prog_info))
+ memset(((void *)(&info_linear->info)) + info_len, 0,
+ sizeof(struct bpf_prog_info) - info_len);
+
+ if (__do_read(ff, info_linear->data, data_len))
+ goto out;
+
+ /* endian mismatch, drop the info, continue */
+ if (ff->ph->needs_swap) {
+ free(info_linear);
+ continue;
+ }
+
+ info_node = malloc(sizeof(struct bpf_prog_info_node));
+ if (!info_node)
+ goto out;
+
+ /* after reading from file, translate offset to address */
+ bpf_program__bpil_offs_to_addr(info_linear);
+ info_node->info_linear = info_linear;
+ perf_env__insert_bpf_prog_info(env, info_node);
+ }
+
+ return 0;
+out:
+ free(info_linear);
+ free(info_node);
+ up_write(&env->bpf_progs.lock);
+ return err;
+}
+
struct feature_ops {
int (*write)(struct feat_fd *ff, struct perf_evlist *evlist);
void (*print)(struct feat_fd *ff, FILE *fp);
@@ -2651,7 +2791,8 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
FEAT_OPN(CACHE, cache, true),
FEAT_OPR(SAMPLE_TIME, sample_time, false),
FEAT_OPR(MEM_TOPOLOGY, mem_topology, true),
- FEAT_OPR(CLOCKID, clockid, false)
+ FEAT_OPR(CLOCKID, clockid, false),
+ FEAT_OPR(BPF_PROG_INFO, bpf_prog_info, false)
};
struct header_print_data {
--git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 0d553ddca0a3..0785c91b4c3a 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -39,6 +39,7 @@ enum {
HEADER_SAMPLE_TIME,
HEADER_MEM_TOPOLOGY,
HEADER_CLOCKID,
+ HEADER_BPF_PROG_INFO,
HEADER_LAST_FEATURE,
HEADER_FEAT_BITS = 256,
};
--
2.17.1
^ permalink raw reply related
* [PATCH v4 perf,bpf 08/15] perf, bpf: save btf in a rbtree in perf_env
From: Song Liu @ 2019-02-26 0:20 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu
In-Reply-To: <20190226002019.3748539-1-songliubraving@fb.com>
btf contains information necessary to annotate bpf programs. This patch
saves btf for bpf programs loaded in the system.
Signed-off-by: Song Liu <songliubraving@fb.com>
---
tools/perf/util/bpf-event.c | 24 ++++++++++++++
tools/perf/util/bpf-event.h | 7 ++++
tools/perf/util/env.c | 65 +++++++++++++++++++++++++++++++++++++
tools/perf/util/env.h | 4 +++
4 files changed, 100 insertions(+)
diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index ce81b2c43a51..370b830f2433 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -34,6 +34,29 @@ int machine__process_bpf_event(struct machine *machine __maybe_unused,
return 0;
}
+static int perf_env__fetch_btf(struct perf_env *env,
+ u32 btf_id,
+ struct btf *btf)
+{
+ struct btf_node *node;
+ u32 data_size;
+ const void *data;
+
+ data = btf__get_raw_data(btf, &data_size);
+
+ node = malloc(data_size + sizeof(struct btf_node));
+
+ if (!node)
+ return -1;
+
+ node->id = btf_id;
+ node->data_size = data_size;
+ memcpy(node->data, data, data_size);
+
+ perf_env__insert_btf(env, node);
+ return 0;
+}
+
/*
* Synthesize PERF_RECORD_KSYMBOL and PERF_RECORD_BPF_EVENT for one bpf
* program. One PERF_RECORD_BPF_EVENT is generated for the program. And
@@ -113,6 +136,7 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
goto out;
}
has_btf = true;
+ perf_env__fetch_btf(env, info->btf_id, btf);
}
/* Synthesize PERF_RECORD_KSYMBOL */
diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h
index fad932f7404f..b9ec394dc7c7 100644
--- a/tools/perf/util/bpf-event.h
+++ b/tools/perf/util/bpf-event.h
@@ -16,6 +16,13 @@ struct bpf_prog_info_node {
struct rb_node rb_node;
};
+struct btf_node {
+ struct rb_node rb_node;
+ u32 id;
+ u32 data_size;
+ char data[];
+};
+
#ifdef HAVE_LIBBPF_SUPPORT
int machine__process_bpf_event(struct machine *machine, union perf_event *event,
struct perf_sample *sample);
diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index 650c14ad7e9b..291b21d8f858 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -63,6 +63,57 @@ struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
return node;
}
+void perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node)
+{
+ struct rb_node *parent = NULL;
+ __u32 btf_id = btf_node->id;
+ struct btf_node *node;
+ struct rb_node **p;
+
+ down_write(&env->bpf_progs.lock);
+ p = &env->bpf_progs.btfs.rb_node;
+
+ while (*p != NULL) {
+ parent = *p;
+ node = rb_entry(parent, struct btf_node, rb_node);
+ if (btf_id < node->id) {
+ p = &(*p)->rb_left;
+ } else if (btf_id > node->id) {
+ p = &(*p)->rb_right;
+ } else {
+ pr_debug("duplicated btf %u\n", btf_id);
+ goto out;
+ }
+ }
+
+ rb_link_node(&btf_node->rb_node, parent, p);
+ rb_insert_color(&btf_node->rb_node, &env->bpf_progs.btfs);
+out:
+ up_write(&env->bpf_progs.lock);
+}
+
+struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id)
+{
+ struct btf_node *node = NULL;
+ struct rb_node *n;
+
+ down_read(&env->bpf_progs.lock);
+ n = env->bpf_progs.btfs.rb_node;
+
+ while (n) {
+ node = rb_entry(n, struct btf_node, rb_node);
+ if (btf_id < node->id)
+ n = n->rb_left;
+ else if (btf_id > node->id)
+ n = n->rb_right;
+ else
+ break;
+ }
+
+ up_read(&env->bpf_progs.lock);
+ return node;
+}
+
/* purge data in bpf_prog_infos tree */
static void perf_env__purge_bpf(struct perf_env *env)
{
@@ -82,6 +133,19 @@ static void perf_env__purge_bpf(struct perf_env *env)
rb_erase_init(&node->rb_node, root);
free(node);
}
+
+ root = &env->bpf_progs.btfs;
+ next = rb_first(root);
+
+ while (next) {
+ struct btf_node *node;
+
+ node = rb_entry(next, struct btf_node, rb_node);
+ next = rb_next(&node->rb_node);
+ rb_erase_init(&node->rb_node, root);
+ free(node);
+ }
+
up_write(&env->bpf_progs.lock);
}
@@ -119,6 +183,7 @@ void perf_env__exit(struct perf_env *env)
static void init_bpf_rb_trees(struct perf_env *env)
{
env->bpf_progs.prog_infos = RB_ROOT;
+ env->bpf_progs.btfs = RB_ROOT;
init_rwsem(&env->bpf_progs.lock);
}
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index 33ef4b2d2a29..b7fc4c71ba6a 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -74,10 +74,12 @@ struct perf_env {
struct {
struct rw_semaphore lock;
struct rb_root prog_infos;
+ struct rb_root btfs;
} bpf_progs;
};
struct bpf_prog_info_node;
+struct btf_node;
extern struct perf_env perf_env;
@@ -97,4 +99,6 @@ void perf_env__insert_bpf_prog_info(struct perf_env *env,
struct bpf_prog_info_node *info_node);
struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
__u32 prog_id);
+void perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node);
+struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id);
#endif /* __PERF_ENV_H */
--
2.17.1
^ permalink raw reply related
* [PATCH v4 perf,bpf 06/15] perf, bpf: save bpf_prog_info in a rbtree in perf_env
From: Song Liu @ 2019-02-26 0:20 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: ast, daniel, kernel-team, peterz, acme, jolsa, namhyung, Song Liu
In-Reply-To: <20190226002019.3748539-1-songliubraving@fb.com>
bpf_prog_info contains information necessary to annotate bpf programs.
This patch saves bpf_prog_info for bpf programs loaded in the system.
Signed-off-by: Song Liu <songliubraving@fb.com>
---
tools/perf/util/bpf-event.c | 32 +++++++++++++-
tools/perf/util/bpf-event.h | 7 ++-
tools/perf/util/env.c | 85 +++++++++++++++++++++++++++++++++++++
tools/perf/util/env.h | 17 ++++++++
4 files changed, 139 insertions(+), 2 deletions(-)
diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index ff7ee149ec46..ce81b2c43a51 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -10,6 +10,7 @@
#include "debug.h"
#include "symbol.h"
#include "machine.h"
+#include "env.h"
#include "session.h"
#define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr))
@@ -54,17 +55,28 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
struct bpf_event *bpf_event = &event->bpf_event;
struct bpf_prog_info_linear *info_linear;
struct perf_tool *tool = session->tool;
+ struct bpf_prog_info_node *info_node;
struct bpf_prog_info *info;
struct btf *btf = NULL;
bool has_btf = false;
+ struct perf_env *env;
u32 sub_prog_cnt, i;
int err = 0;
u64 arrays;
+ /*
+ * for perf-record and perf-report use header.env;
+ * otherwise, use global perf_env.
+ */
+ env = session->data ? &session->header.env : &perf_env;
+
arrays = 1UL << BPF_PROG_INFO_JITED_KSYMS;
arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS;
arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO;
arrays |= 1UL << BPF_PROG_INFO_PROG_TAGS;
+ arrays |= 1UL << BPF_PROG_INFO_JITED_INSNS;
+ arrays |= 1UL << BPF_PROG_INFO_LINE_INFO;
+ arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO;
info_linear = bpf_program__get_prog_info_linear(fd, arrays);
if (IS_ERR_OR_NULL(info_linear)) {
@@ -153,8 +165,8 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
machine, process);
}
- /* Synthesize PERF_RECORD_BPF_EVENT */
if (opts->bpf_event) {
+ /* Synthesize PERF_RECORD_BPF_EVENT */
*bpf_event = (struct bpf_event){
.header = {
.type = PERF_RECORD_BPF_EVENT,
@@ -167,6 +179,24 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
memcpy(bpf_event->tag, info->tag, BPF_TAG_SIZE);
memset((void *)event + event->header.size, 0, machine->id_hdr_size);
event->header.size += machine->id_hdr_size;
+
+ /* save bpf_prog_info to env */
+ info_node = malloc(sizeof(struct bpf_prog_info_node));
+
+ /*
+ * Do not bail out for !info_node, as we still want to
+ * call perf_tool__process_synth_event()
+ */
+ if (info_node) {
+ info_node->info_linear = info_linear;
+ perf_env__insert_bpf_prog_info(env, info_node);
+ info_linear = NULL;
+ }
+
+ /*
+ * process after saving bpf_prog_info to env, so that
+ * required information is ready for look up
+ */
err = perf_tool__process_synth_event(tool, event,
machine, process);
}
diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h
index 6698683612a7..fad932f7404f 100644
--- a/tools/perf/util/bpf-event.h
+++ b/tools/perf/util/bpf-event.h
@@ -3,14 +3,19 @@
#define __PERF_BPF_EVENT_H
#include <linux/compiler.h>
+#include <linux/rbtree.h>
#include "event.h"
struct machine;
union perf_event;
struct perf_sample;
-struct perf_tool;
struct record_opts;
+struct bpf_prog_info_node {
+ struct bpf_prog_info_linear *info_linear;
+ struct rb_node rb_node;
+};
+
#ifdef HAVE_LIBBPF_SUPPORT
int machine__process_bpf_event(struct machine *machine, union perf_event *event,
struct perf_sample *sample);
diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index 4c23779e271a..650c14ad7e9b 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -3,15 +3,93 @@
#include "env.h"
#include "sane_ctype.h"
#include "util.h"
+#include "bpf-event.h"
#include <errno.h>
#include <sys/utsname.h>
+#include <bpf/libbpf.h>
struct perf_env perf_env;
+void perf_env__insert_bpf_prog_info(struct perf_env *env,
+ struct bpf_prog_info_node *info_node)
+{
+ __u32 prog_id = info_node->info_linear->info.id;
+ struct bpf_prog_info_node *node;
+ struct rb_node *parent = NULL;
+ struct rb_node **p;
+
+ down_write(&env->bpf_progs.lock);
+ p = &env->bpf_progs.prog_infos.rb_node;
+
+ while (*p != NULL) {
+ parent = *p;
+ node = rb_entry(parent, struct bpf_prog_info_node, rb_node);
+ if (prog_id < node->info_linear->info.id) {
+ p = &(*p)->rb_left;
+ } else if (prog_id > node->info_linear->info.id) {
+ p = &(*p)->rb_right;
+ } else {
+ pr_debug("duplicated bpf prog info %u\n", prog_id);
+ goto out;
+ }
+ }
+
+ rb_link_node(&info_node->rb_node, parent, p);
+ rb_insert_color(&info_node->rb_node, &env->bpf_progs.prog_infos);
+out:
+ up_write(&env->bpf_progs.lock);
+}
+
+struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
+ __u32 prog_id)
+{
+ struct bpf_prog_info_node *node = NULL;
+ struct rb_node *n;
+
+ down_read(&env->bpf_progs.lock);
+ n = env->bpf_progs.prog_infos.rb_node;
+
+ while (n) {
+ node = rb_entry(n, struct bpf_prog_info_node, rb_node);
+ if (prog_id < node->info_linear->info.id)
+ n = n->rb_left;
+ else if (prog_id > node->info_linear->info.id)
+ n = n->rb_right;
+ else
+ break;
+ }
+
+ up_read(&env->bpf_progs.lock);
+ return node;
+}
+
+/* purge data in bpf_prog_infos tree */
+static void perf_env__purge_bpf(struct perf_env *env)
+{
+ struct rb_root *root;
+ struct rb_node *next;
+
+ down_write(&env->bpf_progs.lock);
+
+ root = &env->bpf_progs.prog_infos;
+ next = rb_first(root);
+
+ while (next) {
+ struct bpf_prog_info_node *node;
+
+ node = rb_entry(next, struct bpf_prog_info_node, rb_node);
+ next = rb_next(&node->rb_node);
+ rb_erase_init(&node->rb_node, root);
+ free(node);
+ }
+ up_write(&env->bpf_progs.lock);
+}
+
void perf_env__exit(struct perf_env *env)
{
int i;
+ perf_env__purge_bpf(env);
zfree(&env->hostname);
zfree(&env->os_release);
zfree(&env->version);
@@ -38,6 +116,12 @@ void perf_env__exit(struct perf_env *env)
zfree(&env->memory_nodes);
}
+static void init_bpf_rb_trees(struct perf_env *env)
+{
+ env->bpf_progs.prog_infos = RB_ROOT;
+ init_rwsem(&env->bpf_progs.lock);
+}
+
int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
{
int i;
@@ -59,6 +143,7 @@ int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
env->nr_cmdline = argc;
+ init_bpf_rb_trees(env);
return 0;
out_free:
zfree(&env->cmdline_argv);
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index d01b8355f4ca..33ef4b2d2a29 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -3,7 +3,9 @@
#define __PERF_ENV_H
#include <linux/types.h>
+#include <linux/rbtree.h>
#include "cpumap.h"
+#include "rwsem.h"
struct cpu_topology_map {
int socket_id;
@@ -64,8 +66,19 @@ struct perf_env {
struct memory_node *memory_nodes;
unsigned long long memory_bsize;
u64 clockid_res_ns;
+
+ /*
+ * bpf_info_lock protects bpf rbtrees. This is needed because the
+ * trees are accessed by different threads in perf-top
+ */
+ struct {
+ struct rw_semaphore lock;
+ struct rb_root prog_infos;
+ } bpf_progs;
};
+struct bpf_prog_info_node;
+
extern struct perf_env perf_env;
void perf_env__exit(struct perf_env *env);
@@ -80,4 +93,8 @@ const char *perf_env__arch(struct perf_env *env);
const char *perf_env__raw_arch(struct perf_env *env);
int perf_env__nr_cpus_avail(struct perf_env *env);
+void perf_env__insert_bpf_prog_info(struct perf_env *env,
+ struct bpf_prog_info_node *info_node);
+struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
+ __u32 prog_id);
#endif /* __PERF_ENV_H */
--
2.17.1
^ permalink raw reply related
* Re: [net-next 01/16] ice: Mark extack argument as __always_unused
From: Stephen Hemminger @ 2019-02-26 0:36 UTC (permalink / raw)
To: Jeff Kirsher
Cc: davem, Bruce Allan, netdev, nhorman, sassmann,
Anirudh Venkataramanan, Andrew Bowers
In-Reply-To: <20190225184306.13505-2-jeffrey.t.kirsher@intel.com>
On Mon, 25 Feb 2019 10:42:51 -0800
Jeff Kirsher <jeffrey.t.kirsher@intel.com> wrote:
> From: Bruce Allan <bruce.w.allan@intel.com>
>
> Commit 87b0984ebfab ("net: Add extack argument to ndo_fdb_add()") in
> net-next added an extended parameter to the .ndo_fdb_add op and changed
> ice_fdb_add() accordingly. Update the function header and add the
> __always_unused attribute to the new parameter to avoid -Wunused-parameter
> warnings.
>
> Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
> Signed-off-by: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com>
> Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
> ---
> drivers/net/ethernet/intel/ice/ice_main.c | 9 +++++----
> 1 file changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
> index 48f033928aa2..9d266d754445 100644
> --- a/drivers/net/ethernet/intel/ice/ice_main.c
> +++ b/drivers/net/ethernet/intel/ice/ice_main.c
> @@ -2435,11 +2435,12 @@ static void ice_set_rx_mode(struct net_device *netdev)
> * @addr: the MAC address entry being added
> * @vid: VLAN id
> * @flags: instructions from stack about fdb operation
> + * @extack: netlink extended ack
> */
> -static int ice_fdb_add(struct ndmsg *ndm, struct nlattr __always_unused *tb[],
> - struct net_device *dev, const unsigned char *addr,
> - u16 vid, u16 flags,
> - struct netlink_ext_ack *extack)
> +static int
> +ice_fdb_add(struct ndmsg *ndm, struct nlattr __always_unused *tb[],
> + struct net_device *dev, const unsigned char *addr, u16 vid,
> + u16 flags, struct netlink_ext_ack __always_unused *extack)
> {
> int err;
>
There are several log messages in ice_fdb_add, why don't you convert those
to be user friendly and use the extended ack mechanism?
^ permalink raw reply
* Re: [PATCH net-next v3 0/7] net: sched: pie: align PIE implementation with RFC 8033
From: Stephen Hemminger @ 2019-02-26 0:38 UTC (permalink / raw)
To: Leslie Monis
Cc: davem, netdev, Mohit P . Tahiliani, Dave Taht, Jamal Hadi Salim
In-Reply-To: <20190225191001.26797-1-lesliemonis@gmail.com>
On Tue, 26 Feb 2019 00:39:54 +0530
Leslie Monis <lesliemonis@gmail.com> wrote:
> The current implementation of the PIE queuing discipline is according to the
> IETF draft [http://tools.ietf.org/html/draft-pan-aqm-pie-00] and the paper
> [PIE: A Lightweight Control Scheme to Address the Bufferbloat Problem].
> However, a lot of necessary modifications and enhancements have been proposed
> in RFC 8033, which have not yet been incorporated in the source code of Linux.
> This patch series helps in achieving the same.
>
> Performance tests carried out using Flent [https://flent.org/]
>
> Changes from v2 to v3:
> - Used div_u64() instead of direct division after explicit type casting as
> recommended by David
>
> Changes from v1 to v2:
> - Excluded the patch setting PIE dynamically active/inactive as the test
> results were unsatisfactory
> - Fixed a scaling issue when adding more auto-tuning cases which caused
> local variables to underflow
> - Changed the long if/else chain to a loop as suggested by Stephen
> - Changed the position of the accu_prob variable in the pie_vars
> structure as recommended by Stephen
>
> Mohit P. Tahiliani (7):
> net: sched: pie: change value of QUEUE_THRESHOLD
> net: sched: pie: change default value of pie_params->target
> net: sched: pie: change default value of pie_params->tupdate
> net: sched: pie: change initial value of pie_vars->burst_time
> net: sched: pie: add more cases to auto-tune alpha and beta
> net: sched: pie: add derandomization mechanism
> net: sched: pie: update references
>
> include/uapi/linux/pkt_sched.h | 2 +-
> net/sched/sch_pie.c | 107 ++++++++++++++++++++-------------
> 2 files changed, 66 insertions(+), 43 deletions(-)
Are you concerned at all that changes to default values might change
expected behavior of existing users?
^ permalink raw reply
* Re: [PATCH v3 bpf-next 0/4] bpf: per program stats
From: Andrii Nakryiko @ 2019-02-26 0:41 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: davem, Daniel Borkmann, edumazet, netdev, bpf, Kernel Team
In-Reply-To: <20190225222842.2031962-1-ast@kernel.org>
On Mon, Feb 25, 2019 at 2:29 PM Alexei Starovoitov <ast@kernel.org> wrote:
>
> Introduce per program stats to monitor the usage BPF
>
> v2->v3:
> - rename to run_time_ns/run_cnt everywhere
>
> v1->v2:
> - fixed u64 stats on 32-bit archs. Thanks Eric
> - use more verbose run_time_ns in json output as suggested by Andrii
> - refactored prog_alloc and clarified behavior of stats in subprogs
>
> Alexei Starovoitov (4):
> bpf: enable program stats
> bpf: expose program stats via bpf_prog_info
> tools/bpf: sync bpf.h into tools
> tools/bpftool: recognize bpf_prog_info run_time_ns and run_cnt
Lgtm, thanks!
Acked-by: Andrii Nakryiko <andriin@fb.com>
>
> include/linux/bpf.h | 9 +++++
> include/linux/filter.h | 20 +++++++++-
> include/uapi/linux/bpf.h | 2 +
> kernel/bpf/core.c | 31 ++++++++++++++-
> kernel/bpf/syscall.c | 39 ++++++++++++++++++-
> kernel/bpf/verifier.c | 7 +++-
> kernel/sysctl.c | 34 ++++++++++++++++
> .../bpftool/Documentation/bpftool-prog.rst | 4 +-
> tools/bpf/bpftool/prog.c | 7 ++++
> tools/include/uapi/linux/bpf.h | 2 +
> 10 files changed, 148 insertions(+), 7 deletions(-)
>
> --
> 2.20.0
>
^ permalink raw reply
* [PATCH net-next] net: hns: use struct_size() in devm_kzalloc()
From: Gustavo A. R. Silva @ 2019-02-26 0:27 UTC (permalink / raw)
To: Yisen Zhuang, Salil Mehta, David S. Miller
Cc: netdev, linux-kernel, Gustavo A. R. Silva
One of the more common cases of allocation size calculations is finding
the size of a structure that has a zero-sized array at the end, along
with memory for some number of elements for that array. For example:
struct foo {
int stuff;
struct boo entry[];
};
instance = devm_kzalloc(dev, sizeof(struct foo) + sizeof(struct boo) * count, GFP_KERNEL);
Instead of leaving these open-coded and prone to type mistakes, we can
now use the new struct_size() helper:
instance = devm_kzalloc(dev, struct_size(instance, entry, count), GFP_KERNEL);
This code was detected with the help of Coccinelle.
Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
---
drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
index 0942e4916d9d..3d07c8a7639d 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
@@ -83,8 +83,9 @@ static int hns_ppe_common_get_cfg(struct dsaf_device *dsaf_dev, int comm_index)
else
ppe_num = HNS_PPE_DEBUG_NW_ENGINE_NUM;
- ppe_common = devm_kzalloc(dsaf_dev->dev, sizeof(*ppe_common) +
- ppe_num * sizeof(struct hns_ppe_cb), GFP_KERNEL);
+ ppe_common = devm_kzalloc(dsaf_dev->dev,
+ struct_size(ppe_common, ppe_cb, ppe_num),
+ GFP_KERNEL);
if (!ppe_common)
return -ENOMEM;
--
2.20.1
^ permalink raw reply related
* Re: [virtio-dev] Re: net_failover slave udev renaming (was Re: [RFC PATCH net-next v6 4/4] netvsc: refactor notifier/event handling code to use the bypass framework)
From: si-wei liu @ 2019-02-26 0:58 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: Samudrala, Sridhar, Siwei Liu, Jiri Pirko, Stephen Hemminger,
David Miller, Netdev, virtualization, virtio-dev,
Brandeburg, Jesse, Alexander Duyck, Jakub Kicinski, Jason Wang,
liran.alon
In-Reply-To: <20190222100753-mutt-send-email-mst@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 6340 bytes --]
On 2/22/2019 7:14 AM, Michael S. Tsirkin wrote:
> On Thu, Feb 21, 2019 at 11:55:11PM -0800, si-wei liu wrote:
>>
>> On 2/21/2019 11:00 PM, Samudrala, Sridhar wrote:
>>>
>>> On 2/21/2019 7:33 PM, si-wei liu wrote:
>>>>
>>>> On 2/21/2019 5:39 PM, Michael S. Tsirkin wrote:
>>>>> On Thu, Feb 21, 2019 at 05:14:44PM -0800, Siwei Liu wrote:
>>>>>> Sorry for replying to this ancient thread. There was some remaining
>>>>>> issue that I don't think the initial net_failover patch got addressed
>>>>>> cleanly, see:
>>>>>>
>>>>>> https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1815268
>>>>>>
>>>>>> The renaming of 'eth0' to 'ens4' fails because the udev userspace was
>>>>>> not specifically writtten for such kernel automatic enslavement.
>>>>>> Specifically, if it is a bond or team, the slave would typically get
>>>>>> renamed *before* virtual device gets created, that's what udev can
>>>>>> control (without getting netdev opened early by the other part of
>>>>>> kernel) and other userspace components for e.g. initramfs,
>>>>>> init-scripts can coordinate well in between. The in-kernel
>>>>>> auto-enslavement of net_failover breaks this userspace convention,
>>>>>> which don't provides a solution if user care about consistent naming
>>>>>> on the slave netdevs specifically.
>>>>>>
>>>>>> Previously this issue had been specifically called out when IFF_HIDDEN
>>>>>> and the 1-netdev was proposed, but no one gives out a solution to this
>>>>>> problem ever since. Please share your mind how to proceed and solve
>>>>>> this userspace issue if netdev does not welcome a 1-netdev model.
>>>>> Above says:
>>>>>
>>>>> there's no motivation in the systemd/udevd community at
>>>>> this point to refactor the rename logic and make it work well with
>>>>> 3-netdev.
>>>>>
>>>>> What would the fix be? Skip slave devices?
>>>>>
>>>> There's nothing user can get if just skipping slave devices - the
>>>> name is still unchanged and unpredictable e.g. eth0, or eth1 the
>>>> next reboot, while the rest may conform to the naming scheme (ens3
>>>> and such). There's no way one can fix this in userspace alone - when
>>>> the failover is created the enslaved netdev was opened by the kernel
>>>> earlier than the userspace is made aware of, and there's no
>>>> negotiation protocol for kernel to know when userspace has done
>>>> initial renaming of the interface. I would expect netdev list should
>>>> at least provide the direction in general for how this can be
>>>> solved...
>
> I was just wondering what did you mean when you said
> "refactor the rename logic and make it work well with 3-netdev" -
> was there a proposal udev rejected?
No. I never believed this particular issue can be fixed in userspace
alone. Previously someone had said it could be, but I never see any work
or relevant discussion ever happened in various userspace communities
(for e.g. dracut, initramfs-tools, systemd, udev, and NetworkManager).
IMHO the root of the issue derives from the kernel, it makes more sense
to start from netdev, work out and decide on a solution: see what can be
done in the kernel in order to fix it, then after that engage userspace
community for the feasibility...
> Anyway, can we write a time diagram for what happens in which order that
> leads to failure? That would help look for triggers that we can tie
> into, or add new ones.
>
See attached diagram.
>
>
>
>
>>> Is there an issue if slave device names are not predictable? The user/admin scripts are expected
>>> to only work with the master failover device.
>> Where does this expectation come from?
>>
>> Admin users may have ethtool or tc configurations that need to deal with
>> predictable interface name. Third-party app which was built upon specifying
>> certain interface name can't be modified to chase dynamic names.
>>
>> Specifically, we have pre-canned image that uses ethtool to fine tune VF
>> offload settings post boot for specific workload. Those images won't work
>> well if the name is constantly changing just after couple rounds of live
>> migration.
> It should be possible to specify the ethtool configuration on the
> master and have it automatically propagated to the slave.
>
> BTW this is something we should look at IMHO.
I was elaborating a few examples that the expectation and assumption
that user/admin scripts only deal with master failover device is
incorrect. It had never been taken good care of, although I did try to
emphasize it from the very beginning.
Basically what you said about propagating the ethtool configuration down
to the slave is the key pursuance of 1-netdev model. However, what I am
seeking now is any alternative that can also fix the specific udev
rename problem, before concluding that 1-netdev is the only solution.
Generally a 1-netdev scheme would take time to implement, while I'm
trying to find a way out to fix this particular naming problem under
3-netdev.
>
>>> Moreover, you were suggesting hiding the lower slave devices anyway. There was some discussion
>>> about moving them to a hidden network namespace so that they are not visible from the default namespace.
>>> I looked into this sometime back, but did not find the right kernel api to create a network namespace within
>>> kernel. If so, we could use this mechanism to simulate a 1-netdev model.
>> Yes, that's one possible implementation (IMHO the key is to make 1-netdev
>> model as much transparent to a real NIC as possible, while a hidden netns is
>> just the vehicle). However, I recall there was resistance around this
>> discussion that even the concept of hiding itself is a taboo for Linux
>> netdev. I would like to summon potential alternatives before concluding
>> 1-netdev is the only solution too soon.
>>
>> Thanks,
>> -Siwei
> Your scripts would not work at all then, right?
At this point we don't claim images with such usage as SR-IOV live
migrate-able. We would flag it as live migrate-able until this ethtool
config issue is fully addressed and a transparent live migration
solution emerges in upstream eventually.
Thanks,
-Siwei
>
>
>>>> -Siwei
>>>>
>>>>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: virtio-dev-unsubscribe@lists.oasis-open.org
> For additional commands, e-mail: virtio-dev-help@lists.oasis-open.org
>
[-- Attachment #2: net_failover_rename_race.txt --]
[-- Type: text/plain, Size: 3587 bytes --]
net_failover(kernel) | network.service (user) | systemd-udevd (user)
--------------------------------------------------+------------------------------+--------------------------------------------
(standby virtio-net and net_failover | |
devices created and initialized, | |
i.e. virtnet_probe()-> | |
net_failover_create() | |
was done.) | |
| |
| runs `ifup ens3' -> |
| ip link set dev ens3 up |
net_failover_open() | |
dev_open(virtnet_dev) | |
virtnet_open(virtnet_dev) | |
netif_carrier_on(failover_dev) | |
... | |
| |
(VF hot plugged in) | |
ixgbevf_probe() | |
register_netdev(ixgbevf_netdev) | |
netdev_register_kobject(ixgbevf_netdev) | |
kobject_add(ixgbevf_dev) | |
device_add(ixgbevf_dev) | |
kobject_uevent(&ixgbevf_dev->kobj, KOBJ_ADD) | |
netlink_broadcast() | |
... | |
call_netdevice_notifiers(NETDEV_REGISTER) | |
failover_event(..., NETDEV_REGISTER, ...) | |
failover_slave_register(ixgbevf_netdev) | |
net_failover_slave_register(ixgbevf_netdev) | |
dev_open(ixgbevf_netdev) | |
| |
| |
| | received ADD uevent from netlink fd
| | ...
| | udev-builtin-net_id.c:dev_pci_slot()
| | (decided to renamed 'eth0' )
| | ip link set dev eth0 name ens4
(dev_change_name() returns -EBUSY as | |
ixgbevf_netdev->flags has IFF_UP) | |
| |
^ permalink raw reply
* Re: [PATCH net-next v3 0/7] net: sched: pie: align PIE implementation with RFC 8033
From: Dave Taht @ 2019-02-26 1:02 UTC (permalink / raw)
To: Stephen Hemminger
Cc: Leslie Monis, David S. Miller, Linux Kernel Network Developers,
Mohit P . Tahiliani, Jamal Hadi Salim
In-Reply-To: <20190225163811.4a6b477b@shemminger-XPS-13-9360>
On Mon, Feb 25, 2019 at 4:38 PM Stephen Hemminger
<stephen@networkplumber.org> wrote:
>
> On Tue, 26 Feb 2019 00:39:54 +0530
> Leslie Monis <lesliemonis@gmail.com> wrote:
>
> > The current implementation of the PIE queuing discipline is according to the
> > IETF draft [http://tools.ietf.org/html/draft-pan-aqm-pie-00] and the paper
> > [PIE: A Lightweight Control Scheme to Address the Bufferbloat Problem].
> > However, a lot of necessary modifications and enhancements have been proposed
> > in RFC 8033, which have not yet been incorporated in the source code of Linux.
> > This patch series helps in achieving the same.
> >
> > Performance tests carried out using Flent [https://flent.org/]
> >
> > Changes from v2 to v3:
> > - Used div_u64() instead of direct division after explicit type casting as
> > recommended by David
> >
> > Changes from v1 to v2:
> > - Excluded the patch setting PIE dynamically active/inactive as the test
> > results were unsatisfactory
> > - Fixed a scaling issue when adding more auto-tuning cases which caused
> > local variables to underflow
> > - Changed the long if/else chain to a loop as suggested by Stephen
> > - Changed the position of the accu_prob variable in the pie_vars
> > structure as recommended by Stephen
> >
> > Mohit P. Tahiliani (7):
> > net: sched: pie: change value of QUEUE_THRESHOLD
> > net: sched: pie: change default value of pie_params->target
> > net: sched: pie: change default value of pie_params->tupdate
> > net: sched: pie: change initial value of pie_vars->burst_time
> > net: sched: pie: add more cases to auto-tune alpha and beta
> > net: sched: pie: add derandomization mechanism
> > net: sched: pie: update references
> >
> > include/uapi/linux/pkt_sched.h | 2 +-
> > net/sched/sch_pie.c | 107 ++++++++++++++++++++-------------
> > 2 files changed, 66 insertions(+), 43 deletions(-)
>
> Are you concerned at all that changes to default values might change
> expected behavior of existing users?
There's existing users?
Most of these changes are really subtle and came out as we went along.
I'd have to *really search* to find my notes from that period,
and I have not evaluated the sum of these new changes, but overall
they were a slight improvement from the defaults as we shipped it way
back when.
I'm not being snarky - are there existing users? Every last person I
know that ever evaluated pie switched to fq_codel. Cisco ended up
going with another bufferbloat-fighting solution in one new device and
that team dissolved.
docsis-pie, well, that's a standard. and that's a bit different from
this pie, but this pie is closer to that pie. And it works ok.
I certainly hope leslie's group has done similar testing to what we
did then ? If there's results I can dig up my old results and see what
compares. I imagine they plan a paper. our old flent test code and
data is all published, but am not willing to spend another minute of
my life on a single queued aqm design unless someone writes me a very
big check for it, which I'd then spend on fixing P4 to run fq-codel.
fq-pie (which is waiting in the wings behind this set of patches) is
ok, as at least, the BSD version was competetive with fq_codel in most
respects. I told 'em they needed to look hard at the rate estimator.
The ECN handling problem mentioned is there on all known versions of
pie, but it's that it reverts to drop too soon for ecn to be
as much benefit as it could be.
and then l4s, which is the subject of 3 upcoming talks at netdevconf,
well... not gonna talk about it. I'm willing to give them their day in
court.
sorry to come across as grumpy. should linux be rfc compliant even if
the rfc has issues? damned if I know.
--
Dave Täht
CTO, TekLibre, LLC
http://www.teklibre.com
Tel: 1-831-205-9740
^ permalink raw reply
* Re: [PATCH net-next] can: kvaser_usb: Use struct_size() in alloc_candev()
From: Gustavo A. R. Silva @ 2019-02-26 0:48 UTC (permalink / raw)
To: Wolfgang Grandegger, Marc Kleine-Budde, David S. Miller
Cc: linux-can, netdev, linux-kernel
In-Reply-To: <20190208031035.GA2665@embeddedor>
Hi all,
Friendly ping:
Who can take this?
Thanks
--
Gustavo
On 2/7/19 9:10 PM, Gustavo A. R. Silva wrote:
> One of the more common cases of allocation size calculations is finding
> the size of a structure that has a zero-sized array at the end, along
> with memory for some number of elements for that array. For example:
>
> struct foo {
> int stuff;
> void *entry[];
> };
>
> instance = alloc(sizeof(struct foo) + count * sizeof(void *));
>
> Instead of leaving these open-coded and prone to type mistakes, we can
> now use the new struct_size() helper:
>
> instance = alloc(struct_size(instance, entry, count));
>
> This code was detected with the help of Coccinelle.
>
> Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
> ---
> drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
> index c89c7d4900d7..0f1d3e807d63 100644
> --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
> +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
> @@ -643,8 +643,7 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev,
> return err;
> }
>
> - netdev = alloc_candev(sizeof(*priv) +
> - dev->max_tx_urbs * sizeof(*priv->tx_contexts),
> + netdev = alloc_candev(struct_size(priv, tx_contexts, dev->max_tx_urbs),
> dev->max_tx_urbs);
> if (!netdev) {
> dev_err(&dev->intf->dev, "Cannot alloc candev\n");
>
^ permalink raw reply
* Re: [PATCH v2 bpf-next 2/9] bpf: Add bpf helper bpf_tcp_enter_cwr
From: Martin Lau @ 2019-02-26 1:30 UTC (permalink / raw)
To: Stanislav Fomichev
Cc: Lawrence Brakmo, netdev, Alexei Starovoitov, Daniel Borkmann,
Eric Dumazet, Kernel Team
In-Reply-To: <20190225231438.GC32115@mini-arch>
On Mon, Feb 25, 2019 at 03:14:38PM -0800, Stanislav Fomichev wrote:
[ ... ]
> >
> > To ensure it is only called from BPF_CGROUP_INET_EGRESS, the
> > attr->expected_attach_type must be specified as BPF_CGROUP_INET_EGRESS
> > during load time if the prog uses this new helper.
> > The newly added prog->enforce_expected_attach_type bit will also be set
> > if this new helper is used. This bit is for backward compatibility reason
> > because currently prog->expected_attach_type has been ignored in
> > BPF_PROG_TYPE_CGROUP_SKB. During attach time,
> > prog->expected_attach_type is only enforced if the
> > prog->enforce_expected_attach_type bit is set.
> > i.e. prog->expected_attach_type is only enforced if this new helper
> > is used by the prog.
> >
[ ... ]
> > @@ -1725,6 +1733,10 @@ static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog,
> > case BPF_PROG_TYPE_CGROUP_SOCK:
> > case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
> > return attach_type == prog->expected_attach_type ? 0 : -EINVAL;
> > + case BPF_PROG_TYPE_CGROUP_SKB:
> > + return prog->enforce_expected_attach_type &&
> > + prog->expected_attach_type != attach_type ?
> > + -EINVAL : 0;
> > default:
> > return 0;
> > }
[ ... ]
> > diff --git a/net/core/filter.c b/net/core/filter.c
> > index 97916eedfe69..ca57ef25279c 100644
> > --- a/net/core/filter.c
> > +++ b/net/core/filter.c
> > @@ -5426,6 +5426,24 @@ static const struct bpf_func_proto bpf_tcp_sock_proto = {
> > .arg1_type = ARG_PTR_TO_SOCK_COMMON,
> > };
> >
> > +BPF_CALL_1(bpf_tcp_enter_cwr, struct tcp_sock *, tp)
> > +{
> > + struct sock *sk = (struct sock *)tp;
> > +
> > + if (sk->sk_state == TCP_ESTABLISHED) {
> > + tcp_enter_cwr(sk);
> > + return 0;
> > + }
> > +
> > + return -EINVAL;
> > +}
> > +
> > +static const struct bpf_func_proto bpf_tcp_enter_cwr_proto = {
> > + .func = bpf_tcp_enter_cwr,
> > + .gpl_only = false,
> > + .ret_type = RET_INTEGER,
> > + .arg1_type = ARG_PTR_TO_TCP_SOCK,
> > +};
> > #endif /* CONFIG_INET */
> >
> > bool bpf_helper_changes_pkt_data(void *func)
> > @@ -5585,6 +5603,13 @@ cg_skb_func_proto(enum bpf_func_id func_id, struct bpf_prog *prog)
> > #ifdef CONFIG_INET
> > case BPF_FUNC_tcp_sock:
> > return &bpf_tcp_sock_proto;
>
> [...]
> > + case BPF_FUNC_tcp_enter_cwr:
> > + if (prog->expected_attach_type == BPF_CGROUP_INET_EGRESS) {
> > + prog->enforce_expected_attach_type = 1;
> > + return &bpf_tcp_enter_cwr_proto;
> Instead of this back and forth with enforce_expected_attach_type, can we
> just do here:
>
> if (prog->expected_attach_type == BPF_CGROUP_INET_EGRESS)
> return &bpf_tcp_enter_cwr_proto;
> else
> return null;
>
> Wouldn't it have the same effect?
The attr->expected_attach_type is currently ignored (i.e. not checked)
during the bpf load time.
How to avoid breaking backward compatibility without selectively
enforcing prog->expected_attach_type during attach time?
^ permalink raw reply
* Re: [virtio-dev] Re: net_failover slave udev renaming (was Re: [RFC PATCH net-next v6 4/4] netvsc: refactor notifier/event handling code to use the bypass framework)
From: Stephen Hemminger @ 2019-02-26 1:39 UTC (permalink / raw)
To: si-wei liu
Cc: Michael S. Tsirkin, Samudrala, Sridhar, Siwei Liu, Jiri Pirko,
David Miller, Netdev, virtualization, virtio-dev,
Brandeburg, Jesse, Alexander Duyck, Jakub Kicinski, Jason Wang,
liran.alon
In-Reply-To: <e6a53bd1-83ab-f170-406a-03276e8c87e2@oracle.com>
On Mon, 25 Feb 2019 16:58:07 -0800
si-wei liu <si-wei.liu@oracle.com> wrote:
> On 2/22/2019 7:14 AM, Michael S. Tsirkin wrote:
> > On Thu, Feb 21, 2019 at 11:55:11PM -0800, si-wei liu wrote:
> >>
> >> On 2/21/2019 11:00 PM, Samudrala, Sridhar wrote:
> >>>
> >>> On 2/21/2019 7:33 PM, si-wei liu wrote:
> >>>>
> >>>> On 2/21/2019 5:39 PM, Michael S. Tsirkin wrote:
> >>>>> On Thu, Feb 21, 2019 at 05:14:44PM -0800, Siwei Liu wrote:
> >>>>>> Sorry for replying to this ancient thread. There was some remaining
> >>>>>> issue that I don't think the initial net_failover patch got addressed
> >>>>>> cleanly, see:
> >>>>>>
> >>>>>> https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1815268
> >>>>>>
> >>>>>> The renaming of 'eth0' to 'ens4' fails because the udev userspace was
> >>>>>> not specifically writtten for such kernel automatic enslavement.
> >>>>>> Specifically, if it is a bond or team, the slave would typically get
> >>>>>> renamed *before* virtual device gets created, that's what udev can
> >>>>>> control (without getting netdev opened early by the other part of
> >>>>>> kernel) and other userspace components for e.g. initramfs,
> >>>>>> init-scripts can coordinate well in between. The in-kernel
> >>>>>> auto-enslavement of net_failover breaks this userspace convention,
> >>>>>> which don't provides a solution if user care about consistent naming
> >>>>>> on the slave netdevs specifically.
> >>>>>>
> >>>>>> Previously this issue had been specifically called out when IFF_HIDDEN
> >>>>>> and the 1-netdev was proposed, but no one gives out a solution to this
> >>>>>> problem ever since. Please share your mind how to proceed and solve
> >>>>>> this userspace issue if netdev does not welcome a 1-netdev model.
> >>>>> Above says:
> >>>>>
> >>>>> there's no motivation in the systemd/udevd community at
> >>>>> this point to refactor the rename logic and make it work well with
> >>>>> 3-netdev.
> >>>>>
> >>>>> What would the fix be? Skip slave devices?
> >>>>>
> >>>> There's nothing user can get if just skipping slave devices - the
> >>>> name is still unchanged and unpredictable e.g. eth0, or eth1 the
> >>>> next reboot, while the rest may conform to the naming scheme (ens3
> >>>> and such). There's no way one can fix this in userspace alone - when
> >>>> the failover is created the enslaved netdev was opened by the kernel
> >>>> earlier than the userspace is made aware of, and there's no
> >>>> negotiation protocol for kernel to know when userspace has done
> >>>> initial renaming of the interface. I would expect netdev list should
> >>>> at least provide the direction in general for how this can be
> >>>> solved...
> >
> > I was just wondering what did you mean when you said
> > "refactor the rename logic and make it work well with 3-netdev" -
> > was there a proposal udev rejected?
> No. I never believed this particular issue can be fixed in userspace
> alone. Previously someone had said it could be, but I never see any work
> or relevant discussion ever happened in various userspace communities
> (for e.g. dracut, initramfs-tools, systemd, udev, and NetworkManager).
> IMHO the root of the issue derives from the kernel, it makes more sense
> to start from netdev, work out and decide on a solution: see what can be
> done in the kernel in order to fix it, then after that engage userspace
> community for the feasibility...
>
> > Anyway, can we write a time diagram for what happens in which order that
> > leads to failure? That would help look for triggers that we can tie
> > into, or add new ones.
> >
>
> See attached diagram.
>
> >
> >
> >
> >
> >>> Is there an issue if slave device names are not predictable? The user/admin scripts are expected
> >>> to only work with the master failover device.
> >> Where does this expectation come from?
> >>
> >> Admin users may have ethtool or tc configurations that need to deal with
> >> predictable interface name. Third-party app which was built upon specifying
> >> certain interface name can't be modified to chase dynamic names.
> >>
> >> Specifically, we have pre-canned image that uses ethtool to fine tune VF
> >> offload settings post boot for specific workload. Those images won't work
> >> well if the name is constantly changing just after couple rounds of live
> >> migration.
> > It should be possible to specify the ethtool configuration on the
> > master and have it automatically propagated to the slave.
> >
> > BTW this is something we should look at IMHO.
> I was elaborating a few examples that the expectation and assumption
> that user/admin scripts only deal with master failover device is
> incorrect. It had never been taken good care of, although I did try to
> emphasize it from the very beginning.
>
> Basically what you said about propagating the ethtool configuration down
> to the slave is the key pursuance of 1-netdev model. However, what I am
> seeking now is any alternative that can also fix the specific udev
> rename problem, before concluding that 1-netdev is the only solution.
> Generally a 1-netdev scheme would take time to implement, while I'm
> trying to find a way out to fix this particular naming problem under
> 3-netdev.
>
> >
> >>> Moreover, you were suggesting hiding the lower slave devices anyway. There was some discussion
> >>> about moving them to a hidden network namespace so that they are not visible from the default namespace.
> >>> I looked into this sometime back, but did not find the right kernel api to create a network namespace within
> >>> kernel. If so, we could use this mechanism to simulate a 1-netdev model.
> >> Yes, that's one possible implementation (IMHO the key is to make 1-netdev
> >> model as much transparent to a real NIC as possible, while a hidden netns is
> >> just the vehicle). However, I recall there was resistance around this
> >> discussion that even the concept of hiding itself is a taboo for Linux
> >> netdev. I would like to summon potential alternatives before concluding
> >> 1-netdev is the only solution too soon.
> >>
> >> Thanks,
> >> -Siwei
> > Your scripts would not work at all then, right?
> At this point we don't claim images with such usage as SR-IOV live
> migrate-able. We would flag it as live migrate-able until this ethtool
> config issue is fully addressed and a transparent live migration
> solution emerges in upstream eventually.
The hyper-v netvsc with 1-dev model uses a timeout to allow udev to do its rename.
I proposed a patch to key state change off of the udev rename, but that patch was
rejected.
^ permalink raw reply
* Re: [PATCH net] sit: use ipv6_mod_enabled to check if ipv6 is disabled
From: Hangbin Liu @ 2019-02-26 1:43 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev, Stefano Brivio, David S . Miller, David Ahern
In-Reply-To: <1dd57d9d-fed2-67b8-ac28-7ef3681eeed2@gmail.com>
On Mon, Feb 25, 2019 at 08:39:27AM -0800, Eric Dumazet wrote:
> >> On 02/24/2019 08:12 PM, Hangbin Liu wrote:
> >>> ipv6_mod_enabled() is more safe and gentle to check if ipv6 is disabled
> >>> at running time.
> >>>
> >>
> >>
> >> Why is it better exactly ?
> >>
> >> IPv6 can be enabled on the host, but disabled per device
> >>
> >> /proc/sys/net/ipv6/conf/{name}/disable_ipv6
> >
> > Sorry, it looks I didn't make it clear in the commit description.
> > This issue only occurs when IPv6 is disabled at boot time as there is
> > no IPv6 route entry. Disable ipv6 on specific interface is not affected.
> > So check ipv6_mod_enabled() is enough and we don't need to worry about
> > the rcu_read_lock or the dev status.
> >
> > Should I update the commit description?
>
> Certainly. Are you telling us skb->dev could be NULL here ?
>
> Because rcu_read_lock() should already be asserted.
>
No. I know skb->dev is not NULL and we have rcu_read_lock() here. But can we
guarantee the skb->dev won't be NULL forever? Maybe I'm a little sensitive.
I mean for only checking if ipv6 is disable at boot time, use
ipv6_mod_enabled() is more suitable.
Thanks
Hangbin
^ permalink raw reply
* [PATCH net-next] net: remove unused struct inet_frag_queue.fragments field
From: Peter Oskolkov @ 2019-02-26 1:43 UTC (permalink / raw)
To: David Miller, netdev; +Cc: Peter Oskolkov, linux-wpan, Peter Oskolkov
Now that all users of struct inet_frag_queue have been converted
to use 'rb_fragments', remove the unused 'fragments' field.
Build with `make allyesconfig` succeeded. ip_defrag selftest passed.
Signed-off-by: Peter Oskolkov <posk@google.com>
---
include/net/inet_frag.h | 4 +--
net/ieee802154/6lowpan/reassembly.c | 1 -
net/ipv4/inet_fragment.c | 44 ++++++++-----------------
net/ipv4/ip_fragment.c | 2 --
net/ipv6/netfilter/nf_conntrack_reasm.c | 1 -
net/ipv6/reassembly.c | 1 -
6 files changed, 14 insertions(+), 39 deletions(-)
diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
index b02bf737d019..378904ee9129 100644
--- a/include/net/inet_frag.h
+++ b/include/net/inet_frag.h
@@ -56,7 +56,6 @@ struct frag_v6_compare_key {
* @timer: queue expiration timer
* @lock: spinlock protecting this frag
* @refcnt: reference count of the queue
- * @fragments: received fragments head
* @rb_fragments: received fragments rb-tree root
* @fragments_tail: received fragments tail
* @last_run_head: the head of the last "run". see ip_fragment.c
@@ -77,8 +76,7 @@ struct inet_frag_queue {
struct timer_list timer;
spinlock_t lock;
refcount_t refcnt;
- struct sk_buff *fragments; /* used in 6lopwpan IPv6. */
- struct rb_root rb_fragments; /* Used in IPv4/IPv6. */
+ struct rb_root rb_fragments;
struct sk_buff *fragments_tail;
struct sk_buff *last_run_head;
ktime_t stamp;
diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c
index bd61633d2c32..4196bcd4105a 100644
--- a/net/ieee802154/6lowpan/reassembly.c
+++ b/net/ieee802154/6lowpan/reassembly.c
@@ -179,7 +179,6 @@ static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, struct sk_buff *skb,
skb->dev = ldev;
skb->tstamp = fq->q.stamp;
- fq->q.fragments = NULL;
fq->q.rb_fragments = RB_ROOT;
fq->q.fragments_tail = NULL;
fq->q.last_run_head = NULL;
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index 9f69411251d0..737808e27f8b 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -203,7 +203,6 @@ EXPORT_SYMBOL(inet_frag_rbtree_purge);
void inet_frag_destroy(struct inet_frag_queue *q)
{
- struct sk_buff *fp;
struct netns_frags *nf;
unsigned int sum, sum_truesize = 0;
struct inet_frags *f;
@@ -212,20 +211,9 @@ void inet_frag_destroy(struct inet_frag_queue *q)
WARN_ON(del_timer(&q->timer) != 0);
/* Release all fragment data. */
- fp = q->fragments;
nf = q->net;
f = nf->f;
- if (fp) {
- do {
- struct sk_buff *xp = fp->next;
-
- sum_truesize += fp->truesize;
- kfree_skb(fp);
- fp = xp;
- } while (fp);
- } else {
- sum_truesize = inet_frag_rbtree_purge(&q->rb_fragments);
- }
+ sum_truesize = inet_frag_rbtree_purge(&q->rb_fragments);
sum = sum_truesize + f->qsize;
call_rcu(&q->rcu, inet_frag_destroy_rcu);
@@ -489,26 +477,20 @@ EXPORT_SYMBOL(inet_frag_reasm_finish);
struct sk_buff *inet_frag_pull_head(struct inet_frag_queue *q)
{
- struct sk_buff *head;
+ struct sk_buff *head, *skb;
- if (q->fragments) {
- head = q->fragments;
- q->fragments = head->next;
- } else {
- struct sk_buff *skb;
+ head = skb_rb_first(&q->rb_fragments);
+ if (!head)
+ return NULL;
+ skb = FRAG_CB(head)->next_frag;
+ if (skb)
+ rb_replace_node(&head->rbnode, &skb->rbnode,
+ &q->rb_fragments);
+ else
+ rb_erase(&head->rbnode, &q->rb_fragments);
+ memset(&head->rbnode, 0, sizeof(head->rbnode));
+ barrier();
- head = skb_rb_first(&q->rb_fragments);
- if (!head)
- return NULL;
- skb = FRAG_CB(head)->next_frag;
- if (skb)
- rb_replace_node(&head->rbnode, &skb->rbnode,
- &q->rb_fragments);
- else
- rb_erase(&head->rbnode, &q->rb_fragments);
- memset(&head->rbnode, 0, sizeof(head->rbnode));
- barrier();
- }
if (head == q->fragments_tail)
q->fragments_tail = NULL;
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 486ecb0aeb87..cf2b0a6a3337 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -261,7 +261,6 @@ static int ip_frag_reinit(struct ipq *qp)
qp->q.flags = 0;
qp->q.len = 0;
qp->q.meat = 0;
- qp->q.fragments = NULL;
qp->q.rb_fragments = RB_ROOT;
qp->q.fragments_tail = NULL;
qp->q.last_run_head = NULL;
@@ -451,7 +450,6 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb,
ip_send_check(iph);
__IP_INC_STATS(net, IPSTATS_MIB_REASMOKS);
- qp->q.fragments = NULL;
qp->q.rb_fragments = RB_ROOT;
qp->q.fragments_tail = NULL;
qp->q.last_run_head = NULL;
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index cb1b4772dac0..3de0e9b0a482 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -365,7 +365,6 @@ static int nf_ct_frag6_reasm(struct frag_queue *fq, struct sk_buff *skb,
skb_network_header_len(skb),
skb->csum);
- fq->q.fragments = NULL;
fq->q.rb_fragments = RB_ROOT;
fq->q.fragments_tail = NULL;
fq->q.last_run_head = NULL;
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 24264d0a4b85..1a832f5e190b 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -304,7 +304,6 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *skb,
rcu_read_lock();
__IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMOKS);
rcu_read_unlock();
- fq->q.fragments = NULL;
fq->q.rb_fragments = RB_ROOT;
fq->q.fragments_tail = NULL;
fq->q.last_run_head = NULL;
--
2.21.0.rc2.261.ga7da99ff1b-goog
^ permalink raw reply related
* Re: [PATCH] tools: testing: selftests: Remove duplicate headers
From: Michael Ellerman @ 2019-02-26 1:48 UTC (permalink / raw)
To: Souptick Joarder, bamv2005, shuah, davem, benh, paulus, adobriyan,
mathieu.desnoyers, peterz, paulmck, boqun.feng, john.stultz, tglx,
sboyd, akpm
Cc: linux-gpio, linux-kselftest, linux-kernel, netdev, linuxppc-dev,
linux-fsdevel, sabyasachi.linux
In-Reply-To: <20190223070901.GA10274@jordon-HP-15-Notebook-PC>
Souptick Joarder <jrdr.linux@gmail.com> writes:
> Remove duplicate headers which are included twice.
>
> Signed-off-by: Sabyasachi Gupta <sabyasachi.linux@gmail.com>
> Signed-off-by: Souptick Joarder <jrdr.linux@gmail.com>
> ---
...
> tools/testing/selftests/powerpc/pmu/ebb/fork_cleanup_test.c | 1 -
I took this hunk via the powerpc tree.
> diff --git a/tools/testing/selftests/powerpc/pmu/ebb/fork_cleanup_test.c b/tools/testing/selftests/powerpc/pmu/ebb/fork_cleanup_test.c
> index 167135b..af1b802 100644
> --- a/tools/testing/selftests/powerpc/pmu/ebb/fork_cleanup_test.c
> +++ b/tools/testing/selftests/powerpc/pmu/ebb/fork_cleanup_test.c
> @@ -11,7 +11,6 @@
> #include <sys/wait.h>
> #include <unistd.h>
> #include <setjmp.h>
> -#include <signal.h>
>
> #include "ebb.h"
cheers
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox