From patchwork Mon Nov 16 06:53:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Hangbin Liu X-Patchwork-Id: 11907551 X-Patchwork-Delegate: dsahern@gmail.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.9 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 38C84C4742C for ; Mon, 16 Nov 2020 07:03:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C9789222B9 for ; Mon, 16 Nov 2020 07:03:14 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="N1RoNgnP" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727153AbgKPGyH (ORCPT ); Mon, 16 Nov 2020 01:54:07 -0500 Received: from us-smtp-delivery-124.mimecast.com ([216.205.24.124]:51140 "EHLO us-smtp-delivery-124.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727435AbgKPGyH (ORCPT ); Mon, 16 Nov 2020 01:54:07 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1605509644; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mNpTnhqVT/lkkDzOBStmitBv9qqoRpOHiUUiZ8tRN8I=; b=N1RoNgnPiFVA6Mg64ePS/cSfrKsGuwxXBrufKQ6DewKCQauYIf2tChjv+3U59We0YaAkvP vypGIM12j0YJuFtWiZ8ANgPzFcFnm+pmfKzdBNdC0WNqjwsI1PJ2mwADLSGKM8I+wIMDaJ jkMu3sjVfr0dfLkmwPLi21JQjlpsLno= Received: from mail-pf1-f199.google.com (mail-pf1-f199.google.com [209.85.210.199]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-441-bK5wgWZYPHm9mIDn4veLpQ-1; Mon, 16 Nov 2020 01:54:01 -0500 X-MC-Unique: bK5wgWZYPHm9mIDn4veLpQ-1 Received: by mail-pf1-f199.google.com with SMTP id 190so11483030pfz.16 for ; Sun, 15 Nov 2020 22:54:01 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=mNpTnhqVT/lkkDzOBStmitBv9qqoRpOHiUUiZ8tRN8I=; b=CLC5hVaDhNJJFq5sAK1GNlLCCoTcDD99Oi/QQkPenRN356SucHPc2aJl9drzTSvLeD bbma+JPNnH634BcTXzmxNJmy17U8PCOTIhVj80nFYH8x2HIDwC4XuKaheamRlTMAC12m 49RI//5uBodNKCRWrZJ9tYmvlvlU+dMe2ASMIKaPZKSvF/uO50+FLLMn/UT5Vp/lsX7s IwUgo5deZU2cjbevmeOJ402iISgKoDOE/x+kpd0sEwb9BhR/qDCybVb3KXTxBU89G/VM K7zOZ4AcleDBb8r+EvLtz/E3IRf1r+gjs1+6l74git1sZ/09ELNIGCqDPFp/naJnf8Cs AaKw== X-Gm-Message-State: AOAM533eB+T/8+t4CBZMXMgLcc4+EzjSthk4I7l+UgQwBS/shsAehWuE UmpZN8uoJyiF3ig42oka9GqIWB50PGvYvcxW4KXd0j8CXhXPPlcypuxI8g2ymQjwd+fR5h2HYCc nEm1CuLKooVY= X-Received: by 2002:a63:d157:: with SMTP id c23mr365274pgj.196.1605509640415; Sun, 15 Nov 2020 22:54:00 -0800 (PST) X-Google-Smtp-Source: ABdhPJzdxss+14SgNwtyF+UF/rZAXrkrof9klnjD+zDqcADLOJjO7MQm+lQlwGp10hgMQihreu3oMQ== X-Received: by 2002:a63:d157:: with SMTP id c23mr365254pgj.196.1605509640121; Sun, 15 Nov 2020 22:54:00 -0800 (PST) Received: from localhost.localdomain.com ([209.132.188.80]) by smtp.gmail.com with ESMTPSA id 16sm18645837pjf.36.2020.11.15.22.53.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 15 Nov 2020 22:53:59 -0800 (PST) From: Hangbin Liu To: Stephen Hemminger , David Ahern Cc: Daniel Borkmann , Martin KaFai Lau , Song Liu , Yonghong Song , David Miller , Jesper Dangaard Brouer , netdev@vger.kernel.org, bpf@vger.kernel.org, Jiri Benc , =?utf-8?q?Toke_H=C3=B8il?= =?utf-8?q?and-J=C3=B8rgensen?= , Hangbin Liu Subject: [PATCHv5 iproute2-next 5/5] examples/bpf: add bpf examples with BTF defined maps Date: Mon, 16 Nov 2020 14:53:05 +0800 Message-Id: <20201116065305.1010651-6-haliu@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20201116065305.1010651-1-haliu@redhat.com> References: <20201109070802.3638167-1-haliu@redhat.com> <20201116065305.1010651-1-haliu@redhat.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: dsahern@gmail.com 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 Signed-off-by: Hangbin Liu --- examples/bpf/README | 6 ++++ examples/bpf/bpf_graft.c | 66 +++++++++++++++++++++++++++++++++++ examples/bpf/bpf_map_in_map.c | 55 +++++++++++++++++++++++++++++ examples/bpf/bpf_shared.c | 53 ++++++++++++++++++++++++++++ include/bpf_api.h | 13 +++++++ 5 files changed, 193 insertions(+) create mode 100644 examples/bpf/bpf_graft.c create mode 100644 examples/bpf/bpf_map_in_map.c create mode 100644 examples/bpf/bpf_shared.c 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 + * -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 + * -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 + * -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"); diff --git a/include/bpf_api.h b/include/bpf_api.h index 89d3488d..82c47089 100644 --- a/include/bpf_api.h +++ b/include/bpf_api.h @@ -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