]> git.proxmox.com Git - mirror_iproute2.git/commitdiff
examples/bpf: add bpf examples with BTF defined maps
authorHangbin Liu <haliu@redhat.com>
Mon, 23 Nov 2020 13:12:01 +0000 (21:12 +0800)
committerDavid Ahern <dsahern@gmail.com>
Wed, 25 Nov 2020 05:14:08 +0000 (22:14 -0700)
Users should try use the new BTF defined maps instead of struct
bpf_elf_map defined maps. The tail call examples are not added yet
as libbpf doesn't currently support declaratively populating tail call
maps.

Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
Signed-off-by: Hangbin Liu <haliu@redhat.com>
Signed-off-by: David Ahern <dsahern@gmail.com>
examples/bpf/README
examples/bpf/bpf_graft.c [new file with mode: 0644]
examples/bpf/bpf_map_in_map.c [new file with mode: 0644]
examples/bpf/bpf_shared.c [new file with mode: 0644]
include/bpf_api.h

index 732bcc8315496ef076c295e6d7640035bd751991..b7261191fc1e4c9c6cf678e02db512dd08c241fa 100644 (file)
@@ -1,6 +1,12 @@
 eBPF toy code examples (running in kernel) to familiarize yourself
 with syntax and features:
 
+- BTF defined map examples
+ - bpf_graft.c         -> Demo on altering runtime behaviour
+ - bpf_shared.c        -> Ingress/egress map sharing example
+ - bpf_map_in_map.c    -> Using map in map example
+
+- legacy struct bpf_elf_map defined map examples
  - legacy/bpf_shared.c         -> Ingress/egress map sharing example
  - legacy/bpf_tailcall.c       -> Using tail call chains
  - legacy/bpf_cyclic.c         -> Simple cycle as tail calls
diff --git a/examples/bpf/bpf_graft.c b/examples/bpf/bpf_graft.c
new file mode 100644 (file)
index 0000000..8066dcc
--- /dev/null
@@ -0,0 +1,66 @@
+#include "../../include/bpf_api.h"
+
+/* This example demonstrates how classifier run-time behaviour
+ * can be altered with tail calls. We start out with an empty
+ * jmp_tc array, then add section aaa to the array slot 0, and
+ * later on atomically replace it with section bbb. Note that
+ * as shown in other examples, the tc loader can prepopulate
+ * tail called sections, here we start out with an empty one
+ * on purpose to show it can also be done this way.
+ *
+ * tc filter add dev foo parent ffff: bpf obj graft.o
+ * tc exec bpf dbg
+ *   [...]
+ *   Socket Thread-20229 [001] ..s. 138993.003923: : fallthrough
+ *   <idle>-0            [001] ..s. 138993.202265: : fallthrough
+ *   Socket Thread-20229 [001] ..s. 138994.004149: : fallthrough
+ *   [...]
+ *
+ * tc exec bpf graft m:globals/jmp_tc key 0 obj graft.o sec aaa
+ * tc exec bpf dbg
+ *   [...]
+ *   Socket Thread-19818 [002] ..s. 139012.053587: : aaa
+ *   <idle>-0            [002] ..s. 139012.172359: : aaa
+ *   Socket Thread-19818 [001] ..s. 139012.173556: : aaa
+ *   [...]
+ *
+ * tc exec bpf graft m:globals/jmp_tc key 0 obj graft.o sec bbb
+ * tc exec bpf dbg
+ *   [...]
+ *   Socket Thread-19818 [002] ..s. 139022.102967: : bbb
+ *   <idle>-0            [002] ..s. 139022.155640: : bbb
+ *   Socket Thread-19818 [001] ..s. 139022.156730: : bbb
+ *   [...]
+ */
+
+struct {
+       __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
+       __uint(key_size, sizeof(uint32_t));
+       __uint(value_size, sizeof(uint32_t));
+       __uint(max_entries, 1);
+       __uint(pinning, LIBBPF_PIN_BY_NAME);
+} jmp_tc __section(".maps");
+
+__section("aaa")
+int cls_aaa(struct __sk_buff *skb)
+{
+       printt("aaa\n");
+       return TC_H_MAKE(1, 42);
+}
+
+__section("bbb")
+int cls_bbb(struct __sk_buff *skb)
+{
+       printt("bbb\n");
+       return TC_H_MAKE(1, 43);
+}
+
+__section_cls_entry
+int cls_entry(struct __sk_buff *skb)
+{
+       tail_call(skb, &jmp_tc, 0);
+       printt("fallthrough\n");
+       return BPF_H_DEFAULT;
+}
+
+BPF_LICENSE("GPL");
diff --git a/examples/bpf/bpf_map_in_map.c b/examples/bpf/bpf_map_in_map.c
new file mode 100644 (file)
index 0000000..39c8626
--- /dev/null
@@ -0,0 +1,55 @@
+#include "../../include/bpf_api.h"
+
+struct inner_map {
+       __uint(type, BPF_MAP_TYPE_ARRAY);
+       __uint(key_size, sizeof(uint32_t));
+       __uint(value_size, sizeof(uint32_t));
+       __uint(max_entries, 1);
+} map_inner __section(".maps");
+
+struct {
+       __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
+       __uint(key_size, sizeof(uint32_t));
+       __uint(value_size, sizeof(uint32_t));
+       __uint(max_entries, 1);
+       __uint(pinning, LIBBPF_PIN_BY_NAME);
+       __array(values, struct inner_map);
+} map_outer __section(".maps") = {
+       .values = {
+               [0] = &map_inner,
+       },
+};
+
+__section("egress")
+int emain(struct __sk_buff *skb)
+{
+       struct bpf_elf_map *map_inner;
+       int key = 0, *val;
+
+       map_inner = map_lookup_elem(&map_outer, &key);
+       if (map_inner) {
+               val = map_lookup_elem(map_inner, &key);
+               if (val)
+                       lock_xadd(val, 1);
+       }
+
+       return BPF_H_DEFAULT;
+}
+
+__section("ingress")
+int imain(struct __sk_buff *skb)
+{
+       struct bpf_elf_map *map_inner;
+       int key = 0, *val;
+
+       map_inner = map_lookup_elem(&map_outer, &key);
+       if (map_inner) {
+               val = map_lookup_elem(map_inner, &key);
+               if (val)
+                       printt("map val: %d\n", *val);
+       }
+
+       return BPF_H_DEFAULT;
+}
+
+BPF_LICENSE("GPL");
diff --git a/examples/bpf/bpf_shared.c b/examples/bpf/bpf_shared.c
new file mode 100644 (file)
index 0000000..99a332f
--- /dev/null
@@ -0,0 +1,53 @@
+#include "../../include/bpf_api.h"
+
+/* Minimal, stand-alone toy map pinning example:
+ *
+ * clang -target bpf -O2 [...] -o bpf_shared.o -c bpf_shared.c
+ * tc filter add dev foo parent 1: bpf obj bpf_shared.o sec egress
+ * tc filter add dev foo parent ffff: bpf obj bpf_shared.o sec ingress
+ *
+ * Both classifier will share the very same map instance in this example,
+ * so map content can be accessed from ingress *and* egress side!
+ *
+ * This example has a pinning of PIN_OBJECT_NS, so it's private and
+ * thus shared among various program sections within the object.
+ *
+ * A setting of PIN_GLOBAL_NS would place it into a global namespace,
+ * so that it can be shared among different object files. A setting
+ * of PIN_NONE (= 0) means no sharing, so each tc invocation a new map
+ * instance is being created.
+ */
+
+struct {
+       __uint(type, BPF_MAP_TYPE_ARRAY);
+       __uint(key_size, sizeof(uint32_t));
+       __uint(value_size, sizeof(uint32_t));
+       __uint(max_entries, 1);
+       __uint(pinning, LIBBPF_PIN_BY_NAME);    /* or LIBBPF_PIN_NONE */
+} map_sh __section(".maps");
+
+__section("egress")
+int emain(struct __sk_buff *skb)
+{
+       int key = 0, *val;
+
+       val = map_lookup_elem(&map_sh, &key);
+       if (val)
+               lock_xadd(val, 1);
+
+       return BPF_H_DEFAULT;
+}
+
+__section("ingress")
+int imain(struct __sk_buff *skb)
+{
+       int key = 0, *val;
+
+       val = map_lookup_elem(&map_sh, &key);
+       if (val)
+               printt("map val: %d\n", *val);
+
+       return BPF_H_DEFAULT;
+}
+
+BPF_LICENSE("GPL");
index 89d3488d0741ba2c4ff234eecfdaf20333089d8e..82c47089f61492b3c66bc531de2e0b31cfd51da3 100644 (file)
 
 #include "bpf_elf.h"
 
+/** libbpf pin type. */
+enum libbpf_pin_type {
+       LIBBPF_PIN_NONE,
+       /* PIN_BY_NAME: pin maps by name (in /sys/fs/bpf by default) */
+       LIBBPF_PIN_BY_NAME,
+};
+
+/** Type helper macros. */
+
+#define __uint(name, val) int (*name)[val]
+#define __type(name, val) typeof(val) *name
+#define __array(name, val) typeof(val) *name[]
+
 /** Misc macros. */
 
 #ifndef __stringify