BPF: Add sample code for new ib_umad tracepoint
authorIra Weiny <ira.weiny@intel.com>
Tue, 19 Mar 2019 21:11:49 +0000 (14:11 -0700)
committerJason Gunthorpe <jgg@mellanox.com>
Wed, 27 Mar 2019 18:53:26 +0000 (15:53 -0300)
Provide a count of class types for a summary of MAD packets.  The example
shows one way to filter the trace data based on management class.

Signed-off-by: Ira Weiny <ira.weiny@intel.com>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
MAINTAINERS
samples/bpf/Makefile
samples/bpf/ibumad_kern.c [new file with mode: 0644]
samples/bpf/ibumad_user.c [new file with mode: 0644]

index 4e851fc..1de122b 100644 (file)
@@ -7655,6 +7655,8 @@ F:        include/uapi/rdma/
 F:     include/rdma/
 F:     include/trace/events/ib_mad.h
 F:     include/trace/events/ib_umad.h
+F:     samples/bpf/ibumad_kern.c
+F:     samples/bpf/ibumad_user.c
 
 INGENIC JZ4780 DMA Driver
 M:     Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com>
index 65e667b..4f0a1cd 100644 (file)
@@ -52,6 +52,7 @@ hostprogs-y += xdpsock
 hostprogs-y += xdp_fwd
 hostprogs-y += task_fd_query
 hostprogs-y += xdp_sample_pkts
+hostprogs-y += ibumad
 hostprogs-y += hbm
 
 # Libbpf dependencies
@@ -108,6 +109,7 @@ xdpsock-objs := xdpsock_user.o
 xdp_fwd-objs := xdp_fwd_user.o
 task_fd_query-objs := bpf_load.o task_fd_query_user.o $(TRACE_HELPERS)
 xdp_sample_pkts-objs := xdp_sample_pkts_user.o $(TRACE_HELPERS)
+ibumad-objs := bpf_load.o ibumad_user.o $(TRACE_HELPERS)
 hbm-objs := bpf_load.o hbm.o $(CGROUP_HELPERS)
 
 # Tell kbuild to always build the programs
@@ -166,6 +168,7 @@ always += xdp_adjust_tail_kern.o
 always += xdp_fwd_kern.o
 always += task_fd_query_kern.o
 always += xdp_sample_pkts_kern.o
+always += ibumad_kern.o
 always += hbm_out_kern.o
 
 KBUILD_HOSTCFLAGS += -I$(objtree)/usr/include
diff --git a/samples/bpf/ibumad_kern.c b/samples/bpf/ibumad_kern.c
new file mode 100644 (file)
index 0000000..38b2b3f
--- /dev/null
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+
+/**
+ * ibumad BPF sample kernel side
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * Copyright(c) 2018 Ira Weiny, Intel Corporation
+ */
+
+#define KBUILD_MODNAME "ibumad_count_pkts_by_class"
+#include <uapi/linux/bpf.h>
+
+#include "bpf_helpers.h"
+
+
+struct bpf_map_def SEC("maps") read_count = {
+       .type        = BPF_MAP_TYPE_ARRAY,
+       .key_size    = sizeof(u32), /* class; u32 required */
+       .value_size  = sizeof(u64), /* count of mads read */
+       .max_entries = 256, /* Room for all Classes */
+};
+
+struct bpf_map_def SEC("maps") write_count = {
+       .type        = BPF_MAP_TYPE_ARRAY,
+       .key_size    = sizeof(u32), /* class; u32 required */
+       .value_size  = sizeof(u64), /* count of mads written */
+       .max_entries = 256, /* Room for all Classes */
+};
+
+#undef DEBUG
+#ifdef DEBUG
+#define bpf_debug(fmt, ...)                         \
+({                                                  \
+       char ____fmt[] = fmt;                       \
+       bpf_trace_printk(____fmt, sizeof(____fmt),  \
+                        ##__VA_ARGS__);            \
+})
+#else
+#define bpf_debug(fmt, ...)
+#endif
+
+/* Taken from the current format defined in
+ * include/trace/events/ib_umad.h
+ * and
+ * /sys/kernel/debug/tracing/events/ib_umad/ib_umad_read/format
+ * /sys/kernel/debug/tracing/events/ib_umad/ib_umad_write/format
+ */
+struct ib_umad_rw_args {
+       u64 pad;
+       u8 port_num;
+       u8 sl;
+       u8 path_bits;
+       u8 grh_present;
+       u32 id;
+       u32 status;
+       u32 timeout_ms;
+       u32 retires;
+       u32 length;
+       u32 qpn;
+       u32 qkey;
+       u8 gid_index;
+       u8 hop_limit;
+       u16 lid;
+       u16 attr_id;
+       u16 pkey_index;
+       u8 base_version;
+       u8 mgmt_class;
+       u8 class_version;
+       u8 method;
+       u32 flow_label;
+       u16 mad_status;
+       u16 class_specific;
+       u32 attr_mod;
+       u64 tid;
+       u8 gid[16];
+       u32 dev_index;
+       u8 traffic_class;
+};
+
+SEC("tracepoint/ib_umad/ib_umad_read_recv")
+int on_ib_umad_read_recv(struct ib_umad_rw_args *ctx)
+{
+       u64 zero = 0, *val;
+       u8 class = ctx->mgmt_class;
+
+       bpf_debug("ib_umad read recv : class 0x%x\n", class);
+
+       val = bpf_map_lookup_elem(&read_count, &class);
+       if (!val) {
+               bpf_map_update_elem(&read_count, &class, &zero, BPF_NOEXIST);
+               val = bpf_map_lookup_elem(&read_count, &class);
+               if (!val)
+                       return 0;
+       }
+
+       (*val) += 1;
+
+       return 0;
+}
+SEC("tracepoint/ib_umad/ib_umad_read_send")
+int on_ib_umad_read_send(struct ib_umad_rw_args *ctx)
+{
+       u64 zero = 0, *val;
+       u8 class = ctx->mgmt_class;
+
+       bpf_debug("ib_umad read send : class 0x%x\n", class);
+
+       val = bpf_map_lookup_elem(&read_count, &class);
+       if (!val) {
+               bpf_map_update_elem(&read_count, &class, &zero, BPF_NOEXIST);
+               val = bpf_map_lookup_elem(&read_count, &class);
+               if (!val)
+                       return 0;
+       }
+
+       (*val) += 1;
+
+       return 0;
+}
+SEC("tracepoint/ib_umad/ib_umad_write")
+int on_ib_umad_write(struct ib_umad_rw_args *ctx)
+{
+       u64 zero = 0, *val;
+       u8 class = ctx->mgmt_class;
+
+       bpf_debug("ib_umad write : class 0x%x\n", class);
+
+       val = bpf_map_lookup_elem(&write_count, &class);
+       if (!val) {
+               bpf_map_update_elem(&write_count, &class, &zero, BPF_NOEXIST);
+               val = bpf_map_lookup_elem(&write_count, &class);
+               if (!val)
+                       return 0;
+       }
+
+       (*val) += 1;
+
+       return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/samples/bpf/ibumad_user.c b/samples/bpf/ibumad_user.c
new file mode 100644 (file)
index 0000000..097d761
--- /dev/null
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+
+/**
+ * ibumad BPF sample user side
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * Copyright(c) 2018 Ira Weiny, Intel Corporation
+ */
+
+#include <linux/bpf.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <limits.h>
+
+#include <sys/resource.h>
+#include <getopt.h>
+#include <net/if.h>
+
+#include "bpf_load.h"
+#include "bpf_util.h"
+#include "bpf/libbpf.h"
+
+static void dump_counts(int fd)
+{
+       __u32 key;
+       __u64 value;
+
+       for (key = 0; key < 256; key++) {
+               if (bpf_map_lookup_elem(fd, &key, &value)) {
+                       printf("failed to read key %u\n", key);
+                       continue;
+               }
+               if (value)
+                       printf("0x%02x : %llu\n", key, value);
+       }
+}
+
+static void dump_all_counts(void)
+{
+       printf("Read 'Class : count'\n");
+       dump_counts(map_fd[0]);
+       printf("Write 'Class : count'\n");
+       dump_counts(map_fd[1]);
+}
+
+static void dump_exit(int sig)
+{
+       dump_all_counts();
+       exit(0);
+}
+
+static const struct option long_options[] = {
+       {"help",      no_argument,       NULL, 'h'},
+       {"delay",     required_argument, NULL, 'd'},
+};
+
+static void usage(char *cmd)
+{
+       printf("eBPF test program to count packets from various IP addresses\n"
+               "Usage: %s <options>\n"
+               "       --help,   -h  this menu\n"
+               "       --delay,  -d  <delay>  wait <delay> sec between prints [1 - 1000000]\n"
+               , cmd
+               );
+}
+
+int main(int argc, char **argv)
+{
+       unsigned long delay = 5;
+       int longindex = 0;
+       int opt;
+       char bpf_file[256];
+
+       /* Create the eBPF kernel code path name.
+        * This follows the pattern of all of the other bpf samples
+        */
+       snprintf(bpf_file, sizeof(bpf_file), "%s_kern.o", argv[0]);
+
+       /* Do one final dump when exiting */
+       signal(SIGINT, dump_exit);
+       signal(SIGTERM, dump_exit);
+
+       while ((opt = getopt_long(argc, argv, "hd:rSw",
+                                 long_options, &longindex)) != -1) {
+               switch (opt) {
+               case 'd':
+                       delay = strtoul(optarg, NULL, 0);
+                       if (delay == ULONG_MAX || delay < 0 ||
+                           delay > 1000000) {
+                               fprintf(stderr, "ERROR: invalid delay : %s\n",
+                                       optarg);
+                               usage(argv[0]);
+                               return 1;
+                       }
+                       break;
+               default:
+               case 'h':
+                       usage(argv[0]);
+                       return 1;
+               }
+       }
+
+       if (load_bpf_file(bpf_file)) {
+               fprintf(stderr, "ERROR: failed to load eBPF from file : %s\n",
+                       bpf_file);
+               return 1;
+       }
+
+       while (1) {
+               sleep(delay);
+               dump_all_counts();
+       }
+
+       return 0;
+}