simple packet drop monitor:
- in-kernel eBPF program attaches to kfree_skb() event and records number
  of packet drops at given location
- userspace iterates over the map every second and prints stats

Usage:
$ sudo dropmon
location 0xffffffff81695995 count 1
location 0xffffffff816d0da9 count 2

location 0xffffffff81695995 count 2
location 0xffffffff816d0da9 count 2

location 0xffffffff81695995 count 3
location 0xffffffff816d0da9 count 2

$ addr2line -ape ./bld_x64/vmlinux 0xffffffff81695995 0xffffffff816d0da9
0xffffffff81695995: ./bld_x64/../net/ipv4/icmp.c:1038
0xffffffff816d0da9: ./bld_x64/../net/unix/af_unix.c:1231

Signed-off-by: Alexei Starovoitov <a...@plumgrid.com>
---
 samples/bpf/Makefile  |    2 +
 samples/bpf/dropmon.c |  129 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 131 insertions(+)
 create mode 100644 samples/bpf/dropmon.c

diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index b5b3600dcdf5..789691374562 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -6,7 +6,9 @@ hostprogs-y := test_verifier test_maps
 hostprogs-y += sock_example
 hostprogs-y += sockex1
 hostprogs-y += sockex2
+hostprogs-y += dropmon
 
+dropmon-objs := dropmon.o libbpf.o
 test_verifier-objs := test_verifier.o libbpf.o
 test_maps-objs := test_maps.o libbpf.o
 sock_example-objs := sock_example.o libbpf.o
diff --git a/samples/bpf/dropmon.c b/samples/bpf/dropmon.c
new file mode 100644
index 000000000000..9a2cd3344d69
--- /dev/null
+++ b/samples/bpf/dropmon.c
@@ -0,0 +1,129 @@
+/* simple packet drop monitor:
+ * - in-kernel eBPF program attaches to kfree_skb() event and records number
+ *   of packet drops at given location
+ * - userspace iterates over the map every second and prints stats
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <linux/bpf.h>
+#include <errno.h>
+#include <linux/unistd.h>
+#include <string.h>
+#include <linux/filter.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include "libbpf.h"
+
+#define TRACEPOINT "/sys/kernel/debug/tracing/events/skb/kfree_skb/"
+
+static int write_to_file(const char *file, const char *str, bool keep_open)
+{
+       int fd, err;
+
+       fd = open(file, O_WRONLY);
+       err = write(fd, str, strlen(str));
+       (void) err;
+
+       if (keep_open) {
+               return fd;
+       } else {
+               close(fd);
+               return -1;
+       }
+}
+
+static int dropmon(void)
+{
+       long long key, next_key, value = 0;
+       int prog_fd, map_fd, i;
+       char fmt[32];
+
+       map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), 
1024);
+       if (map_fd < 0) {
+               printf("failed to create map '%s'\n", strerror(errno));
+               goto cleanup;
+       }
+
+       /* the following eBPF program is equivalent to C:
+        * int filter(struct bpf_context *ctx)
+        * {
+        *   long loc = ctx->arg2;
+        *   long init_val = 1;
+        *   long *value;
+        *
+        *   value = bpf_map_lookup_elem(MAP_ID, &loc);
+        *   if (value) {
+        *      __sync_fetch_and_add(value, 1);
+        *   } else {
+        *      bpf_map_update_elem(MAP_ID, &loc, &init_val, BPF_ANY);
+        *   }
+        *   return 0;
+        * }
+        */
+       struct bpf_insn prog[] = {
+               BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, 8), /* r2 = *(u64 
*)(r1 + 8) */
+               BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -8), /* *(u64 *)(fp 
- 8) = r2 */
+               BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+               BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), /* r2 = fp - 8 */
+               BPF_LD_MAP_FD(BPF_REG_1, map_fd),
+               BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, 
BPF_FUNC_map_lookup_elem),
+               BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
+               BPF_MOV64_IMM(BPF_REG_1, 1), /* r1 = 1 */
+               BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_DW, BPF_REG_0, BPF_REG_1, 
0, 0), /* xadd r0 += r1 */
+               BPF_MOV64_IMM(BPF_REG_0, 0), /* r0 = 0 */
+               BPF_EXIT_INSN(),
+               BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 1), /* *(u64 *)(fp - 16) = 
1 */
+               BPF_MOV64_IMM(BPF_REG_4, BPF_ANY),
+               BPF_MOV64_REG(BPF_REG_3, BPF_REG_10),
+               BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, -16), /* r3 = fp - 16 */
+               BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+               BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), /* r2 = fp - 8 */
+               BPF_LD_MAP_FD(BPF_REG_1, map_fd),
+               BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, 
BPF_FUNC_map_update_elem),
+               BPF_MOV64_IMM(BPF_REG_0, 0), /* r0 = 0 */
+               BPF_EXIT_INSN(),
+       };
+
+       prog_fd = bpf_prog_load(BPF_PROG_TYPE_TRACING_FILTER, prog,
+                               sizeof(prog), "GPL");
+       if (prog_fd < 0) {
+               printf("failed to load prog '%s'\n%s", strerror(errno), 
bpf_log_buf);
+               return -1;
+       }
+
+       sprintf(fmt, "bpf_%d", prog_fd);
+
+       write_to_file(TRACEPOINT "filter", fmt, true);
+
+       for (i = 0; i < 10; i++) {
+               key = 0;
+               while (bpf_get_next_key(map_fd, &key, &next_key) == 0) {
+                       bpf_lookup_elem(map_fd, &next_key, &value);
+                       printf("location 0x%llx count %lld\n", next_key, value);
+                       key = next_key;
+               }
+               if (key)
+                       printf("\n");
+               sleep(1);
+       }
+
+cleanup:
+       /* maps, programs, tracepoint filters will auto cleanup on process exit 
*/
+
+       return 0;
+}
+
+int main(void)
+{
+       FILE *f;
+
+       /* start ping in the background to get some kfree_skb events */
+       f = popen("ping -c5 localhost", "r");
+       (void) f;
+
+       dropmon();
+       return 0;
+}
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to