@@ -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
new file mode 100644
@@ -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");
new file mode 100644
@@ -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");
new file mode 100644
@@ -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");
@@ -19,6 +19,19 @@
#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