summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorHangbin Liu <haliu@redhat.com>2020-11-23 21:12:01 +0800
committerDavid Ahern <dsahern@gmail.com>2020-11-24 22:14:08 -0700
commit71c7c1fb4ff0a7abaf22e4d3052b9a2928019c61 (patch)
tree3eb361827219cb07f3b102862827d3c5e81bc5b2 /examples
parent1ac8285a692e45beb846ee8e38472815b3945747 (diff)
downloadiproute2-71c7c1fb4ff0a7abaf22e4d3052b9a2928019c61.tar.gz
examples/bpf: add bpf examples with BTF defined maps
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>
Diffstat (limited to 'examples')
-rw-r--r--examples/bpf/README6
-rw-r--r--examples/bpf/bpf_graft.c66
-rw-r--r--examples/bpf/bpf_map_in_map.c55
-rw-r--r--examples/bpf/bpf_shared.c53
4 files changed, 180 insertions, 0 deletions
diff --git a/examples/bpf/README b/examples/bpf/README
index 732bcc83..b7261191 100644
--- a/examples/bpf/README
+++ b/examples/bpf/README
@@ -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
index 00000000..8066dcce
--- /dev/null
+++ b/examples/bpf/bpf_graft.c
@@ -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
index 00000000..39c86268
--- /dev/null
+++ b/examples/bpf/bpf_map_in_map.c
@@ -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
index 00000000..99a332f4
--- /dev/null
+++ b/examples/bpf/bpf_shared.c
@@ -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");