From patchwork Mon May 17 22:52:58 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitrii Banshchikov X-Patchwork-Id: 440481 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 531A8C433B4 for ; Mon, 17 May 2021 22:53:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2EE8D61209 for ; Mon, 17 May 2021 22:53:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344204AbhEQWyy (ORCPT ); Mon, 17 May 2021 18:54:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41654 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242469AbhEQWyn (ORCPT ); Mon, 17 May 2021 18:54:43 -0400 Received: from mail-wr1-x42a.google.com (mail-wr1-x42a.google.com [IPv6:2a00:1450:4864:20::42a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3886FC061573 for ; Mon, 17 May 2021 15:53:25 -0700 (PDT) Received: by mail-wr1-x42a.google.com with SMTP id n2so8129562wrm.0 for ; Mon, 17 May 2021 15:53:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ubique-spb-ru.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=5+z9yQBwGKLQ3pjRj4QMkBOoGjzosPzwejTgCIv89Lg=; b=gjq6aHKgbQKZe0q7MmvwG552V4savz9MIu1dlKXExlDljHEZORV3V4QX9LO54J5LTv oSkxgR6gTM+IpBW2gAz0sJIrBCnfAFfxSf6XWp4INx21bLmcPGZKolTiUJ+thB9wsUQQ LK4v6IEyQ4NytSvS/Wkvdc0NB9rRyNoZaV22lGA6wd65ercbjW9xaQBgWEhngw6U5lB4 mVyxm7xgdetVj2Wd43ccy4SQx+Rukx3aQN946mMVfUfK2AQZmMdfbiVKlZsaIWzlbaXz R7+2o2lCdhMVeBrpe/prUXmz/+fQgiBgtWogQ2bPWMEXL8VQvAfhWIj7vofoYpBzZE2a nULQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=5+z9yQBwGKLQ3pjRj4QMkBOoGjzosPzwejTgCIv89Lg=; b=tQaPEsXUSi9MptYb3ZBOvATVPwtDYUEAH7noVhAkBJY/fVsWDEP3B/YbkAuQwl0ywN KrStqXyeHGHbKyAdXGljqT3SKn3MSOpEQsG97aRzgs7KUxeZBnUXEFz9VhR72PSmm8GC 0S5iLllBIFtF8AM0dqyYPbHek6cMYAC7luRBWgl3YrWR2KQyEckBnpEQRG35diB17Kho pfnISqyOKneAnHukjd5dXMcwilor7oewvn1JAxDWkTZWXK8wMn6m0pTGWFca1X8+kvVy vFn9SoLilY1KC+HGemiWRx2Wt48MSmDWj0T2tCWO9mCc21OVnJ0c65ydKM4BN+FCDnr2 YyTg== X-Gm-Message-State: AOAM5337tQ+oDk4ZV44M6UXRJ3ryRwyGRo0M3RQBY0WkR/KpYxsrUhGt U4l2J/gz4mHgkIQNTcJnJwQi2A== X-Google-Smtp-Source: ABdhPJxI8DKO8VaST4Eg//djHKSxxf1H3FzFygWWzTkZBZXBIDoHZQ6bjxxQ8RETtUCkVocSmzMKQg== X-Received: by 2002:a5d:4ccc:: with SMTP id c12mr2489333wrt.137.1621292003993; Mon, 17 May 2021 15:53:23 -0700 (PDT) Received: from localhost ([154.21.15.43]) by smtp.gmail.com with ESMTPSA id q10sm16151668wmc.31.2021.05.17.15.53.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 May 2021 15:53:23 -0700 (PDT) From: Dmitrii Banshchikov To: bpf@vger.kernel.org Cc: Dmitrii Banshchikov , ast@kernel.org, davem@davemloft.net, daniel@iogearbox.net, andrii@kernel.org, kafai@fb.com, songliubraving@fb.com, yhs@fb.com, john.fastabend@gmail.com, kpsingh@kernel.org, netdev@vger.kernel.org, rdna@fb.com Subject: [PATCH bpf-next 01/11] bpfilter: Add types for usermode helper Date: Tue, 18 May 2021 02:52:58 +0400 Message-Id: <20210517225308.720677-2-me@ubique.spb.ru> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210517225308.720677-1-me@ubique.spb.ru> References: <20210517225308.720677-1-me@ubique.spb.ru> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add more definitions that mirror existing iptables' ABI. These definitions will be used in bpfilter usermode helper. Signed-off-by: Dmitrii Banshchikov --- include/uapi/linux/bpfilter.h | 155 ++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/include/uapi/linux/bpfilter.h b/include/uapi/linux/bpfilter.h index cbc1f5813f50..e97d95d0ba54 100644 --- a/include/uapi/linux/bpfilter.h +++ b/include/uapi/linux/bpfilter.h @@ -3,6 +3,13 @@ #define _UAPI_LINUX_BPFILTER_H #include +#include + +#define BPFILTER_FUNCTION_MAXNAMELEN 30 +#define BPFILTER_EXTENSION_MAXNAMELEN 29 + +#define BPFILTER_STANDARD_TARGET "" +#define BPFILTER_ERROR_TARGET "ERROR" enum { BPFILTER_IPT_SO_SET_REPLACE = 64, @@ -18,4 +25,152 @@ enum { BPFILTER_IPT_GET_MAX, }; +enum { + BPFILTER_XT_TABLE_MAXNAMELEN = 32, +}; + +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[0]; +}; + +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[0]; +}; + +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[0]; +}; + +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[0]; +}; + +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[0]; +}; + +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[0]; +}; + #endif /* _UAPI_LINUX_BPFILTER_H */ From patchwork Mon May 17 22:53:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitrii Banshchikov X-Patchwork-Id: 440480 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id BA322C43462 for ; Mon, 17 May 2021 22:53:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9C32D6124C for ; Mon, 17 May 2021 22:53:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344234AbhEQWy5 (ORCPT ); Mon, 17 May 2021 18:54:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41700 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344178AbhEQWyt (ORCPT ); Mon, 17 May 2021 18:54:49 -0400 Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6106CC061756 for ; Mon, 17 May 2021 15:53:32 -0700 (PDT) Received: by mail-wr1-x42b.google.com with SMTP id q5so8058164wrs.4 for ; Mon, 17 May 2021 15:53:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ubique-spb-ru.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=pK3iupwBoYGtCvFJdATRExYDmiCQBy7a92C+G/Pbh88=; b=SbxIg04tx+ArMlJADwoOv/T14jsSdg+ly8uLk5Lu6In27+ip2ATi/DaOVhlO4w3eI3 KAmn7K5KTETwDpcEn035JbNTZhD1YG1F0Sr9cY/8B56VNtzpZeHsVlnlCip5DoIKGD6U k2wqqncXkbcO5SOt0ZZsrhmJIkT26gzfzbpqDnSwWZyCwszOuEO5xkoTEm2IBMhmwxJl 6ANqtkLqZEZAl5KCkvL/dS6pa+RvRZ6qqB73PPF02C5O7g/fURiGTQmp1XcaYZsLEV0x oe0mjkOxxdxKIQHWRKyhSfXchsiTKjAtOFOaagJxPZulK3GczNPZy0LgluK8fFBGN1gr hzPw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=pK3iupwBoYGtCvFJdATRExYDmiCQBy7a92C+G/Pbh88=; b=Soxyd0FtkzV8D/ap9c5OrCjX64fWtERBPYRqU8WovpPzbp2ENvGyWMdW/Bv4Et28rO 5x/YL4pXXOKnms8ABjI/FFAhxTqf2nEXsvChA+tVWjex4tMkUbJEnS0sFWtAealHitlY AzYfHtShnTjdOIRz8pKrmTykM0IwSN0GHah0KN6GtoFU0E4rlqdjU3w+3y8J19YX+Sdv q9r+0vrWLifZc2rscBXIIC1GY0haAv9QsOa77dJ1pJ2CMkpyevBGIZGZFoqazERN3uDL McP9tyGeqjkNxARs04hDAdroHO7BQM2iRQ/9DdEb+gJf+QebYtrC+Smo6WXQ/al0GkPt cChA== X-Gm-Message-State: AOAM532U2Yaf0eiyBJUvJLeT4hvXUpMMSRm+5qQ6D84LCzwVEv271FMr J+S39Cjgd/rX8UrtPOA1lL+Lyg== X-Google-Smtp-Source: ABdhPJxV1/zzO94H4gXiuw9I2n83v9F3qnNxRE7auETPKA17XyRgwOIfnPCs9UOydQoEw/FgZq5Cxg== X-Received: by 2002:adf:ed46:: with SMTP id u6mr1405382wro.295.1621292011131; Mon, 17 May 2021 15:53:31 -0700 (PDT) Received: from localhost ([154.21.15.43]) by smtp.gmail.com with ESMTPSA id h14sm23557487wrq.45.2021.05.17.15.53.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 May 2021 15:53:30 -0700 (PDT) From: Dmitrii Banshchikov To: bpf@vger.kernel.org Cc: Dmitrii Banshchikov , ast@kernel.org, davem@davemloft.net, daniel@iogearbox.net, andrii@kernel.org, kafai@fb.com, songliubraving@fb.com, yhs@fb.com, john.fastabend@gmail.com, kpsingh@kernel.org, netdev@vger.kernel.org, rdna@fb.com Subject: [PATCH bpf-next 03/11] bpfilter: Add IO functions Date: Tue, 18 May 2021 02:53:00 +0400 Message-Id: <20210517225308.720677-4-me@ubique.spb.ru> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210517225308.720677-1-me@ubique.spb.ru> References: <20210517225308.720677-1-me@ubique.spb.ru> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Introduce IO functions for: 1) reading and writing data from a descriptor: read_exact(), write_exact(), 2) reading and writing memory of other processes: pvm_read(), pvm_write(). read_exact() and write_exact() are wrappers over read(2)/write(2) with correct handling of partial read/write. These functions are intended to be used for communication over pipe with the kernel part of bpfilter. pvm_read() and pvm_write() are wrappers over process_vm_readv(2)/process_vm_writev(2) with an interface that uses a single buffer instead of vectored form. These functions are intended to be used for readining/writing memory buffers supplied to iptables ABI setsockopt(2) from other processes. Signed-off-by: Dmitrii Banshchikov Acked-by: Song Liu --- net/bpfilter/Makefile | 2 +- net/bpfilter/io.c | 77 ++++++++++++++ net/bpfilter/io.h | 18 ++++ .../testing/selftests/bpf/bpfilter/.gitignore | 2 + tools/testing/selftests/bpf/bpfilter/Makefile | 17 +++ .../testing/selftests/bpf/bpfilter/test_io.c | 100 ++++++++++++++++++ 6 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 net/bpfilter/io.c create mode 100644 net/bpfilter/io.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_io.c diff --git a/net/bpfilter/Makefile b/net/bpfilter/Makefile index 874d5ef6237d..69a6c139fc7a 100644 --- a/net/bpfilter/Makefile +++ b/net/bpfilter/Makefile @@ -4,7 +4,7 @@ # userprogs := bpfilter_umh -bpfilter_umh-objs := main.o bflog.o +bpfilter_umh-objs := main.o bflog.o io.o userccflags += -I $(srctree)/tools/include/ -I $(srctree)/tools/include/uapi ifeq ($(CONFIG_BPFILTER_UMH), y) diff --git a/net/bpfilter/io.c b/net/bpfilter/io.c new file mode 100644 index 000000000000..e645ae9d7a50 --- /dev/null +++ b/net/bpfilter/io.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#define _GNU_SOURCE + +#include "io.h" + +#include +#include +#include + +#define do_exact(fd, op, buffer, count) \ + ({ \ + size_t total = 0; \ + int err = 0; \ + \ + do { \ + const ssize_t part = op(fd, (buffer) + total, (count) - total); \ + if (part > 0) { \ + total += part; \ + } else if (part == 0 && (count) > 0) { \ + err = -EIO; \ + break; \ + } else if (part == -1) { \ + if (errno == EINTR) \ + continue; \ + err = -errno; \ + break; \ + } \ + } while (total < (count)); \ + \ + err; \ + }) + +int read_exact(int fd, void *buffer, size_t count) +{ + return do_exact(fd, read, buffer, count); +} + +int write_exact(int fd, const void *buffer, size_t count) +{ + return do_exact(fd, write, buffer, count); +} + +int pvm_read(pid_t pid, void *to, const void *from, size_t count) +{ + const struct iovec r_iov = { .iov_base = (void *)from, .iov_len = count }; + const struct iovec l_iov = { .iov_base = to, .iov_len = count }; + size_t total_bytes; + + total_bytes = process_vm_readv(pid, &l_iov, 1, &r_iov, 1, 0); + if (total_bytes == -1) + return -errno; + + if (total_bytes != count) + return -EFAULT; + + return 0; +} + +int pvm_write(pid_t pid, void *to, const void *from, size_t count) +{ + const struct iovec l_iov = { .iov_base = (void *)from, .iov_len = count }; + const struct iovec r_iov = { .iov_base = to, .iov_len = count }; + size_t total_bytes; + + total_bytes = process_vm_writev(pid, &l_iov, 1, &r_iov, 1, 0); + if (total_bytes == -1) + return -errno; + + if (total_bytes != count) + return -EFAULT; + + return 0; +} diff --git a/net/bpfilter/io.h b/net/bpfilter/io.h new file mode 100644 index 000000000000..ab56c8bb8e61 --- /dev/null +++ b/net/bpfilter/io.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#ifndef NET_BPFILTER_IO_H +#define NET_BPFILTER_IO_H + +#include +#include + +int read_exact(int fd, void *buffer, size_t count); +int write_exact(int fd, const void *buffer, size_t count); + +int pvm_read(pid_t pid, void *to, const void *from, size_t count); +int pvm_write(pid_t pid, void *to, const void *from, size_t count); + +#endif // NET_BPFILTER_IO_H diff --git a/tools/testing/selftests/bpf/bpfilter/.gitignore b/tools/testing/selftests/bpf/bpfilter/.gitignore new file mode 100644 index 000000000000..f5785e366013 --- /dev/null +++ b/tools/testing/selftests/bpf/bpfilter/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +test_io diff --git a/tools/testing/selftests/bpf/bpfilter/Makefile b/tools/testing/selftests/bpf/bpfilter/Makefile new file mode 100644 index 000000000000..c02d72d89199 --- /dev/null +++ b/tools/testing/selftests/bpf/bpfilter/Makefile @@ -0,0 +1,17 @@ +# 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_io + +KSFT_KHDR_INSTALL := 1 + +include ../../lib.mk + +$(OUTPUT)/test_io: test_io.c $(BPFILTERSRCDIR)/io.c diff --git a/tools/testing/selftests/bpf/bpfilter/test_io.c b/tools/testing/selftests/bpf/bpfilter/test_io.c new file mode 100644 index 000000000000..e4294930c581 --- /dev/null +++ b/tools/testing/selftests/bpf/bpfilter/test_io.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "io.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "../../kselftest_harness.h" + +FIXTURE(test_pvm) +{ + int wstatus; + int fd[2]; + pid_t pid; + pid_t ppid; + char expected[5]; + char actual[5]; +}; + +FIXTURE_SETUP(test_pvm) +{ + snprintf(self->expected, sizeof(self->expected), "ipfw"); + memset(self->actual, 0, sizeof(self->actual)); + self->ppid = getpid(); + ASSERT_EQ(pipe(self->fd), 0); + self->pid = fork(); + ASSERT_NE(self->pid, -1) TH_LOG("Cannot fork(): %m\n"); + close(self->fd[!!self->pid]); +}; + +FIXTURE_TEARDOWN(test_pvm) +{ + int wstatus; + + if (!self->pid) + exit(0); + + kill(self->pid, SIGKILL); + waitpid(self->pid, &wstatus, -2); + close(self->fd[1]); +} + +TEST_F(test_pvm, read) +{ + if (!self->pid) { + const uint8_t baton = 'x'; + + memcpy(self->actual, self->expected, sizeof(self->actual)); + ASSERT_EQ(write(self->fd[1], &baton, sizeof(baton)), sizeof(baton)); + + pause(); + exit(0); + } else { + int err; + uint8_t baton; + + EXPECT_EQ(read(self->fd[0], &baton, sizeof(baton)), sizeof(baton)); + EXPECT_EQ(baton, 'x'); + + err = pvm_read(self->pid, &self->actual, &self->actual, sizeof(self->actual)); + EXPECT_EQ(err, 0) + TH_LOG("Cannot pvm_read(): %s\n", strerror(-err)); + + EXPECT_EQ(memcmp(&self->expected, &self->actual, sizeof(self->actual)), 0); + } +} + +TEST_F(test_pvm, write) +{ + if (getuid()) + SKIP(return, "pvm_write requires CAP_SYS_PTRACE"); + + if (!self->pid) { + const uint8_t baton = 'x'; + int err; + + err = pvm_write(self->ppid, &self->actual, &self->expected, sizeof(self->expected)); + EXPECT_EQ(err, 0) TH_LOG("Cannot pvm_write: %s\n", strerror(-err)); + + ASSERT_EQ(write(self->fd[1], &baton, sizeof(baton)), sizeof(baton)); + + pause(); + exit(0); + + } else { + uint8_t baton; + + EXPECT_EQ(read(self->fd[0], &baton, sizeof(baton)), sizeof(baton)); + EXPECT_EQ(baton, 'x'); + + EXPECT_EQ(memcmp(&self->expected, &self->actual, sizeof(self->actual)), 0); + } +} + +TEST_HARNESS_MAIN From patchwork Mon May 17 22:53:02 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitrii Banshchikov X-Patchwork-Id: 440479 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 10F44C43461 for ; Mon, 17 May 2021 22:53:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E56B061350 for ; Mon, 17 May 2021 22:53:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344266AbhEQWzD (ORCPT ); Mon, 17 May 2021 18:55:03 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41702 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344094AbhEQWy5 (ORCPT ); Mon, 17 May 2021 18:54:57 -0400 Received: from mail-wm1-x32d.google.com (mail-wm1-x32d.google.com [IPv6:2a00:1450:4864:20::32d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 715C5C061756 for ; Mon, 17 May 2021 15:53:39 -0700 (PDT) Received: by mail-wm1-x32d.google.com with SMTP id f6-20020a1c1f060000b0290175ca89f698so383520wmf.5 for ; Mon, 17 May 2021 15:53:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ubique-spb-ru.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=gqn9Ht5Uc9kmMjixTJxeMDr6SN/Yeqi5Bk9pBkIYrjA=; b=nHIimy9JOGIP/7rqn3MNQlPeFZ59TIfhamSHvy+eDezRbbXcgS+Y6R5OSOkyPsGWAX zaAx7X08owN0daqHekgE/JtkD5hq7yxTZGONwbTwXjhFljzO1eJ/NpoyDjV732IuKqTp sjp3BlBpRP8vBlQ+BatyMWX6wqGu9UL9tT+1EPUKufqXek0r+ghrgKwJaf4V4nM4IPL6 lzbphxfXdwZb3FMdZr6Fef/v0/stltOXkAZwSvmNVLRd1X5hHz3xWkOJ3WdljcAw7oc9 KwD0yy4sU2cG95gW/FltLoPptV/UTIRrRiOMOWcg47DDJT2u3IwZwlQ3l+sa8b1WR1Qx Wfyw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=gqn9Ht5Uc9kmMjixTJxeMDr6SN/Yeqi5Bk9pBkIYrjA=; b=dtnZNbzP6hUK2Ie1zU0YpdcK/WzMWKJk1LDf2sn0K8zn0dleb15vEf2N0I2DKPTxB6 hMGoqmVKNvYEWJ3cs8cJKKc0e36NtK+ihe2akVB/N2uhNmBzAR5pG6adGYBo5E7mtgzH MFLz2ojW4LauqqKHQWIFdBDoZLykVyfC2ENeS0VZSAP04woKKDUELlB/gsbW9cLS9KAt QaCC8pcGagD/hfpcIwXpNIuiOF6hnyzkZuT9FEJp6ohTfwa0twG9ZU9ogXkx2nyLRjmn J69ZwZazdAE1Leto5fH2XcuYaexbGZFXcIRtPX4HU+iq6JXvznG3T3XqBznYODCkJ4MK nLfg== X-Gm-Message-State: AOAM530HxbYb2THtXmH1y8iwNymv89HnGbneeI1YZgRHtpFaPOaPZK+z 1DqDJRy50tKJ593O3TFpAW2o1A== X-Google-Smtp-Source: ABdhPJxhYhg2QExULuqHjygfezwM/USpb63gWCHjeVCgGXDFnFBvJknwCChxlgmCfZrVoFhN1kC5LQ== X-Received: by 2002:a1c:cc0b:: with SMTP id h11mr1388864wmb.87.1621292018169; Mon, 17 May 2021 15:53:38 -0700 (PDT) Received: from localhost ([154.21.15.43]) by smtp.gmail.com with ESMTPSA id h17sm3453928wre.38.2021.05.17.15.53.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 May 2021 15:53:38 -0700 (PDT) From: Dmitrii Banshchikov To: bpf@vger.kernel.org Cc: Dmitrii Banshchikov , ast@kernel.org, davem@davemloft.net, daniel@iogearbox.net, andrii@kernel.org, kafai@fb.com, songliubraving@fb.com, yhs@fb.com, john.fastabend@gmail.com, kpsingh@kernel.org, netdev@vger.kernel.org, rdna@fb.com Subject: [PATCH bpf-next 05/11] bpfilter: Add map container Date: Tue, 18 May 2021 02:53:02 +0400 Message-Id: <20210517225308.720677-6-me@ubique.spb.ru> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210517225308.720677-1-me@ubique.spb.ru> References: <20210517225308.720677-1-me@ubique.spb.ru> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org 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 set of operations is: insert, update and find. Signed-off-by: Dmitrii Banshchikov --- net/bpfilter/Makefile | 2 +- net/bpfilter/map-common.c | 64 +++++++++++++++++++ net/bpfilter/map-common.h | 19 ++++++ .../testing/selftests/bpf/bpfilter/.gitignore | 1 + tools/testing/selftests/bpf/bpfilter/Makefile | 2 + .../testing/selftests/bpf/bpfilter/test_map.c | 63 ++++++++++++++++++ 6 files changed, 150 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/test_map.c diff --git a/net/bpfilter/Makefile b/net/bpfilter/Makefile index 69a6c139fc7a..908fbad680ec 100644 --- a/net/bpfilter/Makefile +++ b/net/bpfilter/Makefile @@ -4,7 +4,7 @@ # userprogs := bpfilter_umh -bpfilter_umh-objs := main.o bflog.o io.o +bpfilter_umh-objs := main.o bflog.o io.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..6a4ab0c5d3ec --- /dev/null +++ b/net/bpfilter/map-common.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#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 *name) +{ + const ENTRY needle = { .key = (char *)name }; + ENTRY *found; + + if (!hsearch_r(needle, FIND, &found, htab)) + return ERR_PTR(-ENOENT); + + return found->data; +} + +int map_update(struct hsearch_data *htab, const char *name, void *data) +{ + const ENTRY needle = { .key = (char *)name, .data = data }; + ENTRY *found; + + if (!hsearch_r(needle, ENTER, &found, htab)) + return -errno; + + found->key = (char *)name; + found->data = data; + + return 0; +} + +int map_insert(struct hsearch_data *htab, const char *name, void *data) +{ + const ENTRY needle = { .key = (char *)name, .data = data }; + ENTRY *found; + + if (!hsearch_r(needle, ENTER, &found, htab)) + return -errno; + + if (found->data != data) + return -EEXIST; + + 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..b29829230eff --- /dev/null +++ b/net/bpfilter/map-common.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#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 *name); +int map_insert(struct hsearch_data *htab, const char *name, void *data); +int map_update(struct hsearch_data *htab, const char *name, void *data); +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 index f5785e366013..be10b50ca289 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 test_io +test_map diff --git a/tools/testing/selftests/bpf/bpfilter/Makefile b/tools/testing/selftests/bpf/bpfilter/Makefile index c02d72d89199..77afbbdf27c5 100644 --- a/tools/testing/selftests/bpf/bpfilter/Makefile +++ b/tools/testing/selftests/bpf/bpfilter/Makefile @@ -9,9 +9,11 @@ BPFILTERSRCDIR := $(top_srcdir)/net/bpfilter CFLAGS += -Wall -g -pthread -I$(TOOLSINCDIR) -I$(APIDIR) -I$(BPFILTERSRCDIR) TEST_GEN_PROGS += test_io +TEST_GEN_PROGS += test_map KSFT_KHDR_INSTALL := 1 include ../../lib.mk $(OUTPUT)/test_io: test_io.c $(BPFILTERSRCDIR)/io.c +$(OUTPUT)/test_map: test_map.c $(BPFILTERSRCDIR)/map-common.c 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..6ac61a634e41 --- /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, insert_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_insert(&self->map, self->key, self->expected)); + ASSERT_EQ(0, map_insert(&self->map, self->key, self->expected)); + ASSERT_EQ(-EEXIST, map_insert(&self->map, self->key, self->actual)); + + found = map_find(&self->map, self->key); + + ASSERT_FALSE(IS_ERR(found)); + ASSERT_STREQ(self->expected, found); +} + +TEST_F(test_map, update) +{ + void *found; + + ASSERT_EQ(0, map_insert(&self->map, self->key, self->actual)); + ASSERT_EQ(0, map_update(&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 Mon May 17 22:53:04 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitrii Banshchikov X-Patchwork-Id: 440478 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6146DC433ED for ; Mon, 17 May 2021 22:53:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3B07D611CC for ; Mon, 17 May 2021 22:53:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344272AbhEQWzN (ORCPT ); Mon, 17 May 2021 18:55:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41776 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344274AbhEQWzE (ORCPT ); Mon, 17 May 2021 18:55:04 -0400 Received: from mail-wm1-x32c.google.com (mail-wm1-x32c.google.com [IPv6:2a00:1450:4864:20::32c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9AE5EC0613ED for ; Mon, 17 May 2021 15:53:46 -0700 (PDT) Received: by mail-wm1-x32c.google.com with SMTP id f75-20020a1c1f4e0000b0290171001e7329so425069wmf.1 for ; Mon, 17 May 2021 15:53:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ubique-spb-ru.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=It14OYF7gMIIbrH0L4XXl28vAWYtIT0X3r0wPJ+ooAY=; b=bd0lBuZfi2VBhYFnwlDUpimoW0GA+Fkkb60UD6aaEyiuhV9IDZ72Hj0qwmZu8Rr1+1 c2qTCmxh3EReSM+at+RgUoy2VnfFy3jHUqfUamr8fYvOP7Gi8iH5h08pSV/JU7B9tPRx IIKAeXzXjPDO8tIOr+UZ2MmF231bS8Clk6mdY/bu8Dnj5KTlmqfN9tBwT8Lg9fCK7X5r LBt7555h2kcxomR5ZfNOu8L5oNOQ4+g1/DtEgFLjFDdFFyOsWjyJSSsZQG8gaTESbG7W H6Ax8Yod/IE1sFAYIhva25xZN6eIC2tThQhgQDBMGlx7NNjnZFH1/MicWDoryR0ppEm5 lJVw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=It14OYF7gMIIbrH0L4XXl28vAWYtIT0X3r0wPJ+ooAY=; b=APG3c600vbs2xXjBaZ73TeScylUTKY+1hjPy7DPvXckS8mjuXpXRnqveLF9rO0kCRe OPnAAsuoxJbms06tWoPSyGkLHY9xvuucMjFOpF2dW5RCKNhvcmOaetovkLKiOH9SuQDy qQRaqYKOrTqW8w8DGlbweKi1K0Rls/pXa2BUCQfm94hOFm+p/B5F9uYPzGulxGo7yCpj Xsxbk1joaP0hjS4Xd0XxBnLg07Qis8VyvLd2Ij5mnDKNsir7r1pcJjiLwcoA6kHft2h5 s7+CkOg1ObYjmZEmhgOFds2tSBADoVd6vT2zBekm/OCFBBzhNIFK7MJEzax7conCpZfv /XXQ== X-Gm-Message-State: AOAM532QqQZicm7un+m9rsNWHPW6Nn2vheYK0fybzTd248aXEWueAxbY tKvtTHa/0n0JAYqHBXjeb5s1JQ== X-Google-Smtp-Source: ABdhPJyeGwXVMAvkZFrMfuxwcAWHZLjeiDV3+/4+fg9U1jReSyUWTUDDAGPrCQUNNudDMTbNy8t8Pw== X-Received: by 2002:a1c:4b0c:: with SMTP id y12mr1400098wma.28.1621292025233; Mon, 17 May 2021 15:53:45 -0700 (PDT) Received: from localhost ([154.21.15.43]) by smtp.gmail.com with ESMTPSA id q10sm16152189wmc.31.2021.05.17.15.53.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 May 2021 15:53:45 -0700 (PDT) From: Dmitrii Banshchikov To: bpf@vger.kernel.org Cc: Dmitrii Banshchikov , ast@kernel.org, davem@davemloft.net, daniel@iogearbox.net, andrii@kernel.org, kafai@fb.com, songliubraving@fb.com, yhs@fb.com, john.fastabend@gmail.com, kpsingh@kernel.org, netdev@vger.kernel.org, rdna@fb.com Subject: [PATCH bpf-next 07/11] bpfilter: Add struct target Date: Tue, 18 May 2021 02:53:04 +0400 Message-Id: <20210517225308.720677-8-me@ubique.spb.ru> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210517225308.720677-1-me@ubique.spb.ru> References: <20210517225308.720677-1-me@ubique.spb.ru> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org struct target_ops defines polymorphic interface for targets. A target consists of pointers to struct target_ops and struct xt_entry_target which contains a payload for the target's type. All target_ops are kept in map target_ops_map by their name. Signed-off-by: Dmitrii Banshchikov --- net/bpfilter/Makefile | 2 +- net/bpfilter/context.c | 34 +++++- net/bpfilter/context.h | 2 + net/bpfilter/target-ops-map.h | 49 ++++++++ net/bpfilter/target.c | 112 ++++++++++++++++++ net/bpfilter/target.h | 34 ++++++ .../testing/selftests/bpf/bpfilter/.gitignore | 1 + tools/testing/selftests/bpf/bpfilter/Makefile | 5 +- .../selftests/bpf/bpfilter/bpfilter_util.h | 31 +++++ .../selftests/bpf/bpfilter/test_target.c | 85 +++++++++++++ 10 files changed, 352 insertions(+), 3 deletions(-) create mode 100644 net/bpfilter/target-ops-map.h create mode 100644 net/bpfilter/target.c create mode 100644 net/bpfilter/target.h create mode 100644 tools/testing/selftests/bpf/bpfilter/bpfilter_util.h create mode 100644 tools/testing/selftests/bpf/bpfilter/test_target.c diff --git a/net/bpfilter/Makefile b/net/bpfilter/Makefile index d1a36dd2c666..f3de07bc8004 100644 --- a/net/bpfilter/Makefile +++ b/net/bpfilter/Makefile @@ -4,7 +4,7 @@ # userprogs := bpfilter_umh -bpfilter_umh-objs := main.o bflog.o io.o map-common.o match.o context.o +bpfilter_umh-objs := main.o bflog.o io.o map-common.o context.o match.o target.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 index 96735c7883bf..a77134008540 100644 --- a/net/bpfilter/context.c +++ b/net/bpfilter/context.c @@ -11,6 +11,7 @@ #include #include "match.h" +#include "target.h" static int init_match_ops_map(struct context *ctx) { @@ -30,12 +31,43 @@ static int init_match_ops_map(struct context *ctx) return 0; } +static int init_target_ops_map(struct context *ctx) +{ + const struct target_ops *target_ops[] = { &standard_target_ops, &error_target_ops }; + int i, err; + + err = create_target_ops_map(&ctx->target_ops_map, ARRAY_SIZE(target_ops)); + if (err) + return err; + + for (i = 0; i < ARRAY_SIZE(target_ops); ++i) { + err = target_ops_map_insert(&ctx->target_ops_map, target_ops[i]); + if (err) + return err; + } + + return 0; +} + int create_context(struct context *ctx) { - return init_match_ops_map(ctx); + int err; + + err = init_match_ops_map(ctx); + if (err) + return err; + + err = init_target_ops_map(ctx); + if (err) { + free_match_ops_map(&ctx->match_ops_map); + return err; + } + + return 0; } void free_context(struct context *ctx) { + free_target_ops_map(&ctx->target_ops_map); free_match_ops_map(&ctx->match_ops_map); } diff --git a/net/bpfilter/context.h b/net/bpfilter/context.h index a3e737b603f0..c62c1ba4781c 100644 --- a/net/bpfilter/context.h +++ b/net/bpfilter/context.h @@ -9,11 +9,13 @@ #include #include "match-ops-map.h" +#include "target-ops-map.h" struct context { FILE *log_file; int log_level; struct match_ops_map match_ops_map; + struct target_ops_map target_ops_map; }; int create_context(struct context *ctx); diff --git a/net/bpfilter/target-ops-map.h b/net/bpfilter/target-ops-map.h new file mode 100644 index 000000000000..6b65241328da --- /dev/null +++ b/net/bpfilter/target-ops-map.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#ifndef NET_BPFILTER_TARGET_OPS_MAP_H +#define NET_BPFILTER_TARGET_OPS_MAP_H + +#include "map-common.h" + +#include + +#include +#include + +#include "target.h" + +struct target_ops_map { + struct hsearch_data index; +}; + +static inline int create_target_ops_map(struct target_ops_map *map, size_t nelem) +{ + return create_map(&map->index, nelem); +} + +static inline const struct target_ops *target_ops_map_find(struct target_ops_map *map, + const char *name) +{ + const size_t namelen = strnlen(name, BPFILTER_EXTENSION_MAXNAMELEN); + + if (namelen < BPFILTER_EXTENSION_MAXNAMELEN) + return map_find(&map->index, name); + + return ERR_PTR(-EINVAL); +} + +static inline int target_ops_map_insert(struct target_ops_map *map, + const struct target_ops *target_ops) +{ + return map_insert(&map->index, target_ops->name, (void *)target_ops); +} + +static inline void free_target_ops_map(struct target_ops_map *map) +{ + free_map(&map->index); +} + +#endif // NET_BPFILTER_TARGET_OPS_MAP_H diff --git a/net/bpfilter/target.c b/net/bpfilter/target.c new file mode 100644 index 000000000000..a18fe477f93c --- /dev/null +++ b/net/bpfilter/target.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#define _GNU_SOURCE + +#include "target.h" + +#include +#include + +#include +#include + +#include "bflog.h" +#include "context.h" +#include "target-ops-map.h" + +static int convert_verdict(int verdict) +{ + return -verdict - 1; +} + +static int standard_target_check(struct context *ctx, const struct bpfilter_ipt_target *ipt_target) +{ + const struct bpfilter_ipt_standard_target *standard_target; + + standard_target = (const struct bpfilter_ipt_standard_target *)ipt_target; + + if (standard_target->verdict > 0) + return 0; + + if (standard_target->verdict < 0) { + if (standard_target->verdict == BPFILTER_RETURN) + return 0; + + switch (convert_verdict(standard_target->verdict)) { + case BPFILTER_NF_ACCEPT: + case BPFILTER_NF_DROP: + case BPFILTER_NF_QUEUE: + return 0; + } + } + + BFLOG_DEBUG(ctx, "invalid verdict: %d\n", standard_target->verdict); + + return -EINVAL; +} + +const struct target_ops standard_target_ops = { + .name = "", + .revision = 0, + .size = sizeof(struct xt_standard_target), + .check = standard_target_check, +}; + +static int error_target_check(struct context *ctx, const struct bpfilter_ipt_target *ipt_target) +{ + const struct bpfilter_ipt_error_target *error_target; + size_t maxlen; + + error_target = (const struct bpfilter_ipt_error_target *)&ipt_target; + maxlen = sizeof(error_target->error_name); + if (strnlen(error_target->error_name, maxlen) == maxlen) { + BFLOG_DEBUG(ctx, "cannot check error target: too long errorname\n"); + return -EINVAL; + } + + return 0; +} + +const struct target_ops error_target_ops = { + .name = "ERROR", + .revision = 0, + .size = sizeof(struct xt_error_target), + .check = error_target_check, +}; + +int init_target(struct context *ctx, const struct bpfilter_ipt_target *ipt_target, + struct target *target) +{ + const size_t maxlen = sizeof(ipt_target->u.user.name); + const struct target_ops *found; + int err; + + if (strnlen(ipt_target->u.user.name, maxlen) == maxlen) { + BFLOG_DEBUG(ctx, "cannot init target: too long target name\n"); + return -EINVAL; + } + + found = target_ops_map_find(&ctx->target_ops_map, ipt_target->u.user.name); + if (IS_ERR(found)) { + BFLOG_DEBUG(ctx, "cannot find target by name: '%s'\n", ipt_target->u.user.name); + return PTR_ERR(found); + } + + if (found->size != ipt_target->u.target_size || + found->revision != ipt_target->u.user.revision) { + BFLOG_DEBUG(ctx, "invalid target: '%s'\n", ipt_target->u.user.name); + return -EINVAL; + } + + err = found->check(ctx, ipt_target); + if (err) + return err; + + target->target_ops = found; + target->ipt_target = ipt_target; + + return 0; +} diff --git a/net/bpfilter/target.h b/net/bpfilter/target.h new file mode 100644 index 000000000000..5d9c4c459c05 --- /dev/null +++ b/net/bpfilter/target.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#ifndef NET_BPFILTER_TARGET_H +#define NET_BPFILTER_TARGET_H + +#include "../../include/uapi/linux/bpfilter.h" + +#include + +struct context; +struct target_ops_map; + +struct target_ops { + char name[BPFILTER_EXTENSION_MAXNAMELEN]; + uint16_t size; + uint8_t revision; + int (*check)(struct context *ctx, const struct bpfilter_ipt_target *ipt_target); +}; + +struct target { + const struct target_ops *target_ops; + const struct bpfilter_ipt_target *ipt_target; +}; + +extern const struct target_ops standard_target_ops; +extern const struct target_ops error_target_ops; + +int init_target(struct context *ctx, const struct bpfilter_ipt_target *ipt_target, + struct target *target); + +#endif // NET_BPFILTER_TARGET_H diff --git a/tools/testing/selftests/bpf/bpfilter/.gitignore b/tools/testing/selftests/bpf/bpfilter/.gitignore index e5073231f811..1856d0515f49 100644 --- a/tools/testing/selftests/bpf/bpfilter/.gitignore +++ b/tools/testing/selftests/bpf/bpfilter/.gitignore @@ -2,3 +2,4 @@ test_io test_map test_match +test_target diff --git a/tools/testing/selftests/bpf/bpfilter/Makefile b/tools/testing/selftests/bpf/bpfilter/Makefile index 362c9a28b88d..78da74b9ee68 100644 --- a/tools/testing/selftests/bpf/bpfilter/Makefile +++ b/tools/testing/selftests/bpf/bpfilter/Makefile @@ -11,6 +11,7 @@ CFLAGS += -Wall -g -pthread -I$(TOOLSINCDIR) -I$(APIDIR) -I$(BPFILTERSRCDIR) TEST_GEN_PROGS += test_io TEST_GEN_PROGS += test_map TEST_GEN_PROGS += test_match +TEST_GEN_PROGS += test_target KSFT_KHDR_INSTALL := 1 @@ -19,4 +20,6 @@ include ../../lib.mk $(OUTPUT)/test_io: test_io.c $(BPFILTERSRCDIR)/io.c $(OUTPUT)/test_map: test_map.c $(BPFILTERSRCDIR)/map-common.c $(OUTPUT)/test_match: test_match.c $(BPFILTERSRCDIR)/match.c $(BPFILTERSRCDIR)/map-common.c \ - $(BPFILTERSRCDIR)/context.c $(BPFILTERSRCDIR)/bflog.c + $(BPFILTERSRCDIR)/context.c $(BPFILTERSRCDIR)/bflog.c $(BPFILTERSRCDIR)/target.c +$(OUTPUT)/test_target: test_target.c $(BPFILTERSRCDIR)/target.c $(BPFILTERSRCDIR)/map-common.c \ + $(BPFILTERSRCDIR)/context.c $(BPFILTERSRCDIR)/bflog.c $(BPFILTERSRCDIR)/match.c 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..d82ff86f280e --- /dev/null +++ b/tools/testing/selftests/bpf/bpfilter/bpfilter_util.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef BPFILTER_UTIL_H +#define BPFILTER_UTIL_H + +#include +#include + +#include + +static inline void init_standard_target(struct xt_standard_target *ipt_target, int revision, + int verdict) +{ + snprintf(ipt_target->target.u.user.name, sizeof(ipt_target->target.u.user.name), "%s", + BPFILTER_STANDARD_TARGET); + ipt_target->target.u.user.revision = revision; + ipt_target->target.u.user.target_size = sizeof(*ipt_target); + ipt_target->verdict = verdict; +} + +static inline void init_error_target(struct xt_error_target *ipt_target, int revision, + const char *error_name) +{ + snprintf(ipt_target->target.u.user.name, sizeof(ipt_target->target.u.user.name), "%s", + BPFILTER_ERROR_TARGET); + ipt_target->target.u.user.revision = revision; + ipt_target->target.u.user.target_size = sizeof(*ipt_target); + snprintf(ipt_target->errorname, sizeof(ipt_target->errorname), "%s", error_name); +} + +#endif // BPFILTER_UTIL_H diff --git a/tools/testing/selftests/bpf/bpfilter/test_target.c b/tools/testing/selftests/bpf/bpfilter/test_target.c new file mode 100644 index 000000000000..6765497b53c4 --- /dev/null +++ b/tools/testing/selftests/bpf/bpfilter/test_target.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE + +#include "context.h" +#include "target.h" + +#include +#include + +#include +#include + +#include "../../kselftest_harness.h" + +#include "bpfilter_util.h" + +FIXTURE(test_standard_target) +{ + struct context ctx; + struct xt_standard_target ipt_target; + struct target target; +}; + +FIXTURE_VARIANT(test_standard_target) +{ + int verdict; +}; + +FIXTURE_VARIANT_ADD(test_standard_target, accept) { + .verdict = -BPFILTER_NF_ACCEPT - 1, +}; + +FIXTURE_VARIANT_ADD(test_standard_target, drop) { + .verdict = -BPFILTER_NF_DROP - 1, +}; + +FIXTURE_SETUP(test_standard_target) +{ + ASSERT_EQ(0, create_context(&self->ctx)); + self->ctx.log_file = stderr; + + memset(&self->ipt_target, 0, sizeof(self->ipt_target)); + init_standard_target(&self->ipt_target, 0, variant->verdict); +} + +FIXTURE_TEARDOWN(test_standard_target) +{ + free_context(&self->ctx); +} + +TEST_F(test_standard_target, init) +{ + ASSERT_EQ(0, init_target(&self->ctx, (const struct bpfilter_ipt_target *)&self->ipt_target, + &self->target)); +} + +FIXTURE(test_error_target) +{ + struct context ctx; + struct xt_error_target ipt_target; + struct target target; +}; + +FIXTURE_SETUP(test_error_target) +{ + ASSERT_EQ(0, create_context(&self->ctx)); + self->ctx.log_file = stderr; + + memset(&self->ipt_target, 0, sizeof(self->ipt_target)); + init_error_target(&self->ipt_target, 0, "x"); +} + +FIXTURE_TEARDOWN(test_error_target) +{ + free_context(&self->ctx); +} + +TEST_F(test_error_target, init) +{ + ASSERT_EQ(0, init_target(&self->ctx, (const struct bpfilter_ipt_target *)&self->ipt_target, + &self->target)); +} + +TEST_HARNESS_MAIN From patchwork Mon May 17 22:53:06 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitrii Banshchikov X-Patchwork-Id: 440477 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.9 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2040EC43461 for ; Mon, 17 May 2021 22:54:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E9B1A61209 for ; Mon, 17 May 2021 22:54:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344274AbhEQWz2 (ORCPT ); Mon, 17 May 2021 18:55:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41756 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344190AbhEQWzL (ORCPT ); Mon, 17 May 2021 18:55:11 -0400 Received: from mail-wr1-x430.google.com (mail-wr1-x430.google.com [IPv6:2a00:1450:4864:20::430]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B2C0AC061756 for ; Mon, 17 May 2021 15:53:53 -0700 (PDT) Received: by mail-wr1-x430.google.com with SMTP id p7so4318686wru.10 for ; Mon, 17 May 2021 15:53:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ubique-spb-ru.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=8AJ+jxD0mJxcb+pXTAGkhVM8Zb8FAm7HQ6ca/RFQITE=; b=Dx7cyi7+dmQb1L7F7l1HrllEOKYUbquCFFVzPGEeIoIaabD6k+kGZG9Xni53H021i9 XfsLPwBam9ulhhH6/oaNz+SDONGeyfdhU7+Zt1LnjaYKunjeqAX8lKDtNEAmQ+fL2gSw P5/7raRuSv8Zx7YvbiR6slSVHkUq8xaPko26epOQcXiBnERa9072x2A6tFc1pZUiU88m UU8eC5dVjDLcaOa/6DTTvCXT8iPm4gjTybg8tp3xUWK1vh+MbQgcmDfJWBO3ThELTRYL A3Y2CnYqhtZT/+Oxxs+4GWSgEG96jpPZGFYr3BWeNCYzNPSrfKXc5GyzAzH5qwDpRBXH /xOQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=8AJ+jxD0mJxcb+pXTAGkhVM8Zb8FAm7HQ6ca/RFQITE=; b=jKT2y3xq0w/79x29rrYrNj1EVGdlRZSX8tQ45ZvA80FROGnPktl4iIVEhybZ9OARjr TtO/qBCKaZUKZGR1HOnuuQivqfEblfbl+4DdBASVzCUtls5thb4shmluw5pshmi2a1+w 7rYvd3HliHXRZ6eU0oqtLMyAcplSc8bo+7Xbw0/aUTwxTA7ONnxztU2ouJ/g3kX6A+iX VaPo41zUH5aHt3ep9BsNaLjQCITqz4gb3l0E8avfLqxliF7+HgYRkQF8OHPxMps/ArOm JkPM78Iegr4H3pXKa78GDgHpOvQezz6W7kZFq1A8Jpva9LWkoqaD7B5Lbtt6wFxhCXHa krYQ== X-Gm-Message-State: AOAM533XMhk7XH/aHA1MuKfgf8BYQNHVkDOC01KcaaXqeHusLNCKafl0 0PsfF/dGYPQ6ecO+RyKvBeCTGQ== X-Google-Smtp-Source: ABdhPJzzVEDlkKffEfvGF0HECbpkOKg7V4rjHT8AKdpmH/do3htHIGp86tF5FASizapoJEfXSmIqzQ== X-Received: by 2002:a5d:4ed1:: with SMTP id s17mr2558698wrv.204.1621292032442; Mon, 17 May 2021 15:53:52 -0700 (PDT) Received: from localhost ([154.21.15.43]) by smtp.gmail.com with ESMTPSA id t17sm11853695wrp.89.2021.05.17.15.53.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 May 2021 15:53:52 -0700 (PDT) From: Dmitrii Banshchikov To: bpf@vger.kernel.org Cc: Dmitrii Banshchikov , ast@kernel.org, davem@davemloft.net, daniel@iogearbox.net, andrii@kernel.org, kafai@fb.com, songliubraving@fb.com, yhs@fb.com, john.fastabend@gmail.com, kpsingh@kernel.org, netdev@vger.kernel.org, rdna@fb.com Subject: [PATCH bpf-next 09/11] bpfilter: Add struct table Date: Tue, 18 May 2021 02:53:06 +0400 Message-Id: <20210517225308.720677-10-me@ubique.spb.ru> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210517225308.720677-1-me@ubique.spb.ru> References: <20210517225308.720677-1-me@ubique.spb.ru> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org A table keeps iptables' blob and an array of struct rule for this blob. The array of rules provides more convenient way to interact with blob's entries. All tables are stored in table_ops_map map which is used for lookups. Also all tables are linked into a list that is used for freeing them. Signed-off-by: Dmitrii Banshchikov --- net/bpfilter/Makefile | 2 +- net/bpfilter/context.c | 103 +++++++++++ net/bpfilter/context.h | 3 + net/bpfilter/table-map.h | 41 +++++ net/bpfilter/table.c | 167 ++++++++++++++++++ net/bpfilter/table.h | 33 ++++ tools/testing/selftests/bpf/bpfilter/Makefile | 10 +- 7 files changed, 354 insertions(+), 5 deletions(-) create mode 100644 net/bpfilter/table-map.h create mode 100644 net/bpfilter/table.c create mode 100644 net/bpfilter/table.h diff --git a/net/bpfilter/Makefile b/net/bpfilter/Makefile index 1191770d41f7..e0090563f2ca 100644 --- a/net/bpfilter/Makefile +++ b/net/bpfilter/Makefile @@ -4,7 +4,7 @@ # userprogs := bpfilter_umh -bpfilter_umh-objs := main.o bflog.o io.o map-common.o context.o match.o target.o rule.o +bpfilter_umh-objs := main.o bflog.o io.o map-common.o context.o match.o target.o rule.o table.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 index a77134008540..5d9679212b25 100644 --- a/net/bpfilter/context.c +++ b/net/bpfilter/context.c @@ -10,7 +10,11 @@ #include #include +#include + #include "match.h" +#include "rule.h" +#include "table.h" #include "target.h" static int init_match_ops_map(struct context *ctx) @@ -49,6 +53,86 @@ static int init_target_ops_map(struct context *ctx) return 0; } +static void init_standard_entry(struct bpfilter_ipt_standard_entry *ipt_entry) +{ + ipt_entry->entry.next_offset = sizeof(*ipt_entry); + ipt_entry->entry.target_offset = sizeof(ipt_entry->entry); + ipt_entry->target.target.u.user.revision = 0; + ipt_entry->target.target.u.user.target_size = sizeof(struct bpfilter_ipt_standard_target); + ipt_entry->target.verdict = -BPFILTER_NF_ACCEPT - 1; +} + +static void init_error_entry(struct bpfilter_ipt_error_entry *ipt_entry) +{ + ipt_entry->entry.next_offset = sizeof(*ipt_entry); + ipt_entry->entry.target_offset = sizeof(ipt_entry->entry); + ipt_entry->target.target.u.target_size = sizeof(struct bpfilter_ipt_error_target); + ipt_entry->target.target.u.user.revision = 0; + snprintf(ipt_entry->target.target.u.user.name, sizeof(ipt_entry->target.target.u.user.name), + "ERROR"); +} + +static struct table *create_filter_table(struct context *ctx) +{ + struct filter_table_entries { + struct bpfilter_ipt_standard_entry local_in; + struct bpfilter_ipt_standard_entry forward; + struct bpfilter_ipt_standard_entry local_out; + struct bpfilter_ipt_error_entry error; + }; + + struct filter_table { + struct bpfilter_ipt_replace replace; + struct filter_table_entries entries; + } filter_table; + + memset(&filter_table, 0, sizeof(filter_table)); + + snprintf(filter_table.replace.name, sizeof(filter_table.replace.name), "filter"); + filter_table.replace.valid_hooks = 1 << BPFILTER_INET_HOOK_LOCAL_IN | + 1 << BPFILTER_INET_HOOK_FORWARD | + 1 << BPFILTER_INET_HOOK_LOCAL_OUT; + filter_table.replace.num_entries = 4; + filter_table.replace.size = sizeof(struct filter_table_entries); + + filter_table.replace.hook_entry[BPFILTER_INET_HOOK_FORWARD] = + offsetof(struct filter_table_entries, forward); + filter_table.replace.underflow[BPFILTER_INET_HOOK_FORWARD] = + offsetof(struct filter_table_entries, forward); + + filter_table.replace.hook_entry[BPFILTER_INET_HOOK_LOCAL_OUT] = + offsetof(struct filter_table_entries, local_out); + filter_table.replace.underflow[BPFILTER_INET_HOOK_LOCAL_OUT] = + offsetof(struct filter_table_entries, local_out); + + init_standard_entry(&filter_table.entries.local_in); + init_standard_entry(&filter_table.entries.forward); + init_standard_entry(&filter_table.entries.local_out); + init_error_entry(&filter_table.entries.error); + + return create_table(ctx, &filter_table.replace); +} + +static int init_table_map(struct context *ctx) +{ + struct table *table; + int err; + + err = create_table_map(&ctx->table_map, 1); + if (err) + return err; + + table = create_filter_table(ctx); + if (IS_ERR(table)) { + free_table_map(&ctx->table_map); + return PTR_ERR(table); + } + + list_add_tail(&table->list, &ctx->table_list); + + return table_map_insert(&ctx->table_map, table); +} + int create_context(struct context *ctx) { int err; @@ -63,11 +147,30 @@ int create_context(struct context *ctx) return err; } + INIT_LIST_HEAD(&ctx->table_list); + + err = init_table_map(ctx); + if (err) { + free_match_ops_map(&ctx->match_ops_map); + free_target_ops_map(&ctx->target_ops_map); + return err; + } + return 0; } void free_context(struct context *ctx) { + struct list_head *t, *n; + + list_for_each_safe(t, n, &ctx->table_list) { + struct table *table; + + table = list_entry(t, struct table, list); + free_table(table); + } + + free_table_map(&ctx->table_map); free_target_ops_map(&ctx->target_ops_map); free_match_ops_map(&ctx->match_ops_map); } diff --git a/net/bpfilter/context.h b/net/bpfilter/context.h index c62c1ba4781c..2d9e3fafb0f8 100644 --- a/net/bpfilter/context.h +++ b/net/bpfilter/context.h @@ -10,12 +10,15 @@ #include "match-ops-map.h" #include "target-ops-map.h" +#include "table-map.h" struct context { FILE *log_file; int log_level; struct match_ops_map match_ops_map; struct target_ops_map target_ops_map; + struct table_map table_map; + struct list_head table_list; }; int create_context(struct context *ctx); diff --git a/net/bpfilter/table-map.h b/net/bpfilter/table-map.h new file mode 100644 index 000000000000..6c5340e88542 --- /dev/null +++ b/net/bpfilter/table-map.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#ifndef NET_BPFILTER_TABLE_MAP_H +#define NET_BPFILTER_TABLE_MAP_H + +#include "map-common.h" +#include "table.h" + +struct table_map { + struct hsearch_data index; +}; + +static inline int create_table_map(struct table_map *map, size_t nelem) +{ + return create_map(&map->index, nelem); +} + +static inline struct table *table_map_find(struct table_map *map, const char *name) +{ + return map_find(&map->index, name); +} + +static inline int table_map_update(struct table_map *map, const char *name, void *data) +{ + return map_update(&map->index, name, data); +} + +static inline int table_map_insert(struct table_map *map, struct table *table) +{ + return map_insert(&map->index, table->name, table); +} + +static inline void free_table_map(struct table_map *map) +{ + free_map(&map->index); +} + +#endif // NET_BPFILTER_TABLE_MAP_H diff --git a/net/bpfilter/table.c b/net/bpfilter/table.c new file mode 100644 index 000000000000..e8be6369ef71 --- /dev/null +++ b/net/bpfilter/table.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#define _GNU_SOURCE + +#include "table.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include "context.h" +#include "rule.h" +#include "table-map.h" + +static int rule_offset_comparator(const void *x, const void *y) +{ + const struct rule *rule = y; + const uint32_t *offset = x; + + return *offset < rule->offset ? -1 : *offset - rule->offset; +} + +static struct rule *table_get_rule_by_offset(struct table *table, uint32_t offset) +{ + return bsearch(&offset, table->rules, table->num_rules, sizeof(table->rules[0]), + rule_offset_comparator); +} + +static int table_init_rules(struct context *ctx, struct table *table, + const struct bpfilter_ipt_replace *ipt_replace) +{ + uint32_t offset; + int i; + + table->entries = malloc(table->size); + if (!table->entries) + return -ENOMEM; + + memcpy(table->entries, ipt_replace->entries, table->size); + + table->rules = calloc(table->num_rules, sizeof(table->rules[0])); + if (!table->rules) + return -ENOMEM; + + offset = 0; + for (i = 0; i < table->num_rules; ++i) { + const struct bpfilter_ipt_entry *ipt_entry; + int err; + + if (table->size < offset) + return -EINVAL; + + if (table->size < offset + sizeof(*ipt_entry)) + return -EINVAL; + + ipt_entry = table->entries + offset; + + if (table->size < offset + ipt_entry->next_offset) + return -EINVAL; + + err = init_rule(ctx, ipt_entry, &table->rules[i]); + if (err) + return err; + + table->rules[i].offset = offset; + offset += ipt_entry->next_offset; + } + + if (offset != ipt_replace->size) + return -EINVAL; + + return 0; +} + +static int table_init_hooks(struct table *table, const struct bpfilter_ipt_replace *ipt_replace) +{ + int i; + + for (i = 0; i < BPFILTER_INET_HOOK_MAX; ++i) { + if (!(table->valid_hooks & (1 << i))) + continue; + + table->hook_entry[i] = table_get_rule_by_offset(table, ipt_replace->hook_entry[i]); + table->underflow[i] = table_get_rule_by_offset(table, ipt_replace->underflow[i]); + + if (!table->hook_entry[i] || !table->underflow[i]) + return -EINVAL; + } + + return 0; +} + +struct table *create_table(struct context *ctx, const struct bpfilter_ipt_replace *ipt_replace) +{ + struct table *table; + int err; + + table = calloc(1, sizeof(*table)); + if (!table) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&table->list); + snprintf(table->name, sizeof(table->name), "%s", ipt_replace->name); + table->valid_hooks = ipt_replace->valid_hooks; + table->num_rules = ipt_replace->num_entries; + table->num_counters = ipt_replace->num_counters; + table->size = ipt_replace->size; + + err = table_init_rules(ctx, table, ipt_replace); + if (err) + goto err_free; + + err = table_init_hooks(table, ipt_replace); + if (err) + goto err_free; + + return table; + +err_free: + free_table(table); + + return ERR_PTR(err); +} + +void table_get_info(const struct table *table, struct bpfilter_ipt_get_info *info) +{ + int i; + + snprintf(info->name, sizeof(info->name), "%s", table->name); + info->valid_hooks = table->valid_hooks; + for (i = 0; i < BPFILTER_INET_HOOK_MAX; ++i) { + const struct rule *hook_entry = table->hook_entry[i]; + const struct rule *underflow = table->underflow[i]; + + info->hook_entry[i] = hook_entry ? hook_entry->offset : 0; + info->underflow[i] = underflow ? underflow->offset : 0; + } + info->num_entries = table->num_rules; + info->size = table->size; +} + +void free_table(struct table *table) +{ + int i; + + if (!table) + return; + + list_del(&table->list); + + if (table->rules) { + for (i = 0; i < table->num_rules; ++i) + free_rule(&table->rules[i]); + free(table->rules); + } + + free(table->entries); + free(table); +} diff --git a/net/bpfilter/table.h b/net/bpfilter/table.h new file mode 100644 index 000000000000..101f6d813c8c --- /dev/null +++ b/net/bpfilter/table.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#ifndef NET_BPFILTER_TABLE_H +#define NET_BPFILTER_TABLE_H + +#include "../../include/uapi/linux/bpfilter.h" + +#include + +struct context; +struct rule; + +struct table { + struct list_head list; + char name[BPFILTER_XT_TABLE_MAXNAMELEN]; + uint32_t valid_hooks; + uint32_t num_rules; + uint32_t num_counters; + uint32_t size; + struct rule *hook_entry[BPFILTER_INET_HOOK_MAX]; + struct rule *underflow[BPFILTER_INET_HOOK_MAX]; + struct rule *rules; + void *entries; +}; + +struct table *create_table(struct context *ctx, const struct bpfilter_ipt_replace *ipt_replace); +void table_get_info(const struct table *table, struct bpfilter_ipt_get_info *info); +void free_table(struct table *table); + +#endif // NET_BPFILTER_TABLE_H diff --git a/tools/testing/selftests/bpf/bpfilter/Makefile b/tools/testing/selftests/bpf/bpfilter/Makefile index 02d860e02c58..131174dd2bdf 100644 --- a/tools/testing/selftests/bpf/bpfilter/Makefile +++ b/tools/testing/selftests/bpf/bpfilter/Makefile @@ -21,9 +21,11 @@ include ../../lib.mk $(OUTPUT)/test_io: test_io.c $(BPFILTERSRCDIR)/io.c $(OUTPUT)/test_map: test_map.c $(BPFILTERSRCDIR)/map-common.c $(OUTPUT)/test_match: test_match.c $(BPFILTERSRCDIR)/match.c $(BPFILTERSRCDIR)/map-common.c \ - $(BPFILTERSRCDIR)/context.c $(BPFILTERSRCDIR)/bflog.c $(BPFILTERSRCDIR)/target.c -$(OUTPUT)/test_target: test_target.c $(BPFILTERSRCDIR)/target.c $(BPFILTERSRCDIR)/map-common.c \ - $(BPFILTERSRCDIR)/context.c $(BPFILTERSRCDIR)/bflog.c $(BPFILTERSRCDIR)/match.c + $(BPFILTERSRCDIR)/context.c $(BPFILTERSRCDIR)/bflog.c $(BPFILTERSRCDIR)/target.c \ + $(BPFILTERSRCDIR)/table.c $(BPFILTERSRCDIR)/rule.c +$(OUTPUT)/test_target: test_target.c $(BPFILTERSRCDIR)/target.c $(BPFILTERSRCDIR)/map-common.c \ + $(BPFILTERSRCDIR)/context.c $(BPFILTERSRCDIR)/bflog.c $(BPFILTERSRCDIR)/match.c \ + $(BPFILTERSRCDIR)/table.c $(BPFILTERSRCDIR)/rule.c $(OUTPUT)/test_rule: test_rule.c $(BPFILTERSRCDIR)/rule.c $(BPFILTERSRCDIR)/bflog.c \ $(BPFILTERSRCDIR)/map-common.c $(BPFILTERSRCDIR)/context.c $(BPFILTERSRCDIR)/match.c \ - $(BPFILTERSRCDIR)/target.c + $(BPFILTERSRCDIR)/target.c $(BPFILTERSRCDIR)/table.c $(BPFILTERSRCDIR)/rule.c From patchwork Mon May 17 22:53:08 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitrii Banshchikov X-Patchwork-Id: 440476 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4131AC433ED for ; Mon, 17 May 2021 22:54:24 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 219C46124C for ; Mon, 17 May 2021 22:54:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344352AbhEQWzi (ORCPT ); Mon, 17 May 2021 18:55:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41798 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344328AbhEQWzR (ORCPT ); Mon, 17 May 2021 18:55:17 -0400 Received: from mail-wm1-x334.google.com (mail-wm1-x334.google.com [IPv6:2a00:1450:4864:20::334]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9C627C06138B for ; Mon, 17 May 2021 15:54:00 -0700 (PDT) Received: by mail-wm1-x334.google.com with SMTP id b7so3783431wmh.5 for ; Mon, 17 May 2021 15:54:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ubique-spb-ru.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=6BZu86G+a+CQ5lboyHSi67mKyj7jNYy4dIGKIAp22DI=; b=ZjDR7WQTSVwGdyZSJpRB3DAGB9Oy/YR5OWbYZIgEtMADji3qezP+4HBn1y/Zs2+Cd/ s338aOt6EQJfilz9zcRXqF0Vqq95qv7a54JjTbh7ZUHUiXBxGanQzaDYrqUEqwz8Vg0o OcITSS5XvHNd3vooD3eV3q/uiRZafuEE6HhWbsKKLHJYisaufnfx4PG0QV4ZIjD129ls LWtR0Uq4eWhrO2j18sur44cESeExi5nahOI3kR8RbOMGJDI9rCA4gNS9YFt548aDXLjn sL9DdMc3UYtaNY40MK8yG0iUwhY6Ua3NmWH+Q1D9Ufqr0Odr6YWs1O8n+IONw90G4/QI 0JlQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=6BZu86G+a+CQ5lboyHSi67mKyj7jNYy4dIGKIAp22DI=; b=tF1LhQH8mA2io72Q4HK5hF2p7B+BI1zDanYixPN/zN1bj52LDXpQRt/JEJ7C8fiM31 fgejXsJRxHmDHB0X4O45AAkqZqRr0r8fDt3QE9RVtJH7gJSwqHDap1RlYEegAdFl8mFS 2HiXMMe/rRFy9HlN/Ft9dhaN504HAlcWFHEokPigkJP7XBZm1eh3YAL4rSE8IdRA8ADD rWbWW0o9NqhjofBYOuHYEzCTkCpuT5LTVSyQnWNRGKQKNYQUfRlBlvrDZqbm6SyPTbWd aok6Jk7q2hALCUB2C3v2lWW//QntCNlckOqShLjox72liBQ2YsJABUR10bTnrMwSfQGq VKfQ== X-Gm-Message-State: AOAM531GzVuDCQtDu3Pthg2zX4CyJjTKRopT4GjjleCWdtUJLn9tJR2s Y18v43wX8DWQXahUlkJ3+WH6XA== X-Google-Smtp-Source: ABdhPJxoSs8hoHf5GGDborHjkwA6ABbZNXeATkpzR/G2JBWzu29Ki9PbnrX25EsDtvv2IpHkrIXXdg== X-Received: by 2002:a1c:4d05:: with SMTP id o5mr1832282wmh.131.1621292039409; Mon, 17 May 2021 15:53:59 -0700 (PDT) Received: from localhost ([154.21.15.43]) by smtp.gmail.com with ESMTPSA id p7sm18925555wrt.24.2021.05.17.15.53.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 May 2021 15:53:59 -0700 (PDT) From: Dmitrii Banshchikov To: bpf@vger.kernel.org Cc: Dmitrii Banshchikov , ast@kernel.org, davem@davemloft.net, daniel@iogearbox.net, andrii@kernel.org, kafai@fb.com, songliubraving@fb.com, yhs@fb.com, john.fastabend@gmail.com, kpsingh@kernel.org, netdev@vger.kernel.org, rdna@fb.com Subject: [PATCH bpf-next 11/11] bpfilter: Handle setsockopts Date: Tue, 18 May 2021 02:53:08 +0400 Message-Id: <20210517225308.720677-12-me@ubique.spb.ru> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210517225308.720677-1-me@ubique.spb.ru> References: <20210517225308.720677-1-me@ubique.spb.ru> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Use earlier introduced infrastructure for and handle setsockopt(2) calls. Signed-off-by: Dmitrii Banshchikov --- net/bpfilter/main.c | 99 ++++++++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 46 deletions(-) diff --git a/net/bpfilter/main.c b/net/bpfilter/main.c index 05e1cfc1e5cd..19c8c2d7ef87 100644 --- a/net/bpfilter/main.c +++ b/net/bpfilter/main.c @@ -1,64 +1,71 @@ // SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + #define _GNU_SOURCE -#include + +#include #include + #include -#include -#include -#include -#include "../../include/uapi/linux/bpf.h" -#include -#include "msgfmt.h" +#include -FILE *debug_f; +#include "bflog.h" +#include "context.h" +#include "io.h" +#include "msgfmt.h" +#include "sockopt.h" -static int handle_get_cmd(struct mbox_request *cmd) +static int setup_context(struct context *ctx) { - switch (cmd->cmd) { - case 0: - return 0; - default: - break; - } - return -ENOPROTOOPT; -} + ctx->log_file = fopen("/dev/kmsg", "w"); + if (!ctx->log_file) + return -errno; -static int handle_set_cmd(struct mbox_request *cmd) -{ - return -ENOPROTOOPT; + setvbuf(ctx->log_file, 0, _IOLBF, 0); + ctx->log_level = BFLOG_LEVEL_NOTICE; + + return 0; } -static void loop(void) +static void loop(struct context *ctx) { - while (1) { - struct mbox_request req; - struct mbox_reply reply; - int n; - - n = read(0, &req, sizeof(req)); - if (n != sizeof(req)) { - fprintf(debug_f, "invalid request %d\n", n); - return; - } - - reply.status = req.is_set ? - handle_set_cmd(&req) : - handle_get_cmd(&req); - - n = write(1, &reply, sizeof(reply)); - if (n != sizeof(reply)) { - fprintf(debug_f, "reply failed %d\n", n); - return; - } + struct mbox_request req; + struct mbox_reply reply; + int err; + + for (;;) { + err = read_exact(STDIN_FILENO, &req, sizeof(req)); + if (err) + BFLOG_FATAL(ctx, "cannot read request: %s\n", strerror(-err)); + + reply.status = handle_sockopt_request(ctx, &req); + + err = write_exact(STDOUT_FILENO, &reply, sizeof(reply)); + if (err) + BFLOG_FATAL(ctx, "cannot write reply: %s\n", strerror(-err)); } } int main(void) { - debug_f = fopen("/dev/kmsg", "w"); - setvbuf(debug_f, 0, _IOLBF, 0); - fprintf(debug_f, "Started bpfilter\n"); - loop(); - fclose(debug_f); + struct context ctx; + int err; + + err = create_context(&ctx); + if (err) + return err; + + err = setup_context(&ctx); + if (err) { + free_context(&ctx); + return err; + } + + BFLOG_NOTICE(&ctx, "started\n"); + + loop(&ctx); + return 0; }