From patchwork Fri Dec 23 23:40:09 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Deslandes X-Patchwork-Id: 13081219 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 907A6C4332F for ; Fri, 23 Dec 2022 23:52:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231970AbiLWXwe (ORCPT ); Fri, 23 Dec 2022 18:52:34 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60872 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231140AbiLWXwd (ORCPT ); Fri, 23 Dec 2022 18:52:33 -0500 X-Greylist: delayed 524 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Fri, 23 Dec 2022 15:52:31 PST Received: from 2.mo546.mail-out.ovh.net (2.mo546.mail-out.ovh.net [178.33.110.155]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 984A413F5E for ; Fri, 23 Dec 2022 15:52:31 -0800 (PST) Received: from ex4.mail.ovh.net (unknown [10.108.20.92]) by mo546.mail-out.ovh.net (Postfix) with ESMTPS id DADF62711D; Fri, 23 Dec 2022 23:43:44 +0000 (UTC) Received: from dev-fedora-x86-64.naccy.de (37.65.8.229) by DAG10EX1.indiv4.local (172.16.2.91) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.16; Sat, 24 Dec 2022 00:43:43 +0100 From: Quentin Deslandes To: CC: , Dmitrii Banshchikov , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Song Liu , Yonghong Song , John Fastabend , KP Singh , Stanislav Fomichev , Hao Luo , Jiri Olsa , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Mykola Lysenko , Shuah Khan , , , , Subject: [PATCH bpf-next v3 01/16] bpfilter: add types for usermode helper Date: Sat, 24 Dec 2022 00:40:09 +0100 Message-ID: <20221223234127.474463-2-qde@naccy.de> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221223234127.474463-1-qde@naccy.de> References: <20221223234127.474463-1-qde@naccy.de> MIME-Version: 1.0 X-Originating-IP: [37.65.8.229] X-ClientProxiedBy: CAS6.indiv4.local (172.16.1.6) To DAG10EX1.indiv4.local (172.16.2.91) X-Ovh-Tracer-Id: 4409305514236374647 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -85 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedvhedrheefgddufecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemucehtddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenogetfedtuddqtdduucdludehmdenucfjughrpefhvfevufffkffojghfggfgtghisehtkeertdertddtnecuhfhrohhmpefsuhgvnhhtihhnucffvghslhgrnhguvghsuceoqhguvgesnhgrtggthidruggvqeenucggtffrrghtthgvrhhnpeduledugfeileetvdelieeujedttedtvedtgfetteevfeejhfffkeeujeetfffgudenucfkphepuddvjedrtddrtddruddpfeejrdeihedrkedrvddvleenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepihhnvghtpeduvdejrddtrddtrddupdhmrghilhhfrhhomhepoehquggvsehnrggttgihrdguvgeqpdhnsggprhgtphhtthhopedupdhrtghpthhtohepshgufhesghhoohhglhgvrdgtohhmpdgsphhfsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhlihhnuhigqdhkvghrnhgvlhesvhhgvghrrdhkvghrnhgvlhdrohhrghdpshhhuhgrhheskhgvrhhnvghlrdhorhhgpdhmhihkohhlrghlsehfsgdrtghomhdpphgrsggvnhhisehrvgguhhgrthdrtghomhdpkhhusggrsehkvghrnhgvlhdrohhrghdpvgguuhhmrgiivghtsehgohhoghhlvgdrtghomhdpuggrvhgvmhesuggrvhgvmhhlohhfthdrnhgvth dpjhholhhsrgeskhgvrhhnvghlrdhorhhgpdhhrgholhhuohesghhoohhglhgvrdgtohhmpdhlihhnuhigqdhkshgvlhhfthgvshhtsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhkphhsihhnghhhsehkvghrnhgvlhdrohhrghdpjhhohhhnrdhfrghsthgrsggvnhgusehgmhgrihhlrdgtohhmpdihhhhssehfsgdrtghomhdpshhonhhgsehkvghrnhgvlhdrohhrghdpmhgrrhhtihhnrdhlrghusehlihhnuhigrdguvghvpdgrnhgurhhiiheskhgvrhhnvghlrdhorhhgpdgurghnihgvlhesihhoghgvrghrsghogidrnhgvthdprghstheskhgvrhhnvghlrdhorhhgpdhmvgesuhgsihhquhgvrdhsphgsrdhruhdpkhgvrhhnvghlqdhtvggrmhesmhgvthgrrdgtohhmpdhnvghtuggvvhesvhhgvghrrdhkvghrnhgvlhdrohhrghdpoffvtefjohhsthepmhhoheegiedpmhhouggvpehsmhhtphhouhht Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net Add required definitions that mirror existing iptables' ABI. Those definitions are needed by usermode helper. Co-developed-by: Dmitrii Banshchikov Signed-off-by: Dmitrii Banshchikov Signed-off-by: Quentin Deslandes --- include/uapi/linux/bpfilter.h | 154 ++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/include/uapi/linux/bpfilter.h b/include/uapi/linux/bpfilter.h index cbc1f5813f50..295fd9caa3c8 100644 --- a/include/uapi/linux/bpfilter.h +++ b/include/uapi/linux/bpfilter.h @@ -3,6 +3,10 @@ #define _UAPI_LINUX_BPFILTER_H #include +#include + +#define BPFILTER_STANDARD_TARGET "" +#define BPFILTER_ERROR_TARGET "ERROR" enum { BPFILTER_IPT_SO_SET_REPLACE = 64, @@ -18,4 +22,154 @@ enum { BPFILTER_IPT_GET_MAX, }; +enum { + BPFILTER_XT_TABLE_MAXNAMELEN = 32, + BPFILTER_FUNCTION_MAXNAMELEN = 30, + BPFILTER_EXTENSION_MAXNAMELEN = 29, +}; + +enum { + BPFILTER_NF_DROP = 0, + BPFILTER_NF_ACCEPT = 1, + BPFILTER_NF_STOLEN = 2, + BPFILTER_NF_QUEUE = 3, + BPFILTER_NF_REPEAT = 4, + BPFILTER_NF_STOP = 5, + BPFILTER_NF_MAX_VERDICT = BPFILTER_NF_STOP, + BPFILTER_RETURN = (-BPFILTER_NF_REPEAT - 1), +}; + +enum { + BPFILTER_INET_HOOK_PRE_ROUTING = 0, + BPFILTER_INET_HOOK_LOCAL_IN = 1, + BPFILTER_INET_HOOK_FORWARD = 2, + BPFILTER_INET_HOOK_LOCAL_OUT = 3, + BPFILTER_INET_HOOK_POST_ROUTING = 4, + BPFILTER_INET_HOOK_MAX, +}; + +enum { + BPFILTER_IPT_F_MASK = 0x03, + BPFILTER_IPT_INV_MASK = 0x7f +}; + +struct bpfilter_ipt_match { + union { + struct { + __u16 match_size; + char name[BPFILTER_EXTENSION_MAXNAMELEN]; + __u8 revision; + } user; + struct { + __u16 match_size; + void *match; + } kernel; + __u16 match_size; + } u; + unsigned char data[]; +}; + +struct bpfilter_ipt_target { + union { + struct { + __u16 target_size; + char name[BPFILTER_EXTENSION_MAXNAMELEN]; + __u8 revision; + } user; + struct { + __u16 target_size; + void *target; + } kernel; + __u16 target_size; + } u; + unsigned char data[]; +}; + +struct bpfilter_ipt_standard_target { + struct bpfilter_ipt_target target; + int verdict; +}; + +struct bpfilter_ipt_error_target { + struct bpfilter_ipt_target target; + char error_name[BPFILTER_FUNCTION_MAXNAMELEN]; +}; + +struct bpfilter_ipt_get_info { + char name[BPFILTER_XT_TABLE_MAXNAMELEN]; + __u32 valid_hooks; + __u32 hook_entry[BPFILTER_INET_HOOK_MAX]; + __u32 underflow[BPFILTER_INET_HOOK_MAX]; + __u32 num_entries; + __u32 size; +}; + +struct bpfilter_ipt_counters { + __u64 packet_cnt; + __u64 byte_cnt; +}; + +struct bpfilter_ipt_counters_info { + char name[BPFILTER_XT_TABLE_MAXNAMELEN]; + __u32 num_counters; + struct bpfilter_ipt_counters counters[]; +}; + +struct bpfilter_ipt_get_revision { + char name[BPFILTER_EXTENSION_MAXNAMELEN]; + __u8 revision; +}; + +struct bpfilter_ipt_ip { + __u32 src; + __u32 dst; + __u32 src_mask; + __u32 dst_mask; + char in_iface[IFNAMSIZ]; + char out_iface[IFNAMSIZ]; + __u8 in_iface_mask[IFNAMSIZ]; + __u8 out_iface_mask[IFNAMSIZ]; + __u16 protocol; + __u8 flags; + __u8 invflags; +}; + +struct bpfilter_ipt_entry { + struct bpfilter_ipt_ip ip; + __u32 bfcache; + __u16 target_offset; + __u16 next_offset; + __u32 comefrom; + struct bpfilter_ipt_counters counters; + __u8 elems[]; +}; + +struct bpfilter_ipt_standard_entry { + struct bpfilter_ipt_entry entry; + struct bpfilter_ipt_standard_target target; +}; + +struct bpfilter_ipt_error_entry { + struct bpfilter_ipt_entry entry; + struct bpfilter_ipt_error_target target; +}; + +struct bpfilter_ipt_get_entries { + char name[BPFILTER_XT_TABLE_MAXNAMELEN]; + __u32 size; + struct bpfilter_ipt_entry entries[]; +}; + +struct bpfilter_ipt_replace { + char name[BPFILTER_XT_TABLE_MAXNAMELEN]; + __u32 valid_hooks; + __u32 num_entries; + __u32 size; + __u32 hook_entry[BPFILTER_INET_HOOK_MAX]; + __u32 underflow[BPFILTER_INET_HOOK_MAX]; + __u32 num_counters; + struct bpfilter_ipt_counters *cntrs; + struct bpfilter_ipt_entry entries[]; +}; + #endif /* _UAPI_LINUX_BPFILTER_H */ From patchwork Fri Dec 23 23:40:10 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Deslandes X-Patchwork-Id: 13081238 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 80DEDC4332F for ; Sat, 24 Dec 2022 00:01:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233051AbiLXABW (ORCPT ); Fri, 23 Dec 2022 19:01:22 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35338 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232862AbiLXABP (ORCPT ); Fri, 23 Dec 2022 19:01:15 -0500 X-Greylist: delayed 595 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Fri, 23 Dec 2022 16:01:14 PST Received: from 4.mo619.mail-out.ovh.net (4.mo619.mail-out.ovh.net [46.105.36.27]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C2B3A2AC for ; Fri, 23 Dec 2022 16:01:14 -0800 (PST) Received: from ex4.mail.ovh.net (unknown [10.109.143.173]) by mo619.mail-out.ovh.net (Postfix) with ESMTPS id 8C1AD22E82; Fri, 23 Dec 2022 23:44:49 +0000 (UTC) Received: from dev-fedora-x86-64.naccy.de (37.65.8.229) by DAG10EX1.indiv4.local (172.16.2.91) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.16; Sat, 24 Dec 2022 00:44:48 +0100 From: Quentin Deslandes To: CC: , Dmitrii Banshchikov , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Song Liu , Yonghong Song , John Fastabend , KP Singh , Stanislav Fomichev , Hao Luo , Jiri Olsa , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Mykola Lysenko , Shuah Khan , , , , Subject: [PATCH bpf-next v3 02/16] tools: add bpfilter usermode helper header Date: Sat, 24 Dec 2022 00:40:10 +0100 Message-ID: <20221223234127.474463-3-qde@naccy.de> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221223234127.474463-1-qde@naccy.de> References: <20221223234127.474463-1-qde@naccy.de> MIME-Version: 1.0 X-Originating-IP: [37.65.8.229] X-ClientProxiedBy: CAS6.indiv4.local (172.16.1.6) To DAG10EX1.indiv4.local (172.16.2.91) X-Ovh-Tracer-Id: 4427601385733353079 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -85 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedvhedrheefgddufecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemucehtddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenogetfedtuddqtdduucdludehmdenucfjughrpefhvfevufffkffojghfggfgtghisehtkeertdertddtnecuhfhrohhmpefsuhgvnhhtihhnucffvghslhgrnhguvghsuceoqhguvgesnhgrtggthidruggvqeenucggtffrrghtthgvrhhnpeduledugfeileetvdelieeujedttedtvedtgfetteevfeejhfffkeeujeetfffgudenucfkphepuddvjedrtddrtddruddpfeejrdeihedrkedrvddvleenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepihhnvghtpeduvdejrddtrddtrddupdhmrghilhhfrhhomhepoehquggvsehnrggttgihrdguvgeqpdhnsggprhgtphhtthhopedupdhrtghpthhtohepshgufhesghhoohhglhgvrdgtohhmpdgsphhfsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhlihhnuhigqdhkvghrnhgvlhesvhhgvghrrdhkvghrnhgvlhdrohhrghdpshhhuhgrhheskhgvrhhnvghlrdhorhhgpdhmhihkohhlrghlsehfsgdrtghomhdpphgrsggvnhhisehrvgguhhgrthdrtghomhdpkhhusggrsehkvghrnhgvlhdrohhrghdpvgguuhhmrgiivghtsehgohhoghhlvgdrtghomhdpuggrvhgvmhesuggrvhgvmhhlohhfthdrnhgvth dpjhholhhsrgeskhgvrhhnvghlrdhorhhgpdhhrgholhhuohesghhoohhglhgvrdgtohhmpdhlihhnuhigqdhkshgvlhhfthgvshhtsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhkphhsihhnghhhsehkvghrnhgvlhdrohhrghdpjhhohhhnrdhfrghsthgrsggvnhgusehgmhgrihhlrdgtohhmpdihhhhssehfsgdrtghomhdpshhonhhgsehkvghrnhgvlhdrohhrghdpmhgrrhhtihhnrdhlrghusehlihhnuhigrdguvghvpdgrnhgurhhiiheskhgvrhhnvghlrdhorhhgpdgurghnihgvlhesihhoghgvrghrsghogidrnhgvthdprghstheskhgvrhhnvghlrdhorhhgpdhmvgesuhgsihhquhgvrdhsphgsrdhruhdpkhgvrhhnvghlqdhtvggrmhesmhgvthgrrdgtohhmpdhnvghtuggvvhesvhhgvghrrdhkvghrnhgvlhdrohhrghdpoffvtefjohhsthepmhhoieduledpmhhouggvpehsmhhtphhouhht Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net Add header containing bpfilter structures definitions, for test purposes. Co-developed-by: Dmitrii Banshchikov Signed-off-by: Dmitrii Banshchikov Signed-off-by: Quentin Deslandes --- tools/include/uapi/linux/bpfilter.h | 175 ++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 tools/include/uapi/linux/bpfilter.h diff --git a/tools/include/uapi/linux/bpfilter.h b/tools/include/uapi/linux/bpfilter.h new file mode 100644 index 000000000000..295fd9caa3c8 --- /dev/null +++ b/tools/include/uapi/linux/bpfilter.h @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_BPFILTER_H +#define _UAPI_LINUX_BPFILTER_H + +#include +#include + +#define BPFILTER_STANDARD_TARGET "" +#define BPFILTER_ERROR_TARGET "ERROR" + +enum { + BPFILTER_IPT_SO_SET_REPLACE = 64, + BPFILTER_IPT_SO_SET_ADD_COUNTERS = 65, + BPFILTER_IPT_SET_MAX, +}; + +enum { + BPFILTER_IPT_SO_GET_INFO = 64, + BPFILTER_IPT_SO_GET_ENTRIES = 65, + BPFILTER_IPT_SO_GET_REVISION_MATCH = 66, + BPFILTER_IPT_SO_GET_REVISION_TARGET = 67, + BPFILTER_IPT_GET_MAX, +}; + +enum { + BPFILTER_XT_TABLE_MAXNAMELEN = 32, + BPFILTER_FUNCTION_MAXNAMELEN = 30, + BPFILTER_EXTENSION_MAXNAMELEN = 29, +}; + +enum { + BPFILTER_NF_DROP = 0, + BPFILTER_NF_ACCEPT = 1, + BPFILTER_NF_STOLEN = 2, + BPFILTER_NF_QUEUE = 3, + BPFILTER_NF_REPEAT = 4, + BPFILTER_NF_STOP = 5, + BPFILTER_NF_MAX_VERDICT = BPFILTER_NF_STOP, + BPFILTER_RETURN = (-BPFILTER_NF_REPEAT - 1), +}; + +enum { + BPFILTER_INET_HOOK_PRE_ROUTING = 0, + BPFILTER_INET_HOOK_LOCAL_IN = 1, + BPFILTER_INET_HOOK_FORWARD = 2, + BPFILTER_INET_HOOK_LOCAL_OUT = 3, + BPFILTER_INET_HOOK_POST_ROUTING = 4, + BPFILTER_INET_HOOK_MAX, +}; + +enum { + BPFILTER_IPT_F_MASK = 0x03, + BPFILTER_IPT_INV_MASK = 0x7f +}; + +struct bpfilter_ipt_match { + union { + struct { + __u16 match_size; + char name[BPFILTER_EXTENSION_MAXNAMELEN]; + __u8 revision; + } user; + struct { + __u16 match_size; + void *match; + } kernel; + __u16 match_size; + } u; + unsigned char data[]; +}; + +struct bpfilter_ipt_target { + union { + struct { + __u16 target_size; + char name[BPFILTER_EXTENSION_MAXNAMELEN]; + __u8 revision; + } user; + struct { + __u16 target_size; + void *target; + } kernel; + __u16 target_size; + } u; + unsigned char data[]; +}; + +struct bpfilter_ipt_standard_target { + struct bpfilter_ipt_target target; + int verdict; +}; + +struct bpfilter_ipt_error_target { + struct bpfilter_ipt_target target; + char error_name[BPFILTER_FUNCTION_MAXNAMELEN]; +}; + +struct bpfilter_ipt_get_info { + char name[BPFILTER_XT_TABLE_MAXNAMELEN]; + __u32 valid_hooks; + __u32 hook_entry[BPFILTER_INET_HOOK_MAX]; + __u32 underflow[BPFILTER_INET_HOOK_MAX]; + __u32 num_entries; + __u32 size; +}; + +struct bpfilter_ipt_counters { + __u64 packet_cnt; + __u64 byte_cnt; +}; + +struct bpfilter_ipt_counters_info { + char name[BPFILTER_XT_TABLE_MAXNAMELEN]; + __u32 num_counters; + struct bpfilter_ipt_counters counters[]; +}; + +struct bpfilter_ipt_get_revision { + char name[BPFILTER_EXTENSION_MAXNAMELEN]; + __u8 revision; +}; + +struct bpfilter_ipt_ip { + __u32 src; + __u32 dst; + __u32 src_mask; + __u32 dst_mask; + char in_iface[IFNAMSIZ]; + char out_iface[IFNAMSIZ]; + __u8 in_iface_mask[IFNAMSIZ]; + __u8 out_iface_mask[IFNAMSIZ]; + __u16 protocol; + __u8 flags; + __u8 invflags; +}; + +struct bpfilter_ipt_entry { + struct bpfilter_ipt_ip ip; + __u32 bfcache; + __u16 target_offset; + __u16 next_offset; + __u32 comefrom; + struct bpfilter_ipt_counters counters; + __u8 elems[]; +}; + +struct bpfilter_ipt_standard_entry { + struct bpfilter_ipt_entry entry; + struct bpfilter_ipt_standard_target target; +}; + +struct bpfilter_ipt_error_entry { + struct bpfilter_ipt_entry entry; + struct bpfilter_ipt_error_target target; +}; + +struct bpfilter_ipt_get_entries { + char name[BPFILTER_XT_TABLE_MAXNAMELEN]; + __u32 size; + struct bpfilter_ipt_entry entries[]; +}; + +struct bpfilter_ipt_replace { + char name[BPFILTER_XT_TABLE_MAXNAMELEN]; + __u32 valid_hooks; + __u32 num_entries; + __u32 size; + __u32 hook_entry[BPFILTER_INET_HOOK_MAX]; + __u32 underflow[BPFILTER_INET_HOOK_MAX]; + __u32 num_counters; + struct bpfilter_ipt_counters *cntrs; + struct bpfilter_ipt_entry entries[]; +}; + +#endif /* _UAPI_LINUX_BPFILTER_H */ From patchwork Fri Dec 23 23:40:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Deslandes X-Patchwork-Id: 13081246 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E1020C4167B for ; Sat, 24 Dec 2022 00:07:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233613AbiLXAHS (ORCPT ); Fri, 23 Dec 2022 19:07:18 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36904 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236512AbiLXAGq (ORCPT ); Fri, 23 Dec 2022 19:06:46 -0500 X-Greylist: delayed 1164 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Fri, 23 Dec 2022 16:05:21 PST Received: from 7.mo547.mail-out.ovh.net (7.mo547.mail-out.ovh.net [46.105.53.191]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A62521A20F for ; Fri, 23 Dec 2022 16:05:19 -0800 (PST) Received: from ex4.mail.ovh.net (unknown [10.110.115.196]) by mo547.mail-out.ovh.net (Postfix) with ESMTPS id E382E20E4E; Fri, 23 Dec 2022 23:45:53 +0000 (UTC) Received: from dev-fedora-x86-64.naccy.de (37.65.8.229) by DAG10EX1.indiv4.local (172.16.2.91) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.16; Sat, 24 Dec 2022 00:45:52 +0100 From: Quentin Deslandes To: CC: , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Song Liu , Yonghong Song , John Fastabend , KP Singh , Stanislav Fomichev , Hao Luo , Jiri Olsa , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Mykola Lysenko , Shuah Khan , Dmitrii Banshchikov , , , , Subject: [PATCH bpf-next v3 03/16] bpfilter: add logging facility Date: Sat, 24 Dec 2022 00:40:11 +0100 Message-ID: <20221223234127.474463-4-qde@naccy.de> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221223234127.474463-1-qde@naccy.de> References: <20221223234127.474463-1-qde@naccy.de> MIME-Version: 1.0 X-Originating-IP: [37.65.8.229] X-ClientProxiedBy: CAS6.indiv4.local (172.16.1.6) To DAG10EX1.indiv4.local (172.16.2.91) X-Ovh-Tracer-Id: 4445897259362283127 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -85 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedvhedrheefgddugecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemucehtddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenogetfedtuddqtdduucdludehmdenucfjughrpefhvfevufffkffojghfggfgtghisehtkeertdertddtnecuhfhrohhmpefsuhgvnhhtihhnucffvghslhgrnhguvghsuceoqhguvgesnhgrtggthidruggvqeenucggtffrrghtthgvrhhnpeduledugfeileetvdelieeujedttedtvedtgfetteevfeejhfffkeeujeetfffgudenucfkphepuddvjedrtddrtddruddpfeejrdeihedrkedrvddvleenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepihhnvghtpeduvdejrddtrddtrddupdhmrghilhhfrhhomhepoehquggvsehnrggttgihrdguvgeqpdhnsggprhgtphhtthhopedupdhrtghpthhtohephhgrohhluhhosehgohhoghhlvgdrtghomhdpsghpfhesvhhgvghrrdhkvghrnhgvlhdrohhrghdplhhinhhugidqkhgvrhhnvghlsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhmvgesuhgsihhquhgvrdhsphgsrdhruhdpshhhuhgrhheskhgvrhhnvghlrdhorhhgpdhmhihkohhlrghlsehfsgdrtghomhdpphgrsggvnhhisehrvgguhhgrthdrtghomhdpkhhusggrsehkvghrnhgvlhdrohhrghdpvgguuhhmrgiivghtsehgohhoghhlvgdrtghomh dpuggrvhgvmhesuggrvhgvmhhlohhfthdrnhgvthdpjhholhhsrgeskhgvrhhnvghlrdhorhhgpdhlihhnuhigqdhkshgvlhhfthgvshhtsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhsughfsehgohhoghhlvgdrtghomhdpkhhpshhinhhghheskhgvrhhnvghlrdhorhhgpdhjohhhnhdrfhgrshhtrggsvghnugesghhmrghilhdrtghomhdphihhshesfhgsrdgtohhmpdhsohhngheskhgvrhhnvghlrdhorhhgpdhmrghrthhinhdrlhgruheslhhinhhugidruggvvhdprghnughrihhisehkvghrnhgvlhdrohhrghdpuggrnhhivghlsehiohhgvggrrhgsohigrdhnvghtpdgrshhtsehkvghrnhgvlhdrohhrghdpkhgvrhhnvghlqdhtvggrmhesmhgvthgrrdgtohhmpdhnvghtuggvvhesvhhgvghrrdhkvghrnhgvlhdrohhrghdpoffvtefjohhsthepmhhoheegjedpmhhouggvpehsmhhtphhouhht Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net bpfilter will log to /dev/kmsg by default. Four different log levels are available. LOG_EMERG() will exit the usermode helper after logging. Signed-off-by: Quentin Deslandes --- net/bpfilter/Makefile | 2 +- net/bpfilter/logger.c | 52 ++++++++++++++++++++++++++++ net/bpfilter/logger.h | 80 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 net/bpfilter/logger.c create mode 100644 net/bpfilter/logger.h diff --git a/net/bpfilter/Makefile b/net/bpfilter/Makefile index cdac82b8c53a..8d9c726ba1a5 100644 --- a/net/bpfilter/Makefile +++ b/net/bpfilter/Makefile @@ -4,7 +4,7 @@ # userprogs := bpfilter_umh -bpfilter_umh-objs := main.o +bpfilter_umh-objs := main.o logger.o userccflags += -I $(srctree)/tools/include/ -I $(srctree)/tools/include/uapi ifeq ($(CONFIG_BPFILTER_UMH), y) diff --git a/net/bpfilter/logger.c b/net/bpfilter/logger.c new file mode 100644 index 000000000000..c256bfef7e6c --- /dev/null +++ b/net/bpfilter/logger.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. + */ + +#include "logger.h" + +#include + +static const char *log_file_path = "/dev/kmsg"; +static FILE *log_file; + +int logger_init(void) +{ + if (log_file) + return 0; + + log_file = fopen(log_file_path, "w"); + if (!log_file) + return -errno; + + if (setvbuf(log_file, 0, _IOLBF, 0)) + return -errno; + + return 0; +} + +void logger_set_file(FILE *file) +{ + log_file = file; +} + +FILE *logger_get_file(void) +{ + return log_file; +} + +int logger_clean(void) +{ + int r; + + if (!log_file) + return 0; + + r = fclose(log_file); + if (r == EOF) + return -errno; + + log_file = NULL; + + return 0; +} diff --git a/net/bpfilter/logger.h b/net/bpfilter/logger.h new file mode 100644 index 000000000000..c44739ec0069 --- /dev/null +++ b/net/bpfilter/logger.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. + */ + +#ifndef NET_BPFILTER_LOGGER_H +#define NET_BPFILTER_LOGGER_H + +#include +#include +#include +#include + +#define _BFLOG_IMPL(level, fmt, ...) \ + do { \ + typeof(level) __level = level; \ + if (logger_get_file()) { \ + fprintf(logger_get_file(), "<%d>bpfilter: " fmt "\n", \ + (__level), ##__VA_ARGS__); \ + } \ + if ((__level) == LOG_EMERG) \ + exit(EXIT_FAILURE); \ + } while (0) + +#define BFLOG_EMERG(fmt, ...) \ + _BFLOG_IMPL(LOG_KERN | LOG_EMERG, fmt, ##__VA_ARGS__) +#define BFLOG_ERR(fmt, ...) \ + _BFLOG_IMPL(LOG_KERN | LOG_ERR, fmt, ##__VA_ARGS__) +#define BFLOG_NOTICE(fmt, ...) \ + _BFLOG_IMPL(LOG_KERN | LOG_NOTICE, fmt, ##__VA_ARGS__) + +#ifdef DEBUG +#define BFLOG_DBG(fmt, ...) BFLOG_IMPL(LOG_KERN | LOG_DEBUG, fmt, ##__VA_ARGS__) +#else +#define BFLOG_DBG(fmt, ...) +#endif + +#define STRERR(v) strerror(abs(v)) + +/** + * logger_init() - Initialise logging facility. + * + * This function is used to open a file to write logs to (see @log_file_path). + * It must be called before using any logging macro, otherwise log messages + * will be discarded. + * + * Return: 0 on success, negative errno value on error. + */ +int logger_init(void); + +/** + * logger_set_file() - Set the FILE pointer to use to log messages. + * @file: new FILE * to the log file. + * + * This function won't check whether the FILE pointer is valid, nor whether + * a file is already opened, this is the responsibility of the caller. Once + * logger_set_file() returns, all new log messages will be printed to the + * FILE * provided. + */ +void logger_set_file(FILE *file); + +/** + * logger_get_file() - Returns a FILE * pointer to the log file. + * + * Return: pointer to the file to log to (as a FILE *), or NULL if the file + * is not valid. + */ +FILE *logger_get_file(void); + +/** + * logger_clean() - Close the log file. + * + * On success, the log file pointer will be NULL. If the function fails, + * the log file pointer remain unchanged and the file should be considered open. + * + * Return: 0 on success, negative errno value on error. + */ +int logger_clean(void); + +#endif // NET_BPFILTER_LOGGER_H From patchwork Fri Dec 23 23:40:12 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Deslandes X-Patchwork-Id: 13081239 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CE9CDC4332F for ; Sat, 24 Dec 2022 00:02:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232077AbiLXACW (ORCPT ); Fri, 23 Dec 2022 19:02:22 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35886 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231214AbiLXACV (ORCPT ); Fri, 23 Dec 2022 19:02:21 -0500 X-Greylist: delayed 597 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Fri, 23 Dec 2022 16:02:20 PST Received: from 2.mo545.mail-out.ovh.net (2.mo545.mail-out.ovh.net [178.33.110.194]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DE884164BE; Fri, 23 Dec 2022 16:02:19 -0800 (PST) Received: from ex4.mail.ovh.net (unknown [10.108.4.242]) by mo545.mail-out.ovh.net (Postfix) with ESMTPS id 56F8125F6D; Fri, 23 Dec 2022 23:46:58 +0000 (UTC) Received: from dev-fedora-x86-64.naccy.de (37.65.8.229) by DAG10EX1.indiv4.local (172.16.2.91) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.16; Sat, 24 Dec 2022 00:46:56 +0100 From: Quentin Deslandes To: CC: , Dmitrii Banshchikov , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Song Liu , Yonghong Song , John Fastabend , KP Singh , Stanislav Fomichev , Hao Luo , Jiri Olsa , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Mykola Lysenko , Shuah Khan , , , , Subject: [PATCH bpf-next v3 04/16] bpfilter: add map container Date: Sat, 24 Dec 2022 00:40:12 +0100 Message-ID: <20221223234127.474463-5-qde@naccy.de> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221223234127.474463-1-qde@naccy.de> References: <20221223234127.474463-1-qde@naccy.de> MIME-Version: 1.0 X-Originating-IP: [37.65.8.229] X-ClientProxiedBy: CAS6.indiv4.local (172.16.1.6) To DAG10EX1.indiv4.local (172.16.2.91) X-Ovh-Tracer-Id: 4463911657738137207 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -85 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedvhedrheefgddufecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemucehtddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenogetfedtuddqtdduucdludehmdenucfjughrpefhvfevufffkffojghfggfgtghisehtkeertdertddtnecuhfhrohhmpefsuhgvnhhtihhnucffvghslhgrnhguvghsuceoqhguvgesnhgrtggthidruggvqeenucggtffrrghtthgvrhhnpeduledugfeileetvdelieeujedttedtvedtgfetteevfeejhfffkeeujeetfffgudenucfkphepuddvjedrtddrtddruddpfeejrdeihedrkedrvddvleenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepihhnvghtpeduvdejrddtrddtrddupdhmrghilhhfrhhomhepoehquggvsehnrggttgihrdguvgeqpdhnsggprhgtphhtthhopedupdhrtghpthhtohepshgufhesghhoohhglhgvrdgtohhmpdgsphhfsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhlihhnuhigqdhkvghrnhgvlhesvhhgvghrrdhkvghrnhgvlhdrohhrghdpshhhuhgrhheskhgvrhhnvghlrdhorhhgpdhmhihkohhlrghlsehfsgdrtghomhdpphgrsggvnhhisehrvgguhhgrthdrtghomhdpkhhusggrsehkvghrnhgvlhdrohhrghdpvgguuhhmrgiivghtsehgohhoghhlvgdrtghomhdpuggrvhgvmhesuggrvhgvmhhlohhfthdrnhgvth dpjhholhhsrgeskhgvrhhnvghlrdhorhhgpdhhrgholhhuohesghhoohhglhgvrdgtohhmpdhlihhnuhigqdhkshgvlhhfthgvshhtsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhkphhsihhnghhhsehkvghrnhgvlhdrohhrghdpjhhohhhnrdhfrghsthgrsggvnhgusehgmhgrihhlrdgtohhmpdihhhhssehfsgdrtghomhdpshhonhhgsehkvghrnhgvlhdrohhrghdpmhgrrhhtihhnrdhlrghusehlihhnuhigrdguvghvpdgrnhgurhhiiheskhgvrhhnvghlrdhorhhgpdgurghnihgvlhesihhoghgvrghrsghogidrnhgvthdprghstheskhgvrhhnvghlrdhorhhgpdhmvgesuhgsihhquhgvrdhsphgsrdhruhdpkhgvrhhnvghlqdhtvggrmhesmhgvthgrrdgtohhmpdhnvghtuggvvhesvhhgvghrrdhkvghrnhgvlhdrohhrghdpoffvtefjohhsthepmhhoheeghedpmhhouggvpehsmhhtphhouhht Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net Introduce common code for an associative container. This common code will be used for maps of matches, targets, and tables. Hash search tables from libc are used as an index. The supported sets of operations is: create, find, upsert, free. Co-developed-by: Dmitrii Banshchikov Signed-off-by: Dmitrii Banshchikov Signed-off-by: Quentin Deslandes --- net/bpfilter/Makefile | 2 +- net/bpfilter/map-common.c | 51 +++++++++++++++ net/bpfilter/map-common.h | 19 ++++++ .../testing/selftests/bpf/bpfilter/.gitignore | 2 + tools/testing/selftests/bpf/bpfilter/Makefile | 19 ++++++ .../testing/selftests/bpf/bpfilter/test_map.c | 63 +++++++++++++++++++ 6 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 net/bpfilter/map-common.c create mode 100644 net/bpfilter/map-common.h create mode 100644 tools/testing/selftests/bpf/bpfilter/.gitignore create mode 100644 tools/testing/selftests/bpf/bpfilter/Makefile create mode 100644 tools/testing/selftests/bpf/bpfilter/test_map.c diff --git a/net/bpfilter/Makefile b/net/bpfilter/Makefile index 8d9c726ba1a5..1b0c399c19df 100644 --- a/net/bpfilter/Makefile +++ b/net/bpfilter/Makefile @@ -4,7 +4,7 @@ # userprogs := bpfilter_umh -bpfilter_umh-objs := main.o logger.o +bpfilter_umh-objs := main.o logger.o map-common.o userccflags += -I $(srctree)/tools/include/ -I $(srctree)/tools/include/uapi ifeq ($(CONFIG_BPFILTER_UMH), y) diff --git a/net/bpfilter/map-common.c b/net/bpfilter/map-common.c new file mode 100644 index 000000000000..cc6c3a59b315 --- /dev/null +++ b/net/bpfilter/map-common.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Telegram FZ-LLC + * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. + */ + +#include "map-common.h" + +#include + +#include +#include + +int create_map(struct hsearch_data *htab, size_t nelem) +{ + memset(htab, 0, sizeof(*htab)); + if (!hcreate_r(nelem, htab)) + return -errno; + + return 0; +} + +void *map_find(struct hsearch_data *htab, const char *key) +{ + const ENTRY needle = { .key = (char *)key }; + ENTRY *found; + + if (!hsearch_r(needle, FIND, &found, htab)) + return ERR_PTR(-ENOENT); + + return found->data; +} + +int map_upsert(struct hsearch_data *htab, const char *key, void *value) +{ + const ENTRY needle = { .key = (char *)key, .data = value }; + ENTRY *found; + + if (!hsearch_r(needle, ENTER, &found, htab)) + return -errno; + + found->key = (char *)key; + found->data = value; + + return 0; +} + +void free_map(struct hsearch_data *htab) +{ + hdestroy_r(htab); +} diff --git a/net/bpfilter/map-common.h b/net/bpfilter/map-common.h new file mode 100644 index 000000000000..666a4ffe9b29 --- /dev/null +++ b/net/bpfilter/map-common.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Telegram FZ-LLC + * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. + */ + +#ifndef NET_BPFILTER_MAP_COMMON_H +#define NET_BPFILTER_MAP_COMMON_H + +#define _GNU_SOURCE + +#include + +int create_map(struct hsearch_data *htab, size_t nelem); +void *map_find(struct hsearch_data *htab, const char *key); +int map_upsert(struct hsearch_data *htab, const char *key, void *value); +void free_map(struct hsearch_data *htab); + +#endif // NET_BPFILTER_MAP_COMMON_H diff --git a/tools/testing/selftests/bpf/bpfilter/.gitignore b/tools/testing/selftests/bpf/bpfilter/.gitignore new file mode 100644 index 000000000000..983fd06cbefa --- /dev/null +++ b/tools/testing/selftests/bpf/bpfilter/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +test_map diff --git a/tools/testing/selftests/bpf/bpfilter/Makefile b/tools/testing/selftests/bpf/bpfilter/Makefile new file mode 100644 index 000000000000..c262aad8c2a4 --- /dev/null +++ b/tools/testing/selftests/bpf/bpfilter/Makefile @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0 + +top_srcdir = ../../../../.. +TOOLSDIR := $(abspath ../../../../) +TOOLSINCDIR := $(TOOLSDIR)/include +APIDIR := $(TOOLSINCDIR)/uapi +BPFILTERSRCDIR := $(top_srcdir)/net/bpfilter + +CFLAGS += -Wall -g -pthread -I$(TOOLSINCDIR) -I$(APIDIR) -I$(BPFILTERSRCDIR) + +TEST_GEN_PROGS += test_map + +KSFT_KHDR_INSTALL := 1 + +include ../../lib.mk + +BPFILTER_MAP_SRCS := $(BPFILTERSRCDIR)/map-common.c + +$(OUTPUT)/test_map: test_map.c $(BPFILTER_MAP_SRCS) diff --git a/tools/testing/selftests/bpf/bpfilter/test_map.c b/tools/testing/selftests/bpf/bpfilter/test_map.c new file mode 100644 index 000000000000..7ed737b78816 --- /dev/null +++ b/tools/testing/selftests/bpf/bpfilter/test_map.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "map-common.h" + +#include + +#include "../../kselftest_harness.h" + +FIXTURE(test_map) +{ + struct hsearch_data map; + const char *key; + void *expected; + void *actual; +}; + +FIXTURE_SETUP(test_map) +{ + const int max_nelements = 100; + + create_map(&self->map, max_nelements); + self->key = "key"; + self->expected = "expected"; + self->actual = "actual"; +} + +FIXTURE_TEARDOWN(test_map) +{ + free_map(&self->map); +} + +TEST_F(test_map, upsert_and_find) +{ + void *found; + + found = map_find(&self->map, self->key); + ASSERT_TRUE(IS_ERR(found)) + ASSERT_EQ(-ENOENT, PTR_ERR(found)) + + ASSERT_EQ(0, map_upsert(&self->map, self->key, self->expected)); + ASSERT_EQ(0, map_upsert(&self->map, self->key, self->expected)); + ASSERT_EQ(0, map_upsert(&self->map, self->key, self->actual)); + + found = map_find(&self->map, self->key); + + ASSERT_FALSE(IS_ERR(found)); + ASSERT_STREQ(self->actual, found); +} + +TEST_F(test_map, update) +{ + void *found; + + ASSERT_EQ(0, map_upsert(&self->map, self->key, self->actual)); + ASSERT_EQ(0, map_upsert(&self->map, self->key, self->expected)); + + found = map_find(&self->map, self->key); + + ASSERT_FALSE(IS_ERR(found)); + ASSERT_STREQ(self->expected, found); +} + +TEST_HARNESS_MAIN From patchwork Fri Dec 23 23:40:13 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Deslandes X-Patchwork-Id: 13081221 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5F617C3DA7D for ; Fri, 23 Dec 2022 23:57:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232624AbiLWX5J (ORCPT ); Fri, 23 Dec 2022 18:57:09 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33764 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231592AbiLWX5G (ORCPT ); Fri, 23 Dec 2022 18:57:06 -0500 X-Greylist: delayed 539 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Fri, 23 Dec 2022 15:57:05 PST Received: from smtpout2.r2.mail-out.ovh.net (smtpout2.r2.mail-out.ovh.net [54.36.141.2]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6AB9115F1E for ; Fri, 23 Dec 2022 15:57:05 -0800 (PST) Received: from ex4.mail.ovh.net (unknown [10.108.20.222]) by mo511.mail-out.ovh.net (Postfix) with ESMTPS id E165C26446; Fri, 23 Dec 2022 23:48:02 +0000 (UTC) Received: from dev-fedora-x86-64.naccy.de (37.65.8.229) by DAG10EX1.indiv4.local (172.16.2.91) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.16; Sat, 24 Dec 2022 00:48:01 +0100 From: Quentin Deslandes To: CC: , Dmitrii Banshchikov , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Song Liu , Yonghong Song , John Fastabend , KP Singh , Stanislav Fomichev , Hao Luo , Jiri Olsa , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Mykola Lysenko , Shuah Khan , , , , Subject: [PATCH bpf-next v3 05/16] bpfilter: add runtime context Date: Sat, 24 Dec 2022 00:40:13 +0100 Message-ID: <20221223234127.474463-6-qde@naccy.de> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221223234127.474463-1-qde@naccy.de> References: <20221223234127.474463-1-qde@naccy.de> MIME-Version: 1.0 X-Originating-IP: [37.65.8.229] X-ClientProxiedBy: CAS6.indiv4.local (172.16.1.6) To DAG10EX1.indiv4.local (172.16.2.91) X-Ovh-Tracer-Id: 4481926058408472183 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -85 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedvhedrheefgddugecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemucehtddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenogetfedtuddqtdduucdludehmdenucfjughrpefhvfevufffkffojghfggfgtghisehtkeertdertddtnecuhfhrohhmpefsuhgvnhhtihhnucffvghslhgrnhguvghsuceoqhguvgesnhgrtggthidruggvqeenucggtffrrghtthgvrhhnpeduledugfeileetvdelieeujedttedtvedtgfetteevfeejhfffkeeujeetfffgudenucfkphepuddvjedrtddrtddruddpfeejrdeihedrkedrvddvleenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepihhnvghtpeduvdejrddtrddtrddupdhmrghilhhfrhhomhepoehquggvsehnrggttgihrdguvgeqpdhnsggprhgtphhtthhopedupdhrtghpthhtohepshgufhesghhoohhglhgvrdgtohhmpdgsphhfsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhlihhnuhigqdhkvghrnhgvlhesvhhgvghrrdhkvghrnhgvlhdrohhrghdpshhhuhgrhheskhgvrhhnvghlrdhorhhgpdhmhihkohhlrghlsehfsgdrtghomhdpphgrsggvnhhisehrvgguhhgrthdrtghomhdpkhhusggrsehkvghrnhgvlhdrohhrghdpvgguuhhmrgiivghtsehgohhoghhlvgdrtghomhdpuggrvhgvmhesuggrvhgvmhhlohhfthdrnhgvth dpjhholhhsrgeskhgvrhhnvghlrdhorhhgpdhhrgholhhuohesghhoohhglhgvrdgtohhmpdhlihhnuhigqdhkshgvlhhfthgvshhtsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhkphhsihhnghhhsehkvghrnhgvlhdrohhrghdpjhhohhhnrdhfrghsthgrsggvnhgusehgmhgrihhlrdgtohhmpdihhhhssehfsgdrtghomhdpshhonhhgsehkvghrnhgvlhdrohhrghdpmhgrrhhtihhnrdhlrghusehlihhnuhigrdguvghvpdgrnhgurhhiiheskhgvrhhnvghlrdhorhhgpdgurghnihgvlhesihhoghgvrghrsghogidrnhgvthdprghstheskhgvrhhnvghlrdhorhhgpdhmvgesuhgsihhquhgvrdhsphgsrdhruhdpkhgvrhhnvghlqdhtvggrmhesmhgvthgrrdgtohhmpdhnvghtuggvvhesvhhgvghrrdhkvghrnhgvlhdrohhrghdpoffvtefjohhsthepmhhoheduuddpmhhouggvpehsmhhtphhouhht Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net Create struct context to store bpfilter's runtime context. Eventually, this structure will contain the maps/tables containing ops structures for matches, targets, tables... Co-developed-by: Dmitrii Banshchikov Signed-off-by: Dmitrii Banshchikov Signed-off-by: Quentin Deslandes --- net/bpfilter/Makefile | 1 + net/bpfilter/context.c | 18 ++++++++++++++++++ net/bpfilter/context.h | 16 ++++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 net/bpfilter/context.c create mode 100644 net/bpfilter/context.h diff --git a/net/bpfilter/Makefile b/net/bpfilter/Makefile index 1b0c399c19df..9878f5fd8152 100644 --- a/net/bpfilter/Makefile +++ b/net/bpfilter/Makefile @@ -5,6 +5,7 @@ userprogs := bpfilter_umh bpfilter_umh-objs := main.o logger.o map-common.o +bpfilter_umh-objs += context.o userccflags += -I $(srctree)/tools/include/ -I $(srctree)/tools/include/uapi ifeq ($(CONFIG_BPFILTER_UMH), y) diff --git a/net/bpfilter/context.c b/net/bpfilter/context.c new file mode 100644 index 000000000000..fdfd5fe78424 --- /dev/null +++ b/net/bpfilter/context.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Telegram FZ-LLC + * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. + */ + +#define _GNU_SOURCE + +#include "context.h" + +int create_context(struct context *ctx) +{ + return 0; +} + +void free_context(struct context *ctx) +{ +} diff --git a/net/bpfilter/context.h b/net/bpfilter/context.h new file mode 100644 index 000000000000..df41b9707a81 --- /dev/null +++ b/net/bpfilter/context.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Telegram FZ-LLC + * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. + */ + +#ifndef NET_BPFILTER_CONTEXT_H +#define NET_BPFILTER_CONTEXT_H + +struct context { +}; + +int create_context(struct context *ctx); +void free_context(struct context *ctx); + +#endif // NET_BPFILTER_CONTEXT_H From patchwork Fri Dec 23 23:40:14 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Deslandes X-Patchwork-Id: 13081220 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 447A8C4332F for ; Fri, 23 Dec 2022 23:55:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230394AbiLWXzb (ORCPT ); Fri, 23 Dec 2022 18:55:31 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33138 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230334AbiLWXza (ORCPT ); Fri, 23 Dec 2022 18:55:30 -0500 X-Greylist: delayed 636 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Fri, 23 Dec 2022 15:55:28 PST Received: from 1.mo547.mail-out.ovh.net (1.mo547.mail-out.ovh.net [178.33.254.253]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2837E1260F; Fri, 23 Dec 2022 15:55:28 -0800 (PST) Received: from ex4.mail.ovh.net (unknown [10.108.4.232]) by mo547.mail-out.ovh.net (Postfix) with ESMTPS id 400A320EC8; Fri, 23 Dec 2022 23:49:08 +0000 (UTC) Received: from dev-fedora-x86-64.naccy.de (37.65.8.229) by DAG10EX1.indiv4.local (172.16.2.91) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.16; Sat, 24 Dec 2022 00:49:06 +0100 From: Quentin Deslandes To: CC: , Dmitrii Banshchikov , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Song Liu , Yonghong Song , John Fastabend , KP Singh , Stanislav Fomichev , Hao Luo , Jiri Olsa , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Mykola Lysenko , Shuah Khan , , , , Subject: [PATCH bpf-next v3 06/16] bpfilter: add BPF bytecode generation infrastructure Date: Sat, 24 Dec 2022 00:40:14 +0100 Message-ID: <20221223234127.474463-7-qde@naccy.de> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221223234127.474463-1-qde@naccy.de> References: <20221223234127.474463-1-qde@naccy.de> MIME-Version: 1.0 X-Originating-IP: [37.65.8.229] X-ClientProxiedBy: CAS6.indiv4.local (172.16.1.6) To DAG10EX1.indiv4.local (172.16.2.91) X-Ovh-Tracer-Id: 4500221931737706103 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -85 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedvhedrheefgddugecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemucehtddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenogetfedtuddqtdduucdludehmdenucfjughrpefhvfevufffkffojghfggfgtghisehtkeertdertddtnecuhfhrohhmpefsuhgvnhhtihhnucffvghslhgrnhguvghsuceoqhguvgesnhgrtggthidruggvqeenucggtffrrghtthgvrhhnpeduledugfeileetvdelieeujedttedtvedtgfetteevfeejhfffkeeujeetfffgudenucfkphepuddvjedrtddrtddruddpfeejrdeihedrkedrvddvleenucevlhhushhtvghrufhiiigvpedunecurfgrrhgrmhepihhnvghtpeduvdejrddtrddtrddupdhmrghilhhfrhhomhepoehquggvsehnrggttgihrdguvgeqpdhnsggprhgtphhtthhopedupdhrtghpthhtohepshgufhesghhoohhglhgvrdgtohhmpdgsphhfsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhlihhnuhigqdhkvghrnhgvlhesvhhgvghrrdhkvghrnhgvlhdrohhrghdpshhhuhgrhheskhgvrhhnvghlrdhorhhgpdhmhihkohhlrghlsehfsgdrtghomhdpphgrsggvnhhisehrvgguhhgrthdrtghomhdpkhhusggrsehkvghrnhgvlhdrohhrghdpvgguuhhmrgiivghtsehgohhoghhlvgdrtghomhdpuggrvhgvmhesuggrvhgvmhhlohhfthdrnhgvth dpjhholhhsrgeskhgvrhhnvghlrdhorhhgpdhhrgholhhuohesghhoohhglhgvrdgtohhmpdhlihhnuhigqdhkshgvlhhfthgvshhtsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhkphhsihhnghhhsehkvghrnhgvlhdrohhrghdpjhhohhhnrdhfrghsthgrsggvnhgusehgmhgrihhlrdgtohhmpdihhhhssehfsgdrtghomhdpshhonhhgsehkvghrnhgvlhdrohhrghdpmhgrrhhtihhnrdhlrghusehlihhnuhigrdguvghvpdgrnhgurhhiiheskhgvrhhnvghlrdhorhhgpdgurghnihgvlhesihhoghgvrghrsghogidrnhgvthdprghstheskhgvrhhnvghlrdhorhhgpdhmvgesuhgsihhquhgvrdhsphgsrdhruhdpkhgvrhhnvghlqdhtvggrmhesmhgvthgrrdgtohhmpdhnvghtuggvvhesvhhgvghrrdhkvghrnhgvlhdrohhrghdpoffvtefjohhsthepmhhoheegjedpmhhouggvpehsmhhtphhouhht Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net Prepare codegen infrastructure to be used by matches, targets, rules, and tables. struct codegen contains an array of struct bpf_insn representing the generated BPF program. The current infrastructure allows for multiple BPF program flavours to be supported (TC, XDP...). Most of the logic will be shared, but each flavour will be able to define its own prologue and epilogue bytecode, as well as packet data access. Loading and unloading flow is also flavour-dependent. Not all required information is known during generation. This commit introduces two bpfilter concepts to resolve this issue: - Fixup: placeholder to replace once code generation is complete. For example, fixup is used to jump to the next rule. The next rule's offset is only known once it has been generated. - Relocation: placeholder to replace before loading the BPF program. BPF maps are an example of features using relocation. Maps are created before the programs are loaded, so their FD is only known at that point in time. Subprogs are required to support user-defined chains and helper subprograms. All already generated subprogs are stored in subprogs array. This sorted array acts as an index. All subprogs awaiting the generation phase are stored in awaiting_subprogs list. struct shared_codegen is used to share data between various BPF programs created by BPF filter. The only currently supported shared data is the map containing the counters for each rule defined: a unique map shared between all the programs stores the counters for all the bpfilter programs. Besides that, there is a runtime_context struct that might be used to store frequently required data such as the size of the packet and pointer to L3/L4 headers. This context is stored on the stack and there are macros to access individual fields of this struct. Immediately after runtime_context on stack, there is a scratchpad area. The calling convention follows the BPF calling convention with a couple of additions: * CODEGEN_REG_CTX(BPF_REG_9) is a pointer to the program context * CODEGEN_REG_RUNTIME_CTX(BPF_REG_8) is a pointer to the runtime context Co-developed-by: Dmitrii Banshchikov Signed-off-by: Dmitrii Banshchikov Signed-off-by: Quentin Deslandes --- net/bpfilter/Makefile | 12 +- net/bpfilter/codegen.c | 530 ++++++++++++++++++ net/bpfilter/codegen.h | 181 ++++++ .../testing/selftests/bpf/bpfilter/.gitignore | 1 + tools/testing/selftests/bpf/bpfilter/Makefile | 19 + 5 files changed, 742 insertions(+), 1 deletion(-) create mode 100644 net/bpfilter/codegen.c create mode 100644 net/bpfilter/codegen.h diff --git a/net/bpfilter/Makefile b/net/bpfilter/Makefile index 9878f5fd8152..ac039f1fac34 100644 --- a/net/bpfilter/Makefile +++ b/net/bpfilter/Makefile @@ -3,11 +3,21 @@ # Makefile for the Linux BPFILTER layer. # +LIBBPF_SRCS = $(srctree)/tools/lib/bpf/ +LIBBPF_A = $(obj)/libbpf.a +LIBBPF_OUT = $(abspath $(obj)) + +$(LIBBPF_A): + $(Q)$(MAKE) -C $(LIBBPF_SRCS) O=$(LIBBPF_OUT)/ OUTPUT=$(LIBBPF_OUT)/ $(LIBBPF_OUT)/libbpf.a + userprogs := bpfilter_umh bpfilter_umh-objs := main.o logger.o map-common.o -bpfilter_umh-objs += context.o +bpfilter_umh-objs += context.o codegen.o +bpfilter_umh-userldlibs := $(LIBBPF_A) -lelf -lz userccflags += -I $(srctree)/tools/include/ -I $(srctree)/tools/include/uapi +$(obj)/bpfilter_umh: $(LIBBPF_A) + ifeq ($(CONFIG_BPFILTER_UMH), y) # builtin bpfilter_umh should be linked with -static # since rootfs isn't mounted at the time of __init diff --git a/net/bpfilter/codegen.c b/net/bpfilter/codegen.c new file mode 100644 index 000000000000..545bc7aeb77c --- /dev/null +++ b/net/bpfilter/codegen.c @@ -0,0 +1,530 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Telegram FZ-LLC + * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. + */ + +#include "codegen.h" + +#include "../../include/uapi/linux/bpfilter.h" + +#include +#include + +#include +#include +#include + +#include "logger.h" + +enum fixup_insn_type { + FIXUP_INSN_OFF, + FIXUP_INSN_IMM, + __MAX_FIXUP_INSN_TYPE +}; + +static int sys_bpf(int cmd, union bpf_attr *attr, unsigned int size) +{ + return syscall(SYS_bpf, cmd, attr, size); +} + +static __u64 bpf_ptr_to_u64(const void *ptr) +{ + return (__u64)(unsigned long)ptr; +} + +static int subprog_desc_comparator(const void *x, const void *y) +{ + const struct codegen_subprog_desc *subprog_x = *(const struct codegen_subprog_desc **)x; + const struct codegen_subprog_desc *subprog_y = *(const struct codegen_subprog_desc **)y; + + if (subprog_x->type != subprog_y->type) + return subprog_x->type - subprog_y->type; + + if (subprog_x->type == CODEGEN_SUBPROG_USER_CHAIN) + return subprog_x->offset - subprog_y->offset; + + BUG_ON(1); + + return -1; +} + +static const struct codegen_subprog_desc *codegen_find_subprog(struct codegen *codegen, + const struct codegen_subprog_desc **subprog) +{ + const struct codegen_subprog_desc **found; + + found = bsearch(subprog, codegen->subprogs, codegen->subprogs_cur, + sizeof(codegen->subprogs[0]), subprog_desc_comparator); + + return found ? *found : NULL; +} + +static const struct codegen_subprog_desc *codegen_find_user_chain_subprog(struct codegen *codegen, + uint32_t offset) +{ + const struct codegen_subprog_desc subprog = { + .type = CODEGEN_SUBPROG_USER_CHAIN, + .offset = offset + }; + const struct codegen_subprog_desc *subprog_ptr = &subprog; + + return codegen_find_subprog(codegen, &subprog_ptr); +} + +int codegen_push_awaiting_subprog(struct codegen *codegen, + struct codegen_subprog_desc *subprog) +{ + struct list_head *t, *n; + + if (codegen_find_subprog(codegen, (const struct codegen_subprog_desc **)&subprog)) { + free(subprog); + return 0; + } + + list_for_each_safe(t, n, &codegen->awaiting_subprogs) { + struct codegen_subprog_desc *awaiting_subprog; + + awaiting_subprog = list_entry(t, struct codegen_subprog_desc, list); + if (!subprog_desc_comparator(&awaiting_subprog, &subprog)) { + free(subprog); + return 0; + } + } + + list_add_tail(&subprog->list, &codegen->awaiting_subprogs); + + return 0; +} + +static int codegen_fixup_insn(struct bpf_insn *insn, enum fixup_insn_type type, + __s32 v) +{ + switch (type) { + case FIXUP_INSN_OFF: + if (insn->off) { + BFLOG_ERR("missing instruction offset"); + return -EINVAL; + } + + insn->off = v; + + return 0; + case FIXUP_INSN_IMM: + if (insn->imm) { + BFLOG_ERR("missing instruction immediate value"); + return -EINVAL; + } + + insn->imm = v; + + return 0; + default: + BFLOG_ERR("invalid fixup instruction type"); + return -EINVAL; + } +} + +int codegen_fixup(struct codegen *codegen, enum codegen_fixup_type fixup_type) +{ + struct list_head *t, *n; + + list_for_each_safe(t, n, &codegen->fixup) { + enum fixup_insn_type type = __MAX_FIXUP_INSN_TYPE; + struct codegen_fixup_desc *fixup; + struct bpf_insn *insn; + __s32 v; + int r; + + fixup = list_entry(t, struct codegen_fixup_desc, list); + if (fixup->type != fixup_type) + continue; + + if (fixup->type >= __MAX_CODEGEN_FIXUP_TYPE) { + BFLOG_ERR("invalid instruction fixup type: %d", + fixup->type); + return -EINVAL; + } + + if (fixup->insn > codegen->len_cur) { + BFLOG_ERR("invalid instruction fixup offset"); + return -EINVAL; + } + + insn = &codegen->img[fixup->insn]; + + if (fixup_type == CODEGEN_FIXUP_NEXT_RULE || + fixup_type == CODEGEN_FIXUP_END_OF_CHAIN) { + type = FIXUP_INSN_OFF; + v = codegen->len_cur - fixup->insn - 1; + } + + if (fixup_type == CODEGEN_FIXUP_JUMP_TO_CHAIN) { + const struct codegen_subprog_desc *subprog; + + subprog = codegen_find_user_chain_subprog(codegen, + fixup->offset); + if (!subprog) { + BFLOG_ERR("subprogram not found for offset %d", + fixup->offset); + return -EINVAL; + } + + type = FIXUP_INSN_OFF; + v = subprog->insn - fixup->insn - 1; + } + + if (fixup_type == CODEGEN_FIXUP_COUNTERS_INDEX) { + type = FIXUP_INSN_IMM; + BFLOG_DBG("fixup counter for rule %d", codegen->rule_index); + v = codegen->rule_index; + } + + r = codegen_fixup_insn(insn, type, v); + if (r) { + BFLOG_ERR("failed to fixup codegen instruction: %s", + STRERR(r)); + return r; + } + + list_del(t); + free(fixup); + } + + return 0; +} + +int emit_fixup(struct codegen *codegen, enum codegen_fixup_type fixup_type, + struct bpf_insn insn) +{ + struct codegen_fixup_desc *fixup; + + fixup = malloc(sizeof(*fixup)); + if (!fixup) { + BFLOG_ERR("out of memory"); + return -ENOMEM; + } + + INIT_LIST_HEAD(&fixup->list); + fixup->type = fixup_type; + fixup->insn = codegen->len_cur; + list_add_tail(&fixup->list, &codegen->fixup); + + EMIT(codegen, insn); + + return 0; +} + +int emit_add_counter(struct codegen *codegen) +{ + struct bpf_insn insns[2] = { BPF_LD_MAP_FD(BPF_REG_ARG1, 0) }; + struct codegen_reloc_desc *reloc; + + reloc = malloc(sizeof(*reloc)); + if (!reloc) { + BFLOG_ERR("out of memory"); + return -ENOMEM; + } + + INIT_LIST_HEAD(&reloc->list); + reloc->type = CODEGEN_RELOC_MAP; + reloc->map = CODEGEN_MAP_COUNTERS; + reloc->insn = codegen->len_cur; + list_add_tail(&reloc->list, &codegen->relocs); + + EMIT(codegen, insns[0]); + EMIT(codegen, insns[1]); + + EMIT_FIXUP(codegen, CODEGEN_FIXUP_COUNTERS_INDEX, + BPF_ST_MEM(BPF_W, BPF_REG_10, STACK_SCRATCHPAD_OFFSET - 4, 0)); + EMIT(codegen, BPF_MOV64_REG(BPF_REG_ARG2, BPF_REG_10)); + EMIT(codegen, + BPF_ALU64_IMM(BPF_ADD, BPF_REG_ARG2, STACK_SCRATCHPAD_OFFSET - 4)); + EMIT(codegen, BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem)); + EMIT(codegen, BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 14)); + + reloc = malloc(sizeof(*reloc)); + if (!reloc) { + BFLOG_ERR("out of memory"); + return -ENOMEM; + } + + INIT_LIST_HEAD(&reloc->list); + reloc->type = CODEGEN_RELOC_MAP; + reloc->map = CODEGEN_MAP_COUNTERS; + reloc->insn = codegen->len_cur; + list_add_tail(&reloc->list, &codegen->relocs); + + EMIT(codegen, insns[0]); + EMIT(codegen, insns[1]); + + EMIT(codegen, BPF_LDX_MEM(BPF_DW, CODEGEN_REG_SCRATCH5, BPF_REG_0, 0)); + EMIT(codegen, BPF_LDX_MEM(BPF_DW, CODEGEN_REG_SCRATCH4, BPF_REG_0, 8)); + EMIT(codegen, BPF_LDX_MEM(BPF_W, CODEGEN_REG_SCRATCH3, CODEGEN_REG_RUNTIME_CTX, + STACK_RUNTIME_CONTEXT_OFFSET(data_size))); + EMIT(codegen, BPF_ALU64_IMM(BPF_ADD, CODEGEN_REG_SCRATCH5, 1)); + EMIT(codegen, + BPF_ALU64_REG(BPF_ADD, CODEGEN_REG_SCRATCH4, CODEGEN_REG_SCRATCH3)); + EMIT(codegen, BPF_STX_MEM(BPF_DW, BPF_REG_0, CODEGEN_REG_SCRATCH5, 0)); + EMIT(codegen, BPF_STX_MEM(BPF_DW, BPF_REG_0, CODEGEN_REG_SCRATCH4, 8)); + EMIT(codegen, BPF_MOV64_REG(BPF_REG_ARG2, BPF_REG_10)); + EMIT(codegen, + BPF_ALU64_IMM(BPF_ADD, BPF_REG_ARG2, STACK_SCRATCHPAD_OFFSET - 4)); + EMIT(codegen, BPF_MOV64_REG(BPF_REG_ARG3, BPF_REG_0)); + EMIT(codegen, BPF_MOV32_IMM(BPF_REG_ARG4, BPF_EXIST)); + EMIT(codegen, BPF_EMIT_CALL(BPF_FUNC_map_update_elem)); + + return 0; +} + +static int codegen_reloc(struct codegen *codegen) +{ + struct shared_codegen *shared_codegen; + struct list_head *t; + + shared_codegen = codegen->shared_codegen; + + list_for_each(t, &codegen->relocs) { + struct codegen_reloc_desc *reloc; + struct bpf_insn *insn; + + reloc = list_entry(t, struct codegen_reloc_desc, list); + + if (reloc->insn >= codegen->len_cur) { + BFLOG_ERR("invalid instruction relocation offset"); + return -EINVAL; + } + + insn = &codegen->img[reloc->insn]; + + if (reloc->type == CODEGEN_RELOC_MAP) { + enum codegen_map_type map_type; + + if (codegen->len_cur <= reloc->insn + 1) { + BFLOG_ERR("invalid instruction relocation map offset"); + return -EINVAL; + } + + if (insn->code != (BPF_LD | BPF_DW | BPF_IMM)) { + BFLOG_ERR("invalid instruction relocation code %d", + insn->code); + return -EINVAL; + } + + map_type = insn->imm; + if (map_type < 0 || map_type >= __MAX_CODEGEN_MAP_TYPE) { + BFLOG_ERR("invalid instruction relocation map type: %d", + map_type); + return -EINVAL; + } + + BUG_ON(shared_codegen->maps_fd[map_type] < 0); + insn->imm = shared_codegen->maps_fd[map_type]; + + continue; + } + + BFLOG_ERR("invalid instruction relocation type %d", reloc->type); + return -EINVAL; + } + + return 0; +} + +static int load_maps(struct codegen *codegen) +{ + struct shared_codegen *shared_codegen; + int i; + + shared_codegen = codegen->shared_codegen; + + if (shared_codegen->maps_refcnt++) + return 0; + + for (i = 0; i < __MAX_CODEGEN_MAP_TYPE; ++i) { + int j; + int fd; + int saved_errno; + union bpf_attr *map; + + BUG_ON(shared_codegen->maps_fd[i] > -1); + + map = &shared_codegen->maps[i]; + fd = sys_bpf(BPF_MAP_CREATE, map, sizeof(*map)); + if (fd > -1) { + BFLOG_DBG("opened BPF map with FD %d", fd); + shared_codegen->maps_fd[i] = fd; + continue; + } + + BFLOG_ERR("bpf syscall failed during map creation: %s", + STRERR(fd)); + saved_errno = errno; + + for (j = 0; j < i; ++j) { + close(shared_codegen->maps_fd[j]); + shared_codegen->maps_fd[j] = -1; + } + + return saved_errno; + } + + return 0; +} + +static void unload_maps(struct codegen *codegen) +{ + struct shared_codegen *shared_codegen; + int i; + + shared_codegen = codegen->shared_codegen; + + if (--shared_codegen->maps_refcnt) + return; + + for (i = 0; i < __MAX_CODEGEN_MAP_TYPE; ++i) { + if (shared_codegen->maps_fd[i] > -1) { + close(shared_codegen->maps_fd[i]); + shared_codegen->maps_fd[i] = -1; + } + } +} + +void create_shared_codegen(struct shared_codegen *shared_codegen) +{ + shared_codegen->maps_refcnt = 0; + + shared_codegen->maps[CODEGEN_MAP_COUNTERS].map_type = + BPF_MAP_TYPE_PERCPU_ARRAY; + shared_codegen->maps[CODEGEN_MAP_COUNTERS].key_size = 4; + shared_codegen->maps[CODEGEN_MAP_COUNTERS].value_size = + sizeof(struct bpfilter_ipt_counters); + shared_codegen->maps[CODEGEN_MAP_COUNTERS].max_entries = 0; + snprintf(shared_codegen->maps[CODEGEN_MAP_COUNTERS].map_name, + sizeof(shared_codegen->maps[CODEGEN_MAP_COUNTERS].map_name), + "bpfilter_cntrs"); + shared_codegen->maps_fd[CODEGEN_MAP_COUNTERS] = -1; +} + +int create_codegen(struct codegen *codegen, enum bpf_prog_type type) +{ + int r; + + memset(codegen, 0, sizeof(*codegen)); + + switch (type) { + default: + BFLOG_ERR("unsupported BPF program type %d", type); + return -EINVAL; + } + + codegen->prog_type = type; + + codegen->log_buf_size = 1 << 20; + codegen->log_buf = malloc(codegen->log_buf_size); + if (!codegen->log_buf) { + BFLOG_ERR("out of memory"); + r = -ENOMEM; + goto err_free; + } + + codegen->len_max = BPF_MAXINSNS; + codegen->img = malloc(codegen->len_max * sizeof(codegen->img[0])); + if (!codegen->img) { + BFLOG_ERR("out of memory"); + r = -ENOMEM; + goto err_free; + } + + codegen->shared_codegen = NULL; + + INIT_LIST_HEAD(&codegen->fixup); + INIT_LIST_HEAD(&codegen->relocs); + INIT_LIST_HEAD(&codegen->awaiting_subprogs); + + return 0; + +err_free: + free(codegen->img); + + return r; +} + +int load_img(struct codegen *codegen) +{ + union bpf_attr attr = {}; + int fd; + int r; + + r = load_maps(codegen); + if (r) { + BFLOG_ERR("failed to load maps: %s", STRERR(r)); + return r; + } + + r = codegen_reloc(codegen); + if (r) { + BFLOG_ERR("failed to generate relocations: %s", STRERR(r)); + return r; + } + + attr.prog_type = codegen->prog_type; + attr.insns = bpf_ptr_to_u64(codegen->img); + attr.insn_cnt = codegen->len_cur; + attr.license = bpf_ptr_to_u64("GPL"); + attr.prog_ifindex = 0; + snprintf(attr.prog_name, sizeof(attr.prog_name), "bpfilter"); + + if (codegen->log_buf && codegen->log_buf_size) { + attr.log_buf = bpf_ptr_to_u64(codegen->log_buf); + attr.log_size = codegen->log_buf_size; + attr.log_level = 1; + } + + fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); + if (fd == -1) { + BFLOG_ERR("failed to load BPF program: %s", codegen->log_buf); + return -errno; + } + + return fd; +} + +void unload_img(struct codegen *codegen) +{ + unload_maps(codegen); +} + +void free_codegen(struct codegen *codegen) +{ + struct list_head *t, *n; + int i; + + list_for_each_safe(t, n, &codegen->fixup) { + struct codegen_fixup_desc *fixup; + + fixup = list_entry(t, struct codegen_fixup_desc, list); + free(fixup); + } + + list_for_each_safe(t, n, &codegen->relocs) { + struct codegen_reloc_desc *reloc; + + reloc = list_entry(t, struct codegen_reloc_desc, list); + free(reloc); + } + + list_for_each_safe(t, n, &codegen->awaiting_subprogs) { + struct codegen_subprog_desc *subprog; + + subprog = list_entry(t, struct codegen_subprog_desc, list); + free(subprog); + } + + for (i = 0; i < codegen->subprogs_cur; ++i) + free(codegen->subprogs[i]); + free(codegen->subprogs); + + free(codegen->log_buf); + free(codegen->img); +} diff --git a/net/bpfilter/codegen.h b/net/bpfilter/codegen.h new file mode 100644 index 000000000000..cca45a13c4aa --- /dev/null +++ b/net/bpfilter/codegen.h @@ -0,0 +1,181 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Telegram FZ-LLC + * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. + */ + +#ifndef NET_BPFILTER_CODEGEN_H +#define NET_BPFILTER_CODEGEN_H + +#include +#include +#include + +#include + +#include +#include +#include + +struct context; + +#define CODEGEN_REG_RETVAL BPF_REG_0 +#define CODEGEN_REG_SCRATCH1 BPF_REG_1 +#define CODEGEN_REG_SCRATCH2 BPF_REG_2 +#define CODEGEN_REG_SCRATCH3 BPF_REG_3 +#define CODEGEN_REG_SCRATCH4 BPF_REG_4 +#define CODEGEN_REG_SCRATCH5 BPF_REG_5 +#define CODEGEN_REG_DATA_END CODEGEN_REG_SCRATCH5 +#define CODEGEN_REG_L3 BPF_REG_6 +#define CODEGEN_REG_L4 BPF_REG_7 +#define CODEGEN_REG_RUNTIME_CTX BPF_REG_8 +#define CODEGEN_REG_CTX BPF_REG_9 + +#define EMIT(codegen, x) \ + do { \ + typeof(codegen) __codegen = codegen; \ + if ((__codegen)->len_cur + 1 > (__codegen)->len_max) \ + return -ENOMEM; \ + (__codegen)->img[codegen->len_cur++] = (x); \ + } while (0) + +#define EMIT_FIXUP(codegen, fixup_type, insn) \ + do { \ + const int __err = emit_fixup((codegen), (fixup_type), (insn)); \ + if (__err) \ + return __err; \ + } while (0) + +#define EMIT_ADD_COUNTER(codegen) \ + do { \ + const int __err = emit_add_counter(codegen); \ + if (__err) \ + return __err; \ + } while (0) + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define EMIT_LITTLE_ENDIAN(codegen, x) EMIT(codegen, x) +#else +#define EMIT_LITTLE_ENDIAN(codegen, x) +#endif + +struct runtime_context { + uint32_t data_size; + void *l3; + void *l4; +}; + +#define STACK_RUNTIME_CONTEXT_OFFSET(field) \ + (-(short)(offsetof(struct runtime_context, field) + \ + sizeof(((struct runtime_context *)NULL)->field))) + +#define STACK_SCRATCHPAD_OFFSET (-(short)sizeof(struct runtime_context)) + +enum codegen_map_type { + CODEGEN_MAP_COUNTERS, + __MAX_CODEGEN_MAP_TYPE +}; + +enum codegen_fixup_type { + CODEGEN_FIXUP_NEXT_RULE, + CODEGEN_FIXUP_END_OF_CHAIN, + CODEGEN_FIXUP_JUMP_TO_CHAIN, + CODEGEN_FIXUP_COUNTERS_INDEX, + __MAX_CODEGEN_FIXUP_TYPE +}; + +struct codegen_fixup_desc { + struct list_head list; + enum codegen_fixup_type type; + uint32_t insn; + union { + uint32_t offset; + }; +}; + +enum codegen_reloc_type { + CODEGEN_RELOC_MAP, + __MAX_CODEGEN_RELOC_TYPE +}; + +struct codegen_reloc_desc { + struct list_head list; + enum codegen_reloc_type type; + uint32_t insn; + union { + struct { + enum codegen_map_type map; + // TODO: add BTF + }; + }; +}; + +enum codegen_subprog_type { + CODEGEN_SUBPROG_USER_CHAIN, +}; + +struct codegen_subprog_desc { + struct list_head list; + enum codegen_subprog_type type; + uint32_t insn; + union { + uint32_t offset; + }; +}; + +struct codegen_ops; +struct shared_codegen; + +struct codegen { + struct context *ctx; + struct bpf_insn *img; + char *log_buf; + size_t log_buf_size; + int iptables_hook; + union { + enum bpf_tc_attach_point bpf_tc_hook; + }; + enum bpf_prog_type prog_type; + uint32_t len_cur; + uint32_t len_max; + uint32_t rule_index; + const struct codegen_ops *codegen_ops; + struct shared_codegen *shared_codegen; + struct list_head fixup; + struct list_head relocs; + struct list_head awaiting_subprogs; + uint16_t subprogs_cur; + uint16_t subprogs_max; + struct codegen_subprog_desc **subprogs; + void *img_ctx; +}; + +struct shared_codegen { + int maps_refcnt; + union bpf_attr maps[__MAX_CODEGEN_MAP_TYPE]; + int maps_fd[__MAX_CODEGEN_MAP_TYPE]; +}; + +struct codegen_ops { + int (*gen_inline_prologue)(struct codegen *codegen); + int (*load_packet_data)(struct codegen *codegen, int dst_reg); + int (*load_packet_data_end)(struct codegen *codegen, int dst_reg); + int (*emit_ret_code)(struct codegen *codegen, int ret_code); + int (*gen_inline_epilogue)(struct codegen *codegen); + int (*load_img)(struct codegen *codegen); + void (*unload_img)(struct codegen *codegen); +}; + +void create_shared_codegen(struct shared_codegen *shared_codegen); +int create_codegen(struct codegen *codegen, enum bpf_prog_type type); +int codegen_push_awaiting_subprog(struct codegen *codegen, + struct codegen_subprog_desc *subprog); +int codegen_fixup(struct codegen *codegen, enum codegen_fixup_type fixup_type); +int emit_fixup(struct codegen *codegen, enum codegen_fixup_type fixup_type, + struct bpf_insn insn); +int emit_add_counter(struct codegen *codegen); +int load_img(struct codegen *codegen); +void unload_img(struct codegen *codegen); +void free_codegen(struct codegen *codegen); + +#endif // NET_BPFILTER_CODEGEN_H diff --git a/tools/testing/selftests/bpf/bpfilter/.gitignore b/tools/testing/selftests/bpf/bpfilter/.gitignore index 983fd06cbefa..39ec0c09dff4 100644 --- a/tools/testing/selftests/bpf/bpfilter/.gitignore +++ b/tools/testing/selftests/bpf/bpfilter/.gitignore @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only +tools/** test_map diff --git a/tools/testing/selftests/bpf/bpfilter/Makefile b/tools/testing/selftests/bpf/bpfilter/Makefile index c262aad8c2a4..e3b8bf76a10c 100644 --- a/tools/testing/selftests/bpf/bpfilter/Makefile +++ b/tools/testing/selftests/bpf/bpfilter/Makefile @@ -5,6 +5,8 @@ TOOLSDIR := $(abspath ../../../../) TOOLSINCDIR := $(TOOLSDIR)/include APIDIR := $(TOOLSINCDIR)/uapi BPFILTERSRCDIR := $(top_srcdir)/net/bpfilter +LIBDIR := $(TOOLSDIR)/lib +BPFDIR := $(LIBDIR)/bpf CFLAGS += -Wall -g -pthread -I$(TOOLSINCDIR) -I$(APIDIR) -I$(BPFILTERSRCDIR) @@ -14,6 +16,23 @@ KSFT_KHDR_INSTALL := 1 include ../../lib.mk +SCRATCH_DIR := $(OUTPUT)/tools +BUILD_DIR := $(SCRATCH_DIR)/build +BPFOBJ_DIR := $(BUILD_DIR)/libbpf +BPFOBJ := $(BPFOBJ_DIR)/libbpf.a + +MAKE_DIRS := $(BPFOBJ_DIR) +$(MAKE_DIRS): + $(call msg,MKDIR,,$@) + $(Q)mkdir -p $@ + +$(BPFOBJ): $(wildcard $(BPFDIR)/*.[ch] $(BPFDIR)/Makefile) \ + ../../../../include/uapi/linux/bpf.h \ + | $(INCLUDE_DIR) $(BUILD_DIR)/libbpf + $(Q)$(MAKE) $(submake_extras) -C $(BPFDIR) OUTPUT=$(BUILD_DIR)/libbpf/ \ + DESTDIR=$(SCRATCH_DIR) prefix= all install_headers + BPFILTER_MAP_SRCS := $(BPFILTERSRCDIR)/map-common.c +BPFILTER_CODEGEN_SRCS := $(BPFILTERSRCDIR)/codegen.c $(BPFOBJ) -lelf -lz $(OUTPUT)/test_map: test_map.c $(BPFILTER_MAP_SRCS) From patchwork Fri Dec 23 23:40:15 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Deslandes X-Patchwork-Id: 13081223 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5C1E4C4332F for ; Fri, 23 Dec 2022 23:57:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232661AbiLWX5R (ORCPT ); Fri, 23 Dec 2022 18:57:17 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33798 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230419AbiLWX5O (ORCPT ); Fri, 23 Dec 2022 18:57:14 -0500 X-Greylist: delayed 420 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Fri, 23 Dec 2022 15:57:13 PST Received: from smtpout7.r2.mail-out.ovh.net (smtpout7.r2.mail-out.ovh.net [54.36.141.7]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 40B6D15F1E for ; Fri, 23 Dec 2022 15:57:13 -0800 (PST) Received: from ex4.mail.ovh.net (unknown [10.110.115.38]) by mo511.mail-out.ovh.net (Postfix) with ESMTPS id 639DE26719; Fri, 23 Dec 2022 23:50:12 +0000 (UTC) Received: from dev-fedora-x86-64.naccy.de (37.65.8.229) by DAG10EX1.indiv4.local (172.16.2.91) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.16; Sat, 24 Dec 2022 00:50:10 +0100 From: Quentin Deslandes To: CC: , Dmitrii Banshchikov , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Song Liu , Yonghong Song , John Fastabend , KP Singh , Stanislav Fomichev , Hao Luo , Jiri Olsa , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Mykola Lysenko , Shuah Khan , , , , Subject: [PATCH bpf-next v3 07/16] bpfilter: add support for TC bytecode generation Date: Sat, 24 Dec 2022 00:40:15 +0100 Message-ID: <20221223234127.474463-8-qde@naccy.de> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221223234127.474463-1-qde@naccy.de> References: <20221223234127.474463-1-qde@naccy.de> MIME-Version: 1.0 X-Originating-IP: [37.65.8.229] X-ClientProxiedBy: CAS6.indiv4.local (172.16.1.6) To DAG10EX1.indiv4.local (172.16.2.91) X-Ovh-Tracer-Id: 4518236328503275127 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -85 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedvhedrheefgddugecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemucehtddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenogetfedtuddqtdduucdludehmdenucfjughrpefhvfevufffkffojghfggfgtghisehtkeertdertddtnecuhfhrohhmpefsuhgvnhhtihhnucffvghslhgrnhguvghsuceoqhguvgesnhgrtggthidruggvqeenucggtffrrghtthgvrhhnpeduledugfeileetvdelieeujedttedtvedtgfetteevfeejhfffkeeujeetfffgudenucfkphepuddvjedrtddrtddruddpfeejrdeihedrkedrvddvleenucevlhhushhtvghrufhiiigvpedunecurfgrrhgrmhepihhnvghtpeduvdejrddtrddtrddupdhmrghilhhfrhhomhepoehquggvsehnrggttgihrdguvgeqpdhnsggprhgtphhtthhopedupdhrtghpthhtohepshgufhesghhoohhglhgvrdgtohhmpdgsphhfsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhlihhnuhigqdhkvghrnhgvlhesvhhgvghrrdhkvghrnhgvlhdrohhrghdpshhhuhgrhheskhgvrhhnvghlrdhorhhgpdhmhihkohhlrghlsehfsgdrtghomhdpphgrsggvnhhisehrvgguhhgrthdrtghomhdpkhhusggrsehkvghrnhgvlhdrohhrghdpvgguuhhmrgiivghtsehgohhoghhlvgdrtghomhdpuggrvhgvmhesuggrvhgvmhhlohhfthdrnhgvth dpjhholhhsrgeskhgvrhhnvghlrdhorhhgpdhhrgholhhuohesghhoohhglhgvrdgtohhmpdhlihhnuhigqdhkshgvlhhfthgvshhtsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhkphhsihhnghhhsehkvghrnhgvlhdrohhrghdpjhhohhhnrdhfrghsthgrsggvnhgusehgmhgrihhlrdgtohhmpdihhhhssehfsgdrtghomhdpshhonhhgsehkvghrnhgvlhdrohhrghdpmhgrrhhtihhnrdhlrghusehlihhnuhigrdguvghvpdgrnhgurhhiiheskhgvrhhnvghlrdhorhhgpdgurghnihgvlhesihhoghgvrghrsghogidrnhgvthdprghstheskhgvrhhnvghlrdhorhhgpdhmvgesuhgsihhquhgvrdhsphgsrdhruhdpkhgvrhhnvghlqdhtvggrmhesmhgvthgrrdgtohhmpdhnvghtuggvvhesvhhgvghrrdhkvghrnhgvlhdrohhrghdpoffvtefjohhsthepmhhoheduuddpmhhouggvpehsmhhtphhouhht Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net Add code generation support for TC hooks. Co-developed-by: Dmitrii Banshchikov Signed-off-by: Dmitrii Banshchikov Signed-off-by: Quentin Deslandes --- net/bpfilter/codegen.c | 151 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) diff --git a/net/bpfilter/codegen.c b/net/bpfilter/codegen.c index 545bc7aeb77c..e7ae7dfa5118 100644 --- a/net/bpfilter/codegen.c +++ b/net/bpfilter/codegen.c @@ -8,6 +8,8 @@ #include "../../include/uapi/linux/bpfilter.h" +#include + #include #include @@ -15,6 +17,8 @@ #include #include +#include + #include "logger.h" enum fixup_insn_type { @@ -390,6 +394,150 @@ static void unload_maps(struct codegen *codegen) } } +static int tc_gen_inline_prologue(struct codegen *codegen) +{ + EMIT(codegen, BPF_MOV64_REG(CODEGEN_REG_CTX, BPF_REG_ARG1)); + EMIT(codegen, BPF_MOV64_REG(CODEGEN_REG_RUNTIME_CTX, BPF_REG_FP)); + EMIT(codegen, BPF_MOV32_IMM(CODEGEN_REG_RETVAL, TC_ACT_OK)); + + return 0; +} + +static int tc_load_packet_data(struct codegen *codegen, int dst_reg) +{ + EMIT(codegen, BPF_LDX_MEM(BPF_W, dst_reg, CODEGEN_REG_CTX, + offsetof(struct __sk_buff, data))); + + return 0; +} + +static int tc_load_packet_data_end(struct codegen *codegen, int dst_reg) +{ + EMIT(codegen, BPF_LDX_MEM(BPF_W, CODEGEN_REG_DATA_END, CODEGEN_REG_CTX, + offsetof(struct __sk_buff, data_end))); + + return 0; +} + +static int tc_emit_ret_code(struct codegen *codegen, int ret_code) +{ + int tc_ret_code; + + if (ret_code == BPFILTER_NF_ACCEPT) + tc_ret_code = TC_ACT_UNSPEC; + else if (ret_code == BPFILTER_NF_DROP) + tc_ret_code = TC_ACT_SHOT; + else + return -EINVAL; + + EMIT(codegen, BPF_MOV32_IMM(BPF_REG_0, tc_ret_code)); + + return 0; +} + +static int tc_gen_inline_epilogue(struct codegen *codegen) +{ + EMIT(codegen, BPF_EXIT_INSN()); + + return 0; +} + +struct tc_img_ctx { + int fd; + struct bpf_tc_hook hook; + struct bpf_tc_opts opts; +}; + +static int tc_load_img(struct codegen *codegen) +{ + struct tc_img_ctx *img_ctx; + int fd; + int r; + + if (codegen->img_ctx) { + BFLOG_ERR("TC context missing from codegen"); + return -EINVAL; + } + + img_ctx = calloc(1, sizeof(*img_ctx)); + if (!img_ctx) { + BFLOG_ERR("out of memory"); + return -ENOMEM; + } + + img_ctx->hook.sz = sizeof(img_ctx->hook); + img_ctx->hook.ifindex = 2; + img_ctx->hook.attach_point = codegen->bpf_tc_hook; + + fd = load_img(codegen); + if (fd < 0) { + BFLOG_ERR("failed to load TC codegen image: %s", STRERR(fd)); + r = fd; + goto err_free; + } + + r = bpf_tc_hook_create(&img_ctx->hook); + if (r && r != -EEXIST) { + BFLOG_ERR("failed to create TC hook: %s\n", STRERR(r)); + goto err_free; + } + + img_ctx->opts.sz = sizeof(img_ctx->opts); + img_ctx->opts.handle = codegen->iptables_hook; + img_ctx->opts.priority = 0; + img_ctx->opts.prog_fd = fd; + r = bpf_tc_attach(&img_ctx->hook, &img_ctx->opts); + if (r) { + BFLOG_ERR("failed to attach TC program: %s", STRERR(r)); + goto err_free; + } + + img_ctx->fd = fd; + codegen->img_ctx = img_ctx; + + return fd; + +err_free: + if (fd > -1) + close(fd); + free(img_ctx); + return r; +} + +static void tc_unload_img(struct codegen *codegen) +{ + struct tc_img_ctx *img_ctx; + int r; + + BUG_ON(!codegen->img_ctx); + + img_ctx = (struct tc_img_ctx *)codegen->img_ctx; + img_ctx->opts.flags = 0; + img_ctx->opts.prog_fd = 0; + img_ctx->opts.prog_id = 0; + r = bpf_tc_detach(&img_ctx->hook, &img_ctx->opts); + if (r) + BFLOG_EMERG("failed to detach TC program: %s", STRERR(r)); + + BUG_ON(img_ctx->fd < 0); + close(img_ctx->fd); + free(img_ctx); + + codegen->img_ctx = NULL; + + unload_img(codegen); +} + +static const struct codegen_ops tc_codegen_ops = { + .gen_inline_prologue = tc_gen_inline_prologue, + .load_packet_data = tc_load_packet_data, + .load_packet_data_end = tc_load_packet_data_end, + .emit_ret_code = tc_emit_ret_code, + .gen_inline_epilogue = tc_gen_inline_epilogue, + .load_img = tc_load_img, + .unload_img = tc_unload_img, +}; + void create_shared_codegen(struct shared_codegen *shared_codegen) { shared_codegen->maps_refcnt = 0; @@ -413,6 +561,9 @@ int create_codegen(struct codegen *codegen, enum bpf_prog_type type) memset(codegen, 0, sizeof(*codegen)); switch (type) { + case BPF_PROG_TYPE_SCHED_CLS: + codegen->codegen_ops = &tc_codegen_ops; + break; default: BFLOG_ERR("unsupported BPF program type %d", type); return -EINVAL; From patchwork Fri Dec 23 23:40:16 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Deslandes X-Patchwork-Id: 13081266 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0F2C5C3DA79 for ; Sat, 24 Dec 2022 00:31:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233096AbiLXAbN (ORCPT ); Fri, 23 Dec 2022 19:31:13 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49598 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232707AbiLXAbM (ORCPT ); Fri, 23 Dec 2022 19:31:12 -0500 Received: from 2.mo619.mail-out.ovh.net (2.mo619.mail-out.ovh.net [178.33.254.187]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1B56A6458 for ; Fri, 23 Dec 2022 16:31:10 -0800 (PST) Received: from ex4.mail.ovh.net (unknown [10.111.208.157]) by mo619.mail-out.ovh.net (Postfix) with ESMTPS id DB864219BD; Fri, 23 Dec 2022 23:51:16 +0000 (UTC) Received: from dev-fedora-x86-64.naccy.de (37.65.8.229) by DAG10EX1.indiv4.local (172.16.2.91) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.16; Sat, 24 Dec 2022 00:51:15 +0100 From: Quentin Deslandes To: CC: , Dmitrii Banshchikov , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Song Liu , Yonghong Song , John Fastabend , KP Singh , Stanislav Fomichev , Hao Luo , Jiri Olsa , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Mykola Lysenko , Shuah Khan , , , , Subject: [PATCH bpf-next v3 08/16] bpfilter: add match structure Date: Sat, 24 Dec 2022 00:40:16 +0100 Message-ID: <20221223234127.474463-9-qde@naccy.de> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221223234127.474463-1-qde@naccy.de> References: <20221223234127.474463-1-qde@naccy.de> MIME-Version: 1.0 X-Originating-IP: [37.65.8.229] X-ClientProxiedBy: CAS6.indiv4.local (172.16.1.6) To DAG10EX1.indiv4.local (172.16.2.91) X-Ovh-Tracer-Id: 4536532202992299639 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -85 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedvhedrheefgdduhecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemucehtddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenogetfedtuddqtdduucdludehmdenucfjughrpefhvfevufffkffojghfggfgtghisehtkeertdertddtnecuhfhrohhmpefsuhgvnhhtihhnucffvghslhgrnhguvghsuceoqhguvgesnhgrtggthidruggvqeenucggtffrrghtthgvrhhnpeffveejjeeiffekueefgfdvudffveetleehiedvheekkeejfedufedvieduudeiffenucffohhmrghinhepuhhsvghrrdhnrghmvgenucfkphepuddvjedrtddrtddruddpfeejrdeihedrkedrvddvleenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepihhnvghtpeduvdejrddtrddtrddupdhmrghilhhfrhhomhepoehquggvsehnrggttgihrdguvgeqpdhnsggprhgtphhtthhopedupdhrtghpthhtohepshgufhesghhoohhglhgvrdgtohhmpdgsphhfsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhlihhnuhigqdhkvghrnhgvlhesvhhgvghrrdhkvghrnhgvlhdrohhrghdpshhhuhgrhheskhgvrhhnvghlrdhorhhgpdhmhihkohhlrghlsehfsgdrtghomhdpphgrsggvnhhisehrvgguhhgrthdrtghomhdpkhhusggrsehkvghrnhgvlhdrohhrghdpvgguuhhmrgiivghtsehgohhoghhlvgdrtghomhdpug grvhgvmhesuggrvhgvmhhlohhfthdrnhgvthdpjhholhhsrgeskhgvrhhnvghlrdhorhhgpdhhrgholhhuohesghhoohhglhgvrdgtohhmpdhlihhnuhigqdhkshgvlhhfthgvshhtsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhkphhsihhnghhhsehkvghrnhgvlhdrohhrghdpjhhohhhnrdhfrghsthgrsggvnhgusehgmhgrihhlrdgtohhmpdihhhhssehfsgdrtghomhdpshhonhhgsehkvghrnhgvlhdrohhrghdpmhgrrhhtihhnrdhlrghusehlihhnuhigrdguvghvpdgrnhgurhhiiheskhgvrhhnvghlrdhorhhgpdgurghnihgvlhesihhoghgvrghrsghogidrnhgvthdprghstheskhgvrhhnvghlrdhorhhgpdhmvgesuhgsihhquhgvrdhsphgsrdhruhdpkhgvrhhnvghlqdhtvggrmhesmhgvthgrrdgtohhmpdhnvghtuggvvhesvhhgvghrrdhkvghrnhgvlhdrohhrghdpoffvtefjohhsthepmhhoieduledpmhhouggvpehsmhhtphhouhht Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net struct match_ops defines a polymorphic interface for matches. A match consists of pointers to struct match_ops and struct xt_entry_match which contains a payload for the match's type. The match interface supports the following operations: - check: validate a rule's match. - gen_inline: generate eBPF bytecode for the match. All match_ops structures are kept in a map by their name. Co-developed-by: Dmitrii Banshchikov Signed-off-by: Dmitrii Banshchikov Signed-off-by: Quentin Deslandes --- net/bpfilter/Makefile | 1 + net/bpfilter/context.c | 43 ++++++++++++ net/bpfilter/context.h | 3 + net/bpfilter/match.c | 55 +++++++++++++++ net/bpfilter/match.h | 35 ++++++++++ .../testing/selftests/bpf/bpfilter/.gitignore | 1 + tools/testing/selftests/bpf/bpfilter/Makefile | 7 ++ .../selftests/bpf/bpfilter/bpfilter_util.h | 22 ++++++ .../selftests/bpf/bpfilter/test_match.c | 69 +++++++++++++++++++ 9 files changed, 236 insertions(+) create mode 100644 net/bpfilter/match.c create mode 100644 net/bpfilter/match.h create mode 100644 tools/testing/selftests/bpf/bpfilter/bpfilter_util.h create mode 100644 tools/testing/selftests/bpf/bpfilter/test_match.c diff --git a/net/bpfilter/Makefile b/net/bpfilter/Makefile index ac039f1fac34..2f8d867a6038 100644 --- a/net/bpfilter/Makefile +++ b/net/bpfilter/Makefile @@ -13,6 +13,7 @@ $(LIBBPF_A): userprogs := bpfilter_umh bpfilter_umh-objs := main.o logger.o map-common.o bpfilter_umh-objs += context.o codegen.o +bpfilter_umh-objs += match.o bpfilter_umh-userldlibs := $(LIBBPF_A) -lelf -lz userccflags += -I $(srctree)/tools/include/ -I $(srctree)/tools/include/uapi diff --git a/net/bpfilter/context.c b/net/bpfilter/context.c index fdfd5fe78424..b5e172412fab 100644 --- a/net/bpfilter/context.c +++ b/net/bpfilter/context.c @@ -8,11 +8,54 @@ #include "context.h" +#include + +#include + +#include "logger.h" +#include "map-common.h" +#include "match.h" + +static const struct match_ops *match_ops[] = { }; + +static int init_match_ops_map(struct context *ctx) +{ + int r; + + r = create_map(&ctx->match_ops_map, ARRAY_SIZE(match_ops)); + if (r) { + BFLOG_ERR("failed to create matches map: %s", STRERR(r)); + return r; + } + + for (int i = 0; i < ARRAY_SIZE(match_ops); ++i) { + const struct match_ops *m = match_ops[i]; + + r = map_upsert(&ctx->match_ops_map, m->name, (void *)m); + if (r) { + BFLOG_ERR("failed to upsert in matches map: %s", + STRERR(r)); + return r; + } + } + + return 0; +} + int create_context(struct context *ctx) { + int r; + + r = init_match_ops_map(ctx); + if (r) { + BFLOG_ERR("failed to initialize matches map: %s", STRERR(r)); + return r; + } + return 0; } void free_context(struct context *ctx) { + free_map(&ctx->match_ops_map); } diff --git a/net/bpfilter/context.h b/net/bpfilter/context.h index df41b9707a81..e36aa8ebf57e 100644 --- a/net/bpfilter/context.h +++ b/net/bpfilter/context.h @@ -7,7 +7,10 @@ #ifndef NET_BPFILTER_CONTEXT_H #define NET_BPFILTER_CONTEXT_H +#include + struct context { + struct hsearch_data match_ops_map; }; int create_context(struct context *ctx); diff --git a/net/bpfilter/match.c b/net/bpfilter/match.c new file mode 100644 index 000000000000..fdb0926442a8 --- /dev/null +++ b/net/bpfilter/match.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Telegram FZ-LLC + * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. + */ + +#define _GNU_SOURCE + +#include "match.h" + +#include + +#include +#include + +#include "context.h" +#include "logger.h" +#include "map-common.h" + +int init_match(struct context *ctx, const struct bpfilter_ipt_match *ipt_match, + struct match *match) +{ + const size_t maxlen = sizeof(ipt_match->u.user.name); + const struct match_ops *found; + int r; + + if (strnlen(ipt_match->u.user.name, maxlen) == maxlen) { + BFLOG_ERR("failed to init match: name too long"); + return -EINVAL; + } + + found = map_find(&ctx->match_ops_map, ipt_match->u.user.name); + if (IS_ERR(found)) { + BFLOG_ERR("failed to find match by name: '%s'", + ipt_match->u.user.name); + return PTR_ERR(found); + } + + if (found->size + sizeof(*ipt_match) != ipt_match->u.match_size || + found->revision != ipt_match->u.user.revision) { + BFLOG_ERR("invalid match: '%s'", ipt_match->u.user.name); + return -EINVAL; + } + + r = found->check(ctx, ipt_match); + if (r) { + BFLOG_ERR("match check failed: %s", STRERR(r)); + return r; + } + + match->match_ops = found; + match->ipt_match = ipt_match; + + return 0; +} diff --git a/net/bpfilter/match.h b/net/bpfilter/match.h new file mode 100644 index 000000000000..c6541e6a6567 --- /dev/null +++ b/net/bpfilter/match.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Telegram FZ-LLC + * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. + */ + +#ifndef NET_BPFILTER_MATCH_H +#define NET_BPFILTER_MATCH_H + +#include "../../include/uapi/linux/bpfilter.h" + +#include + +struct bpfilter_ipt_match; +struct codegen; +struct context; +struct match; + +struct match_ops { + char name[BPFILTER_EXTENSION_MAXNAMELEN]; + uint8_t revision; + uint16_t size; + int (*check)(struct context *ctx, const struct bpfilter_ipt_match *ipt_match); + int (*gen_inline)(struct codegen *ctx, const struct match *match); +}; + +struct match { + const struct match_ops *match_ops; + const struct bpfilter_ipt_match *ipt_match; +}; + +int init_match(struct context *ctx, const struct bpfilter_ipt_match *ipt_match, + struct match *match); + +#endif // NET_BPFILTER_MATCH_H diff --git a/tools/testing/selftests/bpf/bpfilter/.gitignore b/tools/testing/selftests/bpf/bpfilter/.gitignore index 39ec0c09dff4..9ac1b3caf246 100644 --- a/tools/testing/selftests/bpf/bpfilter/.gitignore +++ b/tools/testing/selftests/bpf/bpfilter/.gitignore @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only tools/** test_map +test_match diff --git a/tools/testing/selftests/bpf/bpfilter/Makefile b/tools/testing/selftests/bpf/bpfilter/Makefile index e3b8bf76a10c..10642c1d6a87 100644 --- a/tools/testing/selftests/bpf/bpfilter/Makefile +++ b/tools/testing/selftests/bpf/bpfilter/Makefile @@ -11,6 +11,7 @@ BPFDIR := $(LIBDIR)/bpf CFLAGS += -Wall -g -pthread -I$(TOOLSINCDIR) -I$(APIDIR) -I$(BPFILTERSRCDIR) TEST_GEN_PROGS += test_map +TEST_GEN_PROGS += test_match KSFT_KHDR_INSTALL := 1 @@ -34,5 +35,11 @@ $(BPFOBJ): $(wildcard $(BPFDIR)/*.[ch] $(BPFDIR)/Makefile) \ BPFILTER_MAP_SRCS := $(BPFILTERSRCDIR)/map-common.c BPFILTER_CODEGEN_SRCS := $(BPFILTERSRCDIR)/codegen.c $(BPFOBJ) -lelf -lz +BPFILTER_MATCH_SRCS := $(BPFILTERSRCDIR)/match.c + +BPFILTER_COMMON_SRCS := $(BPFILTER_MAP_SRCS) +BPFILTER_COMMON_SRCS += $(BPFILTERSRCDIR)/context.c $(BPFILTERSRCDIR)/logger.c +BPFILTER_COMMON_SRCS += $(BPFILTER_MATCH_SRCS) $(OUTPUT)/test_map: test_map.c $(BPFILTER_MAP_SRCS) +$(OUTPUT)/test_match: test_match.c $(BPFILTER_COMMON_SRCS) diff --git a/tools/testing/selftests/bpf/bpfilter/bpfilter_util.h b/tools/testing/selftests/bpf/bpfilter/bpfilter_util.h new file mode 100644 index 000000000000..705fd1777a67 --- /dev/null +++ b/tools/testing/selftests/bpf/bpfilter/bpfilter_util.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef BPFILTER_UTIL_H +#define BPFILTER_UTIL_H + +#include + +#include +#include +#include + +static inline void init_entry_match(struct xt_entry_match *match, + uint16_t size, uint8_t revision, + const char *name) +{ + memset(match, 0, sizeof(*match)); + sprintf(match->u.user.name, "%s", name); + match->u.user.match_size = size; + match->u.user.revision = revision; +} + +#endif // BPFILTER_UTIL_H diff --git a/tools/testing/selftests/bpf/bpfilter/test_match.c b/tools/testing/selftests/bpf/bpfilter/test_match.c new file mode 100644 index 000000000000..4a0dc1b14e4d --- /dev/null +++ b/tools/testing/selftests/bpf/bpfilter/test_match.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE + +#include +#include + +#include "../../kselftest_harness.h" + +#include "context.h" +#include "logger.h" +#include "match.h" + +#include "bpfilter_util.h" + +/** + * struct udp_match - Dummy test structure. + * + * This structure provides enough space to allow for name too long, so it + * doesn't overwrite anything. + */ +struct udp_match { + struct xt_entry_match ipt_match; + char placeholder[32]; +}; + +FIXTURE(test_match_init) +{ + struct context ctx; + struct udp_match udp_match; + struct match match; +}; + +FIXTURE_SETUP(test_match_init) +{ + logger_set_file(stderr); + ASSERT_EQ(0, create_context(&self->ctx)); +}; + +FIXTURE_TEARDOWN(test_match_init) +{ + free_context(&self->ctx); +} + +TEST_F(test_match_init, name_too_long) +{ + init_entry_match(&self->udp_match.ipt_match, sizeof(self->udp_match), 0, + "this match name is supposed to be way too long..."); + + ASSERT_EQ(init_match(&self->ctx, + (const struct bpfilter_ipt_match *)&self->udp_match + .ipt_match, + &self->match), + -EINVAL); +} + +TEST_F(test_match_init, not_found) +{ + init_entry_match(&self->udp_match.ipt_match, sizeof(self->udp_match), 0, + "doesn't exist"); + + ASSERT_EQ(init_match(&self->ctx, + (const struct bpfilter_ipt_match *)&self->udp_match + .ipt_match, + &self->match), + -ENOENT); +} + +TEST_HARNESS_MAIN From patchwork Fri Dec 23 23:40:17 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Deslandes X-Patchwork-Id: 13081215 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 85796C4167B for ; Fri, 23 Dec 2022 23:52:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231846AbiLWXw1 (ORCPT ); Fri, 23 Dec 2022 18:52:27 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60826 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231140AbiLWXwZ (ORCPT ); Fri, 23 Dec 2022 18:52:25 -0500 X-Greylist: delayed 193 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Fri, 23 Dec 2022 15:52:23 PST Received: from 6.mo547.mail-out.ovh.net (6.mo547.mail-out.ovh.net [46.105.44.204]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 250721260F for ; Fri, 23 Dec 2022 15:52:23 -0800 (PST) Received: from ex4.mail.ovh.net (unknown [10.111.172.9]) by mo547.mail-out.ovh.net (Postfix) with ESMTPS id 5F61A20ECA; Fri, 23 Dec 2022 23:52:21 +0000 (UTC) Received: from dev-fedora-x86-64.naccy.de (37.65.8.229) by DAG10EX1.indiv4.local (172.16.2.91) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.16; Sat, 24 Dec 2022 00:52:19 +0100 From: Quentin Deslandes To: CC: , Dmitrii Banshchikov , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Song Liu , Yonghong Song , John Fastabend , KP Singh , Stanislav Fomichev , Hao Luo , Jiri Olsa , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Mykola Lysenko , Shuah Khan , , , , Subject: [PATCH bpf-next v3 09/16] bpfilter: add support for src/dst addr and ports Date: Sat, 24 Dec 2022 00:40:17 +0100 Message-ID: <20221223234127.474463-10-qde@naccy.de> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221223234127.474463-1-qde@naccy.de> References: <20221223234127.474463-1-qde@naccy.de> MIME-Version: 1.0 X-Originating-IP: [37.65.8.229] X-ClientProxiedBy: CAS6.indiv4.local (172.16.1.6) To DAG10EX1.indiv4.local (172.16.2.91) X-Ovh-Tracer-Id: 4554828075903086199 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -85 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedvhedrheefgdduhecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemucehtddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenogetfedtuddqtdduucdludehmdenucfjughrpefhvfevufffkffojghfggfgtghisehtkeertdertddtnecuhfhrohhmpefsuhgvnhhtihhnucffvghslhgrnhguvghsuceoqhguvgesnhgrtggthidruggvqeenucggtffrrghtthgvrhhnpeduledugfeileetvdelieeujedttedtvedtgfetteevfeejhfffkeeujeetfffgudenucfkphepuddvjedrtddrtddruddpfeejrdeihedrkedrvddvleenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepihhnvghtpeduvdejrddtrddtrddupdhmrghilhhfrhhomhepoehquggvsehnrggttgihrdguvgeqpdhnsggprhgtphhtthhopedupdhrtghpthhtohepshgufhesghhoohhglhgvrdgtohhmpdgsphhfsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhlihhnuhigqdhkvghrnhgvlhesvhhgvghrrdhkvghrnhgvlhdrohhrghdpshhhuhgrhheskhgvrhhnvghlrdhorhhgpdhmhihkohhlrghlsehfsgdrtghomhdpphgrsggvnhhisehrvgguhhgrthdrtghomhdpkhhusggrsehkvghrnhgvlhdrohhrghdpvgguuhhmrgiivghtsehgohhoghhlvgdrtghomhdpuggrvhgvmhesuggrvhgvmhhlohhfthdrnhgvth dpjhholhhsrgeskhgvrhhnvghlrdhorhhgpdhhrgholhhuohesghhoohhglhgvrdgtohhmpdhlihhnuhigqdhkshgvlhhfthgvshhtsehvghgvrhdrkhgvrhhnvghlrdhorhhgpdhkphhsihhnghhhsehkvghrnhgvlhdrohhrghdpjhhohhhnrdhfrghsthgrsggvnhgusehgmhgrihhlrdgtohhmpdihhhhssehfsgdrtghomhdpshhonhhgsehkvghrnhgvlhdrohhrghdpmhgrrhhtihhnrdhlrghusehlihhnuhigrdguvghvpdgrnhgurhhiiheskhgvrhhnvghlrdhorhhgpdgurghnihgvlhesihhoghgvrghrsghogidrnhgvthdprghstheskhgvrhhnvghlrdhorhhgpdhmvgesuhgsihhquhgvrdhsphgsrdhruhdpkhgvrhhnvghlqdhtvggrmhesmhgvthgrrdgtohhmpdhnvghtuggvvhesvhhgvghrrdhkvghrnhgvlhdrohhrghdpoffvtefjohhsthepmhhoheegjedpmhhouggvpehsmhhtphhouhht Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net Implement support for source and destination addresses and ports matching. Co-developed-by: Dmitrii Banshchikov Signed-off-by: Dmitrii Banshchikov Signed-off-by: Quentin Deslandes --- net/bpfilter/Makefile | 2 +- net/bpfilter/context.c | 2 +- net/bpfilter/match.h | 2 + net/bpfilter/xt_udp.c | 111 ++++++++++++++++++ .../testing/selftests/bpf/bpfilter/.gitignore | 1 + tools/testing/selftests/bpf/bpfilter/Makefile | 6 +- .../selftests/bpf/bpfilter/test_xt_udp.c | 48 ++++++++ 7 files changed, 168 insertions(+), 4 deletions(-) create mode 100644 net/bpfilter/xt_udp.c create mode 100644 tools/testing/selftests/bpf/bpfilter/test_xt_udp.c diff --git a/net/bpfilter/Makefile b/net/bpfilter/Makefile index 2f8d867a6038..345341a9ee30 100644 --- a/net/bpfilter/Makefile +++ b/net/bpfilter/Makefile @@ -13,7 +13,7 @@ $(LIBBPF_A): userprogs := bpfilter_umh bpfilter_umh-objs := main.o logger.o map-common.o bpfilter_umh-objs += context.o codegen.o -bpfilter_umh-objs += match.o +bpfilter_umh-objs += match.o xt_udp.o bpfilter_umh-userldlibs := $(LIBBPF_A) -lelf -lz userccflags += -I $(srctree)/tools/include/ -I $(srctree)/tools/include/uapi diff --git a/net/bpfilter/context.c b/net/bpfilter/context.c index b5e172412fab..f420fb8b6507 100644 --- a/net/bpfilter/context.c +++ b/net/bpfilter/context.c @@ -16,7 +16,7 @@ #include "map-common.h" #include "match.h" -static const struct match_ops *match_ops[] = { }; +static const struct match_ops *match_ops[] = { &xt_udp }; static int init_match_ops_map(struct context *ctx) { diff --git a/net/bpfilter/match.h b/net/bpfilter/match.h index c6541e6a6567..7de3d2a07dc5 100644 --- a/net/bpfilter/match.h +++ b/net/bpfilter/match.h @@ -29,6 +29,8 @@ struct match { const struct bpfilter_ipt_match *ipt_match; }; +extern const struct match_ops xt_udp; + int init_match(struct context *ctx, const struct bpfilter_ipt_match *ipt_match, struct match *match); diff --git a/net/bpfilter/xt_udp.c b/net/bpfilter/xt_udp.c new file mode 100644 index 000000000000..c78cd4341f81 --- /dev/null +++ b/net/bpfilter/xt_udp.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Telegram FZ-LLC + * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include + +#include +#include + +#include "codegen.h" +#include "context.h" +#include "logger.h" +#include "match.h" + +static int xt_udp_check(struct context *ctx, + const struct bpfilter_ipt_match *ipt_match) +{ + const struct xt_udp *udp; + + udp = (const struct xt_udp *)&ipt_match->data; + + if (udp->invflags & XT_UDP_INV_MASK) { + BFLOG_ERR("cannot check match 'udp': invalid flags\n"); + return -EINVAL; + } + + return 0; +} + +static int xt_udp_gen_inline_ports(struct codegen *ctx, int regno, bool inv, + const u16 (*ports)[2]) +{ + if ((*ports)[0] == 0 && (*ports)[1] == 65535) { + if (inv) + EMIT_FIXUP(ctx, CODEGEN_FIXUP_NEXT_RULE, + BPF_JMP_IMM(BPF_JA, 0, 0, 0)); + } else if ((*ports)[0] == (*ports)[1]) { + const u16 port = htons((*ports)[0]); + + EMIT_FIXUP(ctx, CODEGEN_FIXUP_NEXT_RULE, + BPF_JMP_IMM((inv ? BPF_JEQ : BPF_JNE), regno, port, 0)); + } else { + EMIT_LITTLE_ENDIAN(ctx, BPF_ENDIAN(BPF_TO_BE, regno, 16)); + EMIT_FIXUP(ctx, CODEGEN_FIXUP_NEXT_RULE, + BPF_JMP_IMM(inv ? BPF_JGT : BPF_JLT, regno, (*ports)[0], 0)); + EMIT_FIXUP(ctx, CODEGEN_FIXUP_NEXT_RULE, + BPF_JMP_IMM(inv ? BPF_JLT : BPF_JGT, regno, (*ports)[1], 0)); + } + + return 0; +} + +static int xt_udp_gen_inline(struct codegen *ctx, const struct match *match) +{ + const struct xt_udp *udp; + int r; + + udp = (const struct xt_udp *)&match->ipt_match->data; + + EMIT(ctx, BPF_MOV64_REG(CODEGEN_REG_SCRATCH1, CODEGEN_REG_L4)); + EMIT(ctx, BPF_ALU64_IMM(BPF_ADD, CODEGEN_REG_SCRATCH1, sizeof(struct udphdr))); + r = ctx->codegen_ops->load_packet_data_end(ctx, CODEGEN_REG_DATA_END); + if (r) { + BFLOG_ERR("failed to generate code to load packet data end: %s", + STRERR(r)); + return r; + } + + EMIT_FIXUP(ctx, CODEGEN_FIXUP_NEXT_RULE, + BPF_JMP_REG(BPF_JGT, CODEGEN_REG_SCRATCH1, CODEGEN_REG_DATA_END, 0)); + + EMIT(ctx, BPF_LDX_MEM(BPF_H, CODEGEN_REG_SCRATCH4, CODEGEN_REG_L4, + offsetof(struct udphdr, source))); + EMIT(ctx, BPF_LDX_MEM(BPF_H, CODEGEN_REG_SCRATCH5, CODEGEN_REG_L4, + offsetof(struct udphdr, dest))); + + r = xt_udp_gen_inline_ports(ctx, CODEGEN_REG_SCRATCH4, + udp->invflags & XT_UDP_INV_SRCPT, + &udp->spts); + if (r) { + BFLOG_ERR("failed to generate code to match source ports: %s", + STRERR(r)); + return r; + } + + r = xt_udp_gen_inline_ports(ctx, CODEGEN_REG_SCRATCH5, + udp->invflags & XT_UDP_INV_DSTPT, + &udp->dpts); + if (r) { + BFLOG_ERR("failed to generate code to match destination ports: %s", + STRERR(r)); + return r; + } + + return 0; +} + +const struct match_ops xt_udp = { + .name = "udp", + .size = XT_ALIGN(sizeof(struct xt_udp)), + .revision = 0, + .check = xt_udp_check, + .gen_inline = xt_udp_gen_inline +}; diff --git a/tools/testing/selftests/bpf/bpfilter/.gitignore b/tools/testing/selftests/bpf/bpfilter/.gitignore index 9ac1b3caf246..f84cc86493df 100644 --- a/tools/testing/selftests/bpf/bpfilter/.gitignore +++ b/tools/testing/selftests/bpf/bpfilter/.gitignore @@ -2,3 +2,4 @@ tools/** test_map test_match +test_xt_udp diff --git a/tools/testing/selftests/bpf/bpfilter/Makefile b/tools/testing/selftests/bpf/bpfilter/Makefile index 10642c1d6a87..97f8d596de36 100644 --- a/tools/testing/selftests/bpf/bpfilter/Makefile +++ b/tools/testing/selftests/bpf/bpfilter/Makefile @@ -12,6 +12,7 @@ CFLAGS += -Wall -g -pthread -I$(TOOLSINCDIR) -I$(APIDIR) -I$(BPFILTERSRCDIR) TEST_GEN_PROGS += test_map TEST_GEN_PROGS += test_match +TEST_GEN_PROGS += test_xt_udp KSFT_KHDR_INSTALL := 1 @@ -35,11 +36,12 @@ $(BPFOBJ): $(wildcard $(BPFDIR)/*.[ch] $(BPFDIR)/Makefile) \ BPFILTER_MAP_SRCS := $(BPFILTERSRCDIR)/map-common.c BPFILTER_CODEGEN_SRCS := $(BPFILTERSRCDIR)/codegen.c $(BPFOBJ) -lelf -lz -BPFILTER_MATCH_SRCS := $(BPFILTERSRCDIR)/match.c +BPFILTER_MATCH_SRCS := $(BPFILTERSRCDIR)/match.c $(BPFILTERSRCDIR)/xt_udp.c -BPFILTER_COMMON_SRCS := $(BPFILTER_MAP_SRCS) +BPFILTER_COMMON_SRCS := $(BPFILTER_MAP_SRCS) $(BPFILTER_CODEGEN_SRCS) BPFILTER_COMMON_SRCS += $(BPFILTERSRCDIR)/context.c $(BPFILTERSRCDIR)/logger.c BPFILTER_COMMON_SRCS += $(BPFILTER_MATCH_SRCS) $(OUTPUT)/test_map: test_map.c $(BPFILTER_MAP_SRCS) $(OUTPUT)/test_match: test_match.c $(BPFILTER_COMMON_SRCS) +$(OUTPUT)/test_xt_udp: test_xt_udp.c $(BPFILTER_COMMON_SRCS) diff --git a/tools/testing/selftests/bpf/bpfilter/test_xt_udp.c b/tools/testing/selftests/bpf/bpfilter/test_xt_udp.c new file mode 100644 index 000000000000..c0898b0eca30 --- /dev/null +++ b/tools/testing/selftests/bpf/bpfilter/test_xt_udp.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE + +#include +#include + +#include "../../kselftest_harness.h" + +#include "context.h" +#include "logger.h" +#include "match.h" + +#include "bpfilter_util.h" + +FIXTURE(test_xt_udp) +{ + struct context ctx; + struct { + struct xt_entry_match match; + struct xt_udp udp; + + } ipt_match; + struct match match; +}; + +FIXTURE_SETUP(test_xt_udp) +{ + logger_set_file(stderr); + ASSERT_EQ(0, create_context(&self->ctx)); +}; + +FIXTURE_TEARDOWN(test_xt_udp) +{ + free_context(&self->ctx); +}; + +TEST_F(test_xt_udp, init) +{ + init_entry_match((struct xt_entry_match *)&self->ipt_match, + sizeof(self->ipt_match), 0, "udp"); + ASSERT_EQ(init_match(&self->ctx, + (const struct bpfilter_ipt_match *)&self->ipt_match, + &self->match), + 0); +} + +TEST_HARNESS_MAIN