From patchwork Thu Jun 3 10:14:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitrii Banshchikov X-Patchwork-Id: 453842 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,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 53FAAC47082 for ; Thu, 3 Jun 2021 10:15:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3CB9C61287 for ; Thu, 3 Jun 2021 10:15:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230019AbhFCKR3 (ORCPT ); Thu, 3 Jun 2021 06:17:29 -0400 Received: from mail-wr1-f52.google.com ([209.85.221.52]:41533 "EHLO mail-wr1-f52.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229774AbhFCKR3 (ORCPT ); Thu, 3 Jun 2021 06:17:29 -0400 Received: by mail-wr1-f52.google.com with SMTP id h8so5228094wrz.8 for ; Thu, 03 Jun 2021 03:15:44 -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=fEyaH/xoapt+Nbgw1o+/0sbcrWyyWSxcAFw24xpOSpGT7Gxnhs4HqCKDVOZNpcpmZ5 3JOb/f58y/OTJ/iv+2Sy+LGI/J2yGLFZrnDOGELFiH/RdnnqhGSJ2mrxVQ3iAR1Dfuhm YcqRfBNGBnV8RPZCvujxSr6XkYSl9q61xpMJ6WHho3gi0mtnf9s0c6zbc74UUl83KhA6 Ve1GjiGkq4YGYNC/Y2Q+6iRzKoE/89Ml6CEQMK7WfvFukKwzVhSPYp78zktI08CRdGc9 w5lEb9jdpmE2fj5bnuJimofgPNvlgfV3zH2i3nCO+rju/pV5yU2SKHS85FzIT+yn+rok A7jg== 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=S/3kqpXo/G5D3sn46NLg5gW9WD1zvC/prR4nEnlFLpfQJUECbpbTsLaSwpP2kvXcEp BpC2fmLVB+rHx66VZvPEWjEK+KsAjDjBYzXo5zq9ctIwlved070EsZlHc0HOhyTl2Z98 O4lV+V+IlZ3Ki2IakmQGiKoizVTW08udZs6VeigKku66Q0GKs/zYTm6L54E1Y1ft6qTy kVycQVpEjo0YKihKSTg6T6PYdTySGGy8YK4SV2h5bSuqzquxEYVtyRFqjvzi4+GMlbi3 xMJylnyfbSw4gPfbf92oxFrnB0mpAo+BvEdB31VcZ4fY3q4cuBWmZsVST9zKufN0wHkq RVMw== X-Gm-Message-State: AOAM533SecYmFr2xuMTHcJ4TJgpkiEl4DO5MW64Z9IOdcx04E6SjOy4d rksgNI1tvSSwqkit3Qc9nPcRHg== X-Google-Smtp-Source: ABdhPJw2Y8e3+pA1up1bQe4dRrPGqAR9RUUPTI55nH03DR5PgEOXFApWqPdvSTcAWCFcgGeZggRfdw== X-Received: by 2002:a05:6000:12cc:: with SMTP id l12mr37189092wrx.91.1622715284081; Thu, 03 Jun 2021 03:14:44 -0700 (PDT) Received: from localhost ([154.21.15.43]) by smtp.gmail.com with ESMTPSA id p10sm2761055wrr.58.2021.06.03.03.14.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Jun 2021 03:14:43 -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 v1 01/10] bpfilter: Add types for usermode helper Date: Thu, 3 Jun 2021 14:14:16 +0400 Message-Id: <20210603101425.560384-2-me@ubique.spb.ru> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210603101425.560384-1-me@ubique.spb.ru> References: <20210603101425.560384-1-me@ubique.spb.ru> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add more definitions that mirror existing iptables' ABI. These definitions will be used in bpfilter usermode helper. Signed-off-by: Dmitrii Banshchikov --- include/uapi/linux/bpfilter.h | 155 ++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/include/uapi/linux/bpfilter.h b/include/uapi/linux/bpfilter.h index cbc1f5813f50..e97d95d0ba54 100644 --- a/include/uapi/linux/bpfilter.h +++ b/include/uapi/linux/bpfilter.h @@ -3,6 +3,13 @@ #define _UAPI_LINUX_BPFILTER_H #include +#include + +#define BPFILTER_FUNCTION_MAXNAMELEN 30 +#define BPFILTER_EXTENSION_MAXNAMELEN 29 + +#define BPFILTER_STANDARD_TARGET "" +#define BPFILTER_ERROR_TARGET "ERROR" enum { BPFILTER_IPT_SO_SET_REPLACE = 64, @@ -18,4 +25,152 @@ enum { BPFILTER_IPT_GET_MAX, }; +enum { + BPFILTER_XT_TABLE_MAXNAMELEN = 32, +}; + +enum { + BPFILTER_NF_DROP = 0, + BPFILTER_NF_ACCEPT = 1, + BPFILTER_NF_STOLEN = 2, + BPFILTER_NF_QUEUE = 3, + BPFILTER_NF_REPEAT = 4, + BPFILTER_NF_STOP = 5, + BPFILTER_NF_MAX_VERDICT = BPFILTER_NF_STOP, + BPFILTER_RETURN = (-BPFILTER_NF_REPEAT - 1), +}; + +enum { + BPFILTER_INET_HOOK_PRE_ROUTING = 0, + BPFILTER_INET_HOOK_LOCAL_IN = 1, + BPFILTER_INET_HOOK_FORWARD = 2, + BPFILTER_INET_HOOK_LOCAL_OUT = 3, + BPFILTER_INET_HOOK_POST_ROUTING = 4, + BPFILTER_INET_HOOK_MAX, +}; + +enum { + BPFILTER_IPT_F_MASK = 0x03, + BPFILTER_IPT_INV_MASK = 0x7f +}; + +struct bpfilter_ipt_match { + union { + struct { + __u16 match_size; + char name[BPFILTER_EXTENSION_MAXNAMELEN]; + __u8 revision; + } user; + struct { + __u16 match_size; + void *match; + } kernel; + __u16 match_size; + } u; + unsigned char data[0]; +}; + +struct bpfilter_ipt_target { + union { + struct { + __u16 target_size; + char name[BPFILTER_EXTENSION_MAXNAMELEN]; + __u8 revision; + } user; + struct { + __u16 target_size; + void *target; + } kernel; + __u16 target_size; + } u; + unsigned char data[0]; +}; + +struct bpfilter_ipt_standard_target { + struct bpfilter_ipt_target target; + int verdict; +}; + +struct bpfilter_ipt_error_target { + struct bpfilter_ipt_target target; + char error_name[BPFILTER_FUNCTION_MAXNAMELEN]; +}; + +struct bpfilter_ipt_get_info { + char name[BPFILTER_XT_TABLE_MAXNAMELEN]; + __u32 valid_hooks; + __u32 hook_entry[BPFILTER_INET_HOOK_MAX]; + __u32 underflow[BPFILTER_INET_HOOK_MAX]; + __u32 num_entries; + __u32 size; +}; + +struct bpfilter_ipt_counters { + __u64 packet_cnt; + __u64 byte_cnt; +}; + +struct bpfilter_ipt_counters_info { + char name[BPFILTER_XT_TABLE_MAXNAMELEN]; + __u32 num_counters; + struct bpfilter_ipt_counters counters[0]; +}; + +struct bpfilter_ipt_get_revision { + char name[BPFILTER_EXTENSION_MAXNAMELEN]; + __u8 revision; +}; + +struct bpfilter_ipt_ip { + __u32 src; + __u32 dst; + __u32 src_mask; + __u32 dst_mask; + char in_iface[IFNAMSIZ]; + char out_iface[IFNAMSIZ]; + __u8 in_iface_mask[IFNAMSIZ]; + __u8 out_iface_mask[IFNAMSIZ]; + __u16 protocol; + __u8 flags; + __u8 invflags; +}; + +struct bpfilter_ipt_entry { + struct bpfilter_ipt_ip ip; + __u32 bfcache; + __u16 target_offset; + __u16 next_offset; + __u32 comefrom; + struct bpfilter_ipt_counters counters; + __u8 elems[0]; +}; + +struct bpfilter_ipt_standard_entry { + struct bpfilter_ipt_entry entry; + struct bpfilter_ipt_standard_target target; +}; + +struct bpfilter_ipt_error_entry { + struct bpfilter_ipt_entry entry; + struct bpfilter_ipt_error_target target; +}; + +struct bpfilter_ipt_get_entries { + char name[BPFILTER_XT_TABLE_MAXNAMELEN]; + __u32 size; + struct bpfilter_ipt_entry entries[0]; +}; + +struct bpfilter_ipt_replace { + char name[BPFILTER_XT_TABLE_MAXNAMELEN]; + __u32 valid_hooks; + __u32 num_entries; + __u32 size; + __u32 hook_entry[BPFILTER_INET_HOOK_MAX]; + __u32 underflow[BPFILTER_INET_HOOK_MAX]; + __u32 num_counters; + struct bpfilter_ipt_counters *cntrs; + struct bpfilter_ipt_entry entries[0]; +}; + #endif /* _UAPI_LINUX_BPFILTER_H */ From patchwork Thu Jun 3 10:14:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitrii Banshchikov X-Patchwork-Id: 454620 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,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 4349EC47096 for ; Thu, 3 Jun 2021 10:14:52 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2B93D6138C for ; Thu, 3 Jun 2021 10:14:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229774AbhFCKQf (ORCPT ); Thu, 3 Jun 2021 06:16:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44244 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229661AbhFCKQd (ORCPT ); Thu, 3 Jun 2021 06:16:33 -0400 Received: from mail-wm1-x32e.google.com (mail-wm1-x32e.google.com [IPv6:2a00:1450:4864:20::32e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id ECE9EC061756 for ; Thu, 3 Jun 2021 03:14:48 -0700 (PDT) Received: by mail-wm1-x32e.google.com with SMTP id f17so3046336wmf.2 for ; Thu, 03 Jun 2021 03:14:48 -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=fuwQX9b3Q53MKMPqypL/AyJSs6wqqbe8JbkZm20C3Rg=; b=Ng1ja9QPTqcElrIgn69ls55E4UHCCtssErsfSm5LTgt0NIpaG3Vo4B6irV7ISd44+n ckSHdPiY7t3AZBbkwV4WEZmpRyeinTdfZy6ltxo0P7i2nuhtlFvmI3qacsL1tHhmnO2F oaRPQFj4S6q4ia9/RZi0mWh7SDr9lqmfn1fmJyoY9bobPPJqM+Fhah8t6TzetBUw9aoa mxmPu7Gd9ec6326uzUwWFzBbJPsGLcoacI35r05Gmklru7r8iyZyXFj4XFwCutLPIoUq iuu8ikdCbXvPJixNv3bEYm9kV3g+3nMPyD3SQBaq2KL+zr17L0x1Pn7nP8sbviHyRJc/ ALiQ== 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=fuwQX9b3Q53MKMPqypL/AyJSs6wqqbe8JbkZm20C3Rg=; b=Mpet+YoFcFPfsWrJlzB8nB5IVXh/bgTnf3AgJAuDPdOyKDVGFVN1TV6LADTgR8CW2S twup7UkSfiq7pPjgbB+qGuu2XQTy/EDgIk8pnioEHSdVu/fPdWrkn/YUOzgH/L41kGV/ zPEjtrdcNJKdhm0JK/Zxr4CjFs3COO+2fY8CCnTy89r6ho0XqfLx73tC1cCxnn30Es5J Z5EfDQT7ShVSAGn7p1csMfAY6Gi6kScwQoL7LwoleqsL6AlrEnyRoVm4uYBBslUlUGtB tPIbdYgOX7X5AQlnk7YicWWcH7uZI+CFm/gqOhYCIvE6/YrVdQyRuHtXGsdMh9A20U1k 74fw== X-Gm-Message-State: AOAM5301MR5h7EtQ7zJZjbitU0Zc3MRimClrzk13MJhWLxXQEcabbics oIRzA56gVGMskNM3ESWJZTmt8A== X-Google-Smtp-Source: ABdhPJyB7kax9YPkjpWJ1y8nT17B6XVNZrLMU1HKjcHvgOqaOOcsMskoFT+ToeQpczTEIT34me/9ww== X-Received: by 2002:a1c:7218:: with SMTP id n24mr9428382wmc.104.1622715287591; Thu, 03 Jun 2021 03:14:47 -0700 (PDT) Received: from localhost ([154.21.15.43]) by smtp.gmail.com with ESMTPSA id z19sm4581224wmf.31.2021.06.03.03.14.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Jun 2021 03:14:47 -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 v1 02/10] bpfilter: Add logging facility Date: Thu, 3 Jun 2021 14:14:17 +0400 Message-Id: <20210603101425.560384-3-me@ubique.spb.ru> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210603101425.560384-1-me@ubique.spb.ru> References: <20210603101425.560384-1-me@ubique.spb.ru> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org 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/context.h | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 net/bpfilter/context.h diff --git a/net/bpfilter/context.h b/net/bpfilter/context.h new file mode 100644 index 000000000000..e7bc27ee1ace --- /dev/null +++ b/net/bpfilter/context.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#ifndef NET_BPFILTER_CONTEXT_H +#define NET_BPFILTER_CONTEXT_H + +#include + +#include +#include + +struct context { + FILE *log_file; +}; + +#define BFLOG_IMPL(ctx, level, fmt, ...) \ + do { \ + if ((ctx)->log_file) \ + fprintf((ctx)->log_file, "<%d>bpfilter: " fmt, (level), ##__VA_ARGS__); \ + if ((level) == LOG_EMERG) \ + exit(EXIT_FAILURE); \ + } while (0) + +#define BFLOG_EMERG(ctx, fmt, ...) \ + BFLOG_IMPL(ctx, LOG_KERN | LOG_EMERG, "fatal error: " fmt, ##__VA_ARGS__) + +#define BFLOG_NOTICE(ctx, fmt, ...) BFLOG_IMPL(ctx, LOG_KERN | LOG_NOTICE, fmt, ##__VA_ARGS__) + +#if 0 +#define BFLOG_DEBUG(ctx, fmt, ...) BFLOG_IMPL(ctx, LOG_KERN | LOG_DEBUG, fmt, ##__VA_ARGS__) +#else +#define BFLOG_DEBUG(ctx, fmt, ...) +#endif + +#endif // NET_BPFILTER_CONTEXT_H From patchwork Thu Jun 3 10:14:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitrii Banshchikov X-Patchwork-Id: 454618 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,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 4D0C2C47097 for ; Thu, 3 Jun 2021 10:15:10 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2F9576138C for ; Thu, 3 Jun 2021 10:15:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230008AbhFCKQx (ORCPT ); Thu, 3 Jun 2021 06:16:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44260 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229751AbhFCKQx (ORCPT ); Thu, 3 Jun 2021 06:16:53 -0400 Received: from mail-wm1-x32e.google.com (mail-wm1-x32e.google.com [IPv6:2a00:1450:4864:20::32e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4FAABC061756 for ; Thu, 3 Jun 2021 03:14:52 -0700 (PDT) Received: by mail-wm1-x32e.google.com with SMTP id h12-20020a05600c350cb029019fae7a26cdso3333085wmq.5 for ; Thu, 03 Jun 2021 03:14:52 -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=r8pd42ryT9w+DfoVsWZ0ArQGHS2hWGNmOko7/7k+zfcTtxW0dzrh0UpCFzSRrrmFmn 5HJARz6vM+3uzPja/hIZowJ4r3jG7J6gD3Wf9i3DhIplB8KBzs6y1Tdo94vgW3yjdwyj Es95fcDq7uNyS04HWGy6S5LMbAhvhwdRYK55bdamAY06cTcmA4m0Z8FkkU6DsYvYB6bH lpU2aSxfRcQZdnh9doJqthcbhSZKYusKxWXTBZfDBey5vN2auVqdz5Du12vNcnlWtm2Q nPW+jjh//4vm+tCeh8CUIoX9Xsdd2+AtPRsC790A/Pt/6cMFzBHEKU+M3IGRv8PudCXs h8Eg== 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=U1ntuMg6R3gy6tCwjW8Wn8yANWZhNyZSwfl833Ij6UMOIAnT/Ol1l37UTM+LcDFPTs zGLoUZC5WnPRtWT6mYCjhYQThzmMEb6gh7yUSs4MYYDFG9akFRPau9yQGmzAkw/WCetQ n6DK6Hw/gs6ee0J7Lkq/8kWSRbGZ4EKzE+ygWssf4mY1BKwGBQMb0ojjT55PfzsIkbPz hk4kZMfdL1lQLtQQkmRSWHACv4L6j/ooeE9qSWw9gquQkB9aimf0ern2FY9rSE7Rg8C0 baRY7m139WYjoV59HHMoOVXmW2XsQlVv4/MbLQTEPA1pjwEGjzUy+z7KnyBcaFWZEKDx DxlQ== X-Gm-Message-State: AOAM530Dvrm5nQcP9+bzIM49XubjaUEtqdAaXDLP1/u25Gq/rTlo60wR rNymNQX4VNZGH9+edaxL5HPpzmAFjRD2Iq0m52k= X-Google-Smtp-Source: ABdhPJz3CSTrnqRsBuP5C7U2Dx5eOQ4a6aUyE/fJ0cr3a3hT4axC42iwz8SOuRjUX0poKi3G1aHuGA== X-Received: by 2002:a1c:65c2:: with SMTP id z185mr9568342wmb.2.1622715290891; Thu, 03 Jun 2021 03:14:50 -0700 (PDT) Received: from localhost ([154.21.15.43]) by smtp.gmail.com with ESMTPSA id l10sm1028528wrs.11.2021.06.03.03.14.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Jun 2021 03:14:50 -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 v1 03/10] tools: Add bpfilter usermode helper header Date: Thu, 3 Jun 2021 14:14:18 +0400 Message-Id: <20210603101425.560384-4-me@ubique.spb.ru> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210603101425.560384-1-me@ubique.spb.ru> References: <20210603101425.560384-1-me@ubique.spb.ru> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org 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 Thu Jun 3 10:14:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitrii Banshchikov X-Patchwork-Id: 453844 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, 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 6DB2CC47082 for ; Thu, 3 Jun 2021 10:14:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 557B2613E6 for ; Thu, 3 Jun 2021 10:14:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229913AbhFCKQl (ORCPT ); Thu, 3 Jun 2021 06:16:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44280 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229800AbhFCKQk (ORCPT ); Thu, 3 Jun 2021 06:16:40 -0400 Received: from mail-wm1-x32d.google.com (mail-wm1-x32d.google.com [IPv6:2a00:1450:4864:20::32d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B7AFDC06175F for ; Thu, 3 Jun 2021 03:14:55 -0700 (PDT) Received: by mail-wm1-x32d.google.com with SMTP id l11-20020a05600c4f0bb029017a7cd488f5so3399114wmq.0 for ; Thu, 03 Jun 2021 03:14:55 -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=epMo+f/eNlt4LlGPzfnkDskp+A+/a1y/gqFYWM9IJC8=; b=k71EdRkxQcirEAm7G4VJeaOuVbUmxDlMHgMpe5SSPMnAsHYGOd9dpFhwrKNvuYXmnj udk0sZs0umPQ+fG69vd67ZJCWJYDmykNHa89DxIgYptWb7WrgprYV/CJvOOCySEfEFk6 3CbGxJcsayFPncGds0rNZ8v1CYxvNW67y+T1YNOII4WUtG4PHzVYMHVPKuYMtOUCtRu1 c6bpaXtZyRM1P7sRA4dOL2SiPI/NYnqTs7/zxIr9UQUM47sW78Sc2kAovQT/UyXlQDYw Gy78ofFQdCtfFXL0Qgqem5YaS3yug67slA12xzgYEpDCORYh+0ec6HrwO7JTAkoQrsWF DQ/A== 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=epMo+f/eNlt4LlGPzfnkDskp+A+/a1y/gqFYWM9IJC8=; b=leKUPKJpm2y7aMRWkdisJrIu52tU2ikvq6y6+F/9dK5huPP14Iy6iPs3F9xS9QdGHT miiT+xZ7BerxS2b8PhOzGAEEmM5Nj+cgeE+U9/As8HFYFoj08gYDDBL1ah+Mj26QHZoB IxZWwAJRXY9L3HnEi1t4SpQlzoBFKmZwKZeAwm2bmrSn4g2PyQsreQRBbuLHeUweGTYL Ar10JE8adQ4PlKOjEtOKPkAGzqy8I3+Jo4PV0T26ze+Ospl4Uak1KZdrgiMg20V0ZCbz oLmCMJSMYXOCuis3FW/CqjXH8iFzZXKH7PNF1eyFRpyB/FfMHRPhmo9M8n35ZfEJqcQp 0Cdw== X-Gm-Message-State: AOAM531dJDWnO5kJtUKSG9Q3vcQUHR3I3gQ0IKjGLac+JutOoIQ4b8dH STPjefmWKiiSVt0sNT4IijrBiA== X-Google-Smtp-Source: ABdhPJzlibXpfWWZbItFVs1TbLYl8j1xe+IWHe4g323PqtGY4WMHhnGpkKic6h/ZD8W6hvjODNnXeg== X-Received: by 2002:a1c:d5:: with SMTP id 204mr9351093wma.144.1622715294299; Thu, 03 Jun 2021 03:14:54 -0700 (PDT) Received: from localhost ([154.21.15.43]) by smtp.gmail.com with ESMTPSA id s2sm5168987wmc.21.2021.06.03.03.14.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Jun 2021 03:14:54 -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 v1 04/10] bpfilter: Add map container Date: Thu, 3 Jun 2021 14:14:19 +0400 Message-Id: <20210603101425.560384-5-me@ubique.spb.ru> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210603101425.560384-1-me@ubique.spb.ru> References: <20210603101425.560384-1-me@ubique.spb.ru> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Introduce common code for an associative container. This common code will be used for maps of matches, targets and tables. Hash search tables from libc are used as an index. The supported set of operations is: insert, update and find. Signed-off-by: Dmitrii Banshchikov --- net/bpfilter/Makefile | 2 +- net/bpfilter/map-common.c | 64 +++++++++++++++++++ net/bpfilter/map-common.h | 19 ++++++ .../testing/selftests/bpf/bpfilter/.gitignore | 2 + tools/testing/selftests/bpf/bpfilter/Makefile | 17 +++++ .../testing/selftests/bpf/bpfilter/test_map.c | 63 ++++++++++++++++++ 6 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 net/bpfilter/map-common.c create mode 100644 net/bpfilter/map-common.h create mode 100644 tools/testing/selftests/bpf/bpfilter/.gitignore create mode 100644 tools/testing/selftests/bpf/bpfilter/Makefile create mode 100644 tools/testing/selftests/bpf/bpfilter/test_map.c diff --git a/net/bpfilter/Makefile b/net/bpfilter/Makefile index cdac82b8c53a..1809759d08c4 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 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 new file mode 100644 index 000000000000..983fd06cbefa --- /dev/null +++ b/tools/testing/selftests/bpf/bpfilter/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +test_map diff --git a/tools/testing/selftests/bpf/bpfilter/Makefile b/tools/testing/selftests/bpf/bpfilter/Makefile new file mode 100644 index 000000000000..647229a0596c --- /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_map + +KSFT_KHDR_INSTALL := 1 + +include ../../lib.mk + +$(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 Thu Jun 3 10:14:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitrii Banshchikov X-Patchwork-Id: 454617 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=-14.0 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, 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 0B16FC47082 for ; Thu, 3 Jun 2021 10:16:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E2C12613FE for ; Thu, 3 Jun 2021 10:15:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230036AbhFCKRn (ORCPT ); Thu, 3 Jun 2021 06:17:43 -0400 Received: from mail-wm1-f42.google.com ([209.85.128.42]:43566 "EHLO mail-wm1-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229640AbhFCKRm (ORCPT ); Thu, 3 Jun 2021 06:17:42 -0400 Received: by mail-wm1-f42.google.com with SMTP id 3-20020a05600c0243b029019f2f9b2b8aso3365890wmj.2 for ; Thu, 03 Jun 2021 03:15:58 -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=jkMzs1gZP+Wiqtomowse5B6kMYYJOzZY6aRSXqIG0JI=; b=BP/RfwVZGL+MhCm8VqSNAn55REi0aIYV2Kcns2mEiX4rlB304AV6bA0avduvHA2ugd tQYNCkJhRzMcfuRyIxfdJLfXD8WDfBtY3GF0ZIWy0tnocK0MDMpf3AGgsJfh0pvWRdQB rzwloZoBNngrnmsYp1QLusYiPu/39qN7Y+/pKT1jDkIMqSRoQhrJz/1IrkGy5inB9SI8 Jpwpk1uU1XIeilRPBAqFv27nApn1WsktdjvuJhlVeDbMzoiyp2vZO4if8jPI4WwtCG1P mul3/zbII50GwBWZKV3azd7YsQ/IlslkMmU7kR2vVvO+R09Gjq3HJuGHejd+ez3tA8mr EjfA== 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=jkMzs1gZP+Wiqtomowse5B6kMYYJOzZY6aRSXqIG0JI=; b=ptw8AOHisFtIXMhGaUjgPvVUiL59wMB72bRFfqfCaov19O+7cmaY426nhv+Py73Uue vks5lY0JNl9pBtWAgoglc1AbawvpWNovfW3D2lr4/GNlejTBQ5jdvZJsmMV6rv1mLWZC yF4Prtjvf3O5AGPBfAIBf+5AzfXncAAvstHu2HGzue3bv7EHo+zwX6aVo6nkYggVwG93 zlCPr3Bg69l+zsd6O0HiICMGExcFs+FQCoShpeq48n5OnboPA9kofgZmHtXesaWrIYG4 ZhZwomKe7GlzAYKmiFY0urne+g+9p2w3nuT8WuCOpVaSdpYaG0rVwVzIK0Dz/E1HOGsA kShA== X-Gm-Message-State: AOAM530nnssoqa4ofIdwkKXqZ6QpterNpHdBPHf4onY0yTYjmdOswN+R zykpoA4av0oq2zCOQ3Tymdc2ZA== X-Google-Smtp-Source: ABdhPJxTdC/yusBsxx+f4anipFDmYksJN/Jq/7hqvQ9LgHWeydhYim9rEbsUbTSji2FChKlxWnC/9g== X-Received: by 2002:a1c:7907:: with SMTP id l7mr20748100wme.147.1622715297711; Thu, 03 Jun 2021 03:14:57 -0700 (PDT) Received: from localhost ([154.21.15.43]) by smtp.gmail.com with ESMTPSA id y6sm5371063wmy.23.2021.06.03.03.14.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Jun 2021 03:14:57 -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 v1 05/10] bpfilter: Add struct match Date: Thu, 3 Jun 2021 14:14:20 +0400 Message-Id: <20210603101425.560384-6-me@ubique.spb.ru> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210603101425.560384-1-me@ubique.spb.ru> References: <20210603101425.560384-1-me@ubique.spb.ru> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org 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 a map by their name. Signed-off-by: Dmitrii Banshchikov --- net/bpfilter/Makefile | 3 +- net/bpfilter/context.c | 44 +++++++++++++ net/bpfilter/context.h | 5 ++ net/bpfilter/match.c | 49 +++++++++++++++ net/bpfilter/match.h | 33 ++++++++++ net/bpfilter/xt_udp.c | 33 ++++++++++ .../testing/selftests/bpf/bpfilter/.gitignore | 1 + tools/testing/selftests/bpf/bpfilter/Makefile | 7 +++ .../selftests/bpf/bpfilter/test_match.c | 63 +++++++++++++++++++ 9 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 net/bpfilter/context.c create mode 100644 net/bpfilter/match.c create mode 100644 net/bpfilter/match.h create mode 100644 net/bpfilter/xt_udp.c create mode 100644 tools/testing/selftests/bpf/bpfilter/test_match.c diff --git a/net/bpfilter/Makefile b/net/bpfilter/Makefile index 1809759d08c4..59f2d35c1627 100644 --- a/net/bpfilter/Makefile +++ b/net/bpfilter/Makefile @@ -4,7 +4,8 @@ # userprogs := bpfilter_umh -bpfilter_umh-objs := main.o map-common.o +bpfilter_umh-objs := main.o map-common.o match.o context.o +bpfilter_umh-objs += xt_udp.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..6b6203dd22a7 --- /dev/null +++ b/net/bpfilter/context.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#define _GNU_SOURCE + +#include "context.h" + +#include +#include + +#include "map-common.h" +#include "match.h" + +static int init_match_ops_map(struct context *ctx) +{ + const struct match_ops *match_ops[] = { &xt_udp }; + int i, err; + + err = create_map(&ctx->match_ops_map, ARRAY_SIZE(match_ops)); + if (err) + return err; + + for (i = 0; i < ARRAY_SIZE(match_ops); ++i) { + const struct match_ops *m = match_ops[i]; + + err = map_insert(&ctx->match_ops_map, m->name, (void *)m); + 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_map(&ctx->match_ops_map); +} diff --git a/net/bpfilter/context.h b/net/bpfilter/context.h index e7bc27ee1ace..60bb525843b0 100644 --- a/net/bpfilter/context.h +++ b/net/bpfilter/context.h @@ -10,9 +10,11 @@ #include #include +#include struct context { FILE *log_file; + struct hsearch_data match_ops_map; }; #define BFLOG_IMPL(ctx, level, fmt, ...) \ @@ -34,4 +36,7 @@ struct context { #define BFLOG_DEBUG(ctx, fmt, ...) #endif +int create_context(struct context *ctx); +void free_context(struct context *ctx); + #endif // NET_BPFILTER_CONTEXT_H diff --git a/net/bpfilter/match.c b/net/bpfilter/match.c new file mode 100644 index 000000000000..3b49196efabf --- /dev/null +++ b/net/bpfilter/match.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#define _GNU_SOURCE + +#include "match.h" + +#include + +#include +#include + +#include "context.h" +#include "map-common.h" + +int init_match(struct context *ctx, const struct bpfilter_ipt_match *ipt_match, struct match *match) +{ + const size_t maxlen = sizeof(ipt_match->u.user.name); + const struct match_ops *found; + int err; + + if (strnlen(ipt_match->u.user.name, maxlen) == maxlen) { + BFLOG_DEBUG(ctx, "cannot init match: too long match name\n"); + return -EINVAL; + } + + found = 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 + sizeof(*ipt_match) != 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..9879a3670711 --- /dev/null +++ b/net/bpfilter/match.h @@ -0,0 +1,33 @@ +/* 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 { + char name[BPFILTER_EXTENSION_MAXNAMELEN]; + uint8_t revision; + uint16_t size; + int (*check)(struct context *ctx, const struct bpfilter_ipt_match *ipt_match); +}; + +struct match { + const struct match_ops *match_ops; + const struct bpfilter_ipt_match *ipt_match; +}; + +extern const struct match_ops xt_udp; + +int init_match(struct context *ctx, const struct bpfilter_ipt_match *ipt_match, + struct match *match); + +#endif // NET_BPFILTER_MATCH_H diff --git a/net/bpfilter/xt_udp.c b/net/bpfilter/xt_udp.c new file mode 100644 index 000000000000..a7fbe77a53cc --- /dev/null +++ b/net/bpfilter/xt_udp.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#define _GNU_SOURCE + +#include +#include + +#include + +#include "context.h" +#include "match.h" + +static int xt_udp_check(struct context *ctx, const struct bpfilter_ipt_match *ipt_match) +{ + const struct xt_udp *udp; + + udp = (const struct xt_udp *)&ipt_match->data; + + if (udp->invflags & XT_UDP_INV_MASK) { + BFLOG_DEBUG(ctx, "cannot check match 'udp': invalid flags\n"); + return -EINVAL; + } + + return 0; +} + +const struct match_ops xt_udp = { .name = "udp", + .size = XT_ALIGN(sizeof(struct xt_udp)), + .revision = 0, + .check = xt_udp_check }; diff --git a/tools/testing/selftests/bpf/bpfilter/.gitignore b/tools/testing/selftests/bpf/bpfilter/.gitignore index 983fd06cbefa..9250411fa7aa 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_map +test_match diff --git a/tools/testing/selftests/bpf/bpfilter/Makefile b/tools/testing/selftests/bpf/bpfilter/Makefile index 647229a0596c..0ef156cdb198 100644 --- a/tools/testing/selftests/bpf/bpfilter/Makefile +++ b/tools/testing/selftests/bpf/bpfilter/Makefile @@ -9,9 +9,16 @@ BPFILTERSRCDIR := $(top_srcdir)/net/bpfilter CFLAGS += -Wall -g -pthread -I$(TOOLSINCDIR) -I$(APIDIR) -I$(BPFILTERSRCDIR) TEST_GEN_PROGS += test_map +TEST_GEN_PROGS += test_match KSFT_KHDR_INSTALL := 1 include ../../lib.mk +BPFILTER_MATCH_SRCS := $(BPFILTERSRCDIR)/match.c $(BPFILTERSRCDIR)/xt_udp.c + +BPFILTER_COMMON_SRCS := $(BPFILTERSRCDIR)/map-common.c $(BPFILTERSRCDIR)/context.c +BPFILTER_COMMON_SRCS += $(BPFILTER_MATCH_SRCS) + $(OUTPUT)/test_map: test_map.c $(BPFILTERSRCDIR)/map-common.c +$(OUTPUT)/test_match: test_match.c $(BPFILTER_COMMON_SRCS) $(BPFILTER_MATCH_SRCS) 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 Thu Jun 3 10:14:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitrii Banshchikov X-Patchwork-Id: 453843 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, 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 9F1B5C47082 for ; Thu, 3 Jun 2021 10:15:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 889076138C for ; Thu, 3 Jun 2021 10:15:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229982AbhFCKQt (ORCPT ); Thu, 3 Jun 2021 06:16:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44314 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229751AbhFCKQs (ORCPT ); Thu, 3 Jun 2021 06:16:48 -0400 Received: from mail-wm1-x334.google.com (mail-wm1-x334.google.com [IPv6:2a00:1450:4864:20::334]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9432FC06174A for ; Thu, 3 Jun 2021 03:15:03 -0700 (PDT) Received: by mail-wm1-x334.google.com with SMTP id o2-20020a05600c4fc2b029019a0a8f959dso3370220wmq.1 for ; Thu, 03 Jun 2021 03:15:03 -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=aEiyt3MJY6e5YXgHHhWN4KgHY+n/a4B+avDndi1JqsY=; b=oEQTXzJpdvblN8imrOhVlngUzPPr9UK5ybRVBMFrFb7pz8jyUK1bcY8FENEG3WAMQl T6u7m8ISYgAw3brmvVIx8mt4VHdQurtswn1/e5FAWRouifRPlcQD4fSYa1ZbzI0fcJ5r p+j2VrOF9o5w99ANWSlCV5lBelorSRp89jTcK9MnhDUe5PFoKOQ3LKqBaCsrQRCUZ/q0 hHv1NWC1BNHNouPKQ5NZvJB4TbPWFDvY++T3w7bi4FsrNK/cEkM9A4phon87TrCNvvN0 bP1NcIm6+015jhdfYpCumoCbyPAJjBK5dD/+g6Q+LOTiN7Tcr6AqfnUtmg+VVdDUtq5u lOaw== 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=aEiyt3MJY6e5YXgHHhWN4KgHY+n/a4B+avDndi1JqsY=; b=G5XFBIEEHcUhAfRpcrAfP8480Nif8ao3zidv7YxpIn5zhc0a1f30HGm9e5CrPCuGUH kiB+NDWs6XT0kFGxZtGBaeoZLZqHQO6me3MJqemT8WN4dzV9yKz4Uz4CNR9dD+Y95bME kt2eFudoU71NPNgzOc00e0abBdFwVBH4LgOyBOn4tDzGiAWyeirP5BC+EHpchuaP0V0g hnsjUKZK5fo8RfkDqKPlZfUmTKx89RIGPdY5AyC0/hErUcMSexVBf5WlHB1bSgzsZt34 lTbXzk14dvjLII5HLxWj5aQe6b6xIiCXD1k6GrlzXFtSo6DtTnK58SJlUA9B7qrp5zxF hD2g== X-Gm-Message-State: AOAM532cBIRw/9KLgsI5xldql6LcRKPH6LMdBKqz8jZb86hy4dxPbwaC b1rtcX9wiRoN/i3n/qxYVImljQ== X-Google-Smtp-Source: ABdhPJxt1jjl43U0wav1qnigIiz7nstlP6jD0wfIxekVvDzo3eO54vf7uo5F6kuv7K1a1RRoDgDPbA== X-Received: by 2002:a1c:b783:: with SMTP id h125mr9490811wmf.182.1622715302114; Thu, 03 Jun 2021 03:15:02 -0700 (PDT) Received: from localhost ([154.21.15.43]) by smtp.gmail.com with ESMTPSA id p6sm2983321wrf.51.2021.06.03.03.15.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Jun 2021 03:15:01 -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 v1 06/10] bpfilter: Add struct target Date: Thu, 3 Jun 2021 14:14:21 +0400 Message-Id: <20210603101425.560384-7-me@ubique.spb.ru> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210603101425.560384-1-me@ubique.spb.ru> References: <20210603101425.560384-1-me@ubique.spb.ru> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org struct target_ops defines polymorphic interface for targets. A target consists of pointers to struct target_ops and struct xt_entry_target which contains a payload for the target's type. All target_ops are kept in a map by their name. Signed-off-by: Dmitrii Banshchikov --- .clang-format | 2 +- net/bpfilter/Makefile | 2 +- net/bpfilter/context.c | 36 +++++- net/bpfilter/context.h | 1 + net/bpfilter/target.c | 118 ++++++++++++++++++ net/bpfilter/target.h | 49 ++++++++ .../testing/selftests/bpf/bpfilter/.gitignore | 1 + tools/testing/selftests/bpf/bpfilter/Makefile | 7 +- .../selftests/bpf/bpfilter/bpfilter_util.h | 31 +++++ .../selftests/bpf/bpfilter/test_target.c | 85 +++++++++++++ 10 files changed, 327 insertions(+), 5 deletions(-) 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/.clang-format b/.clang-format index c24b147cac01..3212542df113 100644 --- a/.clang-format +++ b/.clang-format @@ -52,7 +52,7 @@ BreakConstructorInitializersBeforeComma: false #BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0 BreakAfterJavaFieldAnnotations: false BreakStringLiterals: false -ColumnLimit: 80 +ColumnLimit: 100 CommentPragmas: '^ IWYU pragma:' #CompactNamespaces: false # Unknown to clang-format-4.0 ConstructorInitializerAllOnOneLineOrOnePerLine: false diff --git a/net/bpfilter/Makefile b/net/bpfilter/Makefile index 59f2d35c1627..031c9dd40d2d 100644 --- a/net/bpfilter/Makefile +++ b/net/bpfilter/Makefile @@ -4,7 +4,7 @@ # userprogs := bpfilter_umh -bpfilter_umh-objs := main.o map-common.o match.o context.o +bpfilter_umh-objs := main.o map-common.o context.o match.o target.o bpfilter_umh-objs += xt_udp.o userccflags += -I $(srctree)/tools/include/ -I $(srctree)/tools/include/uapi diff --git a/net/bpfilter/context.c b/net/bpfilter/context.c index 6b6203dd22a7..6e186399609e 100644 --- a/net/bpfilter/context.c +++ b/net/bpfilter/context.c @@ -12,6 +12,7 @@ #include "map-common.h" #include "match.h" +#include "target.h" static int init_match_ops_map(struct context *ctx) { @@ -33,12 +34,45 @@ 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_map(&ctx->target_ops_map, ARRAY_SIZE(target_ops)); + if (err) + return err; + + for (i = 0; i < ARRAY_SIZE(target_ops); ++i) { + const struct target_ops *t = target_ops[i]; + + err = map_insert(&ctx->target_ops_map, t->name, (void *)t); + 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_map(&ctx->match_ops_map); + return err; + } + + return 0; } void free_context(struct context *ctx) { free_map(&ctx->match_ops_map); + free_map(&ctx->target_ops_map); } diff --git a/net/bpfilter/context.h b/net/bpfilter/context.h index 60bb525843b0..ed268259adcc 100644 --- a/net/bpfilter/context.h +++ b/net/bpfilter/context.h @@ -15,6 +15,7 @@ struct context { FILE *log_file; struct hsearch_data match_ops_map; + struct hsearch_data target_ops_map; }; #define BFLOG_IMPL(ctx, level, fmt, ...) \ diff --git a/net/bpfilter/target.c b/net/bpfilter/target.c new file mode 100644 index 000000000000..f87ef719ea4d --- /dev/null +++ b/net/bpfilter/target.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#define _GNU_SOURCE + +#include "target.h" + +#include +#include + +#include +#include + +#include "context.h" +#include "map-common.h" + +static const struct target_ops *target_ops_map_find(struct hsearch_data *map, const char *name) +{ + const size_t namelen = strnlen(name, BPFILTER_EXTENSION_MAXNAMELEN); + + if (namelen < BPFILTER_EXTENSION_MAXNAMELEN) + return map_find(map, name); + + return ERR_PTR(-EINVAL); +} + +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; + + // Positive values of verdict denote a jump offset into a blob. + if (standard_target->verdict > 0) + return 0; + + // Special values like ACCEPT, DROP, RETURN are encoded as negative values. + 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..e27816d73cc2 --- /dev/null +++ b/net/bpfilter/target.h @@ -0,0 +1,49 @@ +/* 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]; + uint8_t revision; + uint16_t size; + 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; + +/* Restore verdict's special value(ACCEPT, DROP, etc.) from its negative representation. */ +static inline int convert_verdict(int verdict) +{ + return -verdict - 1; +} + +static inline int standard_target_verdict(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; + + return standard_target->verdict; +} + +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 9250411fa7aa..7e077f506af1 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_map test_match +test_target diff --git a/tools/testing/selftests/bpf/bpfilter/Makefile b/tools/testing/selftests/bpf/bpfilter/Makefile index 0ef156cdb198..a11775e8b5af 100644 --- a/tools/testing/selftests/bpf/bpfilter/Makefile +++ b/tools/testing/selftests/bpf/bpfilter/Makefile @@ -10,15 +10,18 @@ CFLAGS += -Wall -g -pthread -I$(TOOLSINCDIR) -I$(APIDIR) -I$(BPFILTERSRCDIR) TEST_GEN_PROGS += test_map TEST_GEN_PROGS += test_match +TEST_GEN_PROGS += test_target KSFT_KHDR_INSTALL := 1 include ../../lib.mk BPFILTER_MATCH_SRCS := $(BPFILTERSRCDIR)/match.c $(BPFILTERSRCDIR)/xt_udp.c +BPFILTER_TARGET_SRCS := $(BPFILTERSRCDIR)/target.c BPFILTER_COMMON_SRCS := $(BPFILTERSRCDIR)/map-common.c $(BPFILTERSRCDIR)/context.c -BPFILTER_COMMON_SRCS += $(BPFILTER_MATCH_SRCS) +BPFILTER_COMMON_SRCS += $(BPFILTER_MATCH_SRCS) $(BPFILTER_TARGET_SRCS) $(OUTPUT)/test_map: test_map.c $(BPFILTERSRCDIR)/map-common.c -$(OUTPUT)/test_match: test_match.c $(BPFILTER_COMMON_SRCS) $(BPFILTER_MATCH_SRCS) +$(OUTPUT)/test_match: test_match.c $(BPFILTER_COMMON_SRCS) +$(OUTPUT)/test_target: test_target.c $(BPFILTER_COMMON_SRCS) diff --git a/tools/testing/selftests/bpf/bpfilter/bpfilter_util.h b/tools/testing/selftests/bpf/bpfilter/bpfilter_util.h new file mode 100644 index 000000000000..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 Thu Jun 3 10:14:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitrii Banshchikov X-Patchwork-Id: 453841 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, 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 C0B90C47096 for ; Thu, 3 Jun 2021 10:16:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9E46761287 for ; Thu, 3 Jun 2021 10:16:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230044AbhFCKRv (ORCPT ); Thu, 3 Jun 2021 06:17:51 -0400 Received: from mail-wr1-f46.google.com ([209.85.221.46]:39677 "EHLO mail-wr1-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229640AbhFCKRu (ORCPT ); Thu, 3 Jun 2021 06:17:50 -0400 Received: by mail-wr1-f46.google.com with SMTP id l2so5263614wrw.6 for ; Thu, 03 Jun 2021 03:16:06 -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=y8W3XdtBsyo4G7m2GOlm4F23ti6XMBPdC4TasHorY8U=; b=r6nOTOVt5iuhnwfTN0/shMtC0jshcHLjtJdP7YGywikchCo7u7hAnAuX1TP3e+UWSd YVH7+QRXbL87kDLvAqLXbB4UbBcPL8HTLxIP346WUvGP78aZjtW+Gu3qoCNiro+hFTrx Iei9hm35IE4HGMJF5BaxPeaM4g5VhqEOH3W5QNru+JM8LQtRg31LySqufrII4lxMslgf +uP9URCS+qCc9lPr5HpEJHJvmkN+mcr93ymNwzy/VSgi8kXrbA4tDOJ65/msz95XOddz RZTFPZ/Cmf2J4C4ftrVQ4lBlTyrv5+YayCJAruuyLGVHX4EiR70HnPj9RjS/oLgjZufk DIBQ== 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=y8W3XdtBsyo4G7m2GOlm4F23ti6XMBPdC4TasHorY8U=; b=er5CmNbT6jtr6/BbF75uNq1KuFIAxXkiHk0IKeub3DV6+hn/Up1LX/KlUxr55XMB5g Exat8lLExg3iyaJTHlpkM+q918yhabcga3UAfwnMvKG/c9o66BRQSaKXv4DKFP1toSeC O5ZN4q5dh4R9FQeC0LJpMZvnVX1PeKcRghEOQgMFwoxvqkps9nyc0dFhloizV5d2WYqX gahfHuBMOawkbYJhHuKzq4W3z2O8qFViBAlQsejULoNwvSabyS2gucNP3DVmXyrDE6kF ksyGNTWGxCCxx1wckvpgBLm1YcHiPnRwEP57EFsPIqhCuUfAeOcZlLIT991c7BvdlQOV 4uig== X-Gm-Message-State: AOAM5338UfBS13P7qUz3wegRAIMp7iraj++tPkEAuQBqZTmsQiGaQ9FS qhA/ElHSsKBg+6obn9wyseHGPKhWnLUfjQgv2AA= X-Google-Smtp-Source: ABdhPJw2hbGU8yvOrHPYQOT+gkY9gGKgAupue+G4io0kYzK8fkoD8IQVUflOPGNaUSQ1cfTZp0z6TQ== X-Received: by 2002:a5d:5902:: with SMTP id v2mr25405209wrd.272.1622715305598; Thu, 03 Jun 2021 03:15:05 -0700 (PDT) Received: from localhost ([154.21.15.43]) by smtp.gmail.com with ESMTPSA id 30sm3052943wrl.37.2021.06.03.03.15.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Jun 2021 03:15:05 -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 v1 07/10] bpfilter: Add struct rule Date: Thu, 3 Jun 2021 14:14:22 +0400 Message-Id: <20210603101425.560384-8-me@ubique.spb.ru> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210603101425.560384-1-me@ubique.spb.ru> References: <20210603101425.560384-1-me@ubique.spb.ru> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org struct rule is an equivalent of struct ipt_entry. A rule consists of zero or more matches and a target. A rule has a pointer to its ipt_entry in 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 | 163 ++++++++++++++++++ net/bpfilter/rule.h | 32 ++++ .../testing/selftests/bpf/bpfilter/.gitignore | 1 + tools/testing/selftests/bpf/bpfilter/Makefile | 5 +- .../selftests/bpf/bpfilter/bpfilter_util.h | 8 + .../selftests/bpf/bpfilter/test_rule.c | 55 ++++++ 7 files changed, 264 insertions(+), 2 deletions(-) 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 031c9dd40d2d..7ce961162283 100644 --- a/net/bpfilter/Makefile +++ b/net/bpfilter/Makefile @@ -4,7 +4,7 @@ # userprogs := bpfilter_umh -bpfilter_umh-objs := main.o map-common.o context.o match.o target.o +bpfilter_umh-objs := main.o map-common.o context.o match.o target.o rule.o bpfilter_umh-objs += xt_udp.o userccflags += -I $(srctree)/tools/include/ -I $(srctree)/tools/include/uapi diff --git a/net/bpfilter/rule.c b/net/bpfilter/rule.c new file mode 100644 index 000000000000..6018b4b7c0cc --- /dev/null +++ b/net/bpfilter/rule.c @@ -0,0 +1,163 @@ +// 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 +#include + +#include "context.h" +#include "match.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 ((uintptr_t)ipt_match % __alignof__(struct bpfilter_ipt_match)) + return -EINVAL; + + if (ipt_entry->target_offset < offset + sizeof(*ipt_match)) + return -EINVAL; + + if (ipt_match->u.match_size < sizeof(*ipt_match)) + return -EINVAL; + + 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 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) { + free(rule->matches); + rule->matches = NULL; + return err; + } + + ++match; + offset += ipt_match->u.match_size; + } + + return 0; +} + +static int check_ipt_entry_ip(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; +} + +bool rule_has_standard_target(const struct rule *rule) +{ + return rule->target.target_ops == &standard_target_ops; +} + +bool is_rule_unconditional(const struct rule *rule) +{ + static const struct bpfilter_ipt_ip unconditional; + + if (rule->num_matches) + return false; + + return !memcmp(&rule->ipt_entry->ip, &unconditional, sizeof(unconditional)); +} + +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(&ipt_entry->ip); + if (err) + return err; + + if (ipt_entry->target_offset < sizeof(*ipt_entry)) + return -EINVAL; + + if (ipt_entry->next_offset < ipt_entry->target_offset + sizeof(*ipt_target)) + return -EINVAL; + + ipt_target = ipt_entry_target(ipt_entry); + + if (ipt_target->u.target_size < sizeof(*ipt_target)) + return -EINVAL; + + if (ipt_entry->next_offset < ipt_entry->target_offset + ipt_target->u.target_size) + return -EINVAL; + + err = init_target(ctx, ipt_target, &rule->target); + if (err) + return err; + + if (rule_has_standard_target(rule)) { + if (XT_ALIGN(ipt_entry->target_offset + + sizeof(struct bpfilter_ipt_standard_target)) != ipt_entry->next_offset) + return -EINVAL; + } + + rule->num_matches = ipt_entry_num_matches(ipt_entry); + if (rule->num_matches < 0) + return rule->num_matches; + + return init_rule_matches(ctx, ipt_entry, rule); +} + +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..cf879a19c670 --- /dev/null +++ b/net/bpfilter/rule.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#ifndef NET_BPFILTER_RULE_H +#define NET_BPFILTER_RULE_H + +#include +#include + +#include "target.h" + +struct bpfilter_ipt_entry; +struct context; +struct match; + +struct rule { + const struct bpfilter_ipt_entry *ipt_entry; + uint32_t came_from; + uint32_t hook_mask; + uint16_t num_matches; + struct match *matches; + struct target target; +}; + +bool rule_has_standard_target(const struct rule *rule); +bool is_rule_unconditional(const struct rule *rule); +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 7e077f506af1..4d7c5083d980 100644 --- a/tools/testing/selftests/bpf/bpfilter/.gitignore +++ b/tools/testing/selftests/bpf/bpfilter/.gitignore @@ -2,3 +2,4 @@ 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 a11775e8b5af..27a1ddcb6dc9 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_map TEST_GEN_PROGS += test_match TEST_GEN_PROGS += test_target +TEST_GEN_PROGS += test_rule KSFT_KHDR_INSTALL := 1 @@ -19,9 +20,11 @@ include ../../lib.mk BPFILTER_MATCH_SRCS := $(BPFILTERSRCDIR)/match.c $(BPFILTERSRCDIR)/xt_udp.c BPFILTER_TARGET_SRCS := $(BPFILTERSRCDIR)/target.c -BPFILTER_COMMON_SRCS := $(BPFILTERSRCDIR)/map-common.c $(BPFILTERSRCDIR)/context.c +BPFILTER_COMMON_SRCS := $(BPFILTERSRCDIR)/map-common.c $(BPFILTERSRCDIR)/context.c \ + $(BPFILTERSRCDIR)/rule.c BPFILTER_COMMON_SRCS += $(BPFILTER_MATCH_SRCS) $(BPFILTER_TARGET_SRCS) $(OUTPUT)/test_map: test_map.c $(BPFILTERSRCDIR)/map-common.c $(OUTPUT)/test_match: test_match.c $(BPFILTER_COMMON_SRCS) $(OUTPUT)/test_target: test_target.c $(BPFILTER_COMMON_SRCS) +$(OUTPUT)/test_rule: test_rule.c $(BPFILTER_COMMON_SRCS) 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 Thu Jun 3 10:14:23 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitrii Banshchikov X-Patchwork-Id: 454615 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,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 3858FC47097 for ; Thu, 3 Jun 2021 10:16:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 23D1B61359 for ; Thu, 3 Jun 2021 10:16:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230055AbhFCKSK (ORCPT ); Thu, 3 Jun 2021 06:18:10 -0400 Received: from mail-wm1-f48.google.com ([209.85.128.48]:42746 "EHLO mail-wm1-f48.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230025AbhFCKSG (ORCPT ); Thu, 3 Jun 2021 06:18:06 -0400 Received: by mail-wm1-f48.google.com with SMTP id o2-20020a05600c4fc2b029019a0a8f959dso3370500wmq.1 for ; Thu, 03 Jun 2021 03:16:09 -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=MWVBG8bhTEvfTNX0c7USO3GdvAznp6eDvMG3ty9z5II=; b=s4x5M5RYrYZvr65JyalSxELpLfoJHYifiEwUAEIxZ1+isRiIJSY3bnItvux5TxzUMX A3ZEysA3/LtnLl7U0V3r7ywU6DqfEKLua2UcG5NStcCpDc0HOBfjnfmLdQYN4ppG5O3A EB0ELyuJtkIQNhd0xx38fgx+bZwfRuVjlaZTzMiRy5MmWWe/cQZDzhdNMf9UuLYR2rm4 ixak4HgPdBjUdI/N4mEo3QaYy3sIwI9V+Y9aTf714/L6pjsCfZ+0btn71XiOQCFRKUAP cPYM4oL6o1L55CkSHc4hb4QAdhNAFOLQDmqZsi6xu6Zv/P0phNU84SaY4MHsrIX7IRwO uEOA== 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=MWVBG8bhTEvfTNX0c7USO3GdvAznp6eDvMG3ty9z5II=; b=Ck8KwZmgm5hCtg0HOawtr218Gx8TDjAnnydnadTzzeZPe5qz/7UGBj/jQtwCu0iRZe jsHTiYew+e7u9JZSkx152HxMxuvEJMx2RpPmiAAOAqZvT91XBUfEZ7UG2RamMWIQQzpv 0oMuG+1hi+l5EOcBe5IqL8XBJxEJmlptAv4ehToKZ+JAAEHRChcanNtMnBtgSGDCWE9Y s2tzPOt10jxSw/STtCfwkv7UNbN0raynJCOeXC62AzW50bp81QOl9SRLlBVF1asEcmQ5 yGhKV8nCWuicrxruYw/fcdMZr/+VCMN3b9eKXFIUI2jjm7tlfgfCMeaYfUoULUvA+oPZ QcqA== X-Gm-Message-State: AOAM530GFO9+2epJrukbTLXtoPzHJFkHrGoC5hWMbAZl3RYzaNhM5XT6 Ut2K3VCE/iD4Y3rMTccyhZiN3g== X-Google-Smtp-Source: ABdhPJzY9Lk15AJLUhUFbRzauVo+JS14USdSjVB1SMw90oo7usk79KrfTvbRDLDTIxpso0fmOxDn+g== X-Received: by 2002:a05:600c:19d3:: with SMTP id u19mr4430741wmq.100.1622715308959; Thu, 03 Jun 2021 03:15:08 -0700 (PDT) Received: from localhost ([154.21.15.43]) by smtp.gmail.com with ESMTPSA id i12sm2293739wmq.7.2021.06.03.03.15.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Jun 2021 03:15:08 -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 v1 08/10] bpfilter: Add struct table Date: Thu, 3 Jun 2021 14:14:23 +0400 Message-Id: <20210603101425.560384-9-me@ubique.spb.ru> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210603101425.560384-1-me@ubique.spb.ru> References: <20210603101425.560384-1-me@ubique.spb.ru> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org A table keeps iptables' blob and an array of struct rule for this blob. The array of rules provides more convenient way to interact with blob's entries. All tables are stored in a 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 | 5 +- net/bpfilter/table.c | 339 ++++++++++++++++++ net/bpfilter/table.h | 39 ++ tools/testing/selftests/bpf/bpfilter/Makefile | 2 +- 6 files changed, 487 insertions(+), 3 deletions(-) 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 7ce961162283..e16fee837ca0 100644 --- a/net/bpfilter/Makefile +++ b/net/bpfilter/Makefile @@ -4,7 +4,7 @@ # userprogs := bpfilter_umh -bpfilter_umh-objs := main.o map-common.o context.o match.o target.o rule.o +bpfilter_umh-objs := main.o map-common.o context.o match.o target.o rule.o table.o bpfilter_umh-objs += xt_udp.o userccflags += -I $(srctree)/tools/include/ -I $(srctree)/tools/include/uapi diff --git a/net/bpfilter/context.c b/net/bpfilter/context.c index 6e186399609e..beb4454d1218 100644 --- a/net/bpfilter/context.c +++ b/net/bpfilter/context.c @@ -10,8 +10,12 @@ #include #include +#include + #include "map-common.h" #include "match.h" +#include "rule.h" +#include "table.h" #include "target.h" static int init_match_ops_map(struct context *ctx) @@ -54,6 +58,88 @@ 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_index(struct context *ctx) +{ + struct table *table; + int err; + + INIT_LIST_HEAD(&ctx->table_index.list); + + err = create_map(&ctx->table_index.map, 1); + if (err) + return err; + + table = create_filter_table(ctx); + if (IS_ERR(table)) { + free_map(&ctx->table_index.map); + return PTR_ERR(table); + } + + list_add_tail(&table->list, &ctx->table_index.list); + + return map_insert(&ctx->table_index.map, table->name, table); +} + int create_context(struct context *ctx) { int err; @@ -68,11 +154,28 @@ int create_context(struct context *ctx) return err; } + err = init_table_index(ctx); + if (err) { + free_map(&ctx->match_ops_map); + free_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_index.list) { + struct table *table; + + table = list_entry(t, struct table, list); + free_table(table); + } + + free_map(&ctx->table_index.map); free_map(&ctx->match_ops_map); free_map(&ctx->target_ops_map); } diff --git a/net/bpfilter/context.h b/net/bpfilter/context.h index ed268259adcc..740d30af9087 100644 --- a/net/bpfilter/context.h +++ b/net/bpfilter/context.h @@ -8,14 +8,17 @@ #include +#include #include #include -#include + +#include "table.h" struct context { FILE *log_file; struct hsearch_data match_ops_map; struct hsearch_data target_ops_map; + struct table_index table_index; }; #define BFLOG_IMPL(ctx, level, fmt, ...) \ diff --git a/net/bpfilter/table.c b/net/bpfilter/table.c new file mode 100644 index 000000000000..506ad3c9402f --- /dev/null +++ b/net/bpfilter/table.c @@ -0,0 +1,339 @@ +// 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" + +static int rule_offset_comparator(const void *x, const void *y) +{ + const struct rule *rule = y; + + return x - (const void *)rule->ipt_entry; +} + +static struct rule *table_find_rule_by_offset(struct table *table, uint32_t offset) +{ + const struct bpfilter_ipt_entry *key; + + key = table->entries + offset; + + return bsearch(key, 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 ((uintptr_t)ipt_entry % __alignof__(struct bpfilter_ipt_entry)) + return -EINVAL; + + 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].ipt_entry = ipt_entry; + offset += ipt_entry->next_offset; + } + + if (offset != ipt_replace->size) + return -EINVAL; + + if (table->num_rules != ipt_replace->num_entries) + return -EINVAL; + + return 0; +} + +static int table_check_hooks(const struct table *table) +{ + uint32_t max_rule_front, max_rule_last; + bool check = false; + int i; + + for (i = 0; i < BPFILTER_INET_HOOK_MAX; ++i) { + if (!(table->valid_hooks & (1 << i))) + continue; + + if (check) { + if (table->hook_entry[i] <= max_rule_front) + return -EINVAL; + + if (table->underflow[i] <= max_rule_last) + return -EINVAL; + } + + max_rule_front = table->hook_entry[i]; + max_rule_last = table->underflow[i]; + check = true; + } + + 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) { + struct rule *rule_front, *rule_last; + int verdict; + + if (!(table->valid_hooks & (1 << i))) + continue; + + rule_front = table_find_rule_by_offset(table, ipt_replace->hook_entry[i]); + rule_last = table_find_rule_by_offset(table, ipt_replace->underflow[i]); + + if (!rule_front || !rule_last) + return -EINVAL; + + if (!is_rule_unconditional(rule_last)) + return -EINVAL; + + if (!rule_has_standard_target(rule_last)) + return -EINVAL; + + verdict = standard_target_verdict(rule_last->target.ipt_target); + if (verdict >= 0) + return -EINVAL; + + verdict = convert_verdict(verdict); + + if (verdict != BPFILTER_NF_DROP && verdict != BPFILTER_NF_ACCEPT) + return -EINVAL; + + table->hook_entry[i] = rule_front - table->rules; + table->underflow[i] = rule_last - table->rules; + } + + return table_check_hooks(table); +} + +static struct rule *next_rule(const struct table *table, struct rule *rule) +{ + const uint32_t i = rule - table->rules; + + if (table->num_rules <= i + 1) + return ERR_PTR(-EINVAL); + + ++rule; + rule->came_from = i; + + return rule; +} + +static struct rule *backtrack_rule(const struct table *table, struct rule *rule) +{ + uint32_t i = rule - table->rules; + int prev_i; + + do { + rule->hook_mask ^= (1 << BPFILTER_INET_HOOK_MAX); + prev_i = i; + i = rule->came_from; + rule->came_from = 0; + + if (i == prev_i) + return NULL; + + rule = &table->rules[i]; + } while (prev_i == i + 1); + + return next_rule(table, rule); +} + +static int table_check_chain(struct table *table, uint32_t hook, struct rule *rule) +{ + uint32_t i = rule - table->rules; + + rule->came_from = i; + + for (;;) { + bool visited; + int verdict; + + if (!rule) + return 0; + + if (IS_ERR(rule)) + return PTR_ERR(rule); + + i = rule - table->rules; + + if (table->num_rules <= i) + return -EINVAL; + + if (rule->hook_mask & (1 << BPFILTER_INET_HOOK_MAX)) + return -EINVAL; + + // already visited + visited = rule->hook_mask & (1 << hook); + rule->hook_mask |= (1 << hook) | (1 << BPFILTER_INET_HOOK_MAX); + + if (visited) { + rule = backtrack_rule(table, rule); + continue; + } + + if (!rule_has_standard_target(rule)) { + rule = next_rule(table, rule); + continue; + } + + verdict = standard_target_verdict(rule->target.ipt_target); + if (verdict > 0) { + rule = table_find_rule_by_offset(table, verdict); + if (!rule) + return -EINVAL; + + rule->came_from = i; + continue; + } + + if (!is_rule_unconditional(rule)) { + rule = next_rule(table, rule); + continue; + } + + rule = backtrack_rule(table, rule); + } + + return 0; +} + +static int table_check_chains(struct table *table) +{ + int i, err; + + for (i = 0, err = 0; !err && i < BPFILTER_INET_HOOK_MAX; ++i) { + if (table->valid_hooks & (1 << i)) + err = table_check_chain(table, i, &table->rules[table->hook_entry[i]]); + } + + return err; +} + +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; + + err = table_check_chains(table); + 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 *rule_front, *rule_last; + + if (!(table->valid_hooks & (1 << i))) { + info->hook_entry[i] = 0; + info->underflow[i] = 0; + continue; + } + + rule_front = &table->rules[table->hook_entry[i]]; + rule_last = &table->rules[table->underflow[i]]; + info->hook_entry[i] = (const void *)rule_front->ipt_entry - table->entries; + info->underflow[i] = (const void *)rule_last->ipt_entry - table->entries; + } + + 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..0f5d653c4460 --- /dev/null +++ b/net/bpfilter/table.h @@ -0,0 +1,39 @@ +/* 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 +#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; + uint32_t hook_entry[BPFILTER_INET_HOOK_MAX]; + uint32_t underflow[BPFILTER_INET_HOOK_MAX]; + struct rule *rules; + void *entries; +}; + +struct table_index { + struct hsearch_data map; + struct list_head list; +}; + +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 27a1ddcb6dc9..267a96a4c8a6 100644 --- a/tools/testing/selftests/bpf/bpfilter/Makefile +++ b/tools/testing/selftests/bpf/bpfilter/Makefile @@ -21,7 +21,7 @@ BPFILTER_MATCH_SRCS := $(BPFILTERSRCDIR)/match.c $(BPFILTERSRCDIR)/xt_udp.c BPFILTER_TARGET_SRCS := $(BPFILTERSRCDIR)/target.c BPFILTER_COMMON_SRCS := $(BPFILTERSRCDIR)/map-common.c $(BPFILTERSRCDIR)/context.c \ - $(BPFILTERSRCDIR)/rule.c + $(BPFILTERSRCDIR)/rule.c $(BPFILTERSRCDIR)/table.c BPFILTER_COMMON_SRCS += $(BPFILTER_MATCH_SRCS) $(BPFILTER_TARGET_SRCS) $(OUTPUT)/test_map: test_map.c $(BPFILTERSRCDIR)/map-common.c From patchwork Thu Jun 3 10:14:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitrii Banshchikov X-Patchwork-Id: 454616 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,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 D7EA5C47082 for ; Thu, 3 Jun 2021 10:16:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C12BC61287 for ; Thu, 3 Jun 2021 10:16:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229913AbhFCKSA (ORCPT ); Thu, 3 Jun 2021 06:18:00 -0400 Received: from mail-wr1-f46.google.com ([209.85.221.46]:43572 "EHLO mail-wr1-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229774AbhFCKR5 (ORCPT ); Thu, 3 Jun 2021 06:17:57 -0400 Received: by mail-wr1-f46.google.com with SMTP id v23so5246822wrd.10 for ; Thu, 03 Jun 2021 03:16:13 -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=AqoBmwpM3mskBpj4ytwLDL0Bod4MyeUCS+0cjyuGHPs=; b=CnrtvE32G9DiEo2EKCwjFh2khsdjCjSeGQgZ/zhmswo8VTJcWfxk2GE3KtHhJ6emwg v+5TBgAdVg0h3DGhedoiRjHin7xijcNx3pbaJnNlBeX4b74WF+5b/ITGIdAl+qQBoDun t5Y+Os1lXLBX20CJCd2Hdt5lyRroQInlSplHoUnwmRzE+6YO2iF7XD6cn4q72ImIwNg9 rOBCf8aGdlGioRuoNtK7lHjNHRisE0a3vQGjE5eHz+Rjzc0x1uIC0uvgXzrA1Rc600DA nM+CuoHGv1oHYfN2LaAfi137mqo7SsdWAda6XScLd0dzLL5mWd8CPrjr5Q+k8vMCJLGq fPdg== 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=AqoBmwpM3mskBpj4ytwLDL0Bod4MyeUCS+0cjyuGHPs=; b=e4R70CL6zCdiyfGDy4QutrPRg2cG6qPbimbKjk6SHK+qMzotNLjoKwmz4UeZyL0qQS 0M8UfkARgsFUmZRD4+b5LQ1pY7vAlMbAuw2+lGyg5cK+nFJd/X9alnkNDaHHeRdSUvKc CuOh0gNieeA2NLFIiqzfWslYlqpSKkuH6TVyT/VdfhQshwQGFMV8gQPStA3lQZR3RVIy 3wZZZwhdto/yiKZrEfJoEqILxOeVyc3N52oijyA7M1mBimuq5IGCC9jVp4WhTb5itJy1 Bz67zMa9xtosZZPQ3OorbCPC80zdV15SZXWBYFafHc0dVmU35gVqM6HQC1F/69YZvyua s3+Q== X-Gm-Message-State: AOAM531yXHrQMYaeDycGlhBo4c20Z1qZN681XTB3xPEap79vhyvKI6sW IKQNWw9+P/JJw8/rWHvJoDbxEg== X-Google-Smtp-Source: ABdhPJwSkIhSqVT26x/8/lIx8Ip3sTyoz4fNAhfE5tZ/ofUBNXAG2e9FQtvk4pJjEcdvFKc5t0cv7A== X-Received: by 2002:a5d:64e1:: with SMTP id g1mr37655277wri.101.1622715312423; Thu, 03 Jun 2021 03:15:12 -0700 (PDT) Received: from localhost ([154.21.15.43]) by smtp.gmail.com with ESMTPSA id o9sm2714580wrw.69.2021.06.03.03.15.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Jun 2021 03:15:12 -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 v1 09/10] bpfilter: Add handling of setsockopt() calls Date: Thu, 3 Jun 2021 14:14:24 +0400 Message-Id: <20210603101425.560384-10-me@ubique.spb.ru> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210603101425.560384-1-me@ubique.spb.ru> References: <20210603101425.560384-1-me@ubique.spb.ru> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org 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 supplied memory buffer is read-written by process_vm_readv(2)/process_vm_writev(2). Signed-off-by: Dmitrii Banshchikov --- net/bpfilter/Makefile | 2 +- net/bpfilter/sockopt.c | 409 +++++++++++++++++++++++++++++++++++++++++ net/bpfilter/sockopt.h | 14 ++ 3 files changed, 424 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 e16fee837ca0..e5979159ce72 100644 --- a/net/bpfilter/Makefile +++ b/net/bpfilter/Makefile @@ -4,7 +4,7 @@ # userprogs := bpfilter_umh -bpfilter_umh-objs := main.o map-common.o context.o match.o target.o rule.o table.o +bpfilter_umh-objs := main.o map-common.o context.o match.o target.o rule.o table.o sockopt.o bpfilter_umh-objs += xt_udp.o userccflags += -I $(srctree)/tools/include/ -I $(srctree)/tools/include/uapi diff --git a/net/bpfilter/sockopt.c b/net/bpfilter/sockopt.c new file mode 100644 index 000000000000..75f36cea4d11 --- /dev/null +++ b/net/bpfilter/sockopt.c @@ -0,0 +1,409 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + +#define _GNU_SOURCE + +#include "sockopt.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include "context.h" +#include "map-common.h" +#include "match.h" +#include "msgfmt.h" + +static int pvm_read(pid_t pid, void *to, const void *from, size_t count) +{ + const struct iovec l_iov = { .iov_base = to, .iov_len = count }; + const struct iovec r_iov = { .iov_base = (void *)from, .iov_len = count }; + ssize_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; +} + +static int pvm_read_from_offset(pid_t pid, void *to, const void *from, size_t offset, size_t count) +{ + return pvm_read(pid, to + offset, from + offset, count); +} + +static 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 }; + ssize_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; +} + +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 = map_find(&ctx->table_index.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 = map_find(&ctx->table_index.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 = 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 int sockopt_get_revision_target(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_TARGET\n"); + + err = read_ipt_get_revision(req, &get_revision); + if (err) + return err; + + found = map_find(&ctx->target_ops_map, get_revision.name); + if (IS_ERR(found)) { + BFLOG_DEBUG(ctx, "cannot find target: '%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 ipt_header, *ipt_replace; + int err; + + if (req->len < sizeof(ipt_header)) + return ERR_PTR(-EINVAL); + + err = pvm_read(req->pid, &ipt_header, (const void *)req->addr, sizeof(ipt_header)); + if (err) + return ERR_PTR(err); + + if (ipt_header.num_counters == 0) + return ERR_PTR(-EINVAL); + + if (ipt_header.num_counters >= INT_MAX / sizeof(struct bpfilter_ipt_counters)) + return ERR_PTR(-ENOMEM); + + ipt_header.name[sizeof(ipt_header.name) - 1] = '\0'; + + ipt_replace = malloc(sizeof(ipt_header) + ipt_header.size); + if (!ipt_replace) + return ERR_PTR(-ENOMEM); + + memcpy(ipt_replace, &ipt_header, sizeof(ipt_header)); + + err = pvm_read_from_offset(req->pid, ipt_replace, (const void *)req->addr, + sizeof(ipt_header), ipt_header.size); + if (err) { + free(ipt_replace); + return ERR_PTR(err); + } + + return ipt_replace; +} + +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 = map_find(&ctx->table_index.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 = map_update(&ctx->table_index.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_index.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; + + 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_from_offset(req->pid, info, (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 = map_find(&ctx->table_index.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); + case BPFILTER_IPT_SO_GET_REVISION_TARGET: + return sockopt_get_revision_target(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 Thu Jun 3 10:14:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitrii Banshchikov X-Patchwork-Id: 453840 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, 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 70DF7C47097 for ; Thu, 3 Jun 2021 10:16:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5C26661287 for ; Thu, 3 Jun 2021 10:16:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230008AbhFCKSE (ORCPT ); Thu, 3 Jun 2021 06:18:04 -0400 Received: from mail-wr1-f52.google.com ([209.85.221.52]:33280 "EHLO mail-wr1-f52.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230025AbhFCKSB (ORCPT ); Thu, 3 Jun 2021 06:18:01 -0400 Received: by mail-wr1-f52.google.com with SMTP id a20so5305049wrc.0 for ; Thu, 03 Jun 2021 03:16:16 -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=DfMkpPCPjdgbpWmKQnrpYpCDmXhDFmEEf/aT0PcTt60=; b=DtrMHmWsg+r4cLaW8247DPMNoo/AUnlsm+VbiZREnKvR8tWuraAPeShAcEq3CDXrtY XDrV81nzfcjQCB3VBT1jNvV5nk2Tl2I+WpOwRW3X/n946caBk58YKy+wuQ5bSRIKrY2d jPbsWk4mO/iwCflRRBtfs5N9Hji1IrclmnxjCNP4pkUj1IfYUT35QC4uvf0JKzZNac4n pm5RXQgdf2KVwHFJguydR4kv/fiOmgFsr+lnOFFfuDV/G9/3Qxz0110AVU5qKuaEeAHN s/8PtMai0A1A/Q9NZzq3xgqDoscwewv4A1F/MEoMhy604AZbzGnQpodFbl+204pdkVvj iWAg== 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=DfMkpPCPjdgbpWmKQnrpYpCDmXhDFmEEf/aT0PcTt60=; b=STBKAUUQSxqPNcmtZTA37UaIfFQqGp78aRHPPzTGr9NfpzX0kbpuTrCO8Qn6+fouPN mQnIuzAAJ4sr3Yg+ZURsHaYk+pBI+KmprtzfgGXPa7JDfYxqBWxzqA19MAqPG4J+VBWi If7wModQkNyYFdG5LZbTg2c98eqU44iegtuHtq1qZNWTjrbUszvHVhwFRBegghz9h+T4 hU5rIpwTPs6x7xgK0FKjjGznVeVFdX0N+FmTDhSw0+po0INs60iPMM3BFdskGUnvyo43 2qoWah4OF6zRcgY93IrBMz53p78Oimi9JzYaUCxgtZqm0AnLmQw9+VJSyKEGkyX455y0 lZgA== X-Gm-Message-State: AOAM5337krYCUgk0d6TTiiRd3IFxaarmICkL6d8DYlLGPBGDxZpcQou2 yAuI1ZiNcNrQpoQNPAoxFdYsEg== X-Google-Smtp-Source: ABdhPJwgK/HcAnen5Jd7wxKBlwBeLtfiOE90l69RDATRfoai0y2BnDFDuZVyn+CbCPvYa+Ym1UoTtw== X-Received: by 2002:a5d:628d:: with SMTP id k13mr12050340wru.410.1622715316029; Thu, 03 Jun 2021 03:15:16 -0700 (PDT) Received: from localhost ([154.21.15.43]) by smtp.gmail.com with ESMTPSA id q5sm2296228wmc.0.2021.06.03.03.15.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Jun 2021 03:15:15 -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 v1 10/10] bpfilter: Handle setsockopts Date: Thu, 3 Jun 2021 14:14:25 +0400 Message-Id: <20210603101425.560384-11-me@ubique.spb.ru> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210603101425.560384-1-me@ubique.spb.ru> References: <20210603101425.560384-1-me@ubique.spb.ru> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Use earlier introduced infrastructure for and handle setsockopt(2) calls. Signed-off-by: Dmitrii Banshchikov --- net/bpfilter/main.c | 123 +++++++++++++++++++++++++++++--------------- 1 file changed, 81 insertions(+), 42 deletions(-) diff --git a/net/bpfilter/main.c b/net/bpfilter/main.c index 05e1cfc1e5cd..4c04898530cf 100644 --- a/net/bpfilter/main.c +++ b/net/bpfilter/main.c @@ -1,64 +1,103 @@ // SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Telegram FZ-LLC + */ + #define _GNU_SOURCE -#include + +#include +#include + #include #include -#include -#include +#include #include -#include "../../include/uapi/linux/bpf.h" -#include + +#include "context.h" #include "msgfmt.h" +#include "sockopt.h" -FILE *debug_f; +#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; \ + }) -static int handle_get_cmd(struct mbox_request *cmd) +static int read_exact(int fd, void *buffer, size_t count) { - switch (cmd->cmd) { - case 0: - return 0; - default: - break; - } - return -ENOPROTOOPT; + return do_exact(fd, read, buffer, count); } -static int handle_set_cmd(struct mbox_request *cmd) +static int write_exact(int fd, const void *buffer, size_t count) { - return -ENOPROTOOPT; + return do_exact(fd, write, buffer, count); +} + +static int setup_context(struct context *ctx) +{ + ctx->log_file = fopen("/dev/kmsg", "w"); + if (!ctx->log_file) + return -errno; + + setvbuf(ctx->log_file, 0, _IOLBF, 0); + + 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_EMERG(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_EMERG(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; }