From patchwork Fri Nov 29 01:22:18 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cong Wang X-Patchwork-Id: 13888385 X-Patchwork-Delegate: bpf@iogearbox.net Received: from mail-pj1-f49.google.com (mail-pj1-f49.google.com [209.85.216.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BB4AD17C77; Fri, 29 Nov 2024 01:22:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732843357; cv=none; b=BzK3EgXMkSiZbbClIuVtAQBsphSSYe/ZcSGGxBN4a6jnzw1TI/7up9PJSJWfkUSinJwnivMEFudNtIyHrIiRg6xxcEKUubJ/mSjPUIHs2ofUpabx20mV/+pBHl/2B8xKGgs7xyPwpta2MoY0yuGDG4LVT/sZzFCELlcyNT7/jrM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732843357; c=relaxed/simple; bh=fJ789znw+pfGIHXh87akZzviWRl3wPB+lGevWQgv08o=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=PdwWVJWgunWTpFMQkMOrYue3aqV9lAyWURi2sNgzB+ckJl61HDrNJ9wyTkG+Z7s6aCwAOAIyOXCPlg27UlJOh1swjSMyqulkysb+THYI9WGg5is/pJ3KsweyFClw0Q3mQ5dJOrIU58hi3yi0kVHNh0vtERz8grvVcqlrZQ2T6CQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=kj179ClF; arc=none smtp.client-ip=209.85.216.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="kj179ClF" Received: by mail-pj1-f49.google.com with SMTP id 98e67ed59e1d1-2ea1c453f0eso962868a91.1; Thu, 28 Nov 2024 17:22:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1732843355; x=1733448155; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=DPc3Co4ldVHrMRzPOt+DOWF0B/8XpbePcgDN8Gbz8Ns=; b=kj179ClFvLghaIYCkZ5Upz9wbglfd6E1PjPWT52XRjStStbgb7Uq5bwiYICgvyhgI9 hN2aSy4hFOsb2vuC4jZzI3HxAvVfRvPBtlj2pTqm/X7GdO7b0SZ48Zc2owfukzMypKvf QQXT0XrNFBZc5NHfIGfhx7LhELfJlHjgP2BXKuoHoNv12FjPo/I0K327qkd6UMoN80Up ijoKlCkhWwQSkp0ghH/VUbJxdFJ4BjsYKO5dIMBHmAJNleXa/C6NgncnXZITOWn42L5R mBrlQ+V0TbIUSezd9nhDY8SJH5R/fCYrKjftwpp0tLphV7XHnTQgWHlyCFSi9MxAxepz bOlg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1732843355; x=1733448155; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=DPc3Co4ldVHrMRzPOt+DOWF0B/8XpbePcgDN8Gbz8Ns=; b=VfU7k/MlzvXJFBo451RrvSEZJ/bpCfQ3IxRgYwfhXg3A63+RA9YtZsSCZ6dD+PeIxa cNFp0hc0fl88mHrjd5A0NxjBSoAqmOgcaSXgD4vEnUXbnSgfRFmAItPK6KahvhenRiID DsE3Wy9/BvZ6Kk4pp/Ju9gRUYID3fZIHiboGhlaDqixSvJaEMfUKQR0IsEGJ5yXl3IB5 H2fL8YRNscZ1OHsEpw76t4STgbCyx4FvmRRXxnhjpZRhGWTcR1u6Gl7ZWvcQkUtBUBZJ Bd4ujSaHOl22F/nyleRK0fT86eyvuoEyVT2kAzNP9fafHc8c3xAAaBMPmblOc+BjTnol mIAg== X-Gm-Message-State: AOJu0Yz373ROChEBuzNioxwyW9vTRkMuCDJD7HSo/IuJG6l4F0Hg/nVv erZfy8Z206aQLMMiLBmb+GPQEtCwvN5jyiDkNt+N/n2wRvidnSaPDaV42g== X-Gm-Gg: ASbGncttlwHrw51zLXiH3WXG7c7ujn6abmGYhiZJTOmOyKTM81xErh3eSWxPlfuEHLS DIB5njzgT5ONI3RP0nzRpEC1IFsFOrTyGOB0eHcWTWuxc12z0us5PYNSwM9AAZL8fEcEPGzK5xb Sr56t4dsi6yC65gddKRC5QVEolKqnzYOiyEsJiBwS9sqjChVgVLaEJL78QEVa/moIZryQsi5aZ3 I6CNx0dZGnrHI+K+0JEYT/0EsZ5QZwRIKaDcAnrxJ5Q1m9dAsnd1bwh55OeGsZwQFIu62Rj1hMC VlE= X-Google-Smtp-Source: AGHT+IH++R4xCW/SfLd24apZitcHNtouIQ4ZNnCnpffi14NpDw+5gW2WPqfFp3D1vQJlGRJke9wnwQ== X-Received: by 2002:a17:90b:4d0d:b0:2ea:853b:2761 with SMTP id 98e67ed59e1d1-2ee097e3d26mr12213057a91.37.1732843354698; Thu, 28 Nov 2024 17:22:34 -0800 (PST) Received: from pop-os.hsd1.ca.comcast.net ([2601:647:6881:9060:7990:ba58:c520:e7e8]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21521905120sm20010215ad.80.2024.11.28.17.22.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 Nov 2024 17:22:34 -0800 (PST) From: Cong Wang To: netdev@vger.kernel.org Cc: bpf@vger.kernel.org, Cong Wang , John Fastabend , Daniel Borkmann Subject: [Patch bpf v2 1/4] bpf: Check negative offsets in __bpf_skb_min_len() Date: Thu, 28 Nov 2024 17:22:18 -0800 Message-Id: <20241129012221.739069-2-xiyou.wangcong@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241129012221.739069-1-xiyou.wangcong@gmail.com> References: <20241129012221.739069-1-xiyou.wangcong@gmail.com> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: bpf@iogearbox.net From: Cong Wang skb_network_offset() and skb_transport_offset() can be negative when they are called after we pull the transport header, for example, when we use eBPF sockmap at the point of ->sk_data_ready(). __bpf_skb_min_len() uses an unsigned int to get these offsets, this leads to a very large number which then causes bpf_skb_change_tail() failed unexpectedly. Fix this by using a signed int to get these offsets and ensure the minimum is at least zero. Fixes: 5293efe62df8 ("bpf: add bpf_skb_change_tail helper") Cc: John Fastabend Cc: Daniel Borkmann Signed-off-by: Cong Wang --- net/core/filter.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index 6625b3f563a4..c1982fd04b25 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -3734,13 +3734,22 @@ static const struct bpf_func_proto bpf_skb_adjust_room_proto = { static u32 __bpf_skb_min_len(const struct sk_buff *skb) { - u32 min_len = skb_network_offset(skb); + int offset = skb_network_offset(skb); + u32 min_len = 0; - if (skb_transport_header_was_set(skb)) - min_len = skb_transport_offset(skb); - if (skb->ip_summed == CHECKSUM_PARTIAL) - min_len = skb_checksum_start_offset(skb) + - skb->csum_offset + sizeof(__sum16); + if (offset > 0) + min_len = offset; + if (skb_transport_header_was_set(skb)) { + offset = skb_transport_offset(skb); + if (offset > 0) + min_len = offset; + } + if (skb->ip_summed == CHECKSUM_PARTIAL) { + offset = skb_checksum_start_offset(skb) + + skb->csum_offset + sizeof(__sum16); + if (offset > 0) + min_len = offset; + } return min_len; } From patchwork Fri Nov 29 01:22:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cong Wang X-Patchwork-Id: 13888386 X-Patchwork-Delegate: bpf@iogearbox.net Received: from mail-pg1-f181.google.com (mail-pg1-f181.google.com [209.85.215.181]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BFFB817C91; Fri, 29 Nov 2024 01:22:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732843358; cv=none; b=ZhTMUkOmGjQvHwXcW3EZqp1s+xsh+db7d8sqXVOPqpc+Fk2//oCSGkxfFc9YVejJEXHth7CuVH92IdVpFK+XkI+1w41HTdYMpLpZE8w+P5K5/4s24YJCsJ5oXmybpEHzUxfFstRfbGds4st+YZ2hX6vG9Nv6Td0oaqpCNoRipwg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732843358; c=relaxed/simple; bh=F7JT4xBisKFMYTJpBnqsx7QxIwVAr4egbfjHF471I5M=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=KmLkjGfjKcFz27ymxa2mQDP9/3lYzXPZEXrUe/BxXsWuiXpywqS353vPTc0WdBYzYxXAV5UqEZ+K53KQaToIndiCx3ZXVtuPXM6DRKdMwYE3JoCc4ca0crShgLUsWNE7uVqLpqbJf1pHgEyOtvUx7k/kwPjgfQPB/pit2u7XgcA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=QZJ5lzvG; arc=none smtp.client-ip=209.85.215.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="QZJ5lzvG" Received: by mail-pg1-f181.google.com with SMTP id 41be03b00d2f7-7ea8c4ce232so1113395a12.0; Thu, 28 Nov 2024 17:22:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1732843356; x=1733448156; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=A5uKx0qV8o+/qU6rwv2ps7xvE7yEZcSPlta89mEJuKA=; b=QZJ5lzvGkBvInpe+bYC1BeKkuga4LPXdrl7gXS3998bt9siISjgjr6ZqhccJhqyTQT 31N+3CNXt3i/tif5o56kPQEi4NKflLSxVFH75d2n6GgxsEIh9LfHiCiJQ9QHeKI/Ybvi IraErhqDCwWESjZLsdWm8IfYf05ble0G+QRKOj/932QGDGFMrzRijZMH2fvH8rx7x0A8 ctx1v7Vjx4YgyHK4xTYEqSFZ2zc06h/NqYiJxKSy5UAaszBZ9J7xLukgCnvREbbubuCq Wpba8Gm5mKjcH1FcpJlhyLBYgmjrAWnluBd+OmPX865eSt0/IsxpbkRWFv8+0j7Fje+/ p9MQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1732843356; x=1733448156; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=A5uKx0qV8o+/qU6rwv2ps7xvE7yEZcSPlta89mEJuKA=; b=qEyvxucBm0lS7fCNocvR0hxQSTPWja7GrCBtS1iLvdLZMkdM5e1b/n49DYeMmsmJTy Li9RUs4TMYAw2Or34TjOzmaK1mlhIYZTfhFM1RwoxBmOvGNBDhj6gr839aIndLLYlWWe yrdnL5h2CE4O65JVxGf9zd+GaSy0exwbZsT6ToTS23G7XXyodmGjA39mfrW8gtD4WDDg ZZCcIwB3u6qFoMPNZCa9Kuw/BH5pByAru4kxKeFbxOa098IgK3O+Vdru+OC7fHQlkjUp LrIUySrvWB/uj8KQSFZkSWPMHcAh5moLm0ZgKojRI390+nVTyv2I8k5FTwEPk9QJkeol X30A== X-Gm-Message-State: AOJu0YwAIJaNYnXDy6C/oPtGBwdY+G8rRQnzvELIJOvwkX8PITr4rdOP lFxjnn55so5qkv4qWnAIwXNExpxoyh0B3SHr5WybNmNuhEMxmaXGCDFgrA== X-Gm-Gg: ASbGncv2GhSWZ8EyzQ1sNoFzWqcMsCnLbKVI/WNNiimGR2qM+rpEtq89TullK3/2LC0 SmcbalJaVaFXLsWbHy5FhKiEwy0wSO+hU0GLLohR/w8CuXUpYMXYI82e1dFY2ezP6RmE2P+4Lhx xrpiXc4Pmr74MbMTxnC/YYg3pYEQ22BVFKA2beyvKwzdT/w+WGlJagNBJGCdDD/y8E0XC+CgOHT uGcIqUuyku+TPK8o9FJFRpoD7aNj6VlyhllUCS3G5IdqaUeyip2dgo7+ZEgctQJ0QHZm8xeC8VM al0= X-Google-Smtp-Source: AGHT+IG3NWrMz3s6bmLPqlk1wtDEhdqlSNbvoWCzs4WGQmNFQViX8s3As28xjGRItpZqITlLzeHJiA== X-Received: by 2002:a17:90b:380c:b0:2ea:b867:ddbb with SMTP id 98e67ed59e1d1-2ee08e9fdf5mr11125812a91.13.1732843355848; Thu, 28 Nov 2024 17:22:35 -0800 (PST) Received: from pop-os.hsd1.ca.comcast.net ([2601:647:6881:9060:7990:ba58:c520:e7e8]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21521905120sm20010215ad.80.2024.11.28.17.22.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 Nov 2024 17:22:35 -0800 (PST) From: Cong Wang To: netdev@vger.kernel.org Cc: bpf@vger.kernel.org, Cong Wang , John Fastabend , Daniel Borkmann , Zijian Zhang Subject: [Patch bpf v2 2/4] selftests/bpf: Add a BPF selftest for bpf_skb_change_tail() Date: Thu, 28 Nov 2024 17:22:19 -0800 Message-Id: <20241129012221.739069-3-xiyou.wangcong@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241129012221.739069-1-xiyou.wangcong@gmail.com> References: <20241129012221.739069-1-xiyou.wangcong@gmail.com> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: bpf@iogearbox.net From: Cong Wang As requested by Daniel, we need to add a selftest to cover bpf_skb_change_tail() cases in skb_verdict. Here we test trimming, growing and error cases, and validate its expected return values and the expected sizes of the payload. Cc: John Fastabend Cc: Daniel Borkmann Cc: Zijian Zhang Signed-off-by: Cong Wang --- .../selftests/bpf/prog_tests/sockmap_basic.c | 51 +++++++++++++++++++ .../bpf/progs/test_sockmap_change_tail.c | 40 +++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/test_sockmap_change_tail.c diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c index fdff0652d7ef..574db6471fb5 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c @@ -12,6 +12,7 @@ #include "test_sockmap_progs_query.skel.h" #include "test_sockmap_pass_prog.skel.h" #include "test_sockmap_drop_prog.skel.h" +#include "test_sockmap_change_tail.skel.h" #include "bpf_iter_sockmap.skel.h" #include "sockmap_helpers.h" @@ -643,6 +644,54 @@ static void test_sockmap_skb_verdict_fionread(bool pass_prog) test_sockmap_drop_prog__destroy(drop); } +static void test_sockmap_skb_verdict_change_tail(void) +{ + struct test_sockmap_change_tail *skel; + int err, map, verdict; + int c1, p1, sent, recvd; + int zero = 0; + char buf[2]; + + skel = test_sockmap_change_tail__open_and_load(); + if (!ASSERT_OK_PTR(skel, "open_and_load")) + return; + verdict = bpf_program__fd(skel->progs.prog_skb_verdict); + map = bpf_map__fd(skel->maps.sock_map_rx); + + err = bpf_prog_attach(verdict, map, BPF_SK_SKB_STREAM_VERDICT, 0); + if (!ASSERT_OK(err, "bpf_prog_attach")) + goto out; + err = create_pair(AF_INET, SOCK_STREAM, &c1, &p1); + if (!ASSERT_OK(err, "create_pair()")) + goto out; + err = bpf_map_update_elem(map, &zero, &c1, BPF_NOEXIST); + if (!ASSERT_OK(err, "bpf_map_update_elem(c1)")) + goto out_close; + sent = xsend(p1, "Tr", 2, 0); + ASSERT_EQ(sent, 2, "xsend(p1)"); + recvd = recv(c1, buf, 2, 0); + ASSERT_EQ(recvd, 1, "recv(c1)"); + ASSERT_EQ(skel->data->change_tail_ret, 0, "change_tail_ret"); + + sent = xsend(p1, "G", 1, 0); + ASSERT_EQ(sent, 1, "xsend(p1)"); + recvd = recv(c1, buf, 2, 0); + ASSERT_EQ(recvd, 2, "recv(c1)"); + ASSERT_EQ(skel->data->change_tail_ret, 0, "change_tail_ret"); + + sent = xsend(p1, "E", 1, 0); + ASSERT_EQ(sent, 1, "xsend(p1)"); + recvd = recv(c1, buf, 1, 0); + ASSERT_EQ(recvd, 1, "recv(c1)"); + ASSERT_EQ(skel->data->change_tail_ret, -EINVAL, "change_tail_ret"); + +out_close: + close(c1); + close(p1); +out: + test_sockmap_change_tail__destroy(skel); +} + static void test_sockmap_skb_verdict_peek_helper(int map) { int err, c1, p1, zero = 0, sent, recvd, avail; @@ -1056,6 +1105,8 @@ void test_sockmap_basic(void) test_sockmap_skb_verdict_fionread(true); if (test__start_subtest("sockmap skb_verdict fionread on drop")) test_sockmap_skb_verdict_fionread(false); + if (test__start_subtest("sockmap skb_verdict change tail")) + test_sockmap_skb_verdict_change_tail(); if (test__start_subtest("sockmap skb_verdict msg_f_peek")) test_sockmap_skb_verdict_peek(); if (test__start_subtest("sockmap skb_verdict msg_f_peek with link")) diff --git a/tools/testing/selftests/bpf/progs/test_sockmap_change_tail.c b/tools/testing/selftests/bpf/progs/test_sockmap_change_tail.c new file mode 100644 index 000000000000..2796dd8545eb --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_sockmap_change_tail.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 ByteDance */ +#include +#include + +struct { + __uint(type, BPF_MAP_TYPE_SOCKMAP); + __uint(max_entries, 1); + __type(key, int); + __type(value, int); +} sock_map_rx SEC(".maps"); + +long change_tail_ret = 1; + +SEC("sk_skb") +int prog_skb_verdict(struct __sk_buff *skb) +{ + char *data, *data_end; + + bpf_skb_pull_data(skb, 1); + data = (char *)(unsigned long)skb->data; + data_end = (char *)(unsigned long)skb->data_end; + + if (data + 1 > data_end) + return SK_PASS; + + if (data[0] == 'T') { /* Trim the packet */ + change_tail_ret = bpf_skb_change_tail(skb, skb->len - 1, 0); + return SK_PASS; + } else if (data[0] == 'G') { /* Grow the packet */ + change_tail_ret = bpf_skb_change_tail(skb, skb->len + 1, 0); + return SK_PASS; + } else if (data[0] == 'E') { /* Error */ + change_tail_ret = bpf_skb_change_tail(skb, 65535, 0); + return SK_PASS; + } + return SK_PASS; +} + +char _license[] SEC("license") = "GPL"; From patchwork Fri Nov 29 01:22:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cong Wang X-Patchwork-Id: 13888387 X-Patchwork-Delegate: bpf@iogearbox.net Received: from mail-pl1-f180.google.com (mail-pl1-f180.google.com [209.85.214.180]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 694392837A; Fri, 29 Nov 2024 01:22:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.180 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732843360; cv=none; b=bn+CM4AMRTPkSbrJHF6LuBfOBusjcsTb3JrXE1XHNPh7s7JmUp0GBO6f1RcrL9ZLzUfuvviG51Tu17LVPk7rUkvMES7jv3ZNuO/Wp21XZC/ppIVwe5D0ZEMSqQPyvOyf9kfOvAU09EmG6t3aBJ2RI6FBO7hh6YmyR1lW8oRKbkM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732843360; c=relaxed/simple; bh=o6+ipYCfyeTJUUzAwSx+HMq7uopLlioUeR7zPrDJfcU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Qqs2f95Gbypj0KCGzJfVhAuOFqVRr1ys5eOMBrQYzla3d9dY5ml98MF/Xh51JZ+0KsuTvJVJ9gaSC1rsfPB2PTz2omr2fcqiOUSu0moCgY9bu2UdEojYT6NQBIYyoz/3B5bsfsLGRqz3IO1nFBqVXjC+L/KqRdz7/ljUBmxXsTU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=QRrLmYY0; arc=none smtp.client-ip=209.85.214.180 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="QRrLmYY0" Received: by mail-pl1-f180.google.com with SMTP id d9443c01a7336-21285c1b196so12191565ad.3; Thu, 28 Nov 2024 17:22:38 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1732843357; x=1733448157; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=EqHj1YtMVxEOHcGbjVYBonaoLEybW60vC4WWr8uTT58=; b=QRrLmYY0ZTk42yKDIxK0uHYayt/E1YTcSnb9+yi7hwrbBpEX2TaV229gJAC3OR6VdB P6erY6jiF12vyarwE3KgfK130tipEQETWIl/ZZx5rxNyDjyTJJ8Kdi4al+aPB8X5V+Bv cGwOQrozVWQrYVsji0SgMWLHiCp5Cm8AH8UUZWKLXBNPBzSWWl8udz4ea1T/8k1gW0g2 zZdC03Gl7JQzyFQY3mxJgI7+QftQOtAjaQzY/BL3Oj+NubsOPmxJNzd4cpDRs4ti/6p8 gGjSz7i3NZ0/XIjrFzR/6SINicofdLOg9LW8uBYeWqA4C3Y7kCEWArfwEBGAArTJZ+H5 SecQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1732843357; x=1733448157; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=EqHj1YtMVxEOHcGbjVYBonaoLEybW60vC4WWr8uTT58=; b=XZcih5Vz9jcL6zjlxtoN9Jq987QxXURl8q4yRUhfNWbXRgvgc9EUo7VzUq38H/pdWB rYYhZBCJZd82CE7QEBeeyEq5GQSHDsnOKTUbllqmEzvdqfbKpvXQsaUPPuUZqvOrw0AP nml3NKOWRlOX9hzkC9QYnUV5ThIuySpbKv+eY8JnHcHSnfMCjJLrqtmjEfTYDDp9Feuh LzGFwzlYRUMuTyeIW3mirz/I9p9DzuUHGuUlWsQl0A0FTGtbuJxkPsUHJ1KEXoF8t5Jz 3QCKOtnMN5XJySZrqqAAxfFlPgz2InIS26uL/kICO90kzwMJKd+JCIk0V4io/xhcakZF RvRA== X-Gm-Message-State: AOJu0YzC+jyHiCKHDvYL0gMdrljtO5yBUzZ7CxQGqfodzAH3xKTLlPf+ ZNtBJjY8doQue516BZX73qenQE47a+T36i8WTGnDNNi9GLA849DuF5edQg== X-Gm-Gg: ASbGncurGPQfeV3xtfe6bMINa1P9L4HKTfN/AsPIYM4+XjjsGJN4vHqxQMiedSh2ghq yBHJFqE3/PUMhZMkEQTnlnXIhWSfVt3OwRozzlAagw3BKbschYYOqu3AB+qCIemQ/BqXeo7Iw/j H0FmID9y0qtOZdxdq1lrbSmBEDXFU8vthRCJ2WsZrYm/o1t4rT72gBIftKTGOU0MfHY1oBPVAzf HM2Zfwnb2cQUv+x1+lQ144pLbslXwq74rI/1mpO9xe2KPaMIiiyXmSrKVketvsqJpPbEdIxyjll BJo= X-Google-Smtp-Source: AGHT+IHIUUq2QLaXanaUqtwfHkftcXQdQnZ9hhoDqgBDHEDnc/q+K/W3zvID+x4OPqp+rRdZ1d5jQg== X-Received: by 2002:a17:902:e809:b0:20c:e005:2c27 with SMTP id d9443c01a7336-21501d645ccmr115274735ad.42.1732843357159; Thu, 28 Nov 2024 17:22:37 -0800 (PST) Received: from pop-os.hsd1.ca.comcast.net ([2601:647:6881:9060:7990:ba58:c520:e7e8]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21521905120sm20010215ad.80.2024.11.28.17.22.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 Nov 2024 17:22:36 -0800 (PST) From: Cong Wang To: netdev@vger.kernel.org Cc: bpf@vger.kernel.org, Cong Wang , John Fastabend , Daniel Borkmann , Zijian Zhang Subject: [Patch bpf v2 3/4] selftests/bpf: Introduce socket_helpers.h for TC tests Date: Thu, 28 Nov 2024 17:22:20 -0800 Message-Id: <20241129012221.739069-4-xiyou.wangcong@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241129012221.739069-1-xiyou.wangcong@gmail.com> References: <20241129012221.739069-1-xiyou.wangcong@gmail.com> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: bpf@iogearbox.net From: Cong Wang Pull socket helpers out of sockmap_helpers.h so that they can be reused for TC tests as well. This prepares for the next patch. Cc: John Fastabend Cc: Daniel Borkmann Cc: Zijian Zhang Signed-off-by: Cong Wang --- .../selftests/bpf/prog_tests/socket_helpers.h | 394 ++++++++++++++++++ .../bpf/prog_tests/sockmap_helpers.h | 385 +---------------- 2 files changed, 395 insertions(+), 384 deletions(-) create mode 100644 tools/testing/selftests/bpf/prog_tests/socket_helpers.h diff --git a/tools/testing/selftests/bpf/prog_tests/socket_helpers.h b/tools/testing/selftests/bpf/prog_tests/socket_helpers.h new file mode 100644 index 000000000000..1bdfb79ef009 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/socket_helpers.h @@ -0,0 +1,394 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __SOCKET_HELPERS__ +#define __SOCKET_HELPERS__ + +#include + +/* include/linux/net.h */ +#define SOCK_TYPE_MASK 0xf + +#define IO_TIMEOUT_SEC 30 +#define MAX_STRERR_LEN 256 + +/* workaround for older vm_sockets.h */ +#ifndef VMADDR_CID_LOCAL +#define VMADDR_CID_LOCAL 1 +#endif + +/* include/linux/cleanup.h */ +#define __get_and_null(p, nullvalue) \ + ({ \ + __auto_type __ptr = &(p); \ + __auto_type __val = *__ptr; \ + *__ptr = nullvalue; \ + __val; \ + }) + +#define take_fd(fd) __get_and_null(fd, -EBADF) + +/* Wrappers that fail the test on error and report it. */ + +#define _FAIL(errnum, fmt...) \ + ({ \ + error_at_line(0, (errnum), __func__, __LINE__, fmt); \ + CHECK_FAIL(true); \ + }) +#define FAIL(fmt...) _FAIL(0, fmt) +#define FAIL_ERRNO(fmt...) _FAIL(errno, fmt) +#define FAIL_LIBBPF(err, msg) \ + ({ \ + char __buf[MAX_STRERR_LEN]; \ + libbpf_strerror((err), __buf, sizeof(__buf)); \ + FAIL("%s: %s", (msg), __buf); \ + }) + + +#define xaccept_nonblock(fd, addr, len) \ + ({ \ + int __ret = \ + accept_timeout((fd), (addr), (len), IO_TIMEOUT_SEC); \ + if (__ret == -1) \ + FAIL_ERRNO("accept"); \ + __ret; \ + }) + +#define xbind(fd, addr, len) \ + ({ \ + int __ret = bind((fd), (addr), (len)); \ + if (__ret == -1) \ + FAIL_ERRNO("bind"); \ + __ret; \ + }) + +#define xclose(fd) \ + ({ \ + int __ret = close((fd)); \ + if (__ret == -1) \ + FAIL_ERRNO("close"); \ + __ret; \ + }) + +#define xconnect(fd, addr, len) \ + ({ \ + int __ret = connect((fd), (addr), (len)); \ + if (__ret == -1) \ + FAIL_ERRNO("connect"); \ + __ret; \ + }) + +#define xgetsockname(fd, addr, len) \ + ({ \ + int __ret = getsockname((fd), (addr), (len)); \ + if (__ret == -1) \ + FAIL_ERRNO("getsockname"); \ + __ret; \ + }) + +#define xgetsockopt(fd, level, name, val, len) \ + ({ \ + int __ret = getsockopt((fd), (level), (name), (val), (len)); \ + if (__ret == -1) \ + FAIL_ERRNO("getsockopt(" #name ")"); \ + __ret; \ + }) + +#define xlisten(fd, backlog) \ + ({ \ + int __ret = listen((fd), (backlog)); \ + if (__ret == -1) \ + FAIL_ERRNO("listen"); \ + __ret; \ + }) + +#define xsetsockopt(fd, level, name, val, len) \ + ({ \ + int __ret = setsockopt((fd), (level), (name), (val), (len)); \ + if (__ret == -1) \ + FAIL_ERRNO("setsockopt(" #name ")"); \ + __ret; \ + }) + +#define xsend(fd, buf, len, flags) \ + ({ \ + ssize_t __ret = send((fd), (buf), (len), (flags)); \ + if (__ret == -1) \ + FAIL_ERRNO("send"); \ + __ret; \ + }) + +#define xrecv_nonblock(fd, buf, len, flags) \ + ({ \ + ssize_t __ret = recv_timeout((fd), (buf), (len), (flags), \ + IO_TIMEOUT_SEC); \ + if (__ret == -1) \ + FAIL_ERRNO("recv"); \ + __ret; \ + }) + +#define xsocket(family, sotype, flags) \ + ({ \ + int __ret = socket(family, sotype, flags); \ + if (__ret == -1) \ + FAIL_ERRNO("socket"); \ + __ret; \ + }) + +static inline void close_fd(int *fd) +{ + if (*fd >= 0) + xclose(*fd); +} + +#define __close_fd __attribute__((cleanup(close_fd))) + +static inline struct sockaddr *sockaddr(struct sockaddr_storage *ss) +{ + return (struct sockaddr *)ss; +} + +static inline void init_addr_loopback4(struct sockaddr_storage *ss, + socklen_t *len) +{ + struct sockaddr_in *addr4 = memset(ss, 0, sizeof(*ss)); + + addr4->sin_family = AF_INET; + addr4->sin_port = 0; + addr4->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + *len = sizeof(*addr4); +} + +static inline void init_addr_loopback6(struct sockaddr_storage *ss, + socklen_t *len) +{ + struct sockaddr_in6 *addr6 = memset(ss, 0, sizeof(*ss)); + + addr6->sin6_family = AF_INET6; + addr6->sin6_port = 0; + addr6->sin6_addr = in6addr_loopback; + *len = sizeof(*addr6); +} + +static inline void init_addr_loopback_vsock(struct sockaddr_storage *ss, + socklen_t *len) +{ + struct sockaddr_vm *addr = memset(ss, 0, sizeof(*ss)); + + addr->svm_family = AF_VSOCK; + addr->svm_port = VMADDR_PORT_ANY; + addr->svm_cid = VMADDR_CID_LOCAL; + *len = sizeof(*addr); +} + +static inline void init_addr_loopback(int family, struct sockaddr_storage *ss, + socklen_t *len) +{ + switch (family) { + case AF_INET: + init_addr_loopback4(ss, len); + return; + case AF_INET6: + init_addr_loopback6(ss, len); + return; + case AF_VSOCK: + init_addr_loopback_vsock(ss, len); + return; + default: + FAIL("unsupported address family %d", family); + } +} + +static inline int enable_reuseport(int s, int progfd) +{ + int err, one = 1; + + err = xsetsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); + if (err) + return -1; + err = xsetsockopt(s, SOL_SOCKET, SO_ATTACH_REUSEPORT_EBPF, &progfd, + sizeof(progfd)); + if (err) + return -1; + + return 0; +} + +static inline int socket_loopback_reuseport(int family, int sotype, int progfd) +{ + struct sockaddr_storage addr; + socklen_t len = 0; + int err, s; + + init_addr_loopback(family, &addr, &len); + + s = xsocket(family, sotype, 0); + if (s == -1) + return -1; + + if (progfd >= 0) + enable_reuseport(s, progfd); + + err = xbind(s, sockaddr(&addr), len); + if (err) + goto close; + + if (sotype & SOCK_DGRAM) + return s; + + err = xlisten(s, SOMAXCONN); + if (err) + goto close; + + return s; +close: + xclose(s); + return -1; +} + +static inline int socket_loopback(int family, int sotype) +{ + return socket_loopback_reuseport(family, sotype, -1); +} + +static inline int poll_connect(int fd, unsigned int timeout_sec) +{ + struct timeval timeout = { .tv_sec = timeout_sec }; + fd_set wfds; + int r, eval; + socklen_t esize = sizeof(eval); + + FD_ZERO(&wfds); + FD_SET(fd, &wfds); + + r = select(fd + 1, NULL, &wfds, NULL, &timeout); + if (r == 0) + errno = ETIME; + if (r != 1) + return -1; + + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &eval, &esize) < 0) + return -1; + if (eval != 0) { + errno = eval; + return -1; + } + + return 0; +} + +static inline int poll_read(int fd, unsigned int timeout_sec) +{ + struct timeval timeout = { .tv_sec = timeout_sec }; + fd_set rfds; + int r; + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + + r = select(fd + 1, &rfds, NULL, NULL, &timeout); + if (r == 0) + errno = ETIME; + + return r == 1 ? 0 : -1; +} + +static inline int accept_timeout(int fd, struct sockaddr *addr, socklen_t *len, + unsigned int timeout_sec) +{ + if (poll_read(fd, timeout_sec)) + return -1; + + return accept(fd, addr, len); +} + +static inline int recv_timeout(int fd, void *buf, size_t len, int flags, + unsigned int timeout_sec) +{ + if (poll_read(fd, timeout_sec)) + return -1; + + return recv(fd, buf, len, flags); +} + + +static inline int create_pair(int family, int sotype, int *p0, int *p1) +{ + __close_fd int s, c = -1, p = -1; + struct sockaddr_storage addr; + socklen_t len = sizeof(addr); + int err; + + s = socket_loopback(family, sotype); + if (s < 0) + return s; + + err = xgetsockname(s, sockaddr(&addr), &len); + if (err) + return err; + + c = xsocket(family, sotype, 0); + if (c < 0) + return c; + + err = connect(c, sockaddr(&addr), len); + if (err) { + if (errno != EINPROGRESS) { + FAIL_ERRNO("connect"); + return err; + } + + err = poll_connect(c, IO_TIMEOUT_SEC); + if (err) { + FAIL_ERRNO("poll_connect"); + return err; + } + } + + switch (sotype & SOCK_TYPE_MASK) { + case SOCK_DGRAM: + err = xgetsockname(c, sockaddr(&addr), &len); + if (err) + return err; + + err = xconnect(s, sockaddr(&addr), len); + if (err) + return err; + + *p0 = take_fd(s); + break; + case SOCK_STREAM: + case SOCK_SEQPACKET: + p = xaccept_nonblock(s, NULL, NULL); + if (p < 0) + return p; + + *p0 = take_fd(p); + break; + default: + FAIL("Unsupported socket type %#x", sotype); + return -EOPNOTSUPP; + } + + *p1 = take_fd(c); + return 0; +} + +static inline int create_socket_pairs(int family, int sotype, int *c0, int *c1, + int *p0, int *p1) +{ + int err; + + err = create_pair(family, sotype, c0, p0); + if (err) + return err; + + err = create_pair(family, sotype, c1, p1); + if (err) { + close(*c0); + close(*p0); + } + + return err; +} + +#endif // __SOCKET_HELPERS__ diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_helpers.h b/tools/testing/selftests/bpf/prog_tests/sockmap_helpers.h index 38e35c72bdaa..3e5571dd578d 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockmap_helpers.h +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_helpers.h @@ -1,139 +1,12 @@ #ifndef __SOCKMAP_HELPERS__ #define __SOCKMAP_HELPERS__ -#include +#include "socket_helpers.h" -/* include/linux/net.h */ -#define SOCK_TYPE_MASK 0xf - -#define IO_TIMEOUT_SEC 30 -#define MAX_STRERR_LEN 256 #define MAX_TEST_NAME 80 -/* workaround for older vm_sockets.h */ -#ifndef VMADDR_CID_LOCAL -#define VMADDR_CID_LOCAL 1 -#endif - #define __always_unused __attribute__((__unused__)) -/* include/linux/cleanup.h */ -#define __get_and_null(p, nullvalue) \ - ({ \ - __auto_type __ptr = &(p); \ - __auto_type __val = *__ptr; \ - *__ptr = nullvalue; \ - __val; \ - }) - -#define take_fd(fd) __get_and_null(fd, -EBADF) - -#define _FAIL(errnum, fmt...) \ - ({ \ - error_at_line(0, (errnum), __func__, __LINE__, fmt); \ - CHECK_FAIL(true); \ - }) -#define FAIL(fmt...) _FAIL(0, fmt) -#define FAIL_ERRNO(fmt...) _FAIL(errno, fmt) -#define FAIL_LIBBPF(err, msg) \ - ({ \ - char __buf[MAX_STRERR_LEN]; \ - libbpf_strerror((err), __buf, sizeof(__buf)); \ - FAIL("%s: %s", (msg), __buf); \ - }) - -/* Wrappers that fail the test on error and report it. */ - -#define xaccept_nonblock(fd, addr, len) \ - ({ \ - int __ret = \ - accept_timeout((fd), (addr), (len), IO_TIMEOUT_SEC); \ - if (__ret == -1) \ - FAIL_ERRNO("accept"); \ - __ret; \ - }) - -#define xbind(fd, addr, len) \ - ({ \ - int __ret = bind((fd), (addr), (len)); \ - if (__ret == -1) \ - FAIL_ERRNO("bind"); \ - __ret; \ - }) - -#define xclose(fd) \ - ({ \ - int __ret = close((fd)); \ - if (__ret == -1) \ - FAIL_ERRNO("close"); \ - __ret; \ - }) - -#define xconnect(fd, addr, len) \ - ({ \ - int __ret = connect((fd), (addr), (len)); \ - if (__ret == -1) \ - FAIL_ERRNO("connect"); \ - __ret; \ - }) - -#define xgetsockname(fd, addr, len) \ - ({ \ - int __ret = getsockname((fd), (addr), (len)); \ - if (__ret == -1) \ - FAIL_ERRNO("getsockname"); \ - __ret; \ - }) - -#define xgetsockopt(fd, level, name, val, len) \ - ({ \ - int __ret = getsockopt((fd), (level), (name), (val), (len)); \ - if (__ret == -1) \ - FAIL_ERRNO("getsockopt(" #name ")"); \ - __ret; \ - }) - -#define xlisten(fd, backlog) \ - ({ \ - int __ret = listen((fd), (backlog)); \ - if (__ret == -1) \ - FAIL_ERRNO("listen"); \ - __ret; \ - }) - -#define xsetsockopt(fd, level, name, val, len) \ - ({ \ - int __ret = setsockopt((fd), (level), (name), (val), (len)); \ - if (__ret == -1) \ - FAIL_ERRNO("setsockopt(" #name ")"); \ - __ret; \ - }) - -#define xsend(fd, buf, len, flags) \ - ({ \ - ssize_t __ret = send((fd), (buf), (len), (flags)); \ - if (__ret == -1) \ - FAIL_ERRNO("send"); \ - __ret; \ - }) - -#define xrecv_nonblock(fd, buf, len, flags) \ - ({ \ - ssize_t __ret = recv_timeout((fd), (buf), (len), (flags), \ - IO_TIMEOUT_SEC); \ - if (__ret == -1) \ - FAIL_ERRNO("recv"); \ - __ret; \ - }) - -#define xsocket(family, sotype, flags) \ - ({ \ - int __ret = socket(family, sotype, flags); \ - if (__ret == -1) \ - FAIL_ERRNO("socket"); \ - __ret; \ - }) - #define xbpf_map_delete_elem(fd, key) \ ({ \ int __ret = bpf_map_delete_elem((fd), (key)); \ @@ -193,130 +66,6 @@ __ret; \ }) -static inline void close_fd(int *fd) -{ - if (*fd >= 0) - xclose(*fd); -} - -#define __close_fd __attribute__((cleanup(close_fd))) - -static inline int poll_connect(int fd, unsigned int timeout_sec) -{ - struct timeval timeout = { .tv_sec = timeout_sec }; - fd_set wfds; - int r, eval; - socklen_t esize = sizeof(eval); - - FD_ZERO(&wfds); - FD_SET(fd, &wfds); - - r = select(fd + 1, NULL, &wfds, NULL, &timeout); - if (r == 0) - errno = ETIME; - if (r != 1) - return -1; - - if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &eval, &esize) < 0) - return -1; - if (eval != 0) { - errno = eval; - return -1; - } - - return 0; -} - -static inline int poll_read(int fd, unsigned int timeout_sec) -{ - struct timeval timeout = { .tv_sec = timeout_sec }; - fd_set rfds; - int r; - - FD_ZERO(&rfds); - FD_SET(fd, &rfds); - - r = select(fd + 1, &rfds, NULL, NULL, &timeout); - if (r == 0) - errno = ETIME; - - return r == 1 ? 0 : -1; -} - -static inline int accept_timeout(int fd, struct sockaddr *addr, socklen_t *len, - unsigned int timeout_sec) -{ - if (poll_read(fd, timeout_sec)) - return -1; - - return accept(fd, addr, len); -} - -static inline int recv_timeout(int fd, void *buf, size_t len, int flags, - unsigned int timeout_sec) -{ - if (poll_read(fd, timeout_sec)) - return -1; - - return recv(fd, buf, len, flags); -} - -static inline void init_addr_loopback4(struct sockaddr_storage *ss, - socklen_t *len) -{ - struct sockaddr_in *addr4 = memset(ss, 0, sizeof(*ss)); - - addr4->sin_family = AF_INET; - addr4->sin_port = 0; - addr4->sin_addr.s_addr = htonl(INADDR_LOOPBACK); - *len = sizeof(*addr4); -} - -static inline void init_addr_loopback6(struct sockaddr_storage *ss, - socklen_t *len) -{ - struct sockaddr_in6 *addr6 = memset(ss, 0, sizeof(*ss)); - - addr6->sin6_family = AF_INET6; - addr6->sin6_port = 0; - addr6->sin6_addr = in6addr_loopback; - *len = sizeof(*addr6); -} - -static inline void init_addr_loopback_vsock(struct sockaddr_storage *ss, - socklen_t *len) -{ - struct sockaddr_vm *addr = memset(ss, 0, sizeof(*ss)); - - addr->svm_family = AF_VSOCK; - addr->svm_port = VMADDR_PORT_ANY; - addr->svm_cid = VMADDR_CID_LOCAL; - *len = sizeof(*addr); -} - -static inline void init_addr_loopback(int family, struct sockaddr_storage *ss, - socklen_t *len) -{ - switch (family) { - case AF_INET: - init_addr_loopback4(ss, len); - return; - case AF_INET6: - init_addr_loopback6(ss, len); - return; - case AF_VSOCK: - init_addr_loopback_vsock(ss, len); - return; - default: - FAIL("unsupported address family %d", family); - } -} - -static inline struct sockaddr *sockaddr(struct sockaddr_storage *ss) -{ - return (struct sockaddr *)ss; -} - static inline int add_to_sockmap(int sock_mapfd, int fd1, int fd2) { u64 value; @@ -334,136 +83,4 @@ static inline int add_to_sockmap(int sock_mapfd, int fd1, int fd2) return xbpf_map_update_elem(sock_mapfd, &key, &value, BPF_NOEXIST); } -static inline int enable_reuseport(int s, int progfd) -{ - int err, one = 1; - - err = xsetsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); - if (err) - return -1; - err = xsetsockopt(s, SOL_SOCKET, SO_ATTACH_REUSEPORT_EBPF, &progfd, - sizeof(progfd)); - if (err) - return -1; - - return 0; -} - -static inline int socket_loopback_reuseport(int family, int sotype, int progfd) -{ - struct sockaddr_storage addr; - socklen_t len = 0; - int err, s; - - init_addr_loopback(family, &addr, &len); - - s = xsocket(family, sotype, 0); - if (s == -1) - return -1; - - if (progfd >= 0) - enable_reuseport(s, progfd); - - err = xbind(s, sockaddr(&addr), len); - if (err) - goto close; - - if (sotype & SOCK_DGRAM) - return s; - - err = xlisten(s, SOMAXCONN); - if (err) - goto close; - - return s; -close: - xclose(s); - return -1; -} - -static inline int socket_loopback(int family, int sotype) -{ - return socket_loopback_reuseport(family, sotype, -1); -} - -static inline int create_pair(int family, int sotype, int *p0, int *p1) -{ - __close_fd int s, c = -1, p = -1; - struct sockaddr_storage addr; - socklen_t len = sizeof(addr); - int err; - - s = socket_loopback(family, sotype); - if (s < 0) - return s; - - err = xgetsockname(s, sockaddr(&addr), &len); - if (err) - return err; - - c = xsocket(family, sotype, 0); - if (c < 0) - return c; - - err = connect(c, sockaddr(&addr), len); - if (err) { - if (errno != EINPROGRESS) { - FAIL_ERRNO("connect"); - return err; - } - - err = poll_connect(c, IO_TIMEOUT_SEC); - if (err) { - FAIL_ERRNO("poll_connect"); - return err; - } - } - - switch (sotype & SOCK_TYPE_MASK) { - case SOCK_DGRAM: - err = xgetsockname(c, sockaddr(&addr), &len); - if (err) - return err; - - err = xconnect(s, sockaddr(&addr), len); - if (err) - return err; - - *p0 = take_fd(s); - break; - case SOCK_STREAM: - case SOCK_SEQPACKET: - p = xaccept_nonblock(s, NULL, NULL); - if (p < 0) - return p; - - *p0 = take_fd(p); - break; - default: - FAIL("Unsupported socket type %#x", sotype); - return -EOPNOTSUPP; - } - - *p1 = take_fd(c); - return 0; -} - -static inline int create_socket_pairs(int family, int sotype, int *c0, int *c1, - int *p0, int *p1) -{ - int err; - - err = create_pair(family, sotype, c0, p0); - if (err) - return err; - - err = create_pair(family, sotype, c1, p1); - if (err) { - close(*c0); - close(*p0); - } - - return err; -} - #endif // __SOCKMAP_HELPERS__ From patchwork Fri Nov 29 01:22:21 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cong Wang X-Patchwork-Id: 13888388 X-Patchwork-Delegate: bpf@iogearbox.net Received: from mail-pl1-f171.google.com (mail-pl1-f171.google.com [209.85.214.171]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B894B40BE5; Fri, 29 Nov 2024 01:22:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732843361; cv=none; b=KrUtbNQfaOI9rLzUi6LyOVeSRyime4NAdt6jYWPPj8H4pZ4zTSCRRvI0jH0ClDBATmT5XR4qaMPicPhLjog3AC2OETaigEhw+ChA7yeF3CLdTpDwUSkSwv1HChoGrgYBh4mfy5ghIgM9l+CG4JojNoMv8ONneNx1sem/+aDbGhA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732843361; c=relaxed/simple; bh=J2jrEWju1jVKn0vlRKQ9FBdIPh81YXEU56bdDxRNoNU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=e+Fz/hIV1zdE/SYSlWI5VZvOp41Xk7dhC1I5T93E2lXQRkuPSVTd715+t+tDgRWiAlNeB6bhqht9B97nRqi9t3n428cVhHCDYhdM7XKXA86pwtlUhUmJ4Xnc20ZMZ+YRHln25agHcaAyHl5RTZybyS5fiD9WVJVRvRRAY/P0oew= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=YwHhdnV1; arc=none smtp.client-ip=209.85.214.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="YwHhdnV1" Received: by mail-pl1-f171.google.com with SMTP id d9443c01a7336-2153a73edd5so2643175ad.2; Thu, 28 Nov 2024 17:22:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1732843359; x=1733448159; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=BBHjmnFgNYCxWG5JxN+rt+rQGcx0todJSez7JTwI7wM=; b=YwHhdnV183bg+EEWCfX6S7LGX3MQFCcB8PmRzz4T8zFlkUjGop1fXyn39H0FNmfsBE K+Phg7rBB2O5OAC7liqmp9gy+UcysKAb2a3xbi0JwKHL41utg3vMNqS63x1sUC75YwFK NYdOAJnES2fC5RTEMnIRyv21b+IA6Vq4IccJ+pg9ZwgJVZFtHGKvUpLhCJMd+I+R2i3j BKz2I6TfRiJuKRQHolflTrFylDGZn3NDzmhdGUjPLWdTvBl3NDOmGJ7nXehwuVv9Ji8t jE19v7jPgfacuK5a9XIYgWQ+XgZEpCbBeWL9M/TCbEP0sGsoAtHGAqI5e95szOgNXvwg kACw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1732843359; x=1733448159; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=BBHjmnFgNYCxWG5JxN+rt+rQGcx0todJSez7JTwI7wM=; b=RzXGqjU9+AAnQI4NkO05RRFzuSqQL7jVJy6wZCaFJJG4+LnYRr/5vUd2y0T7R6rnnz Q9c9ubf2cQk9qsLUhSzvZ0PgpvDIdfvuQkvgpBBN1rKR0X0HmJ2JSP/0ESM25J7DZg8X qSyTZ0nw3t2ar7RpHeZYiP6KSUcnB4TF811Xlv/wrby2bN08Xd/n4g72+3lmt12DQP6J /I0aWOIRrVUklfLPS3QfBiEBS5cGgte9pZ+yeGJmos6KK5tLrUa+Gj1R70hzAZ1Z1/9k NnnqH20AYzEeU21nJ1vTrUF0ij5vNvjKJNgR0sFJ9v8+OoFdUyOeXaoGid9BrbKzwugB fwUA== X-Gm-Message-State: AOJu0YyjR1wiG/ceC+uliE82rQDB/oD/wHpmPU3N8J4QQ9+IaLXdT1c6 rWcZNQ1LuCBv0+jLE11KMExmm7xgILzitrL4sYFoLPC6nIiPrX8IRjpY3g== X-Gm-Gg: ASbGncsUEnl/hMaXCXslP+Q3etKbgH2Hpa/o8J8INMJK5iwDYvOnv2tUP277MYs7hxA 2CoxEp9IL6nI1xzfOUNhQCT/azexwmyBhin+u85EVv+wj6SZlwtB+QWP4yleXF3u6MD8AM/h532 G5fjI36H3IjMHfNvjfj9/BRizWQ+JLKgpplNJzktnocpEay7gZvS2bHyzDhxMynn9rXna1o44gW zdnKtOCnEfAIS+TAct0bFRgEh+29NowMn8QTnLS6kIZZGEe+F9DFHKUiJ6d1AYFh0Gur61w7a1G 8wI= X-Google-Smtp-Source: AGHT+IHwh700/BckVWRm/rz1ESuNAcWfcqgdTpUXx25M+SH7jPkgDqD/3jgnKuaDATNhGTjxJeYZ8g== X-Received: by 2002:a17:902:ec8f:b0:20c:62e1:6361 with SMTP id d9443c01a7336-215018579admr125549245ad.25.1732843358658; Thu, 28 Nov 2024 17:22:38 -0800 (PST) Received: from pop-os.hsd1.ca.comcast.net ([2601:647:6881:9060:7990:ba58:c520:e7e8]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-21521905120sm20010215ad.80.2024.11.28.17.22.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 Nov 2024 17:22:38 -0800 (PST) From: Cong Wang To: netdev@vger.kernel.org Cc: bpf@vger.kernel.org, Cong Wang , John Fastabend , Daniel Borkmann , Zijian Zhang Subject: [Patch bpf v2 4/4] selftests/bpf: Test bpf_skb_change_tail() in TC ingress Date: Thu, 28 Nov 2024 17:22:21 -0800 Message-Id: <20241129012221.739069-5-xiyou.wangcong@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241129012221.739069-1-xiyou.wangcong@gmail.com> References: <20241129012221.739069-1-xiyou.wangcong@gmail.com> Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: bpf@iogearbox.net From: Cong Wang Similarly to the previous test, we also need a test case to cover positive offsets as well, TC is an excellent hook for this. Cc: John Fastabend Cc: Daniel Borkmann Cc: Zijian Zhang Signed-off-by: Cong Wang --- .../selftests/bpf/prog_tests/tc_change_tail.c | 78 ++++++++++++ .../selftests/bpf/progs/test_tc_change_tail.c | 114 ++++++++++++++++++ 2 files changed, 192 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/tc_change_tail.c create mode 100644 tools/testing/selftests/bpf/progs/test_tc_change_tail.c diff --git a/tools/testing/selftests/bpf/prog_tests/tc_change_tail.c b/tools/testing/selftests/bpf/prog_tests/tc_change_tail.c new file mode 100644 index 000000000000..110f54a71a35 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/tc_change_tail.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include + +#include "test_tc_change_tail.skel.h" +#include "socket_helpers.h" + +#define LO_IFINDEX 1 + +void test_tc_change_tail(void) +{ + DECLARE_LIBBPF_OPTS(bpf_tc_hook, hook, .ifindex = LO_IFINDEX, + .attach_point = BPF_TC_INGRESS); + DECLARE_LIBBPF_OPTS(bpf_tc_opts, opts); + struct test_tc_change_tail *skel = NULL; + bool hook_created = false; + int ret, fd; + int c1, p1; + char buf[2]; + + skel = test_tc_change_tail__open_and_load(); + if (!ASSERT_OK_PTR(skel, "test_tc_change_tail__open_and_load")) + return; + ret = bpf_tc_hook_create(&hook); + if (ret == 0) + hook_created = true; + ret = ret == -EEXIST ? 0 : ret; + if (!ASSERT_OK(ret, "bpf_tc_hook_create")) + goto destroy; + fd = bpf_program__fd(skel->progs.change_tail); + opts.prog_fd = fd; + opts.handle = 1; + opts.priority = 1; + opts.flags = BPF_TC_F_REPLACE; + ret = bpf_tc_attach(&hook, &opts); + if (!ASSERT_OK(ret, "bpf_tc_attach")) + goto hook_destroy; + + ret = create_pair(AF_INET, SOCK_STREAM, &c1, &p1); + if (!ASSERT_OK(ret, "create_pair")) + goto detach; + + ret = xsend(p1, "Tr", 2, 0); + ASSERT_EQ(ret, 2, "xsend(p1)"); + ret = recv(c1, buf, 2, 0); + ASSERT_EQ(ret, 2, "recv(c1)"); + ASSERT_EQ(skel->data->change_tail_ret, 0, "change_tail_ret"); + + ret = xsend(p1, "G", 1, 0); + ASSERT_EQ(ret, 1, "xsend(p1)"); + ret = recv(c1, buf, 1, 0); + ASSERT_EQ(ret, 1, "recv(c1)"); + ASSERT_EQ(skel->data->change_tail_ret, 0, "change_tail_ret"); + + ret = xsend(p1, "E", 1, 0); + ASSERT_EQ(ret, 1, "xsend(p1)"); + ret = recv(c1, buf, 1, 0); + ASSERT_EQ(ret, 1, "recv(c1)"); + ASSERT_EQ(skel->data->change_tail_ret, -EINVAL, "change_tail_ret"); + + ret = xsend(p1, "Z", 1, 0); + ASSERT_EQ(ret, 1, "xsend(p1)"); + ret = recv(c1, buf, 1, 0); + ASSERT_EQ(ret, 1, "recv(c1)"); + ASSERT_EQ(skel->data->change_tail_ret, -EINVAL, "change_tail_ret"); + + close(c1); + close(p1); +detach: + bpf_tc_detach(&hook, &opts); +hook_destroy: + if (hook_created) + bpf_tc_hook_destroy(&hook); +destroy: + test_tc_change_tail__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/progs/test_tc_change_tail.c b/tools/testing/selftests/bpf/progs/test_tc_change_tail.c new file mode 100644 index 000000000000..735c7325a2ab --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_tc_change_tail.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include +#include + +long change_tail_ret = 1; + +static __always_inline struct iphdr *parse_ip_header(struct __sk_buff *skb, int *ip_proto) +{ + void *data_end = (void *)(long)skb->data_end; + void *data = (void *)(long)skb->data; + struct ethhdr *eth = data; + struct iphdr *iph; + + /* Verify Ethernet header */ + if ((void *)(data + sizeof(*eth)) > data_end) + return NULL; + + /* Skip Ethernet header to get to IP header */ + iph = (void *)(data + sizeof(struct ethhdr)); + + /* Verify IP header */ + if ((void *)(data + sizeof(struct ethhdr) + sizeof(*iph)) > data_end) + return NULL; + + /* Basic IP header validation */ + if (iph->version != 4) /* Only support IPv4 */ + return NULL; + + if (iph->ihl < 5) /* Minimum IP header length */ + return NULL; + + *ip_proto = iph->protocol; + return iph; +} + +static __always_inline struct tcphdr *parse_tcp_header(struct __sk_buff *skb, struct iphdr *iph) +{ + void *data_end = (void *)(long)skb->data_end; + void *hdr = (void *)iph; + struct tcphdr *tcp; + + /* Calculate TCP header position */ + tcp = hdr + (iph->ihl * 4); + hdr = (void *)tcp; + + /* Verify TCP header bounds */ + if ((void *)(hdr + sizeof(*tcp)) > data_end) + return NULL; + + /* Basic TCP validation */ + if (tcp->doff < 5) /* Minimum TCP header length */ + return NULL; + + /* Success */ + return tcp; +} + +SEC("tc") +int change_tail(struct __sk_buff *skb) +{ + int len = skb->len; + struct tcphdr *tcp; + struct iphdr *iph; + void *data_end; + char *payload; + int ip_proto; + + bpf_skb_pull_data(skb, len); + + data_end = (void *)(long)skb->data_end; + iph = parse_ip_header(skb, &ip_proto); + if (!iph) + return TC_ACT_OK; + + if (ip_proto != IPPROTO_TCP) /* Only support TCP packets */ + return TC_ACT_OK; + + tcp = parse_tcp_header(skb, iph); + if (!tcp) + return TC_ACT_OK; + + payload = (char *)tcp + (tcp->doff * 4); + if (payload + 1 > (char *)data_end) + return TC_ACT_OK; + + if (payload[0] == 'T') { + change_tail_ret = bpf_skb_change_tail(skb, len - 1, 0); + /* Change it back to make TCP happy */ + if (change_tail_ret == 0) + bpf_skb_change_tail(skb, len, 0); + return TC_ACT_OK; + } else if (payload[0] == 'G') { + change_tail_ret = bpf_skb_change_tail(skb, len + 1, 0); + /* Change it back to make TCP happy */ + if (change_tail_ret == 0) + bpf_skb_change_tail(skb, len, 0); + return TC_ACT_OK; + } else if (payload[0] == 'E') { + change_tail_ret = bpf_skb_change_tail(skb, 65535, 0); /* Should fail */ + return TC_ACT_OK; + } else if (payload[0] == 'Z') { + change_tail_ret = bpf_skb_change_tail(skb, 0, 0); /* Should fail */ + return TC_ACT_OK; + } + return TC_ACT_SHOT; +} + +char _license[] SEC("license") = "GPL";