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: 12263297 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 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 E616FC433B4 for ; Mon, 17 May 2021 22:53:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BE9EA611CC for ; Mon, 17 May 2021 22:53:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344189AbhEQWyt (ORCPT ); Mon, 17 May 2021 18:54:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41656 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236593AbhEQWym (ORCPT ); Mon, 17 May 2021 18:54:42 -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 55E90C061756 for ; Mon, 17 May 2021 15:53:25 -0700 (PDT) Received: by mail-wr1-x42b.google.com with SMTP id r12so8073007wrp.1 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=aaMSG70g7YC8dB+Jj5P3PubL20Gt3jjI1d8HPEM+1+mHQCAo2A2ULrlS8wO9suVRIV X8VB8m+NBgcK7htORBocCbmFMwntjhcWMxLGHZ+DRsdg7Df0RAqxu98/5tH48XhZ4OT4 4a2CRo4Eh231BlUDcx3fAg7RIS+mebZDjceRDGqwB6DT34yO46Dp6Xl60VgVvA2v9JAz VwaC/4XoX9T6L8bzICt5E+2YrFUCLCrzZ6EKwzWOY9mbqDj1jssm0s/Bsla4FcbM0q0O i7xyAoEyNhjELIrt4UzlLnxQmH29IawCw98aN0eSKrAe9189jWpZe+MOujlm6wHUGAFg RROA== X-Gm-Message-State: AOAM5305Et/KJCZL2+OT2tLAnQuYoh1xmyRB3rq7zPwmqjya//5/hhTV miiHTaAeGRdqN76WK4FpdMwYSsdJQE9JfqHgfoI= 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: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net 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:52:59 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitrii Banshchikov X-Patchwork-Id: 12263299 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 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 13177C433ED for ; Mon, 17 May 2021 22:53:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E2F8C6124C for ; Mon, 17 May 2021 22:53:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344151AbhEQWyz (ORCPT ); Mon, 17 May 2021 18:54:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41692 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344179AbhEQWys (ORCPT ); Mon, 17 May 2021 18:54:48 -0400 Received: from mail-wr1-x435.google.com (mail-wr1-x435.google.com [IPv6:2a00:1450:4864:20::435]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2400BC0613ED for ; Mon, 17 May 2021 15:53:29 -0700 (PDT) Received: by mail-wr1-x435.google.com with SMTP id a4so8077146wrr.2 for ; Mon, 17 May 2021 15:53:29 -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=IsSJbJrrRvUOfFfyLw4/1xRvXLssRnMYFv4V+J+GoJs=; b=ZKmVdbBr7I/Hvq0LeI/DOPynoHXTDV6hINIeXS5sKo2m6nTBy9+OqSPWTqK0V7hyb4 cT6aHm9I9AhA+CWT+hJ99tArZ1i9I2iWw4xQpGo7fZCrCc4q7xp28DChULyBD8e5JOP8 1scGoeen+AoLjTTrzr1RLSfrcjrDoH/fmWfgbmt3qrBNHoj54LqDa1/2KteE7DTB2nFk 0avchn9sRtppSck0oX61zTANro19/jWV2gjifaEw9bZJKsxs4Dp2MN97gswcKtWboCgg Kik0MnOGlchZLTJRzc52Syo/hhAG2xNQHYAIBhwfC4+KrxxjoCe9zlomM9gXIeLCtLMP 22TA== 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=IsSJbJrrRvUOfFfyLw4/1xRvXLssRnMYFv4V+J+GoJs=; b=ZfTC09BPJvX/vtwIgCHqAiD7iLIo0ihtJaixaG2cNLQ2KnBHknn5uLmVMOsleH8F4g Zoore49gnP7nX19DyYadle9YjKQq4sTa5pMSyubmbJON63aEh1KJjEUoORhS3zv7NEgf Zw4g1rS/h4NJruRQkRmt0/RWyg4CSD5WjP/+LMBTxJRvXjVnNacn+/OktCcyDsvrltVq mte2Mdkei62jctir4GZsfDxEO4AxXrrH71yuqyarq3d+xQw0eb5tqjbXNRKG+9X8yMZk 5N3b9aQxpcqCSM5wQNZAYt9S47rMARR4w74TPT11MXKULloHlumjIai/Byg6hLTETJEr H5CQ== X-Gm-Message-State: AOAM531zEkrs3C8+Z09ha6HIoiUa/fGFurPUVuCzKVjH6g/4STEY7eoO 2wk93PgKF8wyfbawJST1hH2SqVQq34ncTSgqtDA= X-Google-Smtp-Source: ABdhPJwDuvpVHaWIvI9STxcReNex/owAO7gbDE65ygBwWbsImM/w+bsXabDT8rYEWtB4l1CpsAPOMg== X-Received: by 2002:a05:6000:10d1:: with SMTP id b17mr2442588wrx.281.1621292007603; Mon, 17 May 2021 15:53:27 -0700 (PDT) Received: from localhost ([154.21.15.43]) by smtp.gmail.com with ESMTPSA id j14sm770438wmj.19.2021.05.17.15.53.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 May 2021 15:53:27 -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 02/11] bpfilter: Add logging facility Date: Tue, 18 May 2021 02:52:59 +0400 Message-Id: <20210517225308.720677-3-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: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net There are three logging levels for messages: FATAL, NOTICE and DEBUG. When a message is logged with FATAL level it results in bpfilter usermode helper termination. Introduce struct context to avoid use of global objects and store there the logging parameters: log level and log sink. Signed-off-by: Dmitrii Banshchikov --- net/bpfilter/Makefile | 2 +- net/bpfilter/bflog.c | 29 +++++++++++++++++++++++++++++ net/bpfilter/bflog.h | 24 ++++++++++++++++++++++++ net/bpfilter/context.h | 16 ++++++++++++++++ 4 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 net/bpfilter/bflog.c create mode 100644 net/bpfilter/bflog.h create mode 100644 net/bpfilter/context.h diff --git a/net/bpfilter/Makefile b/net/bpfilter/Makefile index cdac82b8c53a..874d5ef6237d 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 bflog.o userccflags += -I $(srctree)/tools/include/ -I $(srctree)/tools/include/uapi ifeq ($(CONFIG_BPFILTER_UMH), y) diff --git a/net/bpfilter/bflog.c b/net/bpfilter/bflog.c new file mode 100644 index 000000000000..2752e39060e4 --- /dev/null +++ b/net/bpfilter/bflog.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#define _GNU_SOURCE + +#include "bflog.h" + +#include +#include +#include + +#include "context.h" + +void bflog(struct context *ctx, int level, const char *fmt, ...) +{ + if (ctx->log_file && + (level == BFLOG_LEVEL_FATAL || (level & ctx->log_level))) { + va_list va; + + va_start(va, fmt); + vfprintf(ctx->log_file, fmt, va); + va_end(va); + } + + if (level == BFLOG_LEVEL_FATAL) + exit(EXIT_FAILURE); +} diff --git a/net/bpfilter/bflog.h b/net/bpfilter/bflog.h new file mode 100644 index 000000000000..4ed12791cfa1 --- /dev/null +++ b/net/bpfilter/bflog.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#ifndef NET_BPFILTER_BFLOG_H +#define NET_BPFILTER_BFLOG_H + +struct context; + +#define BFLOG_IMPL(ctx, level, fmt, ...) bflog(ctx, level, "bpfilter: " fmt, ##__VA_ARGS__) + +#define BFLOG_LEVEL_FATAL (0) +#define BFLOG_LEVEL_NOTICE (1) +#define BFLOG_LEVEL_DEBUG (2) + +#define BFLOG_FATAL(ctx, fmt, ...) \ + BFLOG_IMPL(ctx, BFLOG_LEVEL_FATAL, "fatal error: " fmt, ##__VA_ARGS__) +#define BFLOG_NOTICE(ctx, fmt, ...) BFLOG_IMPL(ctx, BFLOG_LEVEL_NOTICE, fmt, ##__VA_ARGS__) +#define BFLOG_DEBUG(ctx, fmt, ...) BFLOG_IMPL(ctx, BFLOG_LEVEL_DEBUG, fmt, ##__VA_ARGS__) + +void bflog(struct context *ctx, int level, const char *fmt, ...); + +#endif // NET_BPFILTER_BFLOG_H diff --git a/net/bpfilter/context.h b/net/bpfilter/context.h new file mode 100644 index 000000000000..e85c97c3d010 --- /dev/null +++ b/net/bpfilter/context.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#ifndef NET_BPFILTER_CONTEXT_H +#define NET_BPFILTER_CONTEXT_H + +#include + +struct context { + FILE *log_file; + int log_level; +}; + +#endif // NET_BPFILTER_CONTEXT_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: 12263303 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 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 1845FC43461 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 EBB616124C for ; Mon, 17 May 2021 22:53:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344218AbhEQWy4 (ORCPT ); Mon, 17 May 2021 18:54:56 -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 S1344190AbhEQWyt (ORCPT ); Mon, 17 May 2021 18:54:49 -0400 Received: from mail-wr1-x42c.google.com (mail-wr1-x42c.google.com [IPv6:2a00:1450:4864:20::42c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 89B33C06138A for ; Mon, 17 May 2021 15:53:32 -0700 (PDT) Received: by mail-wr1-x42c.google.com with SMTP id p7so4318059wru.10 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=Ta97gC5mn7Kqaxr+YkLc7SCnyFL3iQ0v0Wy9YV5CySoU0cN1uVQYTSec8M7QnUdRMi 7qbWl3q7NeQB6hlwxJQlFeaeTuDBy001fF+6ZGkNq0BmN7E4DUNc4+GBk2QqEH87/OmX 6G+L44q2NNW8flJEFNTRBr68hR7pHtzqtvc3ti5NPnOoVxXg02WhoBo6lJEarPC7l0N8 carlvcC+VRrqL+pIV9rIopypfJT5xbTs03cYAYHZa+nkDYGTYnU2M2d5HOTflYWhII++ MlUUyNiRSOnXwM7KDaf/zMmbTleYv514HCTZcRH+5l7x7LXeL99DIp1uXgvxxMnJp4BA 5VFw== X-Gm-Message-State: AOAM53220EtCSLzxV+F78hwk1+lAd97mHFDhy4uPNW6F2tzM0XzRUE+I YPGIwaJbG/oeuMFW3kQgutpa1TP4HZfq6O0FARQ= 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: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net 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:01 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitrii Banshchikov X-Patchwork-Id: 12263301 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 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 CF290C43460 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 B036A61209 for ; Mon, 17 May 2021 22:53:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344228AbhEQWy5 (ORCPT ); Mon, 17 May 2021 18:54:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41720 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344208AbhEQWyy (ORCPT ); Mon, 17 May 2021 18:54:54 -0400 Received: from mail-wr1-x42d.google.com (mail-wr1-x42d.google.com [IPv6:2a00:1450:4864:20::42d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0B307C06138B for ; Mon, 17 May 2021 15:53:36 -0700 (PDT) Received: by mail-wr1-x42d.google.com with SMTP id j14so6310219wrq.5 for ; Mon, 17 May 2021 15:53:35 -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=LVbCOGU7gtoqVWCuLiLGdbq6lukEGJhpYIytUkCDM00=; b=tv2rM1qLY1x/o/m/UhrKnsyStOn/uF9TW6YAuQmBZjgkBIOyIwFUvSpmsPQxfP1fl1 PeCfGs0TrwPD/XDiby1EluzziQFOnLL4TgvzwlGbY+7NZP8TwFv/NGzjWV4hbxbLftEz G/eU23Fiau6QMsIF0TK79oLi6lY+hxGrrnEX/e4a6+5E5vIpp+RugyJF2puQo/Efvfvd APfDR/LfIREHCGykHJbJ8nhCvagJltoOKXy7Jfs1UfjPux9EY1YueVRjKn+hJ7DjNp2o IBtjHbh1zmevtkZNBfe8o2NQDhtsDYdZt9VDRBSXy5assYXGfHNe9wbXmd7OMdnRG7C4 2pBQ== 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=LVbCOGU7gtoqVWCuLiLGdbq6lukEGJhpYIytUkCDM00=; b=r1XD7gTlfJFh11lb+jYI5vB8a+vsaUQNbuqhGuq2x85IlAqXho/Bn8i3nNVumF/U/D T5qd7JGo7RcmZtywpEKcE51J3cUtLBqqJejHcRNPeK3CJ2GRUWHtGnadOXvbWIg6iNk/ JmhlGqedImkG3lQFTKhuMTAvkaLEFuLo1N2JttAHVyeCAYZtXFQS+PifG0eQVnHR6xij E4KqPGai6tcPEMx/m/4cB0ucrWXdrbtM8pgKzFY1hr5I/hs/Vq9pWWYbQctoLPNUpv64 /H3lhX+VBqBdAPMdWeqfvh0pvpijEBSa35U9uP36tc6RTU6rkNErL5SrrkmmaBptXoKN UU+g== X-Gm-Message-State: AOAM530vh0CdvrmNh9NUCO1SBqnlxqQwCCoyQs43tRoidkwVWPBQIajl MbLPRDan5Ew3ko4z3Hvcxc6+fWjafuGtL47OR7M= X-Google-Smtp-Source: ABdhPJwBM3s88GCibwiJkUteHvKrfv4RM/nq187z16QzLLiZVuzNGHTCfdm2YZVdhA45AxWU9VJ8JQ== X-Received: by 2002:a5d:4304:: with SMTP id h4mr2572700wrq.210.1621292014616; Mon, 17 May 2021 15:53:34 -0700 (PDT) Received: from localhost ([154.21.15.43]) by smtp.gmail.com with ESMTPSA id r1sm3347250wrt.67.2021.05.17.15.53.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 May 2021 15:53:34 -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 04/11] tools: Add bpfilter usermode helper header Date: Tue, 18 May 2021 02:53:01 +0400 Message-Id: <20210517225308.720677-5-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: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net The header will be used in bpfilter usermode helper test infrastructure. Signed-off-by: Dmitrii Banshchikov --- tools/include/uapi/linux/bpfilter.h | 179 ++++++++++++++++++++++++++++ 1 file changed, 179 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..8b49d81f81c8 --- /dev/null +++ b/tools/include/uapi/linux/bpfilter.h @@ -0,0 +1,179 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_BPFILTER_H +#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" + + +#define BPFILTER_ALIGN(__X) __ALIGN_KERNEL(__X, __alignof__(__u64)) + +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, +}; + +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: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: 12263305 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 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 E5C33C433ED for ; Mon, 17 May 2021 22:53:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C3CCA61209 for ; Mon, 17 May 2021 22:53:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344259AbhEQWzB (ORCPT ); Mon, 17 May 2021 18:55:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41718 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344214AbhEQWy4 (ORCPT ); Mon, 17 May 2021 18:54:56 -0400 Received: from mail-wm1-x333.google.com (mail-wm1-x333.google.com [IPv6:2a00:1450:4864:20::333]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 965A9C061763 for ; Mon, 17 May 2021 15:53:39 -0700 (PDT) Received: by mail-wm1-x333.google.com with SMTP id n17-20020a7bc5d10000b0290169edfadac9so404753wmk.1 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=J9xHlL14Hf/A8GOKPS1xU1vA1vrNrrpwmW5iGx4wTPuADNfeoGdzTPKFDV+RR5+5jG G9p0KfH51BuWVpqxESOMNZuJ3kqmheiSayEf8OnA60/zirfcUTM4VfXKKuWfI81MYSLY N95vkV+yEXW+t+bsFIzxZtW3CWZQhjqT9BkEdNd4yRF7mTHJfeP0sj5IwABj+fGhS4+2 sJWulw+JSN64c8CY+O/MImsVlMYV1pU7nQKszvMV1DJKW/eRy2NoXfgf+Tjnc0r4X1eN BcQE4P/ENifwv9xgJW8pQmBvjIqYSI0jXfAJyt9Uec7vJZ113oWydawPCDau2WOb7+KK j73w== X-Gm-Message-State: AOAM532nRvk818Ir7S0cdqAhv1sMuO1Bys/Wd4rcVB1WtDoq1X0ahL3E S5B8Jbr0Q6IszncbDmQM+hLQsPoCqdkB9Ge80Yk= 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: 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 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:03 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitrii Banshchikov X-Patchwork-Id: 12263307 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 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=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 EEFDEC433B4 for ; Mon, 17 May 2021 22:53:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D04A261285 for ; Mon, 17 May 2021 22:53:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344264AbhEQWzC (ORCPT ); Mon, 17 May 2021 18:55:02 -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 S242469AbhEQWzA (ORCPT ); Mon, 17 May 2021 18:55:00 -0400 Received: from mail-wm1-x332.google.com (mail-wm1-x332.google.com [IPv6:2a00:1450:4864:20::332]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1D169C06138C for ; Mon, 17 May 2021 15:53:43 -0700 (PDT) Received: by mail-wm1-x332.google.com with SMTP id b7so3783172wmh.5 for ; Mon, 17 May 2021 15:53:43 -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=vnjpYE6a+/qN6qBE52lhBST4EhfaOWI/BYnTi+GvsjA=; b=r2ryPwPxyQ5WUzorJbvzGt1NNv/BQdIP2e02Uk1uc6KsjV6Dp/hPbDuE3S7LYoHvSK YYP7IAvsmnSNvwrA5ki6QxjL52ckydoDqVyrAND+whvmPc3SxxbeShXxAZ4o5xgeurBS X5kgovSrnbwT0eGrZMTn7LeOGqMvweFtgPy3xAdhCdrZ4qYlER7EL9QDQF9PAP0wNTsy XN8NRQasnQP1zi2F5tscace5v61KFuyejbVseO6PDZRi4UxRb/t4oVEgIVqKc/eSdFmd 9a+X5gOyHlWQFa/L/15brMqbcJzAz2WuPKGsfoFyQa3MgWFJGmO16dJ+Fj9SZajXhrdK t6xQ== 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=vnjpYE6a+/qN6qBE52lhBST4EhfaOWI/BYnTi+GvsjA=; b=YuMmPqWlBX5XQjIxtdU2T5awbMxWSo75bnlbMDnJm+05aLHwnYU1YpX3pZ4sKgGH7N LOEyvvsNWnMYT0Oel8skNfU7gkF2twPdg+zpM10RnSyb/mHYLDTHO6uoVSJCexSbqQvI MaC0yAkr/jMjnQDrbepWQMHHuU9hBYm3cXjral+U1df05zM9NhJHSCCy3nWxE8DU5noE yuncKegXrhk/kVuwFKVJ9XYWH7OrX9xCyZf/nJuefPVKqA4of7xDTeyT+dSVx2w85WYE MulC3htkJr7+hXyECxQ7BDkVI0OwvMl+vmO4Gs4DLRsRzWTZaAFCKmfQDLJCzanADfmN LvrA== X-Gm-Message-State: AOAM532Ab4I4l7dG1qVv8WcBKT/fbgBumTZ6GYm9MScIySgEcGx+I6SB 5aHSkJZDqMvBCHVup5CtyE6wVRgjIoMuOcZITkY= X-Google-Smtp-Source: ABdhPJwk82o7DyR5VfeFIqiOXFgp/m3Bc6j2OyFFn1PNYpDduWe7ExjiG8nEGmUB732xYnMYrjJIpg== X-Received: by 2002:a1c:f70b:: with SMTP id v11mr1918160wmh.186.1621292021546; Mon, 17 May 2021 15:53:41 -0700 (PDT) Received: from localhost ([154.21.15.43]) by smtp.gmail.com with ESMTPSA id n189sm9707881wme.9.2021.05.17.15.53.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 May 2021 15:53:41 -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 06/11] bpfilter: Add struct match Date: Tue, 18 May 2021 02:53:03 +0400 Message-Id: <20210517225308.720677-7-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: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net struct match_ops defines 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. All match_ops are kept in map match_ops_map by their name. Signed-off-by: Dmitrii Banshchikov --- net/bpfilter/Makefile | 2 +- net/bpfilter/context.c | 41 +++++++++++ net/bpfilter/context.h | 6 ++ net/bpfilter/match-ops-map.h | 48 ++++++++++++ net/bpfilter/match.c | 73 +++++++++++++++++++ net/bpfilter/match.h | 34 +++++++++ .../testing/selftests/bpf/bpfilter/.gitignore | 1 + tools/testing/selftests/bpf/bpfilter/Makefile | 3 + .../selftests/bpf/bpfilter/test_match.c | 63 ++++++++++++++++ 9 files changed, 270 insertions(+), 1 deletion(-) create mode 100644 net/bpfilter/context.c create mode 100644 net/bpfilter/match-ops-map.h create mode 100644 net/bpfilter/match.c create mode 100644 net/bpfilter/match.h create mode 100644 tools/testing/selftests/bpf/bpfilter/test_match.c diff --git a/net/bpfilter/Makefile b/net/bpfilter/Makefile index 908fbad680ec..d1a36dd2c666 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 +bpfilter_umh-objs := main.o bflog.o io.o map-common.o match.o 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..96735c7883bf --- /dev/null +++ b/net/bpfilter/context.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#define _GNU_SOURCE + +#include "context.h" + +#include +#include + +#include "match.h" + +static int init_match_ops_map(struct context *ctx) +{ + const struct match_ops *match_ops[] = { &udp_match_ops }; + int i, err; + + err = create_match_ops_map(&ctx->match_ops_map, ARRAY_SIZE(match_ops)); + if (err) + return err; + + for (i = 0; i < ARRAY_SIZE(match_ops); ++i) { + err = match_ops_map_insert(&ctx->match_ops_map, match_ops[i]); + if (err) + return err; + } + + return 0; +} + +int create_context(struct context *ctx) +{ + return init_match_ops_map(ctx); +} + +void free_context(struct context *ctx) +{ + free_match_ops_map(&ctx->match_ops_map); +} diff --git a/net/bpfilter/context.h b/net/bpfilter/context.h index e85c97c3d010..a3e737b603f0 100644 --- a/net/bpfilter/context.h +++ b/net/bpfilter/context.h @@ -8,9 +8,15 @@ #include +#include "match-ops-map.h" + struct context { FILE *log_file; int log_level; + struct match_ops_map match_ops_map; }; +int create_context(struct context *ctx); +void free_context(struct context *ctx); + #endif // NET_BPFILTER_CONTEXT_H diff --git a/net/bpfilter/match-ops-map.h b/net/bpfilter/match-ops-map.h new file mode 100644 index 000000000000..0ff57f2d8da8 --- /dev/null +++ b/net/bpfilter/match-ops-map.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#ifndef NET_BPFILTER_MATCH_OPS_MAP_H +#define NET_BPFILTER_MATCH_OPS_MAP_H + +#include "map-common.h" + +#include + +#include +#include + +#include "match.h" + +struct match_ops_map { + struct hsearch_data index; +}; + +static inline int create_match_ops_map(struct match_ops_map *map, size_t nelem) +{ + return create_map(&map->index, nelem); +} + +static inline const struct match_ops *match_ops_map_find(struct match_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 match_ops_map_insert(struct match_ops_map *map, const struct match_ops *match_ops) +{ + return map_insert(&map->index, match_ops->name, (void *)match_ops); +} + +static inline void free_match_ops_map(struct match_ops_map *map) +{ + free_map(&map->index); +} + +#endif // NET_BPFILTER_MATCT_OPS_MAP_H diff --git a/net/bpfilter/match.c b/net/bpfilter/match.c new file mode 100644 index 000000000000..aeca1b93cd2d --- /dev/null +++ b/net/bpfilter/match.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#define _GNU_SOURCE + +#include "match.h" + +#include +#include + +#include +#include + +#include "bflog.h" +#include "context.h" +#include "match-ops-map.h" + +#define BPFILTER_ALIGN(__X) __ALIGN_KERNEL(__X, __alignof__(__u64)) +#define MATCH_SIZE(type) (sizeof(struct bpfilter_ipt_match) + BPFILTER_ALIGN(sizeof(type))) + +static int udp_match_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_DEBUG(ctx, "cannot check match 'udp': invalid flags\n"); + return -EINVAL; + } + + return 0; +} + +const struct match_ops udp_match_ops = { .name = "udp", + .size = MATCH_SIZE(struct xt_udp), + .revision = 0, + .check = udp_match_check }; + +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 err; + + if (strnlen(ipt_match->u.user.name, maxlen) == maxlen) { + BFLOG_DEBUG(ctx, "cannot init match: too long match name\n"); + return -EINVAL; + } + + found = match_ops_map_find(&ctx->match_ops_map, ipt_match->u.user.name); + if (IS_ERR(found)) { + BFLOG_DEBUG(ctx, "cannot find match by name: '%s'\n", ipt_match->u.user.name); + return PTR_ERR(found); + } + + if (found->size != ipt_match->u.match_size || + found->revision != ipt_match->u.user.revision) { + BFLOG_DEBUG(ctx, "invalid match: '%s'\n", ipt_match->u.user.name); + return -EINVAL; + } + + err = found->check(ctx, ipt_match); + if (err) + return err; + + 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..79b7c87016d4 --- /dev/null +++ b/net/bpfilter/match.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#ifndef NET_BPFILTER_MATCH_H +#define NET_BPFILTER_MATCH_H + +#include "../../include/uapi/linux/bpfilter.h" + +#include + +struct bpfilter_ipt_match; +struct context; +struct match_ops_map; + +struct match_ops { + char name[BPFILTER_EXTENSION_MAXNAMELEN]; + uint16_t size; + uint8_t revision; + int (*check)(struct context *ctx, const struct bpfilter_ipt_match *ipt_match); +}; + +extern const struct match_ops udp_match_ops; + +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 be10b50ca289..e5073231f811 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 test_io test_map +test_match diff --git a/tools/testing/selftests/bpf/bpfilter/Makefile b/tools/testing/selftests/bpf/bpfilter/Makefile index 77afbbdf27c5..362c9a28b88d 100644 --- a/tools/testing/selftests/bpf/bpfilter/Makefile +++ b/tools/testing/selftests/bpf/bpfilter/Makefile @@ -10,6 +10,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 KSFT_KHDR_INSTALL := 1 @@ -17,3 +18,5 @@ 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 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..3a56d79ed24c --- /dev/null +++ b/tools/testing/selftests/bpf/bpfilter/test_match.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE + +#include "context.h" +#include "match.h" + +#include +#include + +#include +#include +#include + +#include + +#include "../../kselftest_harness.h" + +struct udp_match { + struct xt_entry_match ipt_match; + struct xt_udp udp; +}; + +FIXTURE(test_udp_match) +{ + struct context ctx; + struct udp_match udp_match; + struct match match; +}; + +FIXTURE_SETUP(test_udp_match) +{ + ASSERT_EQ(0, create_context(&self->ctx)); + self->ctx.log_file = stderr; + + memset(&self->udp_match, 0, sizeof(self->udp_match)); + snprintf(self->udp_match.ipt_match.u.user.name, + sizeof(self->udp_match.ipt_match.u.user.name), "udp"); + self->udp_match.ipt_match.u.user.match_size = sizeof(struct udp_match); + self->udp_match.ipt_match.u.user.revision = 0; +}; + +FIXTURE_TEARDOWN(test_udp_match) +{ + free_context(&self->ctx); +} + +TEST_F(test_udp_match, init) +{ + self->udp_match.udp.spts[0] = 1; + self->udp_match.udp.spts[1] = 2; + self->udp_match.udp.dpts[0] = 3; + self->udp_match.udp.dpts[1] = 4; + self->udp_match.udp.invflags = 0; + + ASSERT_EQ(init_match(&self->ctx, + (const struct bpfilter_ipt_match *)&self->udp_match + .ipt_match, + &self->match), + 0); +} + +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: 12263309 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 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 87A62C433B4 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 67A4F6128E for ; Mon, 17 May 2021 22:53:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344269AbhEQWzN (ORCPT ); Mon, 17 May 2021 18:55:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41778 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344275AbhEQWzE (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 C3625C06138A for ; Mon, 17 May 2021 15:53:46 -0700 (PDT) Received: by mail-wm1-x32c.google.com with SMTP id s5-20020a7bc0c50000b0290147d0c21c51so418419wmh.4 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=Iu7Kw2XQyt64NElOcUHYmL7WaqhTGp6nOWpMfV5lBotN0qbHA+Aqbi4Wrh2FfiUq2O cBUu1xbNFFTQ6TLV+o1VD0QP693Obf4f/s7f8C81V+/v3I61rtCvzyEoEApZX5k5zGR3 LOe8RTd3LTabGiUUCg6c2vEDrCRJ206NvCG5KEfcErkGADH3tWOFDFNw8e03hnjudg2g sn+QRUmAtEaVrRZ9NM1NUQbS+zB1t0EiYHR6E3eDJio9FSu+b3C2ky3KS+L51jwfgzTw PJ6AykuGLgdlVaDBSzCXas4B/q8D2yXZiqkNOeZ2IPvOIxMvkZuKiJy48RqEiA0rKf7m fQsQ== X-Gm-Message-State: AOAM5313GucmdUxXEP0pqQUP2AdjmNkshCEqwAEBQs39Zqi9gYYOW5hr cK8VKJZ7rwf2bMTCgtcCIIMVOqigTNjnBxF0XOg= 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: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net 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:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitrii Banshchikov X-Patchwork-Id: 12263311 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 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 68CF4C433ED for ; Mon, 17 May 2021 22:54:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4EAAE61209 for ; Mon, 17 May 2021 22:54:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344280AbhEQWzO (ORCPT ); Mon, 17 May 2021 18:55:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41796 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344296AbhEQWzH (ORCPT ); Mon, 17 May 2021 18:55:07 -0400 Received: from mail-wr1-x433.google.com (mail-wr1-x433.google.com [IPv6:2a00:1450:4864:20::433]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7C35BC06138C for ; Mon, 17 May 2021 15:53:50 -0700 (PDT) Received: by mail-wr1-x433.google.com with SMTP id a4so8077674wrr.2 for ; Mon, 17 May 2021 15:53:50 -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=fBmlXuxpodPLFCV6Z3mqL72cuU4IQnrOwtA/np0iQRw=; b=NxZ+9AhsJbent2L5MCyTBwYnpY9+i82pgAXRuuAiU2rnt/pbZd3LyVR/jLI8uBvwPi HwT0YN0qv+bLO+72Aksow+q0SPn2jcrOPYQS/k8jkeQtxFwGVuTZQ2RFZjcrOMioMOXj e5R+L4QGbWTXVWVTm4nopcHJaUQyR2DWIBqeuUFWa/C2/w1Jsyah5PbBpQ1gwUr6/WNM yZ/Ll1HpdVTqXkOG4kv/moV88asH9/os8IoXK5GybOqW4SJuxbarM+sKfYheHmmy86t8 fRoDpH3LxxAi+/AD/LI60A7kksIA03iz0I+VVE7A1ia80aDHIBWOIjl4XuuCnaRS/+Pu gwjg== 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=fBmlXuxpodPLFCV6Z3mqL72cuU4IQnrOwtA/np0iQRw=; b=XZIyLGTX+ERJfy+QbLNVVfKhjdPoc6YyEmNEz0Sv1sq+y0Jo2GiqWwdvmARXqxUU3A czfOzJGryJCoewqLsIMpLd8Big4Erdu4WHFfEqg8+gaNlKj/I2jZwHs/b0bYPsto5wJt zzVlqHTes3ic5RYpbJHDO5fIouZ3HJAhVWrUkINZ1NhH4wIOztaOuM/T4OrkOl94DuIQ KH5AskN0qczFmPwh/08naDpbOUJ18Ygne6ylIDx3cYJ6URmZKrV3cQeg+Ov0IeXI9ktr Cy/dUIIPsVBetwsoyY3AswdsKqHBMJhuU6Dn2lW2I4+Kpznh9v4C/IEiRVqosFlMsCJS 4Hqw== X-Gm-Message-State: AOAM533fAX8k7RV/h4oLj0y0MtpnlBzA7P7vv8uoS4CZwNlbJzfmNrCD ignEQZIrcQQ/OL4u07TejRwEXQICXOiX84qhtr0= X-Google-Smtp-Source: ABdhPJxh8ZRmCYF3CtzithAqkpP8LylGkmCLAaOQJI4xfGHkgq97jrsyIIfkHLiP+JqMKBuG7BFCTQ== X-Received: by 2002:a5d:4e8c:: with SMTP id e12mr2531229wru.94.1621292029018; Mon, 17 May 2021 15:53:49 -0700 (PDT) Received: from localhost ([154.21.15.43]) by smtp.gmail.com with ESMTPSA id b10sm22257300wrr.27.2021.05.17.15.53.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 May 2021 15:53:48 -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 08/11] bpfilter: Add struct rule Date: Tue, 18 May 2021 02:53:05 +0400 Message-Id: <20210517225308.720677-9-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: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net struct rule is an equivalent of struct ipt_entry. A rule consists of zero or more matches and a target. A rule tracks its own offset in iptables' entries blob. struct rule should simplify iteration over a blob and avoid blob's guts in code generation. Signed-off-by: Dmitrii Banshchikov --- net/bpfilter/Makefile | 2 +- net/bpfilter/rule.c | 128 ++++++++++++++++++ net/bpfilter/rule.h | 27 ++++ .../testing/selftests/bpf/bpfilter/.gitignore | 1 + tools/testing/selftests/bpf/bpfilter/Makefile | 4 + .../selftests/bpf/bpfilter/bpfilter_util.h | 8 ++ .../selftests/bpf/bpfilter/test_rule.c | 55 ++++++++ 7 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 net/bpfilter/rule.c create mode 100644 net/bpfilter/rule.h create mode 100644 tools/testing/selftests/bpf/bpfilter/test_rule.c diff --git a/net/bpfilter/Makefile b/net/bpfilter/Makefile index f3de07bc8004..1191770d41f7 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 +bpfilter_umh-objs := main.o bflog.o io.o map-common.o context.o match.o target.o rule.o userccflags += -I $(srctree)/tools/include/ -I $(srctree)/tools/include/uapi ifeq ($(CONFIG_BPFILTER_UMH), y) diff --git a/net/bpfilter/rule.c b/net/bpfilter/rule.c new file mode 100644 index 000000000000..0cbee4656070 --- /dev/null +++ b/net/bpfilter/rule.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#define _GNU_SOURCE + +#include "rule.h" + +#include "../../include/uapi/linux/bpfilter.h" + +#include + +#include +#include + +#include "context.h" +#include "bflog.h" + +static const struct bpfilter_ipt_target * +ipt_entry_target(const struct bpfilter_ipt_entry *ipt_entry) +{ + return (const void *)ipt_entry + ipt_entry->target_offset; +} + +static const struct bpfilter_ipt_match *ipt_entry_match(const struct bpfilter_ipt_entry *entry, + size_t offset) +{ + return (const void *)entry + offset; +} + +static int ipt_entry_num_matches(const struct bpfilter_ipt_entry *ipt_entry) +{ + const struct bpfilter_ipt_match *ipt_match; + uint32_t offset = sizeof(*ipt_entry); + int num_matches = 0; + + while (offset < ipt_entry->target_offset) { + ipt_match = ipt_entry_match(ipt_entry, offset); + + if (ipt_entry->target_offset < offset + ipt_match->u.match_size) + return -EINVAL; + + ++num_matches; + offset += ipt_match->u.match_size; + } + + if (offset != ipt_entry->target_offset) + return -EINVAL; + + return num_matches; +} + +static int check_ipt_entry_ip(struct context *ctx, const struct bpfilter_ipt_ip *ip) +{ + if (ip->flags & ~BPFILTER_IPT_F_MASK) + return -EINVAL; + + if (ip->invflags & ~BPFILTER_IPT_INV_MASK) + return -EINVAL; + + return 0; +} + +static int init_rule_matches(struct context *ctx, const struct bpfilter_ipt_entry *ipt_entry, + struct rule *rule) +{ + const struct bpfilter_ipt_match *ipt_match; + uint32_t offset = sizeof(*ipt_entry); + struct match *match; + int err; + + rule->matches = calloc(rule->num_matches, sizeof(rule->matches[0])); + if (!rule->matches) + return -ENOMEM; + + match = rule->matches; + while (offset < ipt_entry->target_offset) { + ipt_match = ipt_entry_match(ipt_entry, offset); + err = init_match(ctx, ipt_match, match); + if (err) + return err; + + ++match; + offset += ipt_match->u.match_size; + } + + return 0; +} + +int init_rule(struct context *ctx, const struct bpfilter_ipt_entry *ipt_entry, struct rule *rule) +{ + const struct bpfilter_ipt_target *ipt_target; + int err; + + err = check_ipt_entry_ip(ctx, &ipt_entry->ip); + + if (ipt_entry->next_offset < ipt_entry->target_offset) + return -EINVAL; + + if (ipt_entry->target_offset < sizeof(*ipt_entry)) + return -EINVAL; + + ipt_target = ipt_entry_target(ipt_entry); + if (ipt_target->u.target_size != ipt_entry->next_offset - ipt_entry->target_offset) + return -EINVAL; + + err = init_target(ctx, ipt_target, &rule->target); + if (err) + return err; + + rule->num_matches = ipt_entry_num_matches(ipt_entry); + if (rule->num_matches < 0) + return rule->num_matches; + + err = init_rule_matches(ctx, ipt_entry, rule); + if (err) { + free_rule(rule); + return err; + } + + return 0; +} + +void free_rule(struct rule *rule) +{ + free(rule->matches); +} diff --git a/net/bpfilter/rule.h b/net/bpfilter/rule.h new file mode 100644 index 000000000000..b445962485a4 --- /dev/null +++ b/net/bpfilter/rule.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#ifndef NET_BPFILTER_RULE_H +#define NET_BPFILTER_RULE_H + +#include + +#include "target.h" + +struct bpfilter_ipt_entry; +struct context; +struct match; + +struct rule { + uint32_t offset; + uint16_t num_matches; + struct match *matches; + struct target target; +}; + +int init_rule(struct context *ctx, const struct bpfilter_ipt_entry *ipt_entry, struct rule *rule); +void free_rule(struct rule *rule); + +#endif // NET_BPFILTER_RULE_H diff --git a/tools/testing/selftests/bpf/bpfilter/.gitignore b/tools/testing/selftests/bpf/bpfilter/.gitignore index 1856d0515f49..c5ccfe4db881 100644 --- a/tools/testing/selftests/bpf/bpfilter/.gitignore +++ b/tools/testing/selftests/bpf/bpfilter/.gitignore @@ -3,3 +3,4 @@ test_io test_map test_match test_target +test_rule diff --git a/tools/testing/selftests/bpf/bpfilter/Makefile b/tools/testing/selftests/bpf/bpfilter/Makefile index 78da74b9ee68..02d860e02c58 100644 --- a/tools/testing/selftests/bpf/bpfilter/Makefile +++ b/tools/testing/selftests/bpf/bpfilter/Makefile @@ -12,6 +12,7 @@ TEST_GEN_PROGS += test_io TEST_GEN_PROGS += test_map TEST_GEN_PROGS += test_match TEST_GEN_PROGS += test_target +TEST_GEN_PROGS += test_rule KSFT_KHDR_INSTALL := 1 @@ -23,3 +24,6 @@ $(OUTPUT)/test_match: test_match.c $(BPFILTERSRCDIR)/match.c $(BPFILTERSRCDIR)/m $(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 +$(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 diff --git a/tools/testing/selftests/bpf/bpfilter/bpfilter_util.h b/tools/testing/selftests/bpf/bpfilter/bpfilter_util.h index d82ff86f280e..55fb0e959fca 100644 --- a/tools/testing/selftests/bpf/bpfilter/bpfilter_util.h +++ b/tools/testing/selftests/bpf/bpfilter/bpfilter_util.h @@ -7,6 +7,7 @@ #include #include +#include static inline void init_standard_target(struct xt_standard_target *ipt_target, int revision, int verdict) @@ -28,4 +29,11 @@ static inline void init_error_target(struct xt_error_target *ipt_target, int rev snprintf(ipt_target->errorname, sizeof(ipt_target->errorname), "%s", error_name); } +static inline void init_standard_entry(struct ipt_entry *entry, __u16 matches_size) +{ + memset(entry, 0, sizeof(*entry)); + entry->target_offset = sizeof(*entry) + matches_size; + entry->next_offset = sizeof(*entry) + matches_size + sizeof(struct xt_standard_target); +} + #endif // BPFILTER_UTIL_H diff --git a/tools/testing/selftests/bpf/bpfilter/test_rule.c b/tools/testing/selftests/bpf/bpfilter/test_rule.c new file mode 100644 index 000000000000..fe12adf32fe5 --- /dev/null +++ b/tools/testing/selftests/bpf/bpfilter/test_rule.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE + +#include "rule.h" + +#include +#include + +#include + +#include +#include + +#include "../../kselftest_harness.h" + +#include "context.h" +#include "rule.h" + +#include "bpfilter_util.h" + +FIXTURE(test_standard_rule) +{ + struct context ctx; + struct { + struct ipt_entry entry; + struct xt_standard_target target; + } entry; + struct rule rule; +}; + +FIXTURE_SETUP(test_standard_rule) +{ + const int verdict = BPFILTER_NF_ACCEPT; + + ASSERT_EQ(create_context(&self->ctx), 0); + self->ctx.log_file = stderr; + + init_standard_entry(&self->entry.entry, 0); + init_standard_target(&self->entry.target, 0, -verdict - 1); +} + +FIXTURE_TEARDOWN(test_standard_rule) +{ + free_rule(&self->rule); + free_context(&self->ctx); +} + +TEST_F(test_standard_rule, init) +{ + ASSERT_EQ(0, init_rule(&self->ctx, (const struct bpfilter_ipt_entry *)&self->entry.entry, + &self->rule)); +} + +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: 12263313 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 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=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 D2594C433B4 for ; Mon, 17 May 2021 22:54:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B6C7A6124C for ; Mon, 17 May 2021 22:54:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344214AbhEQWz1 (ORCPT ); Mon, 17 May 2021 18:55:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41754 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344208AbhEQWzL (ORCPT ); Mon, 17 May 2021 18:55:11 -0400 Received: from mail-wr1-x42c.google.com (mail-wr1-x42c.google.com [IPv6:2a00:1450:4864:20::42c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F0C3FC061760 for ; Mon, 17 May 2021 15:53:53 -0700 (PDT) Received: by mail-wr1-x42c.google.com with SMTP id j14so6310730wrq.5 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=FDgjbPpIOCMtu+Lfqzv7nVaMiLolmG2BnrMBP7boJH7hq9n+odMwgucLbChTIkNO6d +BgElNkKvDZArnEGyfk0WjrVpCV99HN1CBuoQ6az5GFqn8W64YLL6W0N+Rl3jqEtOEWs 0PonI95rlGDZvjwWzV+AA9ig3ADEalLQQgJv4HHGkE2VpaRHFUXQ8bPKEVGcLZcuzpF0 912A9Grraksk2xSlMH2SDUGNYATwcbC5B5i5MvqDuQA3vwJFNXPIyh7+kP7DyMIgciLI GhsSkdjsbIleDuDILDpNPZF4itHj05/+HVJDl0q7dQ8LLjXQBQ8pAKJYCf/TMncXH5xI XilQ== X-Gm-Message-State: AOAM532PB8yJyFhLHmupAr3rFaXiFdD9COVzG1eXbANj052+T7mI0oLD d/SucppO9FypngywaTf5vScU/e+8eb2mLlyU4qE= 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: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net 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:07 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitrii Banshchikov X-Patchwork-Id: 12263315 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 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 00EFAC433ED for ; Mon, 17 May 2021 22:54:13 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D82CC61209 for ; Mon, 17 May 2021 22:54:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344265AbhEQWz2 (ORCPT ); Mon, 17 May 2021 18:55:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41794 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344275AbhEQWzO (ORCPT ); Mon, 17 May 2021 18:55:14 -0400 Received: from mail-wr1-x436.google.com (mail-wr1-x436.google.com [IPv6:2a00:1450:4864:20::436]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 46785C061761 for ; Mon, 17 May 2021 15:53:57 -0700 (PDT) Received: by mail-wr1-x436.google.com with SMTP id i17so8026892wrq.11 for ; Mon, 17 May 2021 15:53:57 -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=jVs5W8Q7mp+DFqI9hJt1Fi1/9BKgvTs4LikxRXRXvus=; b=YU2HVVdebqEuzumZPGGfdAuMbgnud6qEn8MQhVoGAclEjW/5OpuZvRfsEtXsx7YRA/ lmAr3j43CQe/3e3g0y2K9LbfQgaPDHnMuDy2WbChP0zisMSdMvjxTGkAH+NmCdA2fe89 wrRgj4Cj589aiwKJy+2tYpAVhMJRH5RSXYHlsGDmc+y64RpEdKeZo8ya/8791lIqFPub Xc+3JMjthhPW/U7nK0edgoDQ6J/tAA7T+zkUyOoJwUGpg19lr6Ixhxai/Xmlqpp8NfJx 2n3Ylw1vI0dliGoRYE9sDa3x7fID4q9s48oSiBgxNsZX9H7kXlI40kpproqP5d/FzUXo lynw== 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=jVs5W8Q7mp+DFqI9hJt1Fi1/9BKgvTs4LikxRXRXvus=; b=I99mc7ZBWncGj+kEeEZQh3qZEtAIN4Cyzim868hoJl0lL7bvfj9E4VkFyZx0cPIe3c AHZLLj3/Kbw0Wj9JWsC5RI+i978Eyb3UL6yEQx9SyiDsoiZsWMrTF8I1uWnPFCF5vfmd psfGkAE5jnS1G56d7UDs2vSrKiOhXB0bLeikwMbcmk+gTb8chqaAqjtNRkvpSyEok8RT Hqr2O3kALr5DuNRcXkF/ToLIDBdUFezdQtD07n1p/nFgsymVwGsReP7dx2vTV7Pzd488 ijQ90aj6TuPjDFm4OssOkc3SRhifBX1YY8TLpqck3RV4fJz5sHHLASyjbIxuOkzqbk+y gkmA== X-Gm-Message-State: AOAM533n4q5kBoRa9ZaTfFyoaOWknmop4Q1L1vOPmlpr+8vaJ8DF0XOf frmKX7r8ntE+ATJTeg4As91LtAAaVb/2+OpWKWA= X-Google-Smtp-Source: ABdhPJxC19PmYktYwqjTZbmfasMsCCINXdBH8ITNp2Xi6MBt5E/GKsHd5n8zxOJy4mDJwzWs4FMHXA== X-Received: by 2002:a5d:4dcc:: with SMTP id f12mr1394928wru.224.1621292035773; Mon, 17 May 2021 15:53:55 -0700 (PDT) Received: from localhost ([154.21.15.43]) by smtp.gmail.com with ESMTPSA id t11sm19121827wrz.57.2021.05.17.15.53.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 May 2021 15:53:55 -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 10/11] bpfilter: Add handling of setsockopt() calls Date: Tue, 18 May 2021 02:53:07 +0400 Message-Id: <20210517225308.720677-11-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: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net Add support of iptables' setsockopt(2). The parameters of a setsockopt(2) call are passed by struct mbox_request which contains a type of the setsockopt(2) call and its memory buffer description. The typical way to handle hooked setsockopt(2) call is to read the supplied memory buffer via pvm_read(), process it and write an answer to the process memory via pvm_write(). Signed-off-by: Dmitrii Banshchikov --- net/bpfilter/Makefile | 3 +- net/bpfilter/sockopt.c | 357 +++++++++++++++++++++++++++++++++++++++++ net/bpfilter/sockopt.h | 14 ++ 3 files changed, 373 insertions(+), 1 deletion(-) create mode 100644 net/bpfilter/sockopt.c create mode 100644 net/bpfilter/sockopt.h diff --git a/net/bpfilter/Makefile b/net/bpfilter/Makefile index e0090563f2ca..bae14fc9e396 100644 --- a/net/bpfilter/Makefile +++ b/net/bpfilter/Makefile @@ -4,7 +4,8 @@ # userprogs := bpfilter_umh -bpfilter_umh-objs := main.o bflog.o io.o map-common.o context.o match.o target.o rule.o table.o +bpfilter_umh-objs := main.o bflog.o io.o map-common.o context.o match.o target.o rule.o table.o \ + sockopt.o userccflags += -I $(srctree)/tools/include/ -I $(srctree)/tools/include/uapi ifeq ($(CONFIG_BPFILTER_UMH), y) diff --git a/net/bpfilter/sockopt.c b/net/bpfilter/sockopt.c new file mode 100644 index 000000000000..16f0ade203c0 --- /dev/null +++ b/net/bpfilter/sockopt.c @@ -0,0 +1,357 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#define _GNU_SOURCE + +#include "sockopt.h" + +#include +#include + +#include +#include +#include + +#include "bflog.h" +#include "context.h" +#include "io.h" +#include "msgfmt.h" +#include "table-map.h" + +static int read_ipt_get_info(const struct mbox_request *req, struct bpfilter_ipt_get_info *info) +{ + int err; + + if (req->len != sizeof(*info)) + return -EINVAL; + + err = pvm_read(req->pid, info, (const void *)req->addr, sizeof(*info)); + if (err) + return err; + + info->name[sizeof(info->name) - 1] = '\0'; + + return 0; +} + +static int sockopt_get_info(struct context *ctx, const struct mbox_request *req) +{ + struct bpfilter_ipt_get_info info; + struct table *table; + int err; + + BFLOG_DEBUG(ctx, "handling IPT_SO_GET_INFO\n"); + + if (req->len != sizeof(info)) + return -EINVAL; + + err = read_ipt_get_info(req, &info); + if (err) { + BFLOG_DEBUG(ctx, "cannot read ipt_get_info: %s\n", strerror(-err)); + return err; + } + + table = table_map_find(&ctx->table_map, info.name); + if (IS_ERR(table)) { + BFLOG_DEBUG(ctx, "cannot find table: '%s'\n", info.name); + return -ENOENT; + } + + table_get_info(table, &info); + + return pvm_write(req->pid, (void *)req->addr, &info, sizeof(info)); +} + +static int read_ipt_get_entries(const struct mbox_request *req, + struct bpfilter_ipt_get_entries *entries) +{ + int err; + + if (req->len < sizeof(*entries)) + return -EINVAL; + + err = pvm_read(req->pid, entries, (const void *)req->addr, sizeof(*entries)); + if (err) + return err; + + entries->name[sizeof(entries->name) - 1] = '\0'; + + return 0; +} + +static int sockopt_get_entries(struct context *ctx, const struct mbox_request *req) +{ + struct bpfilter_ipt_get_entries get_entries, *entries; + struct table *table; + int err; + + BFLOG_DEBUG(ctx, "handling IPT_SO_GET_ENTRIES\n"); + + err = read_ipt_get_entries(req, &get_entries); + if (err) { + BFLOG_DEBUG(ctx, "cannot read ipt_get_entries: %s\n", strerror(-err)); + return err; + } + + table = table_map_find(&ctx->table_map, get_entries.name); + if (IS_ERR(table)) { + BFLOG_DEBUG(ctx, "cannot find table: '%s'\n", get_entries.name); + return -ENOENT; + } + + if (get_entries.size != table->size) { + BFLOG_DEBUG(ctx, "table '%s' get entries size mismatch\n", get_entries.name); + return -EINVAL; + } + + entries = (struct bpfilter_ipt_get_entries *)req->addr; + + err = pvm_write(req->pid, entries->name, table->name, sizeof(entries->name)); + if (err) + return err; + + err = pvm_write(req->pid, &entries->size, &table->size, sizeof(table->size)); + if (err) + return err; + + return pvm_write(req->pid, entries->entries, table->entries, table->size); +} + +static int read_ipt_get_revision(const struct mbox_request *req, + struct bpfilter_ipt_get_revision *revision) +{ + int err; + + if (req->len != sizeof(*revision)) + return -EINVAL; + + err = pvm_read(req->pid, revision, (const void *)req->addr, sizeof(*revision)); + if (err) + return err; + + revision->name[sizeof(revision->name) - 1] = '\0'; + + return 0; +} + +static int sockopt_get_revision_match(struct context *ctx, const struct mbox_request *req) +{ + struct bpfilter_ipt_get_revision get_revision; + const struct match_ops *found; + int err; + + BFLOG_DEBUG(ctx, "handling IPT_SO_GET_REVISION_MATCH\n"); + + err = read_ipt_get_revision(req, &get_revision); + if (err) + return err; + + found = match_ops_map_find(&ctx->match_ops_map, get_revision.name); + if (IS_ERR(found)) { + BFLOG_DEBUG(ctx, "cannot find match: '%s'\n", get_revision.name); + return PTR_ERR(found); + } + + return found->revision; +} + +static struct bpfilter_ipt_replace *read_ipt_replace(const struct mbox_request *req) +{ + struct bpfilter_ipt_replace *replace; + int err; + + if (req->len < sizeof(*replace)) + return ERR_PTR(-EINVAL); + + replace = malloc(req->len); + if (!replace) + return ERR_PTR(-ENOMEM); + + err = pvm_read(req->pid, replace, (const void *)req->addr, sizeof(*replace)); + if (err) + goto err_free; + + if (replace->num_counters == 0) { + err = -EINVAL; + goto err_free; + } + + if (replace->num_counters >= INT_MAX / sizeof(struct bpfilter_ipt_counters)) { + err = -ENOMEM; + goto err_free; + } + + replace->name[sizeof(replace->name) - 1] = '\0'; + + // TODO: add more checks here + + err = pvm_read(req->pid, replace->entries, (const void *)req->addr + sizeof(*replace), + req->len - sizeof(*replace)); + if (err) + goto err_free; + + return replace; + +err_free: + free(replace); + + return ERR_PTR(err); +} + +static int sockopt_set_replace(struct context *ctx, const struct mbox_request *req) +{ + struct bpfilter_ipt_replace *ipt_replace; + struct table *table, *new_table = NULL; + int err; + + BFLOG_DEBUG(ctx, "handling IPT_SO_SET_REPLACE\n"); + + ipt_replace = read_ipt_replace(req); + if (IS_ERR(ipt_replace)) { + BFLOG_DEBUG(ctx, "cannot read ipt_replace: %s\n", strerror(-PTR_ERR(ipt_replace))); + return PTR_ERR(ipt_replace); + } + + table = table_map_find(&ctx->table_map, ipt_replace->name); + if (IS_ERR(table)) { + err = PTR_ERR(table); + BFLOG_DEBUG(ctx, "cannot find table: '%s'\n", ipt_replace->name); + goto cleanup; + } + + new_table = create_table(ctx, ipt_replace); + if (IS_ERR(new_table)) { + err = PTR_ERR(new_table); + BFLOG_DEBUG(ctx, "cannot read table: %s\n", strerror(-PTR_ERR(new_table))); + goto cleanup; + } + + // Here be codegen + // ... + // + + err = table_map_update(&ctx->table_map, new_table->name, new_table); + if (err) { + BFLOG_DEBUG(ctx, "cannot update table map: %s\n", strerror(-err)); + goto cleanup; + } + + list_add_tail(&new_table->list, &ctx->table_list); + new_table = table; + +cleanup: + if (!IS_ERR(new_table)) + free_table(new_table); + + free(ipt_replace); + + return err; +} + +static struct bpfilter_ipt_counters_info *read_ipt_counters_info(const struct mbox_request *req) +{ + struct bpfilter_ipt_counters_info *info; + size_t size; + int err; + + if (req->len < sizeof(*info)) + return ERR_PTR(-EINVAL); + + info = malloc(req->len); + if (!info) + return ERR_PTR(-ENOMEM); + + err = pvm_read(req->pid, info, (const void *)req->addr, sizeof(*info)); + if (err) + goto err_free; + + // TODO add more size checks here + + size = info->num_counters * sizeof(info->counters[0]); + if (req->len != sizeof(*info) + size) { + err = -EINVAL; + goto err_free; + } + + info->name[sizeof(info->name) - 1] = '\0'; + + err = pvm_read(req->pid, info->counters, (const void *)req->addr + sizeof(*info), size); + if (err) + goto err_free; + + return info; + +err_free: + free(info); + + return ERR_PTR(err); +} + +static int sockopt_set_add_counters(struct context *ctx, const struct mbox_request *req) +{ + struct bpfilter_ipt_counters_info *info; + struct table *table; + int err = 0; + + BFLOG_DEBUG(ctx, "handling IPT_SO_SET_ADD_COUNTERS\n"); + + info = read_ipt_counters_info(req); + if (IS_ERR(info)) { + err = PTR_ERR(info); + BFLOG_DEBUG(ctx, "cannot read ipt_counters_info: %s\n", strerror(-err)); + goto err_free; + } + + table = table_map_find(&ctx->table_map, info->name); + if (IS_ERR(table)) { + err = PTR_ERR(table); + BFLOG_DEBUG(ctx, "cannot find table: '%s'\n", info->name); + goto err_free; + } + + // TODO handle counters + +err_free: + free(info); + + return err; +} + +static int handle_get_request(struct context *ctx, const struct mbox_request *req) +{ + switch (req->cmd) { + case 0: + return 0; + case BPFILTER_IPT_SO_GET_INFO: + return sockopt_get_info(ctx, req); + case BPFILTER_IPT_SO_GET_ENTRIES: + return sockopt_get_entries(ctx, req); + case BPFILTER_IPT_SO_GET_REVISION_MATCH: + return sockopt_get_revision_match(ctx, req); + } + + BFLOG_NOTICE(ctx, "Unexpected SO_GET request: %d\n", req->cmd); + + return -ENOPROTOOPT; +} + +static int handle_set_request(struct context *ctx, const struct mbox_request *req) +{ + switch (req->cmd) { + case BPFILTER_IPT_SO_SET_REPLACE: + return sockopt_set_replace(ctx, req); + case BPFILTER_IPT_SO_SET_ADD_COUNTERS: + return sockopt_set_add_counters(ctx, req); + } + + BFLOG_NOTICE(ctx, "Unexpected SO_SET request: %d\n", req->cmd); + + return -ENOPROTOOPT; +} + +int handle_sockopt_request(struct context *ctx, const struct mbox_request *req) +{ + return req->is_set ? handle_set_request(ctx, req) : handle_get_request(ctx, req); +} diff --git a/net/bpfilter/sockopt.h b/net/bpfilter/sockopt.h new file mode 100644 index 000000000000..711c2f295d89 --- /dev/null +++ b/net/bpfilter/sockopt.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#ifndef NET_BPFILTER_SOCKOPT_H +#define NET_BPFILTER_SOCKOPT_H + +struct context; +struct mbox_request; + +int handle_sockopt_request(struct context *ctx, const struct mbox_request *req); + +#endif // NET_BPFILTER_SOCKOPT_H 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: 12263317 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 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 C86DFC43462 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 ACC8661261 for ; Mon, 17 May 2021 22:54:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344308AbhEQWza (ORCPT ); Mon, 17 May 2021 18:55:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41846 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344333AbhEQWzR (ORCPT ); Mon, 17 May 2021 18:55:17 -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 C4180C06138C for ; Mon, 17 May 2021 15:54:00 -0700 (PDT) Received: by mail-wm1-x32c.google.com with SMTP id z19-20020a7bc7d30000b029017521c1fb75so421902wmk.0 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=bL/aBaLxt9ZNzlBr+JM5CZkNYT4YTcQYnx3BJPqApZQvb7LEHe2my07DK+leSYmc0V yXoWjR98OILnKYk7cjfrjSeQkE9jXECsVHYNnB2UwYlhvshC8zF39MDiJUaMkcqMJTUB JU8wg6oVZEgFrgGPA4SH+sVdfNsnXM46A/DdI/YQ2UHlyjfVFGqybl4ALYvRBxTcKTBp DtqIxx5JM9zAEECn2B388gXiSE9SmZP88C+idDBnKUxqG8BbHyw9OW95WdmSDdnMeqX4 foqieBnHctpcsuRlfPfKQXzS6qhPgGGcx53+XDTvd9vDArmP8cQ/B8EHEyN9khXCrgtk uAAg== X-Gm-Message-State: AOAM531lURfLMRtPf9eQKooJ8N/i4g/k+v1qDnX9fOki8g9FaYpEOWpa 8UKx7tqtLGMN72g/YpbWYr6eYOKpkAUHnljuWu4= 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: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net 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; }