* [PATCH net-next 0/5] net: ipqess: introduce Qualcomm IPQESS driver
From: Maxime Chevallier @ 2022-04-22 18:03 UTC (permalink / raw)
To: davem, Rob Herring
Cc: Maxime Chevallier, netdev, linux-kernel, devicetree,
thomas.petazzoni, Andrew Lunn, Florian Fainelli, Heiner Kallweit,
Russell King, linux-arm-kernel, Vladimir Oltean, Luka Perkov,
Robert Marko
Hello everyone,
This series introduces a new driver, for the Qualcomm IPQESS Ethernet
Controller, found on the IPQ4019.
The driver itself is pretty straightforward, but has lived out-of-tree
for a while. I've done my best to clean-up some outdated API calls, but
some might remain.
This controller is somewhat special, since it's part of the IPQ4019 SoC
which also includes an QCA8K switch, and uses the IPQESS controller for
the CPU port. The switch is so tightly intergrated with the MAC that it
is connected to the MAC using an internal link (hence the fact that we
only support PHY_INTERFACE_MODE_INTERNAL), and this has some
consequences on the DSA side.
The tagging for the switch isn't done inband as most switch do, but
out-of-band, the DSA tag being included in the DMA descriptor.
So, this series also includes a new DSA tagging protocol, that sets the
DSA port index into skb->shinfo, so that the MAC driver can use it to
build the descriptor. This is definitely unusual, so I'l very openned to
suggestions, comments and reviews on the tagging side of this series.
Thanks to the Sartura folks who worked on a base version of this driver,
and provided test hardware.
Best regards,
Maxime Chevallier
Maxime Chevallier (5):
net: ipqess: introduce the Qualcomm IPQESS driver
net: dsa: add out-of-band tagging protocol
net: ipqess: Add out-of-band DSA tagging support
net: dt-bindings: Introduce the Qualcomm IPQESS Ethernet controller
ARM: dts: qcom: ipq4019: Add description for the IPQESS Ethernet
controller
.../devicetree/bindings/net/qcom,ipqess.yaml | 94 ++
MAINTAINERS | 6 +
arch/arm/boot/dts/qcom-ipq4019.dtsi | 42 +
drivers/net/ethernet/qualcomm/Kconfig | 11 +
drivers/net/ethernet/qualcomm/Makefile | 2 +
drivers/net/ethernet/qualcomm/ipqess/Makefile | 8 +
drivers/net/ethernet/qualcomm/ipqess/ipqess.c | 1258 +++++++++++++++++
drivers/net/ethernet/qualcomm/ipqess/ipqess.h | 515 +++++++
.../ethernet/qualcomm/ipqess/ipqess_ethtool.c | 168 +++
include/linux/skbuff.h | 7 +
include/net/dsa.h | 2 +
net/dsa/Kconfig | 7 +
net/dsa/Makefile | 1 +
net/dsa/tag_oob.c | 45 +
14 files changed, 2166 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/qcom,ipqess.yaml
create mode 100644 drivers/net/ethernet/qualcomm/ipqess/Makefile
create mode 100644 drivers/net/ethernet/qualcomm/ipqess/ipqess.c
create mode 100644 drivers/net/ethernet/qualcomm/ipqess/ipqess.h
create mode 100644 drivers/net/ethernet/qualcomm/ipqess/ipqess_ethtool.c
create mode 100644 net/dsa/tag_oob.c
--
2.35.1
^ permalink raw reply
* [PATCH net-next 3/5] net: ipqess: Add out-of-band DSA tagging support
From: Maxime Chevallier @ 2022-04-22 18:03 UTC (permalink / raw)
To: davem, Rob Herring
Cc: Maxime Chevallier, netdev, linux-kernel, devicetree,
thomas.petazzoni, Andrew Lunn, Florian Fainelli, Heiner Kallweit,
Russell King, linux-arm-kernel, Vladimir Oltean, Luka Perkov,
Robert Marko
In-Reply-To: <20220422180305.301882-1-maxime.chevallier@bootlin.com>
On the IPQ4019, there's an 5 ports switch connected to the CPU through
the IPQESS Ethernet controller. The way the DSA tag is sent-out to that
switch is through the DMA descriptor, due to how tightly it is
integrated with the switch.
This commit uses the out-of-band tagging protocol to get the outgoing
port index for each SKB, and reports it back in the skb->shinfo on the
RX side based on information located in the descriptor.
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
drivers/net/ethernet/qualcomm/ipqess/ipqess.c | 23 +++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/drivers/net/ethernet/qualcomm/ipqess/ipqess.c b/drivers/net/ethernet/qualcomm/ipqess/ipqess.c
index 4ecb8c65417b..32a5cdd1c063 100644
--- a/drivers/net/ethernet/qualcomm/ipqess/ipqess.c
+++ b/drivers/net/ethernet/qualcomm/ipqess/ipqess.c
@@ -20,6 +20,7 @@
#include <linux/skbuff.h>
#include <linux/vmalloc.h>
#include <net/checksum.h>
+#include <net/dsa.h>
#include <net/ip6_checksum.h>
#include "ipqess.h"
@@ -399,6 +400,11 @@ static int ipqess_rx_poll(struct ipqess_rx_ring *rx_ring, int budget)
skb->protocol = eth_type_trans(skb, rx_ring->ess->netdev);
skb_record_rx_queue(skb, rx_ring->ring_id);
+ if (netdev_uses_dsa(rx_ring->ess->netdev)) {
+ skb_shinfo(skb)->dsa_tag_info.dp =
+ FIELD_GET(IPQESS_RRD_PORT_ID_MASK, rd->rrd1);
+ }
+
if (rd->rrd6 & IPQESS_RRD_CSUM_FAIL_MASK)
skb_checksum_none_assert(skb);
else
@@ -706,6 +712,21 @@ static void ipqess_rollback_tx(struct ipqess *eth,
tx_ring->head = start_index;
}
+static void ipqess_process_dsa_tag_sh(struct ipqess *ess, struct sk_buff *skb,
+ u32 *word3)
+{
+ struct skb_shared_info *shinfo = skb_shinfo(skb);
+ struct dsa_tag_info *tag_info = &shinfo->dsa_tag_info;
+
+ if (!netdev_uses_dsa(ess->netdev) ||
+ tag_info->proto != DSA_TAG_PROTO_OOB)
+ return;
+
+ *word3 |= tag_info->dp << IPQESS_TPD_PORT_BITMAP_SHIFT;
+ *word3 |= BIT(IPQESS_TPD_FROM_CPU_SHIFT);
+ *word3 |= 0x3e << IPQESS_TPD_PORT_BITMAP_SHIFT;
+}
+
static int ipqess_tx_map_and_fill(struct ipqess_tx_ring *tx_ring,
struct sk_buff *skb)
{
@@ -716,6 +737,8 @@ static int ipqess_tx_map_and_fill(struct ipqess_tx_ring *tx_ring,
u16 len;
int i;
+ ipqess_process_dsa_tag_sh(tx_ring->ess, skb, &word3);
+
if (skb_is_gso(skb)) {
if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) {
lso_word1 |= IPQESS_TPD_IPV4_EN;
--
2.35.1
^ permalink raw reply related
* [PATCH net-next 2/5] net: dsa: add out-of-band tagging protocol
From: Maxime Chevallier @ 2022-04-22 18:03 UTC (permalink / raw)
To: davem, Rob Herring
Cc: Maxime Chevallier, netdev, linux-kernel, devicetree,
thomas.petazzoni, Andrew Lunn, Florian Fainelli, Heiner Kallweit,
Russell King, linux-arm-kernel, Vladimir Oltean, Luka Perkov,
Robert Marko
In-Reply-To: <20220422180305.301882-1-maxime.chevallier@bootlin.com>
This tagging protocol is designed for the situation where the link
between the MAC and the Switch is designed such that the Destination
Port, which is usually embedded in some part of the Ethernet Header, is
sent out-of-band, and isn't present at all in the Ethernet frame.
This can happen when the MAC and Switch are tightly integrated on an
SoC, as is the case with the Qualcomm IPQ4019 for example, where the DSA
tag is inserted directly into the DMA descriptors. In that case,
the MAC driver is responsible for sending the tag to the switch using
the out-of-band medium. To do so, the MAC driver needs to have the
information of the destination port for that skb.
This tagging protocol relies on a new set of fields in skb->shinfo to
transmit the dsa tagging information to and from the MAC driver.
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
include/linux/skbuff.h | 7 +++++++
include/net/dsa.h | 2 ++
net/dsa/Kconfig | 7 +++++++
net/dsa/Makefile | 1 +
net/dsa/tag_oob.c | 45 ++++++++++++++++++++++++++++++++++++++++++
5 files changed, 62 insertions(+)
create mode 100644 net/dsa/tag_oob.c
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 0ef11df1bc67..6f8012cf9246 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -685,6 +685,11 @@ int skb_zerocopy_iter_stream(struct sock *sk, struct sk_buff *skb,
struct msghdr *msg, int len,
struct ubuf_info *uarg);
+struct dsa_tag_info {
+ unsigned int proto;
+ unsigned int dp;
+};
+
/* This data is invariant across clones and lives at
* the end of the header data, ie. at skb->end.
*/
@@ -701,6 +706,8 @@ struct skb_shared_info {
unsigned int gso_type;
u32 tskey;
+ struct dsa_tag_info dsa_tag_info;
+
/*
* Warning : all fields before dataref are cleared in __alloc_skb()
*/
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 14e10cda7267..9951df858912 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -53,6 +53,7 @@ struct phylink_link_state;
#define DSA_TAG_PROTO_SJA1110_VALUE 23
#define DSA_TAG_PROTO_RTL8_4_VALUE 24
#define DSA_TAG_PROTO_RTL8_4T_VALUE 25
+#define DSA_TAG_PROTO_OOB_VALUE 26
enum dsa_tag_protocol {
DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE,
@@ -81,6 +82,7 @@ enum dsa_tag_protocol {
DSA_TAG_PROTO_SJA1110 = DSA_TAG_PROTO_SJA1110_VALUE,
DSA_TAG_PROTO_RTL8_4 = DSA_TAG_PROTO_RTL8_4_VALUE,
DSA_TAG_PROTO_RTL8_4T = DSA_TAG_PROTO_RTL8_4T_VALUE,
+ DSA_TAG_PROTO_OOB = DSA_TAG_PROTO_OOB_VALUE,
};
struct dsa_switch;
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index 8cb87b5067ee..b7aa4d8552b2 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -57,6 +57,13 @@ config NET_DSA_TAG_HELLCREEK
Say Y or M if you want to enable support for tagging frames
for the Hirschmann Hellcreek TSN switches.
+config NET_DSA_TAG_OOB
+ tristate "Tag driver for Out-of-band tagging drivers"
+ help
+ Say Y or M if you want to enable support for tagging out-of-band. In
+ that case, the MAC driver becomes responsible for sending the tag to
+ the switch, outside the inband data.
+
config NET_DSA_TAG_GSWIP
tristate "Tag driver for Lantiq / Intel GSWIP switches"
help
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
index 9f75820e7c98..b156e20f9c0a 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_NET_DSA_TAG_BRCM_COMMON) += tag_brcm.o
obj-$(CONFIG_NET_DSA_TAG_DSA_COMMON) += tag_dsa.o
obj-$(CONFIG_NET_DSA_TAG_GSWIP) += tag_gswip.o
obj-$(CONFIG_NET_DSA_TAG_HELLCREEK) += tag_hellcreek.o
+obj-$(CONFIG_NET_DSA_TAG_OOB) += tag_oob.o
obj-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o
obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o
obj-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o
diff --git a/net/dsa/tag_oob.c b/net/dsa/tag_oob.c
new file mode 100644
index 000000000000..045c7c06e81f
--- /dev/null
+++ b/net/dsa/tag_oob.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/* Copyright (c) 2022, Maxime Chevallier <maxime.chevallier@bootlin.com> */
+
+#include <linux/bitfield.h>
+
+#include "dsa_priv.h"
+
+static struct sk_buff *oob_tag_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct dsa_port *dp = dsa_slave_to_port(dev);
+ struct dsa_tag_info *tag_info = &skb_shinfo(skb)->dsa_tag_info;
+
+ tag_info->dp = BIT(dp->index);
+ tag_info->proto = DSA_TAG_PROTO_OOB;
+
+ return skb;
+}
+
+static struct sk_buff *oob_tag_rcv(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct dsa_tag_info *tag_info = &skb_shinfo(skb)->dsa_tag_info;
+
+ skb->dev = dsa_master_find_slave(dev, 0, tag_info->dp);
+ if (!skb->dev)
+ return NULL;
+
+ return skb;
+}
+
+const struct dsa_device_ops oob_tag_dsa_ops = {
+ .name = "oob",
+ .proto = DSA_TAG_PROTO_OOB,
+ .xmit = oob_tag_xmit,
+ .rcv = oob_tag_rcv,
+};
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DSA tag driver for out-of-band tagging");
+MODULE_AUTHOR("Maxime Chevallier <maxime.chevallier@bootlin.com>");
+MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_OOB);
+
+module_dsa_tag_driver(oob_tag_dsa_ops);
--
2.35.1
^ permalink raw reply related
* RE: [PATCH net v3] ice: Fix race during aux device (un)plugging
From: Ertman, David M @ 2022-04-22 17:42 UTC (permalink / raw)
To: ivecera, netdev@vger.kernel.org
Cc: poros, mschmidt, Leon Romanovsky, Brandeburg, Jesse,
Nguyen, Anthony L, David S. Miller, Jakub Kicinski, Paolo Abeni,
Saleem, Shiraz, moderated list:INTEL ETHERNET DRIVERS, open list
In-Reply-To: <20220421060906.1902576-1-ivecera@redhat.com>
> -----Original Message-----
> From: Ivan Vecera <ivecera@redhat.com>
> Sent: Wednesday, April 20, 2022 11:09 PM
> To: netdev@vger.kernel.org
> Cc: poros <poros@redhat.com>; mschmidt <mschmidt@redhat.com>; Leon
> Romanovsky <leon@kernel.org>; Brandeburg, Jesse
> <jesse.brandeburg@intel.com>; Nguyen, Anthony L
> <anthony.l.nguyen@intel.com>; David S. Miller <davem@davemloft.net>;
> Jakub Kicinski <kuba@kernel.org>; Paolo Abeni <pabeni@redhat.com>;
> Ertman, David M <david.m.ertman@intel.com>; Saleem, Shiraz
> <shiraz.saleem@intel.com>; moderated list:INTEL ETHERNET DRIVERS <intel-
> wired-lan@lists.osuosl.org>; open list <linux-kernel@vger.kernel.org>
> Subject: [PATCH net v3] ice: Fix race during aux device (un)plugging
>
> Function ice_plug_aux_dev() assigns pf->adev field too early prior
> aux device initialization and on other side ice_unplug_aux_dev()
> starts aux device deinit and at the end assigns NULL to pf->adev.
> This is wrong because pf->adev should always be non-NULL only when
> aux device is fully initialized and ready. This wrong order causes
> a crash when ice_send_event_to_aux() call occurs because that function
> depends on non-NULL value of pf->adev and does not assume that
> aux device is half-initialized or half-destroyed.
> After order correction the race window is tiny but it is still there,
> as Leon mentioned and manipulation with pf->adev needs to be protected
> by mutex.
>
> Fix (un-)plugging functions so pf->adev field is set after aux device
> init and prior aux device destroy and protect pf->adev assignment by
> new mutex. This mutex is also held during ice_send_event_to_aux()
> call to ensure that aux device is valid during that call. Device
> lock used ice_send_event_to_aux() to avoid its concurrent run can
> be removed as this is secured by that mutex.
>
> Reproducer:
> cycle=1
> while :;do
> echo "#### Cycle: $cycle"
>
> ip link set ens7f0 mtu 9000
> ip link add bond0 type bond mode 1 miimon 100
> ip link set bond0 up
> ifenslave bond0 ens7f0
> ip link set bond0 mtu 9000
> ethtool -L ens7f0 combined 1
> ip link del bond0
> ip link set ens7f0 mtu 1500
> sleep 1
>
> let cycle++
> done
>
> In short when the device is added/removed to/from bond the aux device
> is unplugged/plugged. When MTU of the device is changed an event is
> sent to aux device asynchronously. This can race with (un)plugging
> operation and because pf->adev is set too early (plug) or too late
> (unplug) the function ice_send_event_to_aux() can touch uninitialized
> or destroyed fields. In the case of crash below pf->adev->dev.mutex.
>
> Crash:
> [ 53.372066] bond0: (slave ens7f0): making interface the new active one
> [ 53.378622] bond0: (slave ens7f0): Enslaving as an active interface with an u
> p link
> [ 53.386294] IPv6: ADDRCONF(NETDEV_CHANGE): bond0: link becomes
> ready
> [ 53.549104] bond0: (slave ens7f1): Enslaving as a backup interface with an
> up
> link
> [ 54.118906] ice 0000:ca:00.0 ens7f0: Number of in use tx queues changed
> inval
> idating tc mappings. Priority traffic classification disabled!
> [ 54.233374] ice 0000:ca:00.1 ens7f1: Number of in use tx queues changed
> inval
> idating tc mappings. Priority traffic classification disabled!
> [ 54.248204] bond0: (slave ens7f0): Releasing backup interface
> [ 54.253955] bond0: (slave ens7f1): making interface the new active one
> [ 54.274875] bond0: (slave ens7f1): Releasing backup interface
> [ 54.289153] bond0 (unregistering): Released all slaves
> [ 55.383179] MII link monitoring set to 100 ms
> [ 55.398696] bond0: (slave ens7f0): making interface the new active one
> [ 55.405241] BUG: kernel NULL pointer dereference, address:
> 0000000000000080
> [ 55.405289] bond0: (slave ens7f0): Enslaving as an active interface with an u
> p link
> [ 55.412198] #PF: supervisor write access in kernel mode
> [ 55.412200] #PF: error_code(0x0002) - not-present page
> [ 55.412201] PGD 25d2ad067 P4D 0
> [ 55.412204] Oops: 0002 [#1] PREEMPT SMP NOPTI
> [ 55.412207] CPU: 0 PID: 403 Comm: kworker/0:2 Kdump: loaded Tainted: G
> S
> 5.17.0-13579-g57f2d6540f03 #1
> [ 55.429094] bond0: (slave ens7f1): Enslaving as a backup interface with an
> up
> link
> [ 55.430224] Hardware name: Dell Inc. PowerEdge R750/06V45N, BIOS 1.4.4
> 10/07/
> 2021
> [ 55.430226] Workqueue: ice ice_service_task [ice]
> [ 55.468169] RIP: 0010:mutex_unlock+0x10/0x20
> [ 55.472439] Code: 0f b1 13 74 96 eb e0 4c 89 ee eb d8 e8 79 54 ff ff 66 0f 1f 84
> 00 00 00 00 00 0f 1f 44 00 00 65 48 8b 04 25 40 ef 01 00 31 d2 <f0> 48 0f b1 17 75
> 01 c3 e9 e3 fe ff ff 0f 1f 00 0f 1f 44 00 00 48
> [ 55.491186] RSP: 0018:ff4454230d7d7e28 EFLAGS: 00010246
> [ 55.496413] RAX: ff1a79b208b08000 RBX: ff1a79b2182e8880 RCX:
> 0000000000000001
> [ 55.503545] RDX: 0000000000000000 RSI: ff4454230d7d7db0 RDI:
> 0000000000000080
> [ 55.510678] RBP: ff1a79d1c7e48b68 R08: ff4454230d7d7db0 R09:
> 0000000000000041
> [ 55.517812] R10: 00000000000000a5 R11: 00000000000006e6 R12:
> ff1a79d1c7e48bc0
> [ 55.524945] R13: 0000000000000000 R14: ff1a79d0ffc305c0 R15:
> 0000000000000000
> [ 55.532076] FS: 0000000000000000(0000) GS:ff1a79d0ffc00000(0000)
> knlGS:0000000000000000
> [ 55.540163] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [ 55.545908] CR2: 0000000000000080 CR3: 00000003487ae003 CR4:
> 0000000000771ef0
> [ 55.553041] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
> 0000000000000000
> [ 55.560173] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
> 0000000000000400
> [ 55.567305] PKRU: 55555554
> [ 55.570018] Call Trace:
> [ 55.572474] <TASK>
> [ 55.574579] ice_service_task+0xaab/0xef0 [ice]
> [ 55.579130] process_one_work+0x1c5/0x390
> [ 55.583141] ? process_one_work+0x390/0x390
> [ 55.587326] worker_thread+0x30/0x360
> [ 55.590994] ? process_one_work+0x390/0x390
> [ 55.595180] kthread+0xe6/0x110
> [ 55.598325] ? kthread_complete_and_exit+0x20/0x20
> [ 55.603116] ret_from_fork+0x1f/0x30
> [ 55.606698] </TASK>
>
> Fixes: f9f5301e7e2d ("ice: Register auxiliary device to provide RDMA")
> Cc: Leon Romanovsky <leon@kernel.org>
> Signed-off-by: Ivan Vecera <ivecera@redhat.com>
Sorry for previous mis-reply - hit the wrong button.
LGTM
Acked-by: Dave Ertman <david.m.ertman@intel.com>
^ permalink raw reply
* Re: [PATCH 0/7] Remove unused SLOW_DOWN_IO
From: Jakub Kicinski @ 2022-04-22 17:48 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: Richard Henderson, Ivan Kokshaysky, Matt Turner, Michael Ellerman,
Benjamin Herrenschmidt, Paul Mackerras, Yoshinori Sato,
Rich Felker, Chas Williams, David S . Miller, Paolo Abeni,
linux-alpha, linux-ia64, linuxppc-dev, linux-sh,
linux-atm-general, netdev, linux-kernel, Bjorn Helgaas
In-Reply-To: <20220415190817.842864-1-helgaas@kernel.org>
On Fri, 15 Apr 2022 14:08:10 -0500 Bjorn Helgaas wrote:
> From: Bjorn Helgaas <bhelgaas@google.com>
>
> Only alpha, ia64, powerpc, and sh define SLOW_DOWN_IO, and there are no
> actual uses of it. The few references to it are in situations that are
> themselves unused. Remove them all.
>
> It should be safe to apply these independently and in any order. The only
> place SLOW_DOWN_IO is used at all is the lmc_var.h definition of DELAY,
> which is itself never used.
Hi Bojrn! Would you mind reposting just patches 1 and 3 for networking?
LMC got removed in net-next (commit a5b116a0fa90 ("net: wan: remove the
lanmedia (lmc) driver")) so the entire series fails to apply and therefore
defeats all of our patch handling scripts :S
^ permalink raw reply
* Re: [PATCH net-next v1 00/17] Extra IPsec cleanup
From: Leon Romanovsky @ 2022-04-22 17:49 UTC (permalink / raw)
To: Paolo Abeni, Jakub Kicinski, David S . Miller
Cc: Jason Gunthorpe, Saeed Mahameed, linux-netdev, Raed Salem
In-Reply-To: <cover.1650363043.git.leonro@nvidia.com>
On Tue, Apr 19, 2022 at 01:13:36PM +0300, Leon Romanovsky wrote:
> From: Leon Romanovsky <leonro@nvidia.com>
>
> Changelog:
> v1:
> * changed target from mlx5-next to net-next.
> * Improved commit message in patch #1
> * Left function names intact, with _accel_ word in it.
> v0: https://lore.kernel.org/all/cover.1649578827.git.leonro@nvidia.com
>
> --------------------
> After FPGA IPsec removal, we can go further and make sure that flow
> steering logic is aligned to mlx5_core standard together with deep
> cleaning of whole IPsec path.
>
> Thanks
Hi,
I see that this series is marked as "Awaiting Upstream" in patchworks.
https://patchwork.kernel.org/project/netdevbpf/list/?series=633295&state=*
What does it mean? Can you please apply it directly to the netdev tree?
Thanks
>
> Leon Romanovsky (17):
> net/mlx5: Simplify IPsec flow steering init/cleanup functions
> net/mlx5: Check IPsec TX flow steering namespace in advance
> net/mlx5: Don't hide fallback to software IPsec in FS code
> net/mlx5: Reduce useless indirection in IPsec FS add/delete flows
> net/mlx5: Store IPsec ESN update work in XFRM state
> net/mlx5: Remove useless validity check
> net/mlx5: Merge various control path IPsec headers into one file
> net/mlx5: Remove indirections from esp functions
> net/mlx5: Simplify HW context interfaces by using SA entry
> net/mlx5: Clean IPsec FS add/delete rules
> net/mlx5: Make sure that no dangling IPsec FS pointers exist
> net/mlx5: Don't advertise IPsec netdev support for non-IPsec device
> net/mlx5: Simplify IPsec capabilities logic
> net/mlx5: Remove not-supported ICV length
> net/mlx5: Cleanup XFRM attributes struct
> net/mlx5: Allow future addition of IPsec object modifiers
> net/mlx5: Don't perform lookup after already known sec_path
>
> .../net/ethernet/mellanox/mlx5/core/en/fs.h | 1 -
> .../ethernet/mellanox/mlx5/core/en/params.c | 2 +-
> .../mellanox/mlx5/core/en_accel/ipsec.c | 174 +++------
> .../mellanox/mlx5/core/en_accel/ipsec.h | 85 +++-
> .../mellanox/mlx5/core/en_accel/ipsec_fs.c | 362 ++++++------------
> .../mellanox/mlx5/core/en_accel/ipsec_fs.h | 4 +-
> .../mlx5/core/en_accel/ipsec_offload.c | 331 +++-------------
> .../mlx5/core/en_accel/ipsec_offload.h | 14 -
> .../mellanox/mlx5/core/en_accel/ipsec_rxtx.c | 6 +-
> .../mellanox/mlx5/core/en_accel/ipsec_stats.c | 4 +-
> .../net/ethernet/mellanox/mlx5/core/en_main.c | 1 -
> .../net/ethernet/mellanox/mlx5/core/en_rx.c | 2 +-
> .../net/ethernet/mellanox/mlx5/core/main.c | 2 +-
> include/linux/mlx5/accel.h | 153 --------
> include/linux/mlx5/mlx5_ifc.h | 2 -
> 15 files changed, 320 insertions(+), 823 deletions(-)
> delete mode 100644 drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_offload.h
> delete mode 100644 include/linux/mlx5/accel.h
>
> --
> 2.35.1
>
^ permalink raw reply
* Re: [PATCH net v2 1/2] dt-bindings: net: dsa: realtek: cleanup compatible strings
From: Jakub Kicinski @ 2022-04-22 17:56 UTC (permalink / raw)
To: Luiz Angelo Daros de Luca
Cc: David S. Miller, open list:NETWORKING DRIVERS, Linus Walleij,
Alvin Šipraga, Andrew Lunn, Vivien Didelot, Florian Fainelli,
Vladimir Oltean, Paolo Abeni, Rob Herring, krzk+dt,
Arınç ÜNAL, devicetree
In-Reply-To: <CAJq09z5zU1WT4bHjv-=aX49XweKnOmLhnL2w8gSaBe7=Ov1APw@mail.gmail.com>
On Wed, 20 Apr 2022 17:29:00 -0300 Luiz Angelo Daros de Luca wrote:
> > This series was applied to netdev/net-next.git (master)
> > by David S. Miller <davem@davemloft.net>:
> >
> > On Mon, 18 Apr 2022 20:35:57 -0300 you wrote:
> > > Compatible strings are used to help the driver find the chip ID/version
> > > register for each chip family. After that, the driver can setup the
> > > switch accordingly. Keep only the first supported model for each family
> > > as a compatible string and reference other chip models in the
> > > description.
> > >
> > > The removed compatible strings have never been used in a released kernel.
> > >
> > > [...]
> >
> > Here is the summary with links:
> > - [net,v2,1/2] dt-bindings: net: dsa: realtek: cleanup compatible strings
> > https://git.kernel.org/netdev/net-next/c/6f2d04ccae9b
> > - [net,v2,2/2] net: dsa: realtek: remove realtek,rtl8367s string
> > https://git.kernel.org/netdev/net-next/c/fcd30c96af95
> >
>
> I was expecting to get those patches merged to net as well. Otherwise,
> the "realtek,rtl8367s" we are removing will get into a released
> kernel.
Seems reasonable. Unless someone objects I'll "yolo it" and apply
the patches to net as well.
^ permalink raw reply
* Re: [PATCH net-next v1 00/17] Extra IPsec cleanup
From: Saeed Mahameed @ 2022-04-22 17:55 UTC (permalink / raw)
To: Leon Romanovsky
Cc: Paolo Abeni, Jakub Kicinski, David S . Miller, Jason Gunthorpe,
linux-netdev, Raed Salem
In-Reply-To: <YmLqpn6v/HIipias@unreal>
On 22 Apr 20:49, Leon Romanovsky wrote:
>On Tue, Apr 19, 2022 at 01:13:36PM +0300, Leon Romanovsky wrote:
>> From: Leon Romanovsky <leonro@nvidia.com>
>>
>> Changelog:
>> v1:
>> * changed target from mlx5-next to net-next.
>> * Improved commit message in patch #1
>> * Left function names intact, with _accel_ word in it.
>> v0: https://lore.kernel.org/all/cover.1649578827.git.leonro@nvidia.com
>>
>> --------------------
>> After FPGA IPsec removal, we can go further and make sure that flow
>> steering logic is aligned to mlx5_core standard together with deep
>> cleaning of whole IPsec path.
>>
>> Thanks
>
>Hi,
>
>I see that this series is marked as "Awaiting Upstream" in patchworks.
>https://patchwork.kernel.org/project/netdevbpf/list/?series=633295&state=*
>What does it mean? Can you please apply it directly to the netdev tree?
It's waiting for me to apply to net-next-mlx5, Please give me a chance to
review and apply, i just got back from a long time off and i have a long
backlog, i will provide feedback/apply by end of day.
Thanks,
Saeed.
^ permalink raw reply
* Re: [PATCH net v3] ice: Fix race during aux device (un)plugging
From: Leon Romanovsky @ 2022-04-22 17:43 UTC (permalink / raw)
To: Ivan Vecera
Cc: netdev, poros, mschmidt, Jesse Brandeburg, Tony Nguyen,
David S. Miller, Jakub Kicinski, Paolo Abeni, Dave Ertman,
Shiraz Saleem, moderated list:INTEL ETHERNET DRIVERS, open list
In-Reply-To: <20220421060906.1902576-1-ivecera@redhat.com>
On Thu, Apr 21, 2022 at 08:09:05AM +0200, Ivan Vecera wrote:
> Function ice_plug_aux_dev() assigns pf->adev field too early prior
> aux device initialization and on other side ice_unplug_aux_dev()
> starts aux device deinit and at the end assigns NULL to pf->adev.
> This is wrong because pf->adev should always be non-NULL only when
> aux device is fully initialized and ready. This wrong order causes
> a crash when ice_send_event_to_aux() call occurs because that function
> depends on non-NULL value of pf->adev and does not assume that
> aux device is half-initialized or half-destroyed.
> After order correction the race window is tiny but it is still there,
> as Leon mentioned and manipulation with pf->adev needs to be protected
> by mutex.
>
> Fix (un-)plugging functions so pf->adev field is set after aux device
> init and prior aux device destroy and protect pf->adev assignment by
> new mutex. This mutex is also held during ice_send_event_to_aux()
> call to ensure that aux device is valid during that call. Device
> lock used ice_send_event_to_aux() to avoid its concurrent run can
> be removed as this is secured by that mutex.
>
> Reproducer:
> cycle=1
> while :;do
> echo "#### Cycle: $cycle"
>
> ip link set ens7f0 mtu 9000
> ip link add bond0 type bond mode 1 miimon 100
> ip link set bond0 up
> ifenslave bond0 ens7f0
> ip link set bond0 mtu 9000
> ethtool -L ens7f0 combined 1
> ip link del bond0
> ip link set ens7f0 mtu 1500
> sleep 1
>
> let cycle++
> done
>
> In short when the device is added/removed to/from bond the aux device
> is unplugged/plugged. When MTU of the device is changed an event is
> sent to aux device asynchronously. This can race with (un)plugging
> operation and because pf->adev is set too early (plug) or too late
> (unplug) the function ice_send_event_to_aux() can touch uninitialized
> or destroyed fields. In the case of crash below pf->adev->dev.mutex.
>
> Crash:
> [ 53.372066] bond0: (slave ens7f0): making interface the new active one
> [ 53.378622] bond0: (slave ens7f0): Enslaving as an active interface with an u
> p link
> [ 53.386294] IPv6: ADDRCONF(NETDEV_CHANGE): bond0: link becomes ready
> [ 53.549104] bond0: (slave ens7f1): Enslaving as a backup interface with an up
> link
> [ 54.118906] ice 0000:ca:00.0 ens7f0: Number of in use tx queues changed inval
> idating tc mappings. Priority traffic classification disabled!
> [ 54.233374] ice 0000:ca:00.1 ens7f1: Number of in use tx queues changed inval
> idating tc mappings. Priority traffic classification disabled!
> [ 54.248204] bond0: (slave ens7f0): Releasing backup interface
> [ 54.253955] bond0: (slave ens7f1): making interface the new active one
> [ 54.274875] bond0: (slave ens7f1): Releasing backup interface
> [ 54.289153] bond0 (unregistering): Released all slaves
> [ 55.383179] MII link monitoring set to 100 ms
> [ 55.398696] bond0: (slave ens7f0): making interface the new active one
> [ 55.405241] BUG: kernel NULL pointer dereference, address: 0000000000000080
> [ 55.405289] bond0: (slave ens7f0): Enslaving as an active interface with an u
> p link
> [ 55.412198] #PF: supervisor write access in kernel mode
> [ 55.412200] #PF: error_code(0x0002) - not-present page
> [ 55.412201] PGD 25d2ad067 P4D 0
> [ 55.412204] Oops: 0002 [#1] PREEMPT SMP NOPTI
> [ 55.412207] CPU: 0 PID: 403 Comm: kworker/0:2 Kdump: loaded Tainted: G S
> 5.17.0-13579-g57f2d6540f03 #1
> [ 55.429094] bond0: (slave ens7f1): Enslaving as a backup interface with an up
> link
> [ 55.430224] Hardware name: Dell Inc. PowerEdge R750/06V45N, BIOS 1.4.4 10/07/
> 2021
> [ 55.430226] Workqueue: ice ice_service_task [ice]
> [ 55.468169] RIP: 0010:mutex_unlock+0x10/0x20
> [ 55.472439] Code: 0f b1 13 74 96 eb e0 4c 89 ee eb d8 e8 79 54 ff ff 66 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 65 48 8b 04 25 40 ef 01 00 31 d2 <f0> 48 0f b1 17 75 01 c3 e9 e3 fe ff ff 0f 1f 00 0f 1f 44 00 00 48
> [ 55.491186] RSP: 0018:ff4454230d7d7e28 EFLAGS: 00010246
> [ 55.496413] RAX: ff1a79b208b08000 RBX: ff1a79b2182e8880 RCX: 0000000000000001
> [ 55.503545] RDX: 0000000000000000 RSI: ff4454230d7d7db0 RDI: 0000000000000080
> [ 55.510678] RBP: ff1a79d1c7e48b68 R08: ff4454230d7d7db0 R09: 0000000000000041
> [ 55.517812] R10: 00000000000000a5 R11: 00000000000006e6 R12: ff1a79d1c7e48bc0
> [ 55.524945] R13: 0000000000000000 R14: ff1a79d0ffc305c0 R15: 0000000000000000
> [ 55.532076] FS: 0000000000000000(0000) GS:ff1a79d0ffc00000(0000) knlGS:0000000000000000
> [ 55.540163] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [ 55.545908] CR2: 0000000000000080 CR3: 00000003487ae003 CR4: 0000000000771ef0
> [ 55.553041] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> [ 55.560173] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
> [ 55.567305] PKRU: 55555554
> [ 55.570018] Call Trace:
> [ 55.572474] <TASK>
> [ 55.574579] ice_service_task+0xaab/0xef0 [ice]
> [ 55.579130] process_one_work+0x1c5/0x390
> [ 55.583141] ? process_one_work+0x390/0x390
> [ 55.587326] worker_thread+0x30/0x360
> [ 55.590994] ? process_one_work+0x390/0x390
> [ 55.595180] kthread+0xe6/0x110
> [ 55.598325] ? kthread_complete_and_exit+0x20/0x20
> [ 55.603116] ret_from_fork+0x1f/0x30
> [ 55.606698] </TASK>
>
> Fixes: f9f5301e7e2d ("ice: Register auxiliary device to provide RDMA")
> Cc: Leon Romanovsky <leon@kernel.org>
> Signed-off-by: Ivan Vecera <ivecera@redhat.com>
> ---
> drivers/net/ethernet/intel/ice/ice.h | 1 +
> drivers/net/ethernet/intel/ice/ice_idc.c | 33 ++++++++++++++---------
> drivers/net/ethernet/intel/ice/ice_main.c | 2 ++
> 3 files changed, 23 insertions(+), 13 deletions(-)
>
Thanks,
Reviewed-by: Leon Romanovsky <leonro@nvidia.com>
^ permalink raw reply
* [PATCH v7 RESEND] efi: Do not import certificates from UEFI Secure Boot for T2 Macs
From: Aditya Garg @ 2022-04-22 17:39 UTC (permalink / raw)
To: jarkko@kernel.org, zohar@linux.ibm.com, dmitry.kasatkin@gmail.com,
jmorris@namei.org, serge@hallyn.com, ast@kernel.org,
daniel@iogearbox.net, andrii@kernel.org, kafai@fb.com,
songliubraving@fb.com, yhs@fb.com, john.fastabend@gmail.com,
kpsingh@kernel.org
Cc: linux-integrity@vger.kernel.org, keyrings@vger.kernel.org,
linux-security-module@vger.kernel.org,
linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
bpf@vger.kernel.org, Orlando Chamberlain, admin@kodeit.net,
stable@vger.kernel.org
In-Reply-To: <958B8D22-F11E-4B5D-9F44-6F0626DBCB63@live.com>
From: Aditya Garg <gargaditya08@live.com>
On Apple T2 Macs, when Linux attempts to read the db and dbx efi variables
at early boot to load UEFI Secure Boot certificates, a page fault occurs
in Apple firmware code and EFI runtime services are disabled with the
following logs:
[Firmware Bug]: Page fault caused by firmware at PA: 0xffffb1edc0068000
WARNING: CPU: 3 PID: 104 at arch/x86/platform/efi/quirks.c:735 efi_crash_gracefully_on_page_fault+0x50/0xf0
(Removed some logs from here)
Call Trace:
<TASK>
page_fault_oops+0x4f/0x2c0
? search_bpf_extables+0x6b/0x80
? search_module_extables+0x50/0x80
? search_exception_tables+0x5b/0x60
kernelmode_fixup_or_oops+0x9e/0x110
__bad_area_nosemaphore+0x155/0x190
bad_area_nosemaphore+0x16/0x20
do_kern_addr_fault+0x8c/0xa0
exc_page_fault+0xd8/0x180
asm_exc_page_fault+0x1e/0x30
(Removed some logs from here)
? __efi_call+0x28/0x30
? switch_mm+0x20/0x30
? efi_call_rts+0x19a/0x8e0
? process_one_work+0x222/0x3f0
? worker_thread+0x4a/0x3d0
? kthread+0x17a/0x1a0
? process_one_work+0x3f0/0x3f0
? set_kthread_struct+0x40/0x40
? ret_from_fork+0x22/0x30
</TASK>
---[ end trace 1f82023595a5927f ]---
efi: Froze efi_rts_wq and disabled EFI Runtime Services
integrity: Couldn't get size: 0x8000000000000015
integrity: MODSIGN: Couldn't get UEFI db list
efi: EFI Runtime Services are disabled!
integrity: Couldn't get size: 0x8000000000000015
integrity: Couldn't get UEFI dbx list
integrity: Couldn't get size: 0x8000000000000015
integrity: Couldn't get mokx list
integrity: Couldn't get size: 0x80000000
So we avoid reading these UEFI variables and thus prevent the crash.
Cc: stable@vger.kernel.org
Signed-off-by: Aditya Garg <gargaditya08@live.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
---
v2 :- Reduce code size of the table.
v3 :- Close the brackets which were left open by mistake.
v4 :- Fix comment style issues, remove blank spaces and limit use of dmi_first_match()
v4 RESEND :- Add stable to cc
v5 :- Rewrite the description
v6 :- Make description more clear
v7 :- Minor changes and add reviewed by
.../platform_certs/keyring_handler.h | 8 +++++
security/integrity/platform_certs/load_uefi.c | 33 +++++++++++++++++++
2 files changed, 41 insertions(+)
diff --git a/security/integrity/platform_certs/keyring_handler.h b/security/integrity/platform_certs/keyring_handler.h
index 284558f30..212d894a8 100644
--- a/security/integrity/platform_certs/keyring_handler.h
+++ b/security/integrity/platform_certs/keyring_handler.h
@@ -35,3 +35,11 @@ efi_element_handler_t get_handler_for_mok(const efi_guid_t *sig_type);
efi_element_handler_t get_handler_for_dbx(const efi_guid_t *sig_type);
#endif
+
+#ifndef UEFI_QUIRK_SKIP_CERT
+#define UEFI_QUIRK_SKIP_CERT(vendor, product) \
+ .matches = { \
+ DMI_MATCH(DMI_BOARD_VENDOR, vendor), \
+ DMI_MATCH(DMI_PRODUCT_NAME, product), \
+ },
+#endif
diff --git a/security/integrity/platform_certs/load_uefi.c b/security/integrity/platform_certs/load_uefi.c
index 5f45c3c07..1a7e7d597 100644
--- a/security/integrity/platform_certs/load_uefi.c
+++ b/security/integrity/platform_certs/load_uefi.c
@@ -3,6 +3,7 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/cred.h>
+#include <linux/dmi.h>
#include <linux/err.h>
#include <linux/efi.h>
#include <linux/slab.h>
@@ -12,6 +13,31 @@
#include "../integrity.h"
#include "keyring_handler.h"
+/*
+ * On T2 Macs reading the db and dbx efi variables to load UEFI Secure Boot
+ * certificates causes occurrence of a page fault in Apple's firmware and
+ * a crash disabling EFI runtime services. The following quirk skips reading
+ * these variables.
+ */
+static const struct dmi_system_id uefi_skip_cert[] = {
+ { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,1") },
+ { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,2") },
+ { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,3") },
+ { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro15,4") },
+ { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,1") },
+ { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,2") },
+ { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,3") },
+ { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookPro16,4") },
+ { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookAir8,1") },
+ { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookAir8,2") },
+ { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacBookAir9,1") },
+ { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacMini8,1") },
+ { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "MacPro7,1") },
+ { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "iMac20,1") },
+ { UEFI_QUIRK_SKIP_CERT("Apple Inc.", "iMac20,2") },
+ { }
+};
+
/*
* Look to see if a UEFI variable called MokIgnoreDB exists and return true if
* it does.
@@ -138,6 +164,13 @@ static int __init load_uefi_certs(void)
unsigned long dbsize = 0, dbxsize = 0, mokxsize = 0;
efi_status_t status;
int rc = 0;
+ const struct dmi_system_id *dmi_id;
+
+ dmi_id = dmi_first_match(uefi_skip_cert);
+ if (dmi_id) {
+ pr_err("Reading UEFI Secure Boot Certs is not supported on T2 Macs.\n");
+ return false;
+ }
if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
return false;
--
2.25.1
^ permalink raw reply related
* Re: [PATCH net-next 1/4] net: pcs: xpcs: add CL37 1000BASE-X AN support
From: kernel test robot @ 2022-04-22 17:35 UTC (permalink / raw)
To: Ong Boon Leong, Alexandre Torgue, Jose Abreu, Andrew Lunn,
Heiner Kallweit, Russell King, Paolo Abeni, David S . Miller,
Jakub Kicinski, Maxime Coquelin, Giuseppe Cavallaro
Cc: llvm, kbuild-all, netdev, linux-stm32, linux-arm-kernel,
linux-kernel, Ong Boon Leong
In-Reply-To: <20220422073505.810084-2-boon.leong.ong@intel.com>
Hi Ong,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on net-next/master]
url: https://github.com/intel-lab-lkp/linux/commits/Ong-Boon-Leong/pcs-xpcs-stmmac-add-1000BASE-X-AN-for-network-switch/20220422-154446
base: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git 9c8774e629a1950c24b44e3c8fb93d76fb644b49
config: i386-randconfig-a013 (https://download.01.org/0day-ci/archive/20220423/202204230159.Tixm42oR-lkp@intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 5bd87350a5ae429baf8f373cb226a57b62f87280)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/dc88c5b7c183eeaff9db0e88d7b0d1d7f73e830b
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Ong-Boon-Leong/pcs-xpcs-stmmac-add-1000BASE-X-AN-for-network-switch/20220422-154446
git checkout dc88c5b7c183eeaff9db0e88d7b0d1d7f73e830b
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=i386 SHELL=/bin/bash drivers/net/dsa/sja1105/
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All errors (new ones prefixed by >>):
>> drivers/net/dsa/sja1105/sja1105_main.c:2334:52: error: too few arguments to function call, expected 4, have 3
rc = xpcs_do_config(xpcs, priv->phy_mode[i], mode);
~~~~~~~~~~~~~~ ^
include/linux/pcs/pcs-xpcs.h:33:5: note: 'xpcs_do_config' declared here
int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
^
1 error generated.
vim +2334 drivers/net/dsa/sja1105/sja1105_main.c
2eea1fa82f681b Vladimir Oltean 2019-11-12 2224
6666cebc5e306f Vladimir Oltean 2019-05-02 2225 /* For situations where we need to change a setting at runtime that is only
6666cebc5e306f Vladimir Oltean 2019-05-02 2226 * available through the static configuration, resetting the switch in order
6666cebc5e306f Vladimir Oltean 2019-05-02 2227 * to upload the new static config is unavoidable. Back up the settings we
6666cebc5e306f Vladimir Oltean 2019-05-02 2228 * modify at runtime (currently only MAC) and restore them after uploading,
6666cebc5e306f Vladimir Oltean 2019-05-02 2229 * such that this operation is relatively seamless.
6666cebc5e306f Vladimir Oltean 2019-05-02 2230 */
2eea1fa82f681b Vladimir Oltean 2019-11-12 2231 int sja1105_static_config_reload(struct sja1105_private *priv,
2eea1fa82f681b Vladimir Oltean 2019-11-12 2232 enum sja1105_reset_reason reason)
6666cebc5e306f Vladimir Oltean 2019-05-02 2233 {
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2234 struct ptp_system_timestamp ptp_sts_before;
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2235 struct ptp_system_timestamp ptp_sts_after;
82760d7f2ea638 Vladimir Oltean 2021-05-24 2236 int speed_mbps[SJA1105_MAX_NUM_PORTS];
84db00f2c04338 Vladimir Oltean 2021-05-31 2237 u16 bmcr[SJA1105_MAX_NUM_PORTS] = {0};
6666cebc5e306f Vladimir Oltean 2019-05-02 2238 struct sja1105_mac_config_entry *mac;
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2239 struct dsa_switch *ds = priv->ds;
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2240 s64 t1, t2, t3, t4;
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2241 s64 t12, t34;
6666cebc5e306f Vladimir Oltean 2019-05-02 2242 int rc, i;
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2243 s64 now;
6666cebc5e306f Vladimir Oltean 2019-05-02 2244
af580ae2dcb250 Vladimir Oltean 2019-11-09 2245 mutex_lock(&priv->mgmt_lock);
af580ae2dcb250 Vladimir Oltean 2019-11-09 2246
6666cebc5e306f Vladimir Oltean 2019-05-02 2247 mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
6666cebc5e306f Vladimir Oltean 2019-05-02 2248
8400cff60b472c Vladimir Oltean 2019-06-08 2249 /* Back up the dynamic link speed changed by sja1105_adjust_port_config
8400cff60b472c Vladimir Oltean 2019-06-08 2250 * in order to temporarily restore it to SJA1105_SPEED_AUTO - which the
8400cff60b472c Vladimir Oltean 2019-06-08 2251 * switch wants to see in the static config in order to allow us to
8400cff60b472c Vladimir Oltean 2019-06-08 2252 * change it through the dynamic interface later.
6666cebc5e306f Vladimir Oltean 2019-05-02 2253 */
542043e91df452 Vladimir Oltean 2021-05-24 2254 for (i = 0; i < ds->num_ports; i++) {
3ad1d171548e85 Vladimir Oltean 2021-06-11 2255 u32 reg_addr = mdiobus_c45_addr(MDIO_MMD_VEND2, MDIO_CTRL1);
3ad1d171548e85 Vladimir Oltean 2021-06-11 2256
41fed17fdbe531 Vladimir Oltean 2021-05-31 2257 speed_mbps[i] = sja1105_port_speed_to_ethtool(priv,
41fed17fdbe531 Vladimir Oltean 2021-05-31 2258 mac[i].speed);
41fed17fdbe531 Vladimir Oltean 2021-05-31 2259 mac[i].speed = priv->info->port_speed[SJA1105_SPEED_AUTO];
6666cebc5e306f Vladimir Oltean 2019-05-02 2260
3ad1d171548e85 Vladimir Oltean 2021-06-11 2261 if (priv->xpcs[i])
3ad1d171548e85 Vladimir Oltean 2021-06-11 2262 bmcr[i] = mdiobus_read(priv->mdio_pcs, i, reg_addr);
84db00f2c04338 Vladimir Oltean 2021-05-31 2263 }
ffe10e679cec9a Vladimir Oltean 2020-03-20 2264
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2265 /* No PTP operations can run right now */
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2266 mutex_lock(&priv->ptp_data.lock);
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2267
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2268 rc = __sja1105_ptp_gettimex(ds, &now, &ptp_sts_before);
61c77533b82ba8 Vladimir Oltean 2021-06-18 2269 if (rc < 0) {
61c77533b82ba8 Vladimir Oltean 2021-06-18 2270 mutex_unlock(&priv->ptp_data.lock);
61c77533b82ba8 Vladimir Oltean 2021-06-18 2271 goto out;
61c77533b82ba8 Vladimir Oltean 2021-06-18 2272 }
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2273
6666cebc5e306f Vladimir Oltean 2019-05-02 2274 /* Reset switch and send updated static configuration */
6666cebc5e306f Vladimir Oltean 2019-05-02 2275 rc = sja1105_static_config_upload(priv);
61c77533b82ba8 Vladimir Oltean 2021-06-18 2276 if (rc < 0) {
61c77533b82ba8 Vladimir Oltean 2021-06-18 2277 mutex_unlock(&priv->ptp_data.lock);
61c77533b82ba8 Vladimir Oltean 2021-06-18 2278 goto out;
61c77533b82ba8 Vladimir Oltean 2021-06-18 2279 }
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2280
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2281 rc = __sja1105_ptp_settime(ds, 0, &ptp_sts_after);
61c77533b82ba8 Vladimir Oltean 2021-06-18 2282 if (rc < 0) {
61c77533b82ba8 Vladimir Oltean 2021-06-18 2283 mutex_unlock(&priv->ptp_data.lock);
61c77533b82ba8 Vladimir Oltean 2021-06-18 2284 goto out;
61c77533b82ba8 Vladimir Oltean 2021-06-18 2285 }
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2286
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2287 t1 = timespec64_to_ns(&ptp_sts_before.pre_ts);
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2288 t2 = timespec64_to_ns(&ptp_sts_before.post_ts);
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2289 t3 = timespec64_to_ns(&ptp_sts_after.pre_ts);
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2290 t4 = timespec64_to_ns(&ptp_sts_after.post_ts);
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2291 /* Mid point, corresponds to pre-reset PTPCLKVAL */
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2292 t12 = t1 + (t2 - t1) / 2;
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2293 /* Mid point, corresponds to post-reset PTPCLKVAL, aka 0 */
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2294 t34 = t3 + (t4 - t3) / 2;
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2295 /* Advance PTPCLKVAL by the time it took since its readout */
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2296 now += (t34 - t12);
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2297
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2298 __sja1105_ptp_adjtime(ds, now);
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2299
6cf99c13ea07b5 Vladimir Oltean 2019-11-09 2300 mutex_unlock(&priv->ptp_data.lock);
6666cebc5e306f Vladimir Oltean 2019-05-02 2301
2eea1fa82f681b Vladimir Oltean 2019-11-12 2302 dev_info(priv->ds->dev,
2eea1fa82f681b Vladimir Oltean 2019-11-12 2303 "Reset switch and programmed static config. Reason: %s\n",
2eea1fa82f681b Vladimir Oltean 2019-11-12 2304 sja1105_reset_reasons[reason]);
2eea1fa82f681b Vladimir Oltean 2019-11-12 2305
6666cebc5e306f Vladimir Oltean 2019-05-02 2306 /* Configure the CGU (PLLs) for MII and RMII PHYs.
6666cebc5e306f Vladimir Oltean 2019-05-02 2307 * For these interfaces there is no dynamic configuration
6666cebc5e306f Vladimir Oltean 2019-05-02 2308 * needed, since PLLs have same settings at all speeds.
6666cebc5e306f Vladimir Oltean 2019-05-02 2309 */
cb5a82d2b9aaca Vladimir Oltean 2021-06-18 2310 if (priv->info->clocking_setup) {
c50376783f23ff Vladimir Oltean 2021-05-24 2311 rc = priv->info->clocking_setup(priv);
6666cebc5e306f Vladimir Oltean 2019-05-02 2312 if (rc < 0)
6666cebc5e306f Vladimir Oltean 2019-05-02 2313 goto out;
cb5a82d2b9aaca Vladimir Oltean 2021-06-18 2314 }
6666cebc5e306f Vladimir Oltean 2019-05-02 2315
542043e91df452 Vladimir Oltean 2021-05-24 2316 for (i = 0; i < ds->num_ports; i++) {
3ad1d171548e85 Vladimir Oltean 2021-06-11 2317 struct dw_xpcs *xpcs = priv->xpcs[i];
3ad1d171548e85 Vladimir Oltean 2021-06-11 2318 unsigned int mode;
84db00f2c04338 Vladimir Oltean 2021-05-31 2319
8400cff60b472c Vladimir Oltean 2019-06-08 2320 rc = sja1105_adjust_port_config(priv, i, speed_mbps[i]);
6666cebc5e306f Vladimir Oltean 2019-05-02 2321 if (rc < 0)
6666cebc5e306f Vladimir Oltean 2019-05-02 2322 goto out;
ffe10e679cec9a Vladimir Oltean 2020-03-20 2323
3ad1d171548e85 Vladimir Oltean 2021-06-11 2324 if (!xpcs)
84db00f2c04338 Vladimir Oltean 2021-05-31 2325 continue;
84db00f2c04338 Vladimir Oltean 2021-05-31 2326
3ad1d171548e85 Vladimir Oltean 2021-06-11 2327 if (bmcr[i] & BMCR_ANENABLE)
3ad1d171548e85 Vladimir Oltean 2021-06-11 2328 mode = MLO_AN_INBAND;
3ad1d171548e85 Vladimir Oltean 2021-06-11 2329 else if (priv->fixed_link[i])
3ad1d171548e85 Vladimir Oltean 2021-06-11 2330 mode = MLO_AN_FIXED;
3ad1d171548e85 Vladimir Oltean 2021-06-11 2331 else
3ad1d171548e85 Vladimir Oltean 2021-06-11 2332 mode = MLO_AN_PHY;
ffe10e679cec9a Vladimir Oltean 2020-03-20 2333
3ad1d171548e85 Vladimir Oltean 2021-06-11 @2334 rc = xpcs_do_config(xpcs, priv->phy_mode[i], mode);
3ad1d171548e85 Vladimir Oltean 2021-06-11 2335 if (rc < 0)
3ad1d171548e85 Vladimir Oltean 2021-06-11 2336 goto out;
ffe10e679cec9a Vladimir Oltean 2020-03-20 2337
3ad1d171548e85 Vladimir Oltean 2021-06-11 2338 if (!phylink_autoneg_inband(mode)) {
ffe10e679cec9a Vladimir Oltean 2020-03-20 2339 int speed = SPEED_UNKNOWN;
ffe10e679cec9a Vladimir Oltean 2020-03-20 2340
56b63466333b25 Vladimir Oltean 2021-06-11 2341 if (priv->phy_mode[i] == PHY_INTERFACE_MODE_2500BASEX)
56b63466333b25 Vladimir Oltean 2021-06-11 2342 speed = SPEED_2500;
56b63466333b25 Vladimir Oltean 2021-06-11 2343 else if (bmcr[i] & BMCR_SPEED1000)
ffe10e679cec9a Vladimir Oltean 2020-03-20 2344 speed = SPEED_1000;
84db00f2c04338 Vladimir Oltean 2021-05-31 2345 else if (bmcr[i] & BMCR_SPEED100)
ffe10e679cec9a Vladimir Oltean 2020-03-20 2346 speed = SPEED_100;
053d8ad10d585a Vladimir Oltean 2021-03-04 2347 else
ffe10e679cec9a Vladimir Oltean 2020-03-20 2348 speed = SPEED_10;
ffe10e679cec9a Vladimir Oltean 2020-03-20 2349
3ad1d171548e85 Vladimir Oltean 2021-06-11 2350 xpcs_link_up(&xpcs->pcs, mode, priv->phy_mode[i],
3ad1d171548e85 Vladimir Oltean 2021-06-11 2351 speed, DUPLEX_FULL);
ffe10e679cec9a Vladimir Oltean 2020-03-20 2352 }
ffe10e679cec9a Vladimir Oltean 2020-03-20 2353 }
4d7525085a9ba8 Vladimir Oltean 2020-05-28 2354
4d7525085a9ba8 Vladimir Oltean 2020-05-28 2355 rc = sja1105_reload_cbs(priv);
4d7525085a9ba8 Vladimir Oltean 2020-05-28 2356 if (rc < 0)
4d7525085a9ba8 Vladimir Oltean 2020-05-28 2357 goto out;
6666cebc5e306f Vladimir Oltean 2019-05-02 2358 out:
af580ae2dcb250 Vladimir Oltean 2019-11-09 2359 mutex_unlock(&priv->mgmt_lock);
af580ae2dcb250 Vladimir Oltean 2019-11-09 2360
6666cebc5e306f Vladimir Oltean 2019-05-02 2361 return rc;
6666cebc5e306f Vladimir Oltean 2019-05-02 2362 }
6666cebc5e306f Vladimir Oltean 2019-05-02 2363
--
0-DAY CI Kernel Test Service
https://01.org/lkp
^ permalink raw reply
* [PATCH bpf-next v6 1/6] bpf: Use ipv6_only_sock in bpf_tcp_gen_syncookie
From: Maxim Mikityanskiy @ 2022-04-22 17:24 UTC (permalink / raw)
To: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, netdev
Cc: Tariq Toukan, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, David S. Miller, Jakub Kicinski,
Petar Penkov, Lorenz Bauer, Eric Dumazet, Hideaki YOSHIFUJI,
David Ahern, Shuah Khan, Jesper Dangaard Brouer,
Nathan Chancellor, Nick Desaulniers, Joe Stringer, Florent Revest,
linux-kselftest, Toke Høiland-Jørgensen,
Kumar Kartikeya Dwivedi, Florian Westphal, pabeni,
Maxim Mikityanskiy
In-Reply-To: <20220422172422.4037988-1-maximmi@nvidia.com>
Instead of querying the sk_ipv6only field directly, use the dedicated
ipv6_only_sock helper.
Signed-off-by: Maxim Mikityanskiy <maximmi@nvidia.com>
Reviewed-by: Tariq Toukan <tariqt@nvidia.com>
Acked-by: John Fastabend <john.fastabend@gmail.com>
Acked-by: Lorenz Bauer <lmb@cloudflare.com>
Acked-by: Petar Penkov <ppenkov@google.com>
---
net/core/filter.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/core/filter.c b/net/core/filter.c
index 8847316ee20e..207a13db5c80 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -7099,7 +7099,7 @@ BPF_CALL_5(bpf_tcp_gen_syncookie, struct sock *, sk, void *, iph, u32, iph_len,
*/
switch (((struct iphdr *)iph)->version) {
case 4:
- if (sk->sk_family == AF_INET6 && sk->sk_ipv6only)
+ if (sk->sk_family == AF_INET6 && ipv6_only_sock(sk))
return -EINVAL;
mss = tcp_v4_get_syncookie(sk, iph, th, &cookie);
--
2.30.2
^ permalink raw reply related
* Re: [PATCH net-next] net: generalize skb freeing deferral to per-cpu lists
From: Eric Dumazet @ 2022-04-22 17:25 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: Eric Dumazet, David S . Miller, Paolo Abeni, netdev
In-Reply-To: <CANn89iLK5i9y5=iAHS=8+SinGkmGgEXR=xk=ATpnXPakD1j-vQ@mail.gmail.com>
On Fri, Apr 22, 2022 at 9:50 AM Eric Dumazet <edumazet@google.com> wrote:
>
> On Fri, Apr 22, 2022 at 9:40 AM Jakub Kicinski <kuba@kernel.org> wrote:
> >
> > If so maybe we can avoid some dirtying and use a single-linked list?
> > No point modifying the cache line of the skb already on the list.
>
> Good idea, I can think about it.
>
My first implementation was using an llist (as current per-socket llist),
but then I needed the count as well, so I converted to standard sk_buff_head
It seems we can hand code to:
spinlock_t lock;
struct sk_buff *skb_head;
int count;
We also could keep an llist, and an atomic_t for the count, but that
would require two atomic ops, so no good.
^ permalink raw reply
* [PATCH bpf-next v6 6/6] bpf: Allow the new syncookie helpers to work with SKBs
From: Maxim Mikityanskiy @ 2022-04-22 17:24 UTC (permalink / raw)
To: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, netdev
Cc: Tariq Toukan, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, David S. Miller, Jakub Kicinski,
Petar Penkov, Lorenz Bauer, Eric Dumazet, Hideaki YOSHIFUJI,
David Ahern, Shuah Khan, Jesper Dangaard Brouer,
Nathan Chancellor, Nick Desaulniers, Joe Stringer, Florent Revest,
linux-kselftest, Toke Høiland-Jørgensen,
Kumar Kartikeya Dwivedi, Florian Westphal, pabeni,
Maxim Mikityanskiy
In-Reply-To: <20220422172422.4037988-1-maximmi@nvidia.com>
This commits allows the new BPF helpers to work in SKB context (in TC
BPF programs): bpf_tcp_raw_{gen,check}_syncookie_ipv{4,6}.
The sample application and selftest are updated to support the TC mode.
It's not the recommended mode of operation, because the SKB is already
created at this point, and it's unlikely that the BPF program will
provide any substantional speedup compared to regular SYN cookies or
synproxy.
Signed-off-by: Maxim Mikityanskiy <maximmi@nvidia.com>
Reviewed-by: Tariq Toukan <tariqt@nvidia.com>
---
net/core/filter.c | 10 ++
.../selftests/bpf/prog_tests/xdp_synproxy.c | 53 +++++--
.../selftests/bpf/progs/xdp_synproxy_kern.c | 141 +++++++++++++-----
tools/testing/selftests/bpf/xdp_synproxy.c | 94 +++++++++---
4 files changed, 230 insertions(+), 68 deletions(-)
diff --git a/net/core/filter.c b/net/core/filter.c
index ffb7e93f60c5..4f631cac3130 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -7905,6 +7905,16 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
return &bpf_sk_assign_proto;
case BPF_FUNC_skb_set_tstamp:
return &bpf_skb_set_tstamp_proto;
+#ifdef CONFIG_SYN_COOKIES
+ case BPF_FUNC_tcp_raw_gen_syncookie_ipv4:
+ return &bpf_tcp_raw_gen_syncookie_ipv4_proto;
+ case BPF_FUNC_tcp_raw_gen_syncookie_ipv6:
+ return &bpf_tcp_raw_gen_syncookie_ipv6_proto;
+ case BPF_FUNC_tcp_raw_check_syncookie_ipv4:
+ return &bpf_tcp_raw_check_syncookie_ipv4_proto;
+ case BPF_FUNC_tcp_raw_check_syncookie_ipv6:
+ return &bpf_tcp_raw_check_syncookie_ipv6_proto;
+#endif
#endif
default:
return bpf_sk_base_func_proto(func_id);
diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_synproxy.c b/tools/testing/selftests/bpf/prog_tests/xdp_synproxy.c
index e08b28e25047..09320967d865 100644
--- a/tools/testing/selftests/bpf/prog_tests/xdp_synproxy.c
+++ b/tools/testing/selftests/bpf/prog_tests/xdp_synproxy.c
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
#include <test_progs.h>
#include <network_helpers.h>
@@ -7,9 +8,11 @@
goto out; \
})
-#define SYS_OUT(cmd) ({ \
- FILE *f = popen((cmd), "r"); \
- if (!ASSERT_OK_PTR(f, (cmd))) \
+#define SYS_OUT(cmd, ...) ({ \
+ char buf[1024]; \
+ snprintf(buf, sizeof(buf), (cmd), ##__VA_ARGS__); \
+ FILE *f = popen(buf, "r"); \
+ if (!ASSERT_OK_PTR(f, buf)) \
goto out; \
f; \
})
@@ -21,9 +24,10 @@ static bool expect_str(char *buf, size_t size, const char *str)
return !memcmp(buf, str, size);
}
-void test_xdp_synproxy(void)
+static void test_synproxy(bool xdp)
{
int server_fd = -1, client_fd = -1, accept_fd = -1;
+ char *prog_id, *prog_id_end;
struct nstoken *ns = NULL;
FILE *ctrl_file = NULL;
char buf[1024];
@@ -39,8 +43,9 @@ void test_xdp_synproxy(void)
// When checksum offload is enabled, the XDP program sees wrong
// checksums and drops packets.
SYS("ethtool -K tmp0 tx off");
- // Workaround required for veth.
- SYS("ip link set tmp0 xdp object xdp_dummy.o section xdp 2> /dev/null");
+ if (xdp)
+ // Workaround required for veth.
+ SYS("ip link set tmp0 xdp object xdp_dummy.o section xdp 2> /dev/null");
ns = open_netns("synproxy");
if (!ASSERT_OK_PTR(ns, "setns"))
@@ -60,14 +65,34 @@ void test_xdp_synproxy(void)
SYS("iptables -t filter -A INPUT \
-i tmp1 -m state --state INVALID -j DROP");
- ctrl_file = SYS_OUT("./xdp_synproxy --iface tmp1 --ports 8080 --single \
- --mss4 1460 --mss6 1440 --wscale 7 --ttl 64");
+ ctrl_file = SYS_OUT("./xdp_synproxy --iface tmp1 --ports 8080 \
+ --single --mss4 1460 --mss6 1440 \
+ --wscale 7 --ttl 64%s", xdp ? "" : " --tc");
size = fread(buf, 1, sizeof(buf), ctrl_file);
pclose(ctrl_file);
if (!ASSERT_TRUE(expect_str(buf, size, "Total SYNACKs generated: 0\n"),
"initial SYNACKs"))
goto out;
+ if (!xdp) {
+ ctrl_file = SYS_OUT("tc filter show dev tmp1 ingress");
+ size = fread(buf, 1, sizeof(buf), ctrl_file);
+ pclose(ctrl_file);
+ prog_id = memmem(buf, size, " id ", 4);
+ if (!ASSERT_OK_PTR(prog_id, "find prog id"))
+ goto out;
+ prog_id += 4;
+ if (!ASSERT_LT(prog_id, buf + size, "find prog id begin"))
+ goto out;
+ prog_id_end = prog_id;
+ while (prog_id_end < buf + size && *prog_id_end >= '0' &&
+ *prog_id_end <= '9')
+ prog_id_end++;
+ if (!ASSERT_LT(prog_id_end, buf + size, "find prog id end"))
+ goto out;
+ *prog_id_end = '\0';
+ }
+
server_fd = start_server(AF_INET, SOCK_STREAM, "198.18.0.2", 8080, 0);
if (!ASSERT_GE(server_fd, 0, "start_server"))
goto out;
@@ -87,7 +112,11 @@ void test_xdp_synproxy(void)
if (!ASSERT_OK_PTR(ns, "setns"))
goto out;
- ctrl_file = SYS_OUT("./xdp_synproxy --iface tmp1 --single");
+ if (xdp)
+ ctrl_file = SYS_OUT("./xdp_synproxy --iface tmp1 --single");
+ else
+ ctrl_file = SYS_OUT("./xdp_synproxy --prog %s --single",
+ prog_id);
size = fread(buf, 1, sizeof(buf), ctrl_file);
pclose(ctrl_file);
if (!ASSERT_TRUE(expect_str(buf, size, "Total SYNACKs generated: 1\n"),
@@ -107,3 +136,9 @@ void test_xdp_synproxy(void)
system("ip link del tmp0");
system("ip netns del synproxy");
}
+
+void test_xdp_synproxy(void)
+{
+ test_synproxy(true);
+ test_synproxy(false);
+}
diff --git a/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c b/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c
index 7bebec6f2627..b94ada161786 100644
--- a/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c
+++ b/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c
@@ -7,6 +7,9 @@
#include <bpf/bpf_endian.h>
#include <asm/errno.h>
+#define TC_ACT_OK 0
+#define TC_ACT_SHOT 2
+
#define NSEC_PER_SEC 1000000000L
#define ETH_ALEN 6
@@ -80,6 +83,12 @@ extern struct nf_conn *bpf_xdp_ct_lookup(struct xdp_md *xdp_ctx,
struct bpf_ct_opts *opts,
__u32 len_opts) __ksym;
+extern struct nf_conn *bpf_skb_ct_lookup(struct __sk_buff *skb_ctx,
+ struct bpf_sock_tuple *bpf_tuple,
+ u32 len_tuple,
+ struct bpf_ct_opts *opts,
+ u32 len_opts) __ksym;
+
extern void bpf_ct_release(struct nf_conn *ct) __ksym;
static __always_inline void swap_eth_addr(__u8 *a, __u8 *b)
@@ -380,7 +389,7 @@ static __always_inline int tcp_dissect(void *data, void *data_end,
return XDP_TX;
}
-static __always_inline int tcp_lookup(struct xdp_md *ctx, struct header_pointers *hdr)
+static __always_inline int tcp_lookup(void *ctx, struct header_pointers *hdr, bool xdp)
{
struct bpf_ct_opts ct_lookup_opts = {
.netns_id = BPF_F_CURRENT_NETNS,
@@ -410,7 +419,10 @@ static __always_inline int tcp_lookup(struct xdp_md *ctx, struct header_pointers
// The verifier can't track that either ipv4 or ipv6 is not NULL.
return XDP_ABORTED;
}
- ct = bpf_xdp_ct_lookup(ctx, &tup, tup_size, &ct_lookup_opts, sizeof(ct_lookup_opts));
+ if (xdp)
+ ct = bpf_xdp_ct_lookup(ctx, &tup, tup_size, &ct_lookup_opts, sizeof(ct_lookup_opts));
+ else
+ ct = bpf_skb_ct_lookup(ctx, &tup, tup_size, &ct_lookup_opts, sizeof(ct_lookup_opts));
if (ct) {
unsigned long status = ct->status;
@@ -523,8 +535,9 @@ static __always_inline void tcpv6_gen_synack(struct header_pointers *hdr,
}
static __always_inline int syncookie_handle_syn(struct header_pointers *hdr,
- struct xdp_md *ctx,
- void *data, void *data_end)
+ void *ctx,
+ void *data, void *data_end,
+ bool xdp)
{
__u32 old_pkt_size, new_pkt_size;
// Unlike clang 10, clang 11 and 12 generate code that doesn't pass the
@@ -656,8 +669,13 @@ static __always_inline int syncookie_handle_syn(struct header_pointers *hdr,
// Set the new packet size.
old_pkt_size = data_end - data;
new_pkt_size = sizeof(*hdr->eth) + ip_len + hdr->tcp->doff * 4;
- if (bpf_xdp_adjust_tail(ctx, new_pkt_size - old_pkt_size))
- return XDP_ABORTED;
+ if (xdp) {
+ if (bpf_xdp_adjust_tail(ctx, new_pkt_size - old_pkt_size))
+ return XDP_ABORTED;
+ } else {
+ if (bpf_skb_change_tail(ctx, new_pkt_size, 0))
+ return XDP_ABORTED;
+ }
values_inc_synacks();
@@ -683,68 +701,119 @@ static __always_inline int syncookie_handle_ack(struct header_pointers *hdr)
return XDP_PASS;
}
-SEC("xdp/syncookie")
-int syncookie_xdp(struct xdp_md *ctx)
+static __always_inline int syncookie_part1(void *ctx, void *data, void *data_end,
+ struct header_pointers *hdr, bool xdp)
{
- void *data_end = (void *)(long)ctx->data_end;
- void *data = (void *)(long)ctx->data;
- struct header_pointers hdr;
- __s64 value;
- int ret;
-
struct bpf_ct_opts ct_lookup_opts = {
.netns_id = BPF_F_CURRENT_NETNS,
.l4proto = IPPROTO_TCP,
};
+ int ret;
- ret = tcp_dissect(data, data_end, &hdr);
+ ret = tcp_dissect(data, data_end, hdr);
if (ret != XDP_TX)
return ret;
- ret = tcp_lookup(ctx, &hdr);
+ ret = tcp_lookup(ctx, hdr, xdp);
if (ret != XDP_TX)
return ret;
// Packet is TCP and doesn't belong to an established connection.
- if ((hdr.tcp->syn ^ hdr.tcp->ack) != 1)
+ if ((hdr->tcp->syn ^ hdr->tcp->ack) != 1)
return XDP_DROP;
- // Grow the TCP header to TCP_MAXLEN to be able to pass any hdr.tcp_len
+ // Grow the TCP header to TCP_MAXLEN to be able to pass any hdr->tcp_len
// to bpf_tcp_raw_gen_syncookie_ipv{4,6} and pass the verifier.
- if (bpf_xdp_adjust_tail(ctx, TCP_MAXLEN - hdr.tcp_len))
- return XDP_ABORTED;
+ if (xdp) {
+ if (bpf_xdp_adjust_tail(ctx, TCP_MAXLEN - hdr->tcp_len))
+ return XDP_ABORTED;
+ } else {
+ // Without volatile the verifier throws this error:
+ // R9 32-bit pointer arithmetic prohibited
+ volatile u64 old_len = data_end - data;
- data_end = (void *)(long)ctx->data_end;
- data = (void *)(long)ctx->data;
+ if (bpf_skb_change_tail(ctx, old_len + TCP_MAXLEN - hdr->tcp_len, 0))
+ return XDP_ABORTED;
+ }
+
+ return XDP_TX;
+}
- if (hdr.ipv4) {
- hdr.eth = data;
- hdr.ipv4 = (void *)hdr.eth + sizeof(*hdr.eth);
+static __always_inline int syncookie_part2(void *ctx, void *data, void *data_end,
+ struct header_pointers *hdr, bool xdp)
+{
+ if (hdr->ipv4) {
+ hdr->eth = data;
+ hdr->ipv4 = (void *)hdr->eth + sizeof(*hdr->eth);
// IPV4_MAXLEN is needed when calculating checksum.
// At least sizeof(struct iphdr) is needed here to access ihl.
- if ((void *)hdr.ipv4 + IPV4_MAXLEN > data_end)
+ if ((void *)hdr->ipv4 + IPV4_MAXLEN > data_end)
return XDP_ABORTED;
- hdr.tcp = (void *)hdr.ipv4 + hdr.ipv4->ihl * 4;
- } else if (hdr.ipv6) {
- hdr.eth = data;
- hdr.ipv6 = (void *)hdr.eth + sizeof(*hdr.eth);
- hdr.tcp = (void *)hdr.ipv6 + sizeof(*hdr.ipv6);
+ hdr->tcp = (void *)hdr->ipv4 + hdr->ipv4->ihl * 4;
+ } else if (hdr->ipv6) {
+ hdr->eth = data;
+ hdr->ipv6 = (void *)hdr->eth + sizeof(*hdr->eth);
+ hdr->tcp = (void *)hdr->ipv6 + sizeof(*hdr->ipv6);
} else {
return XDP_ABORTED;
}
- if ((void *)hdr.tcp + TCP_MAXLEN > data_end)
+ if ((void *)hdr->tcp + TCP_MAXLEN > data_end)
return XDP_ABORTED;
// We run out of registers, tcp_len gets spilled to the stack, and the
// verifier forgets its min and max values checked above in tcp_dissect.
- hdr.tcp_len = hdr.tcp->doff * 4;
- if (hdr.tcp_len < sizeof(*hdr.tcp))
+ hdr->tcp_len = hdr->tcp->doff * 4;
+ if (hdr->tcp_len < sizeof(*hdr->tcp))
return XDP_ABORTED;
- return hdr.tcp->syn ? syncookie_handle_syn(&hdr, ctx, data, data_end) :
- syncookie_handle_ack(&hdr);
+ return hdr->tcp->syn ? syncookie_handle_syn(hdr, ctx, data, data_end, xdp) :
+ syncookie_handle_ack(hdr);
+}
+
+SEC("xdp/syncookie")
+int syncookie_xdp(struct xdp_md *ctx)
+{
+ void *data_end = (void *)(long)ctx->data_end;
+ void *data = (void *)(long)ctx->data;
+ struct header_pointers hdr;
+ int ret;
+
+ ret = syncookie_part1(ctx, data, data_end, &hdr, true);
+ if (ret != XDP_TX)
+ return ret;
+
+ data_end = (void *)(long)ctx->data_end;
+ data = (void *)(long)ctx->data;
+
+ return syncookie_part2(ctx, data, data_end, &hdr, true);
+}
+
+SEC("tc")
+int syncookie_tc(struct __sk_buff *skb)
+{
+ void *data_end = (void *)(long)skb->data_end;
+ void *data = (void *)(long)skb->data;
+ struct header_pointers hdr;
+ int ret;
+
+ ret = syncookie_part1(skb, data, data_end, &hdr, false);
+ if (ret != XDP_TX)
+ return ret == XDP_PASS ? TC_ACT_OK : TC_ACT_SHOT;
+
+ data_end = (void *)(long)skb->data_end;
+ data = (void *)(long)skb->data;
+
+ ret = syncookie_part2(skb, data, data_end, &hdr, false);
+ switch (ret) {
+ case XDP_PASS:
+ return TC_ACT_OK;
+ case XDP_TX:
+ return bpf_redirect(skb->ifindex, 0);
+ default:
+ return TC_ACT_SHOT;
+ }
}
char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/xdp_synproxy.c b/tools/testing/selftests/bpf/xdp_synproxy.c
index 2b9585f2bc00..6b37e95c38ee 100644
--- a/tools/testing/selftests/bpf/xdp_synproxy.c
+++ b/tools/testing/selftests/bpf/xdp_synproxy.c
@@ -18,6 +18,7 @@
static unsigned int ifindex;
static __u32 attached_prog_id;
+static bool attached_tc;
static void noreturn cleanup(int sig)
{
@@ -28,6 +29,20 @@ static void noreturn cleanup(int sig)
if (attached_prog_id == 0)
exit(0);
+ if (attached_tc) {
+ DECLARE_LIBBPF_OPTS(bpf_tc_hook, hook,
+ .ifindex = ifindex,
+ .attach_point = BPF_TC_INGRESS);
+
+ err = bpf_tc_hook_destroy(&hook);
+ if (err < 0) {
+ fprintf(stderr, "Error: bpf_tc_hook_destroy: %s\n", strerror(-err));
+ fprintf(stderr, "Failed to destroy the TC hook\n");
+ exit(1);
+ }
+ exit(0);
+ }
+
prog_fd = bpf_prog_get_fd_by_id(attached_prog_id);
if (prog_fd < 0) {
fprintf(stderr, "Error: bpf_prog_get_fd_by_id: %s\n", strerror(-prog_fd));
@@ -55,7 +70,7 @@ static void noreturn cleanup(int sig)
static noreturn void usage(const char *progname)
{
- fprintf(stderr, "Usage: %s [--iface <iface>|--prog <prog_id>] [--mss4 <mss ipv4> --mss6 <mss ipv6> --wscale <wscale> --ttl <ttl>] [--ports <port1>,<port2>,...] [--single]\n",
+ fprintf(stderr, "Usage: %s [--iface <iface>|--prog <prog_id>] [--mss4 <mss ipv4> --mss6 <mss ipv6> --wscale <wscale> --ttl <ttl>] [--ports <port1>,<port2>,...] [--single] [--tc]\n",
progname);
exit(1);
}
@@ -74,7 +89,7 @@ static unsigned long parse_arg_ul(const char *progname, const char *arg, unsigne
}
static void parse_options(int argc, char *argv[], unsigned int *ifindex, __u32 *prog_id,
- __u64 *tcpipopts, char **ports, bool *single)
+ __u64 *tcpipopts, char **ports, bool *single, bool *tc)
{
static struct option long_options[] = {
{ "help", no_argument, NULL, 'h' },
@@ -86,6 +101,7 @@ static void parse_options(int argc, char *argv[], unsigned int *ifindex, __u32 *
{ "ttl", required_argument, NULL, 't' },
{ "ports", required_argument, NULL, 'p' },
{ "single", no_argument, NULL, 's' },
+ { "tc", no_argument, NULL, 'c' },
{ NULL, 0, NULL, 0 },
};
unsigned long mss4, mss6, wscale, ttl;
@@ -143,6 +159,9 @@ static void parse_options(int argc, char *argv[], unsigned int *ifindex, __u32 *
case 's':
*single = true;
break;
+ case 'c':
+ *tc = true;
+ break;
default:
usage(argv[0]);
}
@@ -164,7 +183,7 @@ static void parse_options(int argc, char *argv[], unsigned int *ifindex, __u32 *
usage(argv[0]);
}
-static int syncookie_attach(const char *argv0, unsigned int ifindex)
+static int syncookie_attach(const char *argv0, unsigned int ifindex, bool tc)
{
struct bpf_prog_info info = {};
__u32 info_len = sizeof(info);
@@ -188,9 +207,9 @@ static int syncookie_attach(const char *argv0, unsigned int ifindex)
return err;
}
- prog = bpf_object__find_program_by_name(obj, "syncookie_xdp");
+ prog = bpf_object__find_program_by_name(obj, tc ? "syncookie_tc" : "syncookie_xdp");
if (!prog) {
- fprintf(stderr, "Error: bpf_object__find_program_by_name: program syncookie_xdp was not found\n");
+ fprintf(stderr, "Error: bpf_object__find_program_by_name: program was not found\n");
return -ENOENT;
}
@@ -201,21 +220,50 @@ static int syncookie_attach(const char *argv0, unsigned int ifindex)
fprintf(stderr, "Error: bpf_obj_get_info_by_fd: %s\n", strerror(-err));
goto out;
}
+ attached_tc = tc;
attached_prog_id = info.id;
signal(SIGINT, cleanup);
signal(SIGTERM, cleanup);
- err = bpf_xdp_attach(ifindex, prog_fd, XDP_FLAGS_UPDATE_IF_NOEXIST, NULL);
- if (err < 0) {
- fprintf(stderr, "Error: bpf_set_link_xdp_fd: %s\n", strerror(-err));
- signal(SIGINT, SIG_DFL);
- signal(SIGTERM, SIG_DFL);
- attached_prog_id = 0;
- goto out;
+ if (tc) {
+ DECLARE_LIBBPF_OPTS(bpf_tc_hook, hook,
+ .ifindex = ifindex,
+ .attach_point = BPF_TC_INGRESS);
+ DECLARE_LIBBPF_OPTS(bpf_tc_opts, opts,
+ .handle = 1,
+ .priority = 1,
+ .prog_fd = prog_fd);
+
+ err = bpf_tc_hook_create(&hook);
+ if (err < 0) {
+ fprintf(stderr, "Error: bpf_tc_hook_create: %s\n",
+ strerror(-err));
+ goto fail;
+ }
+ err = bpf_tc_attach(&hook, &opts);
+ if (err < 0) {
+ fprintf(stderr, "Error: bpf_tc_attach: %s\n",
+ strerror(-err));
+ goto fail;
+ }
+
+ } else {
+ err = bpf_xdp_attach(ifindex, prog_fd,
+ XDP_FLAGS_UPDATE_IF_NOEXIST, NULL);
+ if (err < 0) {
+ fprintf(stderr, "Error: bpf_set_link_xdp_fd: %s\n",
+ strerror(-err));
+ goto fail;
+ }
}
err = 0;
out:
bpf_object__close(obj);
return err;
+fail:
+ signal(SIGINT, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
+ attached_prog_id = 0;
+ goto out;
}
static int syncookie_open_bpf_maps(__u32 prog_id, int *values_map_fd, int *ports_map_fd)
@@ -248,11 +296,6 @@ static int syncookie_open_bpf_maps(__u32 prog_id, int *values_map_fd, int *ports
goto out;
}
- if (prog_info.type != BPF_PROG_TYPE_XDP) {
- fprintf(stderr, "Error: BPF prog type is not BPF_PROG_TYPE_XDP\n");
- err = -ENOENT;
- goto out;
- }
if (prog_info.nr_map_ids < 2) {
fprintf(stderr, "Error: Found %u BPF maps, expected at least 2\n",
prog_info.nr_map_ids);
@@ -319,17 +362,22 @@ int main(int argc, char *argv[])
char *ports;
bool single;
int err = 0;
+ bool tc;
- parse_options(argc, argv, &ifindex, &prog_id, &tcpipopts, &ports, &single);
+ parse_options(argc, argv, &ifindex, &prog_id, &tcpipopts, &ports,
+ &single, &tc);
if (prog_id == 0) {
- err = bpf_xdp_query_id(ifindex, 0, &prog_id);
- if (err < 0) {
- fprintf(stderr, "Error: bpf_get_link_xdp_id: %s\n", strerror(-err));
- goto out;
+ if (!tc) {
+ err = bpf_xdp_query_id(ifindex, 0, &prog_id);
+ if (err < 0) {
+ fprintf(stderr, "Error: bpf_get_link_xdp_id: %s\n",
+ strerror(-err));
+ goto out;
+ }
}
if (prog_id == 0) {
- err = syncookie_attach(argv[0], ifindex);
+ err = syncookie_attach(argv[0], ifindex, tc);
if (err < 0)
goto out;
prog_id = attached_prog_id;
--
2.30.2
^ permalink raw reply related
* Re: [PATCH bpf-next v5 4/6] bpf: Add helpers to issue and check SYN cookies in XDP
From: Maxim Mikityanskiy @ 2022-04-22 17:23 UTC (permalink / raw)
To: Daniel Borkmann
Cc: bpf, Alexei Starovoitov, Andrii Nakryiko, netdev, Tariq Toukan,
Martin KaFai Lau, Song Liu, Yonghong Song, John Fastabend,
KP Singh, David S. Miller, Jakub Kicinski, Petar Penkov,
Lorenz Bauer, Eric Dumazet, Hideaki YOSHIFUJI, David Ahern,
Shuah Khan, Jesper Dangaard Brouer, Nathan Chancellor,
Nick Desaulniers, Joe Stringer, Florent Revest, linux-kselftest,
Toke Høiland-Jørgensen, Kumar Kartikeya Dwivedi,
Florian Westphal
In-Reply-To: <e75057fd-42d4-071e-b8b9-0b93e643adfd@iogearbox.net>
On 2022-04-14 01:48, Daniel Borkmann wrote:
> On 4/13/22 3:41 PM, Maxim Mikityanskiy wrote:
> [...]
>> /* integer value in 'imm' field of BPF_CALL instruction selects
>> which helper
>> diff --git a/net/core/filter.c b/net/core/filter.c
>> index 7446b0ba4e38..428cc63ecdf7 100644
>> --- a/net/core/filter.c
>> +++ b/net/core/filter.c
>> @@ -7425,6 +7425,124 @@ static const struct bpf_func_proto
>> bpf_skb_set_tstamp_proto = {
>> .arg3_type = ARG_ANYTHING,
>> };
>> +BPF_CALL_3(bpf_tcp_raw_gen_syncookie_ipv4, struct iphdr *, iph,
>> + struct tcphdr *, th, u32, th_len)
>> +{
>> +#ifdef CONFIG_SYN_COOKIES
>> + u32 cookie;
>> + u16 mss;
>> +
>> + if (unlikely(th_len < sizeof(*th) || th_len != th->doff * 4))
>> + return -EINVAL;
>> +
>> + mss = tcp_parse_mss_option(th, 0) ?: TCP_MSS_DEFAULT;
>> + cookie = __cookie_v4_init_sequence(iph, th, &mss);
>> +
>> + return cookie | ((u64)mss << 32);
>> +#else
>> + return -EOPNOTSUPP;
>> +#endif /* CONFIG_SYN_COOKIES */
>
> This (and for other added helpers below) will be rather tricky to probe
> for availability
> e.g. via `bpftool feature probe [...]`. Much better if you wrap the
> ifdef CONFIG_SYN_COOKIES
> around the {xdp,tc_cls_act}_func_proto() instead as we do elsewhere.
Just for the record, I copied this pattern from the existing SYN cookie
helpers, but what you suggest makes sense, so I'll fix it for my helpers
and resubmit.
>> +}
>> +
>> +static const struct bpf_func_proto
>> bpf_tcp_raw_gen_syncookie_ipv4_proto = {
>> + .func = bpf_tcp_raw_gen_syncookie_ipv4,
>> + .gpl_only = true, /* __cookie_v4_init_sequence() is GPL */
>> + .pkt_access = true,
>> + .ret_type = RET_INTEGER,
>> + .arg1_type = ARG_PTR_TO_MEM,
>> + .arg1_size = sizeof(struct iphdr),
>> + .arg2_type = ARG_PTR_TO_MEM,
>> + .arg3_type = ARG_CONST_SIZE,
>> +};
>> +
>> +BPF_CALL_3(bpf_tcp_raw_gen_syncookie_ipv6, struct ipv6hdr *, iph,
>> + struct tcphdr *, th, u32, th_len)
>> +{
>> +#ifndef CONFIG_SYN_COOKIES
>> + return -EOPNOTSUPP;
>> +#elif !IS_BUILTIN(CONFIG_IPV6)
>> + return -EPROTONOSUPPORT;
>> +#else
>> + const u16 mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) -
>> + sizeof(struct ipv6hdr);
>> + u32 cookie;
>> + u16 mss;
>> +
>> + if (unlikely(th_len < sizeof(*th) || th_len != th->doff * 4))
>> + return -EINVAL;
>> +
>> + mss = tcp_parse_mss_option(th, 0) ?: mss_clamp;
>> + cookie = __cookie_v6_init_sequence(iph, th, &mss);
>> +
>> + return cookie | ((u64)mss << 32);
>> +#endif
>> +}
>> +
>> +static const struct bpf_func_proto
>> bpf_tcp_raw_gen_syncookie_ipv6_proto = {
>> + .func = bpf_tcp_raw_gen_syncookie_ipv6,
>> + .gpl_only = true, /* __cookie_v6_init_sequence() is GPL */
>> + .pkt_access = true,
>> + .ret_type = RET_INTEGER,
>> + .arg1_type = ARG_PTR_TO_MEM,
>> + .arg1_size = sizeof(struct ipv6hdr),
>> + .arg2_type = ARG_PTR_TO_MEM,
>> + .arg3_type = ARG_CONST_SIZE,
>> +};
> [...]
>> bool bpf_helper_changes_pkt_data(void *func)
>> @@ -7837,6 +7955,14 @@ xdp_func_proto(enum bpf_func_id func_id, const
>> struct bpf_prog *prog)
>> return &bpf_tcp_check_syncookie_proto;
>> case BPF_FUNC_tcp_gen_syncookie:
>> return &bpf_tcp_gen_syncookie_proto;
>> + case BPF_FUNC_tcp_raw_gen_syncookie_ipv4:
>> + return &bpf_tcp_raw_gen_syncookie_ipv4_proto;
>> + case BPF_FUNC_tcp_raw_gen_syncookie_ipv6:
>> + return &bpf_tcp_raw_gen_syncookie_ipv6_proto;
>> + case BPF_FUNC_tcp_raw_check_syncookie_ipv4:
>> + return &bpf_tcp_raw_check_syncookie_ipv4_proto;
>> + case BPF_FUNC_tcp_raw_check_syncookie_ipv6:
>> + return &bpf_tcp_raw_check_syncookie_ipv6_proto;
>> #endif
>> default:
>> return bpf_sk_base_func_proto(func_id);
^ permalink raw reply
* [PATCH bpf-next v6 5/6] bpf: Add selftests for raw syncookie helpers
From: Maxim Mikityanskiy @ 2022-04-22 17:24 UTC (permalink / raw)
To: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, netdev
Cc: Tariq Toukan, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, David S. Miller, Jakub Kicinski,
Petar Penkov, Lorenz Bauer, Eric Dumazet, Hideaki YOSHIFUJI,
David Ahern, Shuah Khan, Jesper Dangaard Brouer,
Nathan Chancellor, Nick Desaulniers, Joe Stringer, Florent Revest,
linux-kselftest, Toke Høiland-Jørgensen,
Kumar Kartikeya Dwivedi, Florian Westphal, pabeni,
Maxim Mikityanskiy
In-Reply-To: <20220422172422.4037988-1-maximmi@nvidia.com>
This commit adds selftests for the new BPF helpers:
bpf_tcp_raw_{gen,check}_syncookie_ipv{4,6}.
xdp_synproxy_kern.c is a BPF program that generates SYN cookies on
allowed TCP ports and sends SYNACKs to clients, accelerating synproxy
iptables module.
xdp_synproxy.c is a userspace control application that allows to
configure the following options in runtime: list of allowed ports, MSS,
window scale, TTL.
A selftest is added to prog_tests that leverages the above programs to
test the functionality of the new helpers.
Signed-off-by: Maxim Mikityanskiy <maximmi@nvidia.com>
Reviewed-by: Tariq Toukan <tariqt@nvidia.com>
---
tools/testing/selftests/bpf/.gitignore | 1 +
tools/testing/selftests/bpf/Makefile | 2 +-
.../selftests/bpf/prog_tests/xdp_synproxy.c | 109 +++
.../selftests/bpf/progs/xdp_synproxy_kern.c | 750 ++++++++++++++++++
tools/testing/selftests/bpf/xdp_synproxy.c | 418 ++++++++++
5 files changed, 1279 insertions(+), 1 deletion(-)
create mode 100644 tools/testing/selftests/bpf/prog_tests/xdp_synproxy.c
create mode 100644 tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c
create mode 100644 tools/testing/selftests/bpf/xdp_synproxy.c
diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore
index 595565eb68c0..ca2f47f45670 100644
--- a/tools/testing/selftests/bpf/.gitignore
+++ b/tools/testing/selftests/bpf/.gitignore
@@ -43,3 +43,4 @@ test_cpp
*.tmp
xdpxceiver
xdp_redirect_multi
+xdp_synproxy
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index bafdc5373a13..1b117673778e 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -82,7 +82,7 @@ TEST_PROGS_EXTENDED := with_addr.sh \
TEST_GEN_PROGS_EXTENDED = test_sock_addr test_skb_cgroup_id_user \
flow_dissector_load test_flow_dissector test_tcp_check_syncookie_user \
test_lirc_mode2_user xdping test_cpp runqslower bench bpf_testmod.ko \
- xdpxceiver xdp_redirect_multi
+ xdpxceiver xdp_redirect_multi xdp_synproxy
TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read
diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_synproxy.c b/tools/testing/selftests/bpf/prog_tests/xdp_synproxy.c
new file mode 100644
index 000000000000..e08b28e25047
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/xdp_synproxy.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <test_progs.h>
+#include <network_helpers.h>
+
+#define SYS(cmd) ({ \
+ if (!ASSERT_OK(system(cmd), (cmd))) \
+ goto out; \
+})
+
+#define SYS_OUT(cmd) ({ \
+ FILE *f = popen((cmd), "r"); \
+ if (!ASSERT_OK_PTR(f, (cmd))) \
+ goto out; \
+ f; \
+})
+
+static bool expect_str(char *buf, size_t size, const char *str)
+{
+ if (size != strlen(str))
+ return false;
+ return !memcmp(buf, str, size);
+}
+
+void test_xdp_synproxy(void)
+{
+ int server_fd = -1, client_fd = -1, accept_fd = -1;
+ struct nstoken *ns = NULL;
+ FILE *ctrl_file = NULL;
+ char buf[1024];
+ size_t size;
+
+ SYS("ip netns add synproxy");
+
+ SYS("ip link add tmp0 type veth peer name tmp1");
+ SYS("ip link set tmp1 netns synproxy");
+ SYS("ip link set tmp0 up");
+ SYS("ip addr replace 198.18.0.1/24 dev tmp0");
+
+ // When checksum offload is enabled, the XDP program sees wrong
+ // checksums and drops packets.
+ SYS("ethtool -K tmp0 tx off");
+ // Workaround required for veth.
+ SYS("ip link set tmp0 xdp object xdp_dummy.o section xdp 2> /dev/null");
+
+ ns = open_netns("synproxy");
+ if (!ASSERT_OK_PTR(ns, "setns"))
+ goto out;
+
+ SYS("ip link set lo up");
+ SYS("ip link set tmp1 up");
+ SYS("ip addr replace 198.18.0.2/24 dev tmp1");
+ SYS("sysctl -w net.ipv4.tcp_syncookies=2");
+ SYS("sysctl -w net.ipv4.tcp_timestamps=1");
+ SYS("sysctl -w net.netfilter.nf_conntrack_tcp_loose=0");
+ SYS("iptables -t raw -I PREROUTING \
+ -i tmp1 -p tcp -m tcp --syn --dport 8080 -j CT --notrack");
+ SYS("iptables -t filter -A INPUT \
+ -i tmp1 -p tcp -m tcp --dport 8080 -m state --state INVALID,UNTRACKED \
+ -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460");
+ SYS("iptables -t filter -A INPUT \
+ -i tmp1 -m state --state INVALID -j DROP");
+
+ ctrl_file = SYS_OUT("./xdp_synproxy --iface tmp1 --ports 8080 --single \
+ --mss4 1460 --mss6 1440 --wscale 7 --ttl 64");
+ size = fread(buf, 1, sizeof(buf), ctrl_file);
+ pclose(ctrl_file);
+ if (!ASSERT_TRUE(expect_str(buf, size, "Total SYNACKs generated: 0\n"),
+ "initial SYNACKs"))
+ goto out;
+
+ server_fd = start_server(AF_INET, SOCK_STREAM, "198.18.0.2", 8080, 0);
+ if (!ASSERT_GE(server_fd, 0, "start_server"))
+ goto out;
+
+ close_netns(ns);
+ ns = NULL;
+
+ client_fd = connect_to_fd(server_fd, 10000);
+ if (!ASSERT_GE(client_fd, 0, "connect_to_fd"))
+ goto out;
+
+ accept_fd = accept(server_fd, NULL, NULL);
+ if (!ASSERT_GE(accept_fd, 0, "accept"))
+ goto out;
+
+ ns = open_netns("synproxy");
+ if (!ASSERT_OK_PTR(ns, "setns"))
+ goto out;
+
+ ctrl_file = SYS_OUT("./xdp_synproxy --iface tmp1 --single");
+ size = fread(buf, 1, sizeof(buf), ctrl_file);
+ pclose(ctrl_file);
+ if (!ASSERT_TRUE(expect_str(buf, size, "Total SYNACKs generated: 1\n"),
+ "SYNACKs after connection"))
+ goto out;
+
+out:
+ if (accept_fd >= 0)
+ close(accept_fd);
+ if (client_fd >= 0)
+ close(client_fd);
+ if (server_fd >= 0)
+ close(server_fd);
+ if (ns)
+ close_netns(ns);
+
+ system("ip link del tmp0");
+ system("ip netns del synproxy");
+}
diff --git a/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c b/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c
new file mode 100644
index 000000000000..7bebec6f2627
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c
@@ -0,0 +1,750 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
+
+#include "vmlinux.h"
+
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+#include <asm/errno.h>
+
+#define NSEC_PER_SEC 1000000000L
+
+#define ETH_ALEN 6
+#define ETH_P_IP 0x0800
+#define ETH_P_IPV6 0x86DD
+
+#define tcp_flag_word(tp) (((union tcp_word_hdr *)(tp))->words[3])
+
+#define IP_DF 0x4000
+#define IP_MF 0x2000
+#define IP_OFFSET 0x1fff
+
+#define NEXTHDR_TCP 6
+
+#define TCPOPT_NOP 1
+#define TCPOPT_EOL 0
+#define TCPOPT_MSS 2
+#define TCPOPT_WINDOW 3
+#define TCPOPT_SACK_PERM 4
+#define TCPOPT_TIMESTAMP 8
+
+#define TCPOLEN_MSS 4
+#define TCPOLEN_WINDOW 3
+#define TCPOLEN_SACK_PERM 2
+#define TCPOLEN_TIMESTAMP 10
+
+#define TCP_TS_HZ 1000
+#define TS_OPT_WSCALE_MASK 0xf
+#define TS_OPT_SACK (1 << 4)
+#define TS_OPT_ECN (1 << 5)
+#define TSBITS 6
+#define TSMASK (((__u32)1 << TSBITS) - 1)
+#define TCP_MAX_WSCALE 14U
+
+#define IPV4_MAXLEN 60
+#define TCP_MAXLEN 60
+
+#define DEFAULT_MSS4 1460
+#define DEFAULT_MSS6 1440
+#define DEFAULT_WSCALE 7
+#define DEFAULT_TTL 64
+#define MAX_ALLOWED_PORTS 8
+
+#define swap(a, b) \
+ do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)
+
+#define __get_unaligned_t(type, ptr) ({ \
+ const struct { type x; } __attribute__((__packed__)) *__pptr = (typeof(__pptr))(ptr); \
+ __pptr->x; \
+})
+
+#define get_unaligned(ptr) __get_unaligned_t(typeof(*(ptr)), (ptr))
+
+struct {
+ __uint(type, BPF_MAP_TYPE_ARRAY);
+ __type(key, __u32);
+ __type(value, __u64);
+ __uint(max_entries, 2);
+} values SEC(".maps");
+
+struct {
+ __uint(type, BPF_MAP_TYPE_ARRAY);
+ __type(key, __u32);
+ __type(value, __u16);
+ __uint(max_entries, MAX_ALLOWED_PORTS);
+} allowed_ports SEC(".maps");
+
+extern struct nf_conn *bpf_xdp_ct_lookup(struct xdp_md *xdp_ctx,
+ struct bpf_sock_tuple *bpf_tuple,
+ __u32 len_tuple,
+ struct bpf_ct_opts *opts,
+ __u32 len_opts) __ksym;
+
+extern void bpf_ct_release(struct nf_conn *ct) __ksym;
+
+static __always_inline void swap_eth_addr(__u8 *a, __u8 *b)
+{
+ __u8 tmp[ETH_ALEN];
+
+ __builtin_memcpy(tmp, a, ETH_ALEN);
+ __builtin_memcpy(a, b, ETH_ALEN);
+ __builtin_memcpy(b, tmp, ETH_ALEN);
+}
+
+static __always_inline __u16 csum_fold(__u32 csum)
+{
+ csum = (csum & 0xffff) + (csum >> 16);
+ csum = (csum & 0xffff) + (csum >> 16);
+ return (__u16)~csum;
+}
+
+static __always_inline __u16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
+ __u32 len, __u8 proto,
+ __u32 csum)
+{
+ __u64 s = csum;
+
+ s += (__u32)saddr;
+ s += (__u32)daddr;
+#if defined(__BIG_ENDIAN__)
+ s += proto + len;
+#elif defined(__LITTLE_ENDIAN__)
+ s += (proto + len) << 8;
+#else
+#error Unknown endian
+#endif
+ s = (s & 0xffffffff) + (s >> 32);
+ s = (s & 0xffffffff) + (s >> 32);
+
+ return csum_fold((__u32)s);
+}
+
+static __always_inline __u16 csum_ipv6_magic(const struct in6_addr *saddr,
+ const struct in6_addr *daddr,
+ __u32 len, __u8 proto, __u32 csum)
+{
+ __u64 sum = csum;
+ int i;
+
+#pragma unroll
+ for (i = 0; i < 4; i++)
+ sum += (__u32)saddr->in6_u.u6_addr32[i];
+
+#pragma unroll
+ for (i = 0; i < 4; i++)
+ sum += (__u32)daddr->in6_u.u6_addr32[i];
+
+ // Don't combine additions to avoid 32-bit overflow.
+ sum += bpf_htonl(len);
+ sum += bpf_htonl(proto);
+
+ sum = (sum & 0xffffffff) + (sum >> 32);
+ sum = (sum & 0xffffffff) + (sum >> 32);
+
+ return csum_fold((__u32)sum);
+}
+
+static __always_inline __u64 tcp_clock_ns(void)
+{
+ return bpf_ktime_get_ns();
+}
+
+static __always_inline __u32 tcp_ns_to_ts(__u64 ns)
+{
+ return ns / (NSEC_PER_SEC / TCP_TS_HZ);
+}
+
+static __always_inline __u32 tcp_time_stamp_raw(void)
+{
+ return tcp_ns_to_ts(tcp_clock_ns());
+}
+
+struct tcpopt_context {
+ __u8 *ptr;
+ __u8 *end;
+ void *data_end;
+ __be32 *tsecr;
+ __u8 wscale;
+ bool option_timestamp;
+ bool option_sack;
+};
+
+static int tscookie_tcpopt_parse(struct tcpopt_context *ctx)
+{
+ __u8 opcode, opsize;
+
+ if (ctx->ptr >= ctx->end)
+ return 1;
+ if (ctx->ptr >= ctx->data_end)
+ return 1;
+
+ opcode = ctx->ptr[0];
+
+ if (opcode == TCPOPT_EOL)
+ return 1;
+ if (opcode == TCPOPT_NOP) {
+ ++ctx->ptr;
+ return 0;
+ }
+
+ if (ctx->ptr + 1 >= ctx->end)
+ return 1;
+ if (ctx->ptr + 1 >= ctx->data_end)
+ return 1;
+ opsize = ctx->ptr[1];
+ if (opsize < 2)
+ return 1;
+
+ if (ctx->ptr + opsize > ctx->end)
+ return 1;
+
+ switch (opcode) {
+ case TCPOPT_WINDOW:
+ if (opsize == TCPOLEN_WINDOW && ctx->ptr + TCPOLEN_WINDOW <= ctx->data_end)
+ ctx->wscale = ctx->ptr[2] < TCP_MAX_WSCALE ? ctx->ptr[2] : TCP_MAX_WSCALE;
+ break;
+ case TCPOPT_TIMESTAMP:
+ if (opsize == TCPOLEN_TIMESTAMP && ctx->ptr + TCPOLEN_TIMESTAMP <= ctx->data_end) {
+ ctx->option_timestamp = true;
+ /* Client's tsval becomes our tsecr. */
+ *ctx->tsecr = get_unaligned((__be32 *)(ctx->ptr + 2));
+ }
+ break;
+ case TCPOPT_SACK_PERM:
+ if (opsize == TCPOLEN_SACK_PERM)
+ ctx->option_sack = true;
+ break;
+ }
+
+ ctx->ptr += opsize;
+
+ return 0;
+}
+
+static int tscookie_tcpopt_parse_batch(__u32 index, void *context)
+{
+ int i;
+
+ for (i = 0; i < 7; i++)
+ if (tscookie_tcpopt_parse(context))
+ return 1;
+ return 0;
+}
+
+static __always_inline bool tscookie_init(struct tcphdr *tcp_header,
+ __u16 tcp_len, __be32 *tsval,
+ __be32 *tsecr, void *data_end)
+{
+ struct tcpopt_context loop_ctx = {
+ .ptr = (__u8 *)(tcp_header + 1),
+ .end = (__u8 *)tcp_header + tcp_len,
+ .data_end = data_end,
+ .tsecr = tsecr,
+ .wscale = TS_OPT_WSCALE_MASK,
+ .option_timestamp = false,
+ .option_sack = false,
+ };
+ u32 cookie;
+
+ bpf_loop(6, tscookie_tcpopt_parse_batch, &loop_ctx, 0);
+
+ if (!loop_ctx.option_timestamp)
+ return false;
+
+ cookie = tcp_time_stamp_raw() & ~TSMASK;
+ cookie |= loop_ctx.wscale & TS_OPT_WSCALE_MASK;
+ if (loop_ctx.option_sack)
+ cookie |= TS_OPT_SACK;
+ if (tcp_header->ece && tcp_header->cwr)
+ cookie |= TS_OPT_ECN;
+ *tsval = bpf_htonl(cookie);
+
+ return true;
+}
+
+static __always_inline void values_get_tcpipopts(__u16 *mss, __u8 *wscale,
+ __u8 *ttl, bool ipv6)
+{
+ __u32 key = 0;
+ __u64 *value;
+
+ value = bpf_map_lookup_elem(&values, &key);
+ if (value && *value != 0) {
+ if (ipv6)
+ *mss = (*value >> 32) & 0xffff;
+ else
+ *mss = *value & 0xffff;
+ *wscale = (*value >> 16) & 0xf;
+ *ttl = (*value >> 24) & 0xff;
+ return;
+ }
+
+ *mss = ipv6 ? DEFAULT_MSS6 : DEFAULT_MSS4;
+ *wscale = DEFAULT_WSCALE;
+ *ttl = DEFAULT_TTL;
+}
+
+static __always_inline void values_inc_synacks(void)
+{
+ __u32 key = 1;
+ __u32 *value;
+
+ value = bpf_map_lookup_elem(&values, &key);
+ if (value)
+ __sync_fetch_and_add(value, 1);
+}
+
+static __always_inline bool check_port_allowed(__u16 port)
+{
+ __u32 i;
+
+ for (i = 0; i < MAX_ALLOWED_PORTS; i++) {
+ __u32 key = i;
+ __u16 *value;
+
+ value = bpf_map_lookup_elem(&allowed_ports, &key);
+
+ if (!value)
+ break;
+ // 0 is a terminator value. Check it first to avoid matching on
+ // a forbidden port == 0 and returning true.
+ if (*value == 0)
+ break;
+
+ if (*value == port)
+ return true;
+ }
+
+ return false;
+}
+
+struct header_pointers {
+ struct ethhdr *eth;
+ struct iphdr *ipv4;
+ struct ipv6hdr *ipv6;
+ struct tcphdr *tcp;
+ __u16 tcp_len;
+};
+
+static __always_inline int tcp_dissect(void *data, void *data_end,
+ struct header_pointers *hdr)
+{
+ hdr->eth = data;
+ if (hdr->eth + 1 > data_end)
+ return XDP_DROP;
+
+ switch (bpf_ntohs(hdr->eth->h_proto)) {
+ case ETH_P_IP:
+ hdr->ipv6 = NULL;
+
+ hdr->ipv4 = (void *)hdr->eth + sizeof(*hdr->eth);
+ if (hdr->ipv4 + 1 > data_end)
+ return XDP_DROP;
+ if (hdr->ipv4->ihl * 4 < sizeof(*hdr->ipv4))
+ return XDP_DROP;
+ if (hdr->ipv4->version != 4)
+ return XDP_DROP;
+
+ if (hdr->ipv4->protocol != IPPROTO_TCP)
+ return XDP_PASS;
+
+ hdr->tcp = (void *)hdr->ipv4 + hdr->ipv4->ihl * 4;
+ break;
+ case ETH_P_IPV6:
+ hdr->ipv4 = NULL;
+
+ hdr->ipv6 = (void *)hdr->eth + sizeof(*hdr->eth);
+ if (hdr->ipv6 + 1 > data_end)
+ return XDP_DROP;
+ if (hdr->ipv6->version != 6)
+ return XDP_DROP;
+
+ // XXX: Extension headers are not supported and could circumvent
+ // XDP SYN flood protection.
+ if (hdr->ipv6->nexthdr != NEXTHDR_TCP)
+ return XDP_PASS;
+
+ hdr->tcp = (void *)hdr->ipv6 + sizeof(*hdr->ipv6);
+ break;
+ default:
+ // XXX: VLANs will circumvent XDP SYN flood protection.
+ return XDP_PASS;
+ }
+
+ if (hdr->tcp + 1 > data_end)
+ return XDP_DROP;
+ hdr->tcp_len = hdr->tcp->doff * 4;
+ if (hdr->tcp_len < sizeof(*hdr->tcp))
+ return XDP_DROP;
+
+ return XDP_TX;
+}
+
+static __always_inline int tcp_lookup(struct xdp_md *ctx, struct header_pointers *hdr)
+{
+ struct bpf_ct_opts ct_lookup_opts = {
+ .netns_id = BPF_F_CURRENT_NETNS,
+ .l4proto = IPPROTO_TCP,
+ };
+ struct bpf_sock_tuple tup = {};
+ struct nf_conn *ct;
+ __u32 tup_size;
+
+ if (hdr->ipv4) {
+ // TCP doesn't normally use fragments, and XDP can't reassemble them.
+ if ((hdr->ipv4->frag_off & bpf_htons(IP_DF | IP_MF | IP_OFFSET)) != bpf_htons(IP_DF))
+ return XDP_DROP;
+
+ tup.ipv4.saddr = hdr->ipv4->saddr;
+ tup.ipv4.daddr = hdr->ipv4->daddr;
+ tup.ipv4.sport = hdr->tcp->source;
+ tup.ipv4.dport = hdr->tcp->dest;
+ tup_size = sizeof(tup.ipv4);
+ } else if (hdr->ipv6) {
+ __builtin_memcpy(tup.ipv6.saddr, &hdr->ipv6->saddr, sizeof(tup.ipv6.saddr));
+ __builtin_memcpy(tup.ipv6.daddr, &hdr->ipv6->daddr, sizeof(tup.ipv6.daddr));
+ tup.ipv6.sport = hdr->tcp->source;
+ tup.ipv6.dport = hdr->tcp->dest;
+ tup_size = sizeof(tup.ipv6);
+ } else {
+ // The verifier can't track that either ipv4 or ipv6 is not NULL.
+ return XDP_ABORTED;
+ }
+ ct = bpf_xdp_ct_lookup(ctx, &tup, tup_size, &ct_lookup_opts, sizeof(ct_lookup_opts));
+ if (ct) {
+ unsigned long status = ct->status;
+
+ bpf_ct_release(ct);
+ if (status & IPS_CONFIRMED_BIT)
+ return XDP_PASS;
+ } else if (ct_lookup_opts.error != -ENOENT) {
+ return XDP_ABORTED;
+ }
+
+ // error == -ENOENT || !(status & IPS_CONFIRMED_BIT)
+ return XDP_TX;
+}
+
+static __always_inline __u8 tcp_mkoptions(__be32 *buf, __be32 *tsopt, __u16 mss,
+ __u8 wscale)
+{
+ __be32 *start = buf;
+
+ *buf++ = bpf_htonl((TCPOPT_MSS << 24) | (TCPOLEN_MSS << 16) | mss);
+
+ if (!tsopt)
+ return buf - start;
+
+ if (tsopt[0] & bpf_htonl(1 << 4))
+ *buf++ = bpf_htonl((TCPOPT_SACK_PERM << 24) |
+ (TCPOLEN_SACK_PERM << 16) |
+ (TCPOPT_TIMESTAMP << 8) |
+ TCPOLEN_TIMESTAMP);
+ else
+ *buf++ = bpf_htonl((TCPOPT_NOP << 24) |
+ (TCPOPT_NOP << 16) |
+ (TCPOPT_TIMESTAMP << 8) |
+ TCPOLEN_TIMESTAMP);
+ *buf++ = tsopt[0];
+ *buf++ = tsopt[1];
+
+ if ((tsopt[0] & bpf_htonl(0xf)) != bpf_htonl(0xf))
+ *buf++ = bpf_htonl((TCPOPT_NOP << 24) |
+ (TCPOPT_WINDOW << 16) |
+ (TCPOLEN_WINDOW << 8) |
+ wscale);
+
+ return buf - start;
+}
+
+static __always_inline void tcp_gen_synack(struct tcphdr *tcp_header,
+ __u32 cookie, __be32 *tsopt,
+ __u16 mss, __u8 wscale)
+{
+ void *tcp_options;
+
+ tcp_flag_word(tcp_header) = TCP_FLAG_SYN | TCP_FLAG_ACK;
+ if (tsopt && (tsopt[0] & bpf_htonl(1 << 5)))
+ tcp_flag_word(tcp_header) |= TCP_FLAG_ECE;
+ tcp_header->doff = 5; // doff is part of tcp_flag_word.
+ swap(tcp_header->source, tcp_header->dest);
+ tcp_header->ack_seq = bpf_htonl(bpf_ntohl(tcp_header->seq) + 1);
+ tcp_header->seq = bpf_htonl(cookie);
+ tcp_header->window = 0;
+ tcp_header->urg_ptr = 0;
+ tcp_header->check = 0; // Rely on hardware checksum offload.
+
+ tcp_options = (void *)(tcp_header + 1);
+ tcp_header->doff += tcp_mkoptions(tcp_options, tsopt, mss, wscale);
+}
+
+static __always_inline void tcpv4_gen_synack(struct header_pointers *hdr,
+ __u32 cookie, __be32 *tsopt)
+{
+ __u8 wscale;
+ __u16 mss;
+ __u8 ttl;
+
+ values_get_tcpipopts(&mss, &wscale, &ttl, false);
+
+ swap_eth_addr(hdr->eth->h_source, hdr->eth->h_dest);
+
+ swap(hdr->ipv4->saddr, hdr->ipv4->daddr);
+ hdr->ipv4->check = 0; // Rely on hardware checksum offload.
+ hdr->ipv4->tos = 0;
+ hdr->ipv4->id = 0;
+ hdr->ipv4->ttl = ttl;
+
+ tcp_gen_synack(hdr->tcp, cookie, tsopt, mss, wscale);
+
+ hdr->tcp_len = hdr->tcp->doff * 4;
+ hdr->ipv4->tot_len = bpf_htons(sizeof(*hdr->ipv4) + hdr->tcp_len);
+}
+
+static __always_inline void tcpv6_gen_synack(struct header_pointers *hdr,
+ __u32 cookie, __be32 *tsopt)
+{
+ __u8 wscale;
+ __u16 mss;
+ __u8 ttl;
+
+ values_get_tcpipopts(&mss, &wscale, &ttl, true);
+
+ swap_eth_addr(hdr->eth->h_source, hdr->eth->h_dest);
+
+ swap(hdr->ipv6->saddr, hdr->ipv6->daddr);
+ *(__be32 *)hdr->ipv6 = bpf_htonl(0x60000000);
+ hdr->ipv6->hop_limit = ttl;
+
+ tcp_gen_synack(hdr->tcp, cookie, tsopt, mss, wscale);
+
+ hdr->tcp_len = hdr->tcp->doff * 4;
+ hdr->ipv6->payload_len = bpf_htons(hdr->tcp_len);
+}
+
+static __always_inline int syncookie_handle_syn(struct header_pointers *hdr,
+ struct xdp_md *ctx,
+ void *data, void *data_end)
+{
+ __u32 old_pkt_size, new_pkt_size;
+ // Unlike clang 10, clang 11 and 12 generate code that doesn't pass the
+ // BPF verifier if tsopt is not volatile. Volatile forces it to store
+ // the pointer value and use it directly, otherwise tcp_mkoptions is
+ // (mis)compiled like this:
+ // if (!tsopt)
+ // return buf - start;
+ // reg = stored_return_value_of_tscookie_init;
+ // if (reg)
+ // tsopt = tsopt_buf;
+ // else
+ // tsopt = NULL;
+ // ...
+ // *buf++ = tsopt[1];
+ // It creates a dead branch where tsopt is assigned NULL, but the
+ // verifier can't prove it's dead and blocks the program.
+ __be32 * volatile tsopt = NULL;
+ __be32 tsopt_buf[2] = {};
+ __u16 ip_len;
+ __u32 cookie;
+ __s64 value;
+
+ // Checksum is not yet verified, but both checksum failure and TCP
+ // header checks return XDP_DROP, so the order doesn't matter.
+ if (hdr->tcp->fin || hdr->tcp->rst)
+ return XDP_DROP;
+
+ // Issue SYN cookies on allowed ports, drop SYN packets on blocked
+ // ports.
+ if (!check_port_allowed(bpf_ntohs(hdr->tcp->dest)))
+ return XDP_DROP;
+
+ if (hdr->ipv4) {
+ // Check the IPv4 and TCP checksums before creating a SYNACK.
+ value = bpf_csum_diff(0, 0, (void *)hdr->ipv4, hdr->ipv4->ihl * 4, 0);
+ if (value < 0)
+ return XDP_ABORTED;
+ if (csum_fold(value) != 0)
+ return XDP_DROP; // Bad IPv4 checksum.
+
+ value = bpf_csum_diff(0, 0, (void *)hdr->tcp, hdr->tcp_len, 0);
+ if (value < 0)
+ return XDP_ABORTED;
+ if (csum_tcpudp_magic(hdr->ipv4->saddr, hdr->ipv4->daddr,
+ hdr->tcp_len, IPPROTO_TCP, value) != 0)
+ return XDP_DROP; // Bad TCP checksum.
+
+ ip_len = sizeof(*hdr->ipv4);
+
+ value = bpf_tcp_raw_gen_syncookie_ipv4(hdr->ipv4, hdr->tcp,
+ hdr->tcp_len);
+ } else if (hdr->ipv6) {
+ // Check the TCP checksum before creating a SYNACK.
+ value = bpf_csum_diff(0, 0, (void *)hdr->tcp, hdr->tcp_len, 0);
+ if (value < 0)
+ return XDP_ABORTED;
+ if (csum_ipv6_magic(&hdr->ipv6->saddr, &hdr->ipv6->daddr,
+ hdr->tcp_len, IPPROTO_TCP, value) != 0)
+ return XDP_DROP; // Bad TCP checksum.
+
+ ip_len = sizeof(*hdr->ipv6);
+
+ value = bpf_tcp_raw_gen_syncookie_ipv6(hdr->ipv6, hdr->tcp,
+ hdr->tcp_len);
+ } else {
+ return XDP_ABORTED;
+ }
+
+ if (value < 0)
+ return XDP_ABORTED;
+ cookie = (__u32)value;
+
+ if (tscookie_init((void *)hdr->tcp, hdr->tcp_len,
+ &tsopt_buf[0], &tsopt_buf[1], data_end))
+ tsopt = tsopt_buf;
+
+ // Check that there is enough space for a SYNACK. It also covers
+ // the check that the destination of the __builtin_memmove below
+ // doesn't overflow.
+ if (data + sizeof(*hdr->eth) + ip_len + TCP_MAXLEN > data_end)
+ return XDP_ABORTED;
+
+ if (hdr->ipv4) {
+ if (hdr->ipv4->ihl * 4 > sizeof(*hdr->ipv4)) {
+ struct tcphdr *new_tcp_header;
+
+ new_tcp_header = data + sizeof(*hdr->eth) + sizeof(*hdr->ipv4);
+ __builtin_memmove(new_tcp_header, hdr->tcp, sizeof(*hdr->tcp));
+ hdr->tcp = new_tcp_header;
+
+ hdr->ipv4->ihl = sizeof(*hdr->ipv4) / 4;
+ }
+
+ tcpv4_gen_synack(hdr, cookie, tsopt);
+ } else if (hdr->ipv6) {
+ tcpv6_gen_synack(hdr, cookie, tsopt);
+ } else {
+ return XDP_ABORTED;
+ }
+
+ // Recalculate checksums.
+ hdr->tcp->check = 0;
+ value = bpf_csum_diff(0, 0, (void *)hdr->tcp, hdr->tcp_len, 0);
+ if (value < 0)
+ return XDP_ABORTED;
+ if (hdr->ipv4) {
+ hdr->tcp->check = csum_tcpudp_magic(hdr->ipv4->saddr,
+ hdr->ipv4->daddr,
+ hdr->tcp_len,
+ IPPROTO_TCP,
+ value);
+
+ hdr->ipv4->check = 0;
+ value = bpf_csum_diff(0, 0, (void *)hdr->ipv4, sizeof(*hdr->ipv4), 0);
+ if (value < 0)
+ return XDP_ABORTED;
+ hdr->ipv4->check = csum_fold(value);
+ } else if (hdr->ipv6) {
+ hdr->tcp->check = csum_ipv6_magic(&hdr->ipv6->saddr,
+ &hdr->ipv6->daddr,
+ hdr->tcp_len,
+ IPPROTO_TCP,
+ value);
+ } else {
+ return XDP_ABORTED;
+ }
+
+ // Set the new packet size.
+ old_pkt_size = data_end - data;
+ new_pkt_size = sizeof(*hdr->eth) + ip_len + hdr->tcp->doff * 4;
+ if (bpf_xdp_adjust_tail(ctx, new_pkt_size - old_pkt_size))
+ return XDP_ABORTED;
+
+ values_inc_synacks();
+
+ return XDP_TX;
+}
+
+static __always_inline int syncookie_handle_ack(struct header_pointers *hdr)
+{
+ int err;
+
+ if (hdr->tcp->rst)
+ return XDP_DROP;
+
+ if (hdr->ipv4)
+ err = bpf_tcp_raw_check_syncookie_ipv4(hdr->ipv4, hdr->tcp);
+ else if (hdr->ipv6)
+ err = bpf_tcp_raw_check_syncookie_ipv6(hdr->ipv6, hdr->tcp);
+ else
+ return XDP_ABORTED;
+ if (err)
+ return XDP_DROP;
+
+ return XDP_PASS;
+}
+
+SEC("xdp/syncookie")
+int syncookie_xdp(struct xdp_md *ctx)
+{
+ void *data_end = (void *)(long)ctx->data_end;
+ void *data = (void *)(long)ctx->data;
+ struct header_pointers hdr;
+ __s64 value;
+ int ret;
+
+ struct bpf_ct_opts ct_lookup_opts = {
+ .netns_id = BPF_F_CURRENT_NETNS,
+ .l4proto = IPPROTO_TCP,
+ };
+
+ ret = tcp_dissect(data, data_end, &hdr);
+ if (ret != XDP_TX)
+ return ret;
+
+ ret = tcp_lookup(ctx, &hdr);
+ if (ret != XDP_TX)
+ return ret;
+
+ // Packet is TCP and doesn't belong to an established connection.
+
+ if ((hdr.tcp->syn ^ hdr.tcp->ack) != 1)
+ return XDP_DROP;
+
+ // Grow the TCP header to TCP_MAXLEN to be able to pass any hdr.tcp_len
+ // to bpf_tcp_raw_gen_syncookie_ipv{4,6} and pass the verifier.
+ if (bpf_xdp_adjust_tail(ctx, TCP_MAXLEN - hdr.tcp_len))
+ return XDP_ABORTED;
+
+ data_end = (void *)(long)ctx->data_end;
+ data = (void *)(long)ctx->data;
+
+ if (hdr.ipv4) {
+ hdr.eth = data;
+ hdr.ipv4 = (void *)hdr.eth + sizeof(*hdr.eth);
+ // IPV4_MAXLEN is needed when calculating checksum.
+ // At least sizeof(struct iphdr) is needed here to access ihl.
+ if ((void *)hdr.ipv4 + IPV4_MAXLEN > data_end)
+ return XDP_ABORTED;
+ hdr.tcp = (void *)hdr.ipv4 + hdr.ipv4->ihl * 4;
+ } else if (hdr.ipv6) {
+ hdr.eth = data;
+ hdr.ipv6 = (void *)hdr.eth + sizeof(*hdr.eth);
+ hdr.tcp = (void *)hdr.ipv6 + sizeof(*hdr.ipv6);
+ } else {
+ return XDP_ABORTED;
+ }
+
+ if ((void *)hdr.tcp + TCP_MAXLEN > data_end)
+ return XDP_ABORTED;
+
+ // We run out of registers, tcp_len gets spilled to the stack, and the
+ // verifier forgets its min and max values checked above in tcp_dissect.
+ hdr.tcp_len = hdr.tcp->doff * 4;
+ if (hdr.tcp_len < sizeof(*hdr.tcp))
+ return XDP_ABORTED;
+
+ return hdr.tcp->syn ? syncookie_handle_syn(&hdr, ctx, data, data_end) :
+ syncookie_handle_ack(&hdr);
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/xdp_synproxy.c b/tools/testing/selftests/bpf/xdp_synproxy.c
new file mode 100644
index 000000000000..2b9585f2bc00
--- /dev/null
+++ b/tools/testing/selftests/bpf/xdp_synproxy.c
@@ -0,0 +1,418 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/* Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
+
+#include <stdnoreturn.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <bpf/bpf.h>
+#include <bpf/libbpf.h>
+#include <net/if.h>
+#include <linux/if_link.h>
+#include <linux/limits.h>
+
+static unsigned int ifindex;
+static __u32 attached_prog_id;
+
+static void noreturn cleanup(int sig)
+{
+ DECLARE_LIBBPF_OPTS(bpf_xdp_attach_opts, opts);
+ int prog_fd;
+ int err;
+
+ if (attached_prog_id == 0)
+ exit(0);
+
+ prog_fd = bpf_prog_get_fd_by_id(attached_prog_id);
+ if (prog_fd < 0) {
+ fprintf(stderr, "Error: bpf_prog_get_fd_by_id: %s\n", strerror(-prog_fd));
+ err = bpf_xdp_attach(ifindex, -1, 0, NULL);
+ if (err < 0) {
+ fprintf(stderr, "Error: bpf_set_link_xdp_fd: %s\n", strerror(-err));
+ fprintf(stderr, "Failed to detach XDP program\n");
+ exit(1);
+ }
+ } else {
+ opts.old_prog_fd = prog_fd;
+ err = bpf_xdp_attach(ifindex, -1, XDP_FLAGS_REPLACE, &opts);
+ close(prog_fd);
+ if (err < 0) {
+ fprintf(stderr, "Error: bpf_set_link_xdp_fd_opts: %s\n", strerror(-err));
+ // Not an error if already replaced by someone else.
+ if (err != -EEXIST) {
+ fprintf(stderr, "Failed to detach XDP program\n");
+ exit(1);
+ }
+ }
+ }
+ exit(0);
+}
+
+static noreturn void usage(const char *progname)
+{
+ fprintf(stderr, "Usage: %s [--iface <iface>|--prog <prog_id>] [--mss4 <mss ipv4> --mss6 <mss ipv6> --wscale <wscale> --ttl <ttl>] [--ports <port1>,<port2>,...] [--single]\n",
+ progname);
+ exit(1);
+}
+
+static unsigned long parse_arg_ul(const char *progname, const char *arg, unsigned long limit)
+{
+ unsigned long res;
+ char *endptr;
+
+ errno = 0;
+ res = strtoul(arg, &endptr, 10);
+ if (errno != 0 || *endptr != '\0' || arg[0] == '\0' || res > limit)
+ usage(progname);
+
+ return res;
+}
+
+static void parse_options(int argc, char *argv[], unsigned int *ifindex, __u32 *prog_id,
+ __u64 *tcpipopts, char **ports, bool *single)
+{
+ static struct option long_options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "iface", required_argument, NULL, 'i' },
+ { "prog", required_argument, NULL, 'x' },
+ { "mss4", required_argument, NULL, 4 },
+ { "mss6", required_argument, NULL, 6 },
+ { "wscale", required_argument, NULL, 'w' },
+ { "ttl", required_argument, NULL, 't' },
+ { "ports", required_argument, NULL, 'p' },
+ { "single", no_argument, NULL, 's' },
+ { NULL, 0, NULL, 0 },
+ };
+ unsigned long mss4, mss6, wscale, ttl;
+ unsigned int tcpipopts_mask = 0;
+
+ if (argc < 2)
+ usage(argv[0]);
+
+ *ifindex = 0;
+ *prog_id = 0;
+ *tcpipopts = 0;
+ *ports = NULL;
+ *single = false;
+
+ while (true) {
+ int opt;
+
+ opt = getopt_long(argc, argv, "", long_options, NULL);
+ if (opt == -1)
+ break;
+
+ switch (opt) {
+ case 'h':
+ usage(argv[0]);
+ break;
+ case 'i':
+ *ifindex = if_nametoindex(optarg);
+ if (*ifindex == 0)
+ usage(argv[0]);
+ break;
+ case 'x':
+ *prog_id = parse_arg_ul(argv[0], optarg, UINT32_MAX);
+ if (*prog_id == 0)
+ usage(argv[0]);
+ break;
+ case 4:
+ mss4 = parse_arg_ul(argv[0], optarg, UINT16_MAX);
+ tcpipopts_mask |= 1 << 0;
+ break;
+ case 6:
+ mss6 = parse_arg_ul(argv[0], optarg, UINT16_MAX);
+ tcpipopts_mask |= 1 << 1;
+ break;
+ case 'w':
+ wscale = parse_arg_ul(argv[0], optarg, 14);
+ tcpipopts_mask |= 1 << 2;
+ break;
+ case 't':
+ ttl = parse_arg_ul(argv[0], optarg, UINT8_MAX);
+ tcpipopts_mask |= 1 << 3;
+ break;
+ case 'p':
+ *ports = optarg;
+ break;
+ case 's':
+ *single = true;
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+ if (optind < argc)
+ usage(argv[0]);
+
+ if (tcpipopts_mask == 0xf) {
+ if (mss4 == 0 || mss6 == 0 || wscale == 0 || ttl == 0)
+ usage(argv[0]);
+ *tcpipopts = (mss6 << 32) | (ttl << 24) | (wscale << 16) | mss4;
+ } else if (tcpipopts_mask != 0) {
+ usage(argv[0]);
+ }
+
+ if (*ifindex != 0 && *prog_id != 0)
+ usage(argv[0]);
+ if (*ifindex == 0 && *prog_id == 0)
+ usage(argv[0]);
+}
+
+static int syncookie_attach(const char *argv0, unsigned int ifindex)
+{
+ struct bpf_prog_info info = {};
+ __u32 info_len = sizeof(info);
+ char xdp_filename[PATH_MAX];
+ struct bpf_program *prog;
+ struct bpf_object *obj;
+ int prog_fd;
+ int err;
+
+ snprintf(xdp_filename, sizeof(xdp_filename), "%s_kern.o", argv0);
+ obj = bpf_object__open_file(xdp_filename, NULL);
+ err = libbpf_get_error(obj);
+ if (err < 0) {
+ fprintf(stderr, "Error: bpf_object__open_file: %s\n", strerror(-err));
+ return err;
+ }
+
+ err = bpf_object__load(obj);
+ if (err < 0) {
+ fprintf(stderr, "Error: bpf_object__open_file: %s\n", strerror(-err));
+ return err;
+ }
+
+ prog = bpf_object__find_program_by_name(obj, "syncookie_xdp");
+ if (!prog) {
+ fprintf(stderr, "Error: bpf_object__find_program_by_name: program syncookie_xdp was not found\n");
+ return -ENOENT;
+ }
+
+ prog_fd = bpf_program__fd(prog);
+
+ err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);
+ if (err < 0) {
+ fprintf(stderr, "Error: bpf_obj_get_info_by_fd: %s\n", strerror(-err));
+ goto out;
+ }
+ attached_prog_id = info.id;
+ signal(SIGINT, cleanup);
+ signal(SIGTERM, cleanup);
+ err = bpf_xdp_attach(ifindex, prog_fd, XDP_FLAGS_UPDATE_IF_NOEXIST, NULL);
+ if (err < 0) {
+ fprintf(stderr, "Error: bpf_set_link_xdp_fd: %s\n", strerror(-err));
+ signal(SIGINT, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
+ attached_prog_id = 0;
+ goto out;
+ }
+ err = 0;
+out:
+ bpf_object__close(obj);
+ return err;
+}
+
+static int syncookie_open_bpf_maps(__u32 prog_id, int *values_map_fd, int *ports_map_fd)
+{
+ struct bpf_prog_info prog_info;
+ __u32 map_ids[8];
+ __u32 info_len;
+ int prog_fd;
+ int err;
+ int i;
+
+ *values_map_fd = -1;
+ *ports_map_fd = -1;
+
+ prog_fd = bpf_prog_get_fd_by_id(prog_id);
+ if (prog_fd < 0) {
+ fprintf(stderr, "Error: bpf_prog_get_fd_by_id: %s\n", strerror(-prog_fd));
+ return prog_fd;
+ }
+
+ prog_info = (struct bpf_prog_info) {
+ .nr_map_ids = 8,
+ .map_ids = (__u64)map_ids,
+ };
+ info_len = sizeof(prog_info);
+
+ err = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &info_len);
+ if (err != 0) {
+ fprintf(stderr, "Error: bpf_obj_get_info_by_fd: %s\n", strerror(-err));
+ goto out;
+ }
+
+ if (prog_info.type != BPF_PROG_TYPE_XDP) {
+ fprintf(stderr, "Error: BPF prog type is not BPF_PROG_TYPE_XDP\n");
+ err = -ENOENT;
+ goto out;
+ }
+ if (prog_info.nr_map_ids < 2) {
+ fprintf(stderr, "Error: Found %u BPF maps, expected at least 2\n",
+ prog_info.nr_map_ids);
+ err = -ENOENT;
+ goto out;
+ }
+
+ for (i = 0; i < prog_info.nr_map_ids; i++) {
+ struct bpf_map_info map_info = {};
+ int map_fd;
+
+ err = bpf_map_get_fd_by_id(map_ids[i]);
+ if (err < 0) {
+ fprintf(stderr, "Error: bpf_map_get_fd_by_id: %s\n", strerror(-err));
+ goto err_close_map_fds;
+ }
+ map_fd = err;
+
+ info_len = sizeof(map_info);
+ err = bpf_obj_get_info_by_fd(map_fd, &map_info, &info_len);
+ if (err != 0) {
+ fprintf(stderr, "Error: bpf_obj_get_info_by_fd: %s\n", strerror(-err));
+ close(map_fd);
+ goto err_close_map_fds;
+ }
+ if (strcmp(map_info.name, "values") == 0) {
+ *values_map_fd = map_fd;
+ continue;
+ }
+ if (strcmp(map_info.name, "allowed_ports") == 0) {
+ *ports_map_fd = map_fd;
+ continue;
+ }
+ close(map_fd);
+ }
+
+ if (*values_map_fd != -1 && *ports_map_fd != -1) {
+ err = 0;
+ goto out;
+ }
+
+ err = -ENOENT;
+
+err_close_map_fds:
+ if (*values_map_fd != -1)
+ close(*values_map_fd);
+ if (*ports_map_fd != -1)
+ close(*ports_map_fd);
+ *values_map_fd = -1;
+ *ports_map_fd = -1;
+
+out:
+ close(prog_fd);
+ return err;
+}
+
+int main(int argc, char *argv[])
+{
+ int values_map_fd, ports_map_fd;
+ __u64 tcpipopts;
+ bool firstiter;
+ __u64 prevcnt;
+ __u32 prog_id;
+ char *ports;
+ bool single;
+ int err = 0;
+
+ parse_options(argc, argv, &ifindex, &prog_id, &tcpipopts, &ports, &single);
+
+ if (prog_id == 0) {
+ err = bpf_xdp_query_id(ifindex, 0, &prog_id);
+ if (err < 0) {
+ fprintf(stderr, "Error: bpf_get_link_xdp_id: %s\n", strerror(-err));
+ goto out;
+ }
+ if (prog_id == 0) {
+ err = syncookie_attach(argv[0], ifindex);
+ if (err < 0)
+ goto out;
+ prog_id = attached_prog_id;
+ }
+ }
+
+ err = syncookie_open_bpf_maps(prog_id, &values_map_fd, &ports_map_fd);
+ if (err < 0)
+ goto out;
+
+ if (ports) {
+ __u16 port_last = 0;
+ __u32 port_idx = 0;
+ char *p = ports;
+
+ fprintf(stderr, "Replacing allowed ports\n");
+
+ while (p && *p != '\0') {
+ char *token = strsep(&p, ",");
+ __u16 port;
+
+ port = parse_arg_ul(argv[0], token, UINT16_MAX);
+ err = bpf_map_update_elem(ports_map_fd, &port_idx, &port, BPF_ANY);
+ if (err != 0) {
+ fprintf(stderr, "Error: bpf_map_update_elem: %s\n", strerror(-err));
+ fprintf(stderr, "Failed to add port %u (index %u)\n",
+ port, port_idx);
+ goto out_close_maps;
+ }
+ fprintf(stderr, "Added port %u\n", port);
+ port_idx++;
+ }
+ err = bpf_map_update_elem(ports_map_fd, &port_idx, &port_last, BPF_ANY);
+ if (err != 0) {
+ fprintf(stderr, "Error: bpf_map_update_elem: %s\n", strerror(-err));
+ fprintf(stderr, "Failed to add the terminator value 0 (index %u)\n",
+ port_idx);
+ goto out_close_maps;
+ }
+ }
+
+ if (tcpipopts) {
+ __u32 key = 0;
+
+ fprintf(stderr, "Replacing TCP/IP options\n");
+
+ err = bpf_map_update_elem(values_map_fd, &key, &tcpipopts, BPF_ANY);
+ if (err != 0) {
+ fprintf(stderr, "Error: bpf_map_update_elem: %s\n", strerror(-err));
+ goto out_close_maps;
+ }
+ }
+
+ if ((ports || tcpipopts) && attached_prog_id == 0 && !single)
+ goto out_close_maps;
+
+ prevcnt = 0;
+ firstiter = true;
+ while (true) {
+ __u32 key = 1;
+ __u64 value;
+
+ err = bpf_map_lookup_elem(values_map_fd, &key, &value);
+ if (err != 0) {
+ fprintf(stderr, "Error: bpf_map_lookup_elem: %s\n", strerror(-err));
+ goto out_close_maps;
+ }
+ if (firstiter) {
+ prevcnt = value;
+ firstiter = false;
+ }
+ if (single) {
+ printf("Total SYNACKs generated: %llu\n", value);
+ break;
+ }
+ printf("SYNACKs generated: %llu (total %llu)\n", value - prevcnt, value);
+ prevcnt = value;
+ sleep(1);
+ }
+
+out_close_maps:
+ close(values_map_fd);
+ close(ports_map_fd);
+out:
+ return err == 0 ? 0 : 1;
+}
--
2.30.2
^ permalink raw reply related
* [PATCH bpf-next v6 4/6] bpf: Add helpers to issue and check SYN cookies in XDP
From: Maxim Mikityanskiy @ 2022-04-22 17:24 UTC (permalink / raw)
To: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, netdev
Cc: Tariq Toukan, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, David S. Miller, Jakub Kicinski,
Petar Penkov, Lorenz Bauer, Eric Dumazet, Hideaki YOSHIFUJI,
David Ahern, Shuah Khan, Jesper Dangaard Brouer,
Nathan Chancellor, Nick Desaulniers, Joe Stringer, Florent Revest,
linux-kselftest, Toke Høiland-Jørgensen,
Kumar Kartikeya Dwivedi, Florian Westphal, pabeni,
Maxim Mikityanskiy
In-Reply-To: <20220422172422.4037988-1-maximmi@nvidia.com>
The new helpers bpf_tcp_raw_{gen,check}_syncookie_ipv{4,6} allow an XDP
program to generate SYN cookies in response to TCP SYN packets and to
check those cookies upon receiving the first ACK packet (the final
packet of the TCP handshake).
Unlike bpf_tcp_{gen,check}_syncookie these new helpers don't need a
listening socket on the local machine, which allows to use them together
with synproxy to accelerate SYN cookie generation.
Signed-off-by: Maxim Mikityanskiy <maximmi@nvidia.com>
Reviewed-by: Tariq Toukan <tariqt@nvidia.com>
---
include/net/tcp.h | 1 +
include/uapi/linux/bpf.h | 78 ++++++++++++++++++++++
net/core/filter.c | 118 +++++++++++++++++++++++++++++++++
net/ipv4/tcp_input.c | 3 +-
scripts/bpf_doc.py | 4 ++
tools/include/uapi/linux/bpf.h | 78 ++++++++++++++++++++++
6 files changed, 281 insertions(+), 1 deletion(-)
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 6d50a662bf89..b9617974e4d0 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -432,6 +432,7 @@ u16 tcp_v4_get_syncookie(struct sock *sk, struct iphdr *iph,
struct tcphdr *th, u32 *cookie);
u16 tcp_v6_get_syncookie(struct sock *sk, struct ipv6hdr *iph,
struct tcphdr *th, u32 *cookie);
+u16 tcp_parse_mss_option(const struct tcphdr *th, u16 user_mss);
u16 tcp_get_syncookie_mss(struct request_sock_ops *rsk_ops,
const struct tcp_request_sock_ops *af_ops,
struct sock *sk, struct tcphdr *th);
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 5e1679af8282..ee218bae74c3 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -5145,6 +5145,80 @@ union bpf_attr {
* The **hash_algo** is returned on success,
* **-EOPNOTSUP** if the hash calculation failed or **-EINVAL** if
* invalid arguments are passed.
+ *
+ * s64 bpf_tcp_raw_gen_syncookie_ipv4(struct iphdr *iph, struct tcphdr *th, u32 th_len)
+ * Description
+ * Try to issue a SYN cookie for the packet with corresponding
+ * IPv4/TCP headers, *iph* and *th*, without depending on a
+ * listening socket.
+ *
+ * *iph* points to the IPv4 header.
+ *
+ * *th* points to the start of the TCP header, while *th_len*
+ * contains the length of the TCP header (at least
+ * **sizeof**\ (**struct tcphdr**)).
+ * Return
+ * On success, lower 32 bits hold the generated SYN cookie in
+ * followed by 16 bits which hold the MSS value for that cookie,
+ * and the top 16 bits are unused.
+ *
+ * On failure, the returned value is one of the following:
+ *
+ * **-EINVAL** if *th_len* is invalid.
+ *
+ * s64 bpf_tcp_raw_gen_syncookie_ipv6(struct ipv6hdr *iph, struct tcphdr *th, u32 th_len)
+ * Description
+ * Try to issue a SYN cookie for the packet with corresponding
+ * IPv6/TCP headers, *iph* and *th*, without depending on a
+ * listening socket.
+ *
+ * *iph* points to the IPv6 header.
+ *
+ * *th* points to the start of the TCP header, while *th_len*
+ * contains the length of the TCP header (at least
+ * **sizeof**\ (**struct tcphdr**)).
+ * Return
+ * On success, lower 32 bits hold the generated SYN cookie in
+ * followed by 16 bits which hold the MSS value for that cookie,
+ * and the top 16 bits are unused.
+ *
+ * On failure, the returned value is one of the following:
+ *
+ * **-EINVAL** if *th_len* is invalid.
+ *
+ * **-EPROTONOSUPPORT** if CONFIG_IPV6 is not builtin.
+ *
+ * int bpf_tcp_raw_check_syncookie_ipv4(struct iphdr *iph, struct tcphdr *th)
+ * Description
+ * Check whether *iph* and *th* contain a valid SYN cookie ACK
+ * without depending on a listening socket.
+ *
+ * *iph* points to the IPv4 header.
+ *
+ * *th* points to the TCP header.
+ * Return
+ * 0 if *iph* and *th* are a valid SYN cookie ACK.
+ *
+ * On failure, the returned value is one of the following:
+ *
+ * **-EACCES** if the SYN cookie is not valid.
+ *
+ * int bpf_tcp_raw_check_syncookie_ipv6(struct ipv6hdr *iph, struct tcphdr *th)
+ * Description
+ * Check whether *iph* and *th* contain a valid SYN cookie ACK
+ * without depending on a listening socket.
+ *
+ * *iph* points to the IPv6 header.
+ *
+ * *th* points to the TCP header.
+ * Return
+ * 0 if *iph* and *th* are a valid SYN cookie ACK.
+ *
+ * On failure, the returned value is one of the following:
+ *
+ * **-EACCES** if the SYN cookie is not valid.
+ *
+ * **-EPROTONOSUPPORT** if CONFIG_IPV6 is not builtin.
*/
#define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \
@@ -5341,6 +5415,10 @@ union bpf_attr {
FN(copy_from_user_task), \
FN(skb_set_tstamp), \
FN(ima_file_hash), \
+ FN(tcp_raw_gen_syncookie_ipv4), \
+ FN(tcp_raw_gen_syncookie_ipv6), \
+ FN(tcp_raw_check_syncookie_ipv4), \
+ FN(tcp_raw_check_syncookie_ipv6), \
/* */
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
diff --git a/net/core/filter.c b/net/core/filter.c
index 207a13db5c80..ffb7e93f60c5 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -7434,6 +7434,114 @@ static const struct bpf_func_proto bpf_skb_set_tstamp_proto = {
.arg3_type = ARG_ANYTHING,
};
+#ifdef CONFIG_SYN_COOKIES
+BPF_CALL_3(bpf_tcp_raw_gen_syncookie_ipv4, struct iphdr *, iph,
+ struct tcphdr *, th, u32, th_len)
+{
+ u32 cookie;
+ u16 mss;
+
+ if (unlikely(th_len < sizeof(*th) || th_len != th->doff * 4))
+ return -EINVAL;
+
+ mss = tcp_parse_mss_option(th, 0) ?: TCP_MSS_DEFAULT;
+ cookie = __cookie_v4_init_sequence(iph, th, &mss);
+
+ return cookie | ((u64)mss << 32);
+}
+
+static const struct bpf_func_proto bpf_tcp_raw_gen_syncookie_ipv4_proto = {
+ .func = bpf_tcp_raw_gen_syncookie_ipv4,
+ .gpl_only = true, /* __cookie_v4_init_sequence() is GPL */
+ .pkt_access = true,
+ .ret_type = RET_INTEGER,
+ .arg1_type = ARG_PTR_TO_MEM,
+ .arg1_size = sizeof(struct iphdr),
+ .arg2_type = ARG_PTR_TO_MEM,
+ .arg3_type = ARG_CONST_SIZE,
+};
+
+BPF_CALL_3(bpf_tcp_raw_gen_syncookie_ipv6, struct ipv6hdr *, iph,
+ struct tcphdr *, th, u32, th_len)
+{
+#if IS_BUILTIN(CONFIG_IPV6)
+ const u16 mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) -
+ sizeof(struct ipv6hdr);
+ u32 cookie;
+ u16 mss;
+
+ if (unlikely(th_len < sizeof(*th) || th_len != th->doff * 4))
+ return -EINVAL;
+
+ mss = tcp_parse_mss_option(th, 0) ?: mss_clamp;
+ cookie = __cookie_v6_init_sequence(iph, th, &mss);
+
+ return cookie | ((u64)mss << 32);
+#else
+ return -EPROTONOSUPPORT;
+#endif
+}
+
+static const struct bpf_func_proto bpf_tcp_raw_gen_syncookie_ipv6_proto = {
+ .func = bpf_tcp_raw_gen_syncookie_ipv6,
+ .gpl_only = true, /* __cookie_v6_init_sequence() is GPL */
+ .pkt_access = true,
+ .ret_type = RET_INTEGER,
+ .arg1_type = ARG_PTR_TO_MEM,
+ .arg1_size = sizeof(struct ipv6hdr),
+ .arg2_type = ARG_PTR_TO_MEM,
+ .arg3_type = ARG_CONST_SIZE,
+};
+
+BPF_CALL_2(bpf_tcp_raw_check_syncookie_ipv4, struct iphdr *, iph,
+ struct tcphdr *, th)
+{
+ u32 cookie = ntohl(th->ack_seq) - 1;
+
+ if (__cookie_v4_check(iph, th, cookie) > 0)
+ return 0;
+
+ return -EACCES;
+}
+
+static const struct bpf_func_proto bpf_tcp_raw_check_syncookie_ipv4_proto = {
+ .func = bpf_tcp_raw_check_syncookie_ipv4,
+ .gpl_only = true, /* __cookie_v4_check is GPL */
+ .pkt_access = true,
+ .ret_type = RET_INTEGER,
+ .arg1_type = ARG_PTR_TO_MEM,
+ .arg1_size = sizeof(struct iphdr),
+ .arg2_type = ARG_PTR_TO_MEM,
+ .arg2_size = sizeof(struct tcphdr),
+};
+
+BPF_CALL_2(bpf_tcp_raw_check_syncookie_ipv6, struct ipv6hdr *, iph,
+ struct tcphdr *, th)
+{
+#if IS_BUILTIN(CONFIG_IPV6)
+ u32 cookie = ntohl(th->ack_seq) - 1;
+
+ if (__cookie_v6_check(iph, th, cookie) > 0)
+ return 0;
+
+ return -EACCES;
+#else
+ return -EPROTONOSUPPORT;
+#endif
+}
+
+static const struct bpf_func_proto bpf_tcp_raw_check_syncookie_ipv6_proto = {
+ .func = bpf_tcp_raw_check_syncookie_ipv6,
+ .gpl_only = true, /* __cookie_v6_check is GPL */
+ .pkt_access = true,
+ .ret_type = RET_INTEGER,
+ .arg1_type = ARG_PTR_TO_MEM,
+ .arg1_size = sizeof(struct ipv6hdr),
+ .arg2_type = ARG_PTR_TO_MEM,
+ .arg2_size = sizeof(struct tcphdr),
+};
+#endif /* CONFIG_SYN_COOKIES */
+
#endif /* CONFIG_INET */
bool bpf_helper_changes_pkt_data(void *func)
@@ -7846,6 +7954,16 @@ xdp_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
return &bpf_tcp_check_syncookie_proto;
case BPF_FUNC_tcp_gen_syncookie:
return &bpf_tcp_gen_syncookie_proto;
+#ifdef CONFIG_SYN_COOKIES
+ case BPF_FUNC_tcp_raw_gen_syncookie_ipv4:
+ return &bpf_tcp_raw_gen_syncookie_ipv4_proto;
+ case BPF_FUNC_tcp_raw_gen_syncookie_ipv6:
+ return &bpf_tcp_raw_gen_syncookie_ipv6_proto;
+ case BPF_FUNC_tcp_raw_check_syncookie_ipv4:
+ return &bpf_tcp_raw_check_syncookie_ipv4_proto;
+ case BPF_FUNC_tcp_raw_check_syncookie_ipv6:
+ return &bpf_tcp_raw_check_syncookie_ipv6_proto;
+#endif
#endif
default:
return bpf_sk_base_func_proto(func_id);
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 1595b76ea2be..0eb77cc4c05d 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -3963,7 +3963,7 @@ static bool smc_parse_options(const struct tcphdr *th,
/* Try to parse the MSS option from the TCP header. Return 0 on failure, clamped
* value on success.
*/
-static u16 tcp_parse_mss_option(const struct tcphdr *th, u16 user_mss)
+u16 tcp_parse_mss_option(const struct tcphdr *th, u16 user_mss)
{
const unsigned char *ptr = (const unsigned char *)(th + 1);
int length = (th->doff * 4) - sizeof(struct tcphdr);
@@ -4002,6 +4002,7 @@ static u16 tcp_parse_mss_option(const struct tcphdr *th, u16 user_mss)
}
return mss;
}
+EXPORT_SYMBOL_GPL(tcp_parse_mss_option);
/* Look for tcp options. Normally only called on SYN and SYNACK packets.
* But, this can also be called on packets in the established flow when
diff --git a/scripts/bpf_doc.py b/scripts/bpf_doc.py
index 096625242475..3d0b65e6dea7 100755
--- a/scripts/bpf_doc.py
+++ b/scripts/bpf_doc.py
@@ -633,6 +633,8 @@ class PrinterHelpers(Printer):
'struct socket',
'struct file',
'struct bpf_timer',
+ 'struct iphdr',
+ 'struct ipv6hdr',
]
known_types = {
'...',
@@ -682,6 +684,8 @@ class PrinterHelpers(Printer):
'struct socket',
'struct file',
'struct bpf_timer',
+ 'struct iphdr',
+ 'struct ipv6hdr',
}
mapped_types = {
'u8': '__u8',
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 5e1679af8282..ee218bae74c3 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -5145,6 +5145,80 @@ union bpf_attr {
* The **hash_algo** is returned on success,
* **-EOPNOTSUP** if the hash calculation failed or **-EINVAL** if
* invalid arguments are passed.
+ *
+ * s64 bpf_tcp_raw_gen_syncookie_ipv4(struct iphdr *iph, struct tcphdr *th, u32 th_len)
+ * Description
+ * Try to issue a SYN cookie for the packet with corresponding
+ * IPv4/TCP headers, *iph* and *th*, without depending on a
+ * listening socket.
+ *
+ * *iph* points to the IPv4 header.
+ *
+ * *th* points to the start of the TCP header, while *th_len*
+ * contains the length of the TCP header (at least
+ * **sizeof**\ (**struct tcphdr**)).
+ * Return
+ * On success, lower 32 bits hold the generated SYN cookie in
+ * followed by 16 bits which hold the MSS value for that cookie,
+ * and the top 16 bits are unused.
+ *
+ * On failure, the returned value is one of the following:
+ *
+ * **-EINVAL** if *th_len* is invalid.
+ *
+ * s64 bpf_tcp_raw_gen_syncookie_ipv6(struct ipv6hdr *iph, struct tcphdr *th, u32 th_len)
+ * Description
+ * Try to issue a SYN cookie for the packet with corresponding
+ * IPv6/TCP headers, *iph* and *th*, without depending on a
+ * listening socket.
+ *
+ * *iph* points to the IPv6 header.
+ *
+ * *th* points to the start of the TCP header, while *th_len*
+ * contains the length of the TCP header (at least
+ * **sizeof**\ (**struct tcphdr**)).
+ * Return
+ * On success, lower 32 bits hold the generated SYN cookie in
+ * followed by 16 bits which hold the MSS value for that cookie,
+ * and the top 16 bits are unused.
+ *
+ * On failure, the returned value is one of the following:
+ *
+ * **-EINVAL** if *th_len* is invalid.
+ *
+ * **-EPROTONOSUPPORT** if CONFIG_IPV6 is not builtin.
+ *
+ * int bpf_tcp_raw_check_syncookie_ipv4(struct iphdr *iph, struct tcphdr *th)
+ * Description
+ * Check whether *iph* and *th* contain a valid SYN cookie ACK
+ * without depending on a listening socket.
+ *
+ * *iph* points to the IPv4 header.
+ *
+ * *th* points to the TCP header.
+ * Return
+ * 0 if *iph* and *th* are a valid SYN cookie ACK.
+ *
+ * On failure, the returned value is one of the following:
+ *
+ * **-EACCES** if the SYN cookie is not valid.
+ *
+ * int bpf_tcp_raw_check_syncookie_ipv6(struct ipv6hdr *iph, struct tcphdr *th)
+ * Description
+ * Check whether *iph* and *th* contain a valid SYN cookie ACK
+ * without depending on a listening socket.
+ *
+ * *iph* points to the IPv6 header.
+ *
+ * *th* points to the TCP header.
+ * Return
+ * 0 if *iph* and *th* are a valid SYN cookie ACK.
+ *
+ * On failure, the returned value is one of the following:
+ *
+ * **-EACCES** if the SYN cookie is not valid.
+ *
+ * **-EPROTONOSUPPORT** if CONFIG_IPV6 is not builtin.
*/
#define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \
@@ -5341,6 +5415,10 @@ union bpf_attr {
FN(copy_from_user_task), \
FN(skb_set_tstamp), \
FN(ima_file_hash), \
+ FN(tcp_raw_gen_syncookie_ipv4), \
+ FN(tcp_raw_gen_syncookie_ipv6), \
+ FN(tcp_raw_check_syncookie_ipv4), \
+ FN(tcp_raw_check_syncookie_ipv6), \
/* */
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
--
2.30.2
^ permalink raw reply related
* [PATCH bpf-next v6 3/6] bpf: Allow helpers to accept pointers with a fixed size
From: Maxim Mikityanskiy @ 2022-04-22 17:24 UTC (permalink / raw)
To: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, netdev
Cc: Tariq Toukan, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, David S. Miller, Jakub Kicinski,
Petar Penkov, Lorenz Bauer, Eric Dumazet, Hideaki YOSHIFUJI,
David Ahern, Shuah Khan, Jesper Dangaard Brouer,
Nathan Chancellor, Nick Desaulniers, Joe Stringer, Florent Revest,
linux-kselftest, Toke Høiland-Jørgensen,
Kumar Kartikeya Dwivedi, Florian Westphal, pabeni,
Maxim Mikityanskiy
In-Reply-To: <20220422172422.4037988-1-maximmi@nvidia.com>
Before this commit, the BPF verifier required ARG_PTR_TO_MEM arguments
to be followed by ARG_CONST_SIZE holding the size of the memory region.
The helpers had to check that size in runtime.
There are cases where the size expected by a helper is a compile-time
constant. Checking it in runtime is an unnecessary overhead and waste of
BPF registers.
This commit allows helpers to accept ARG_PTR_TO_MEM arguments without
the corresponding ARG_CONST_SIZE, given that they define the memory
region size in struct bpf_func_proto.
Signed-off-by: Maxim Mikityanskiy <maximmi@nvidia.com>
Reviewed-by: Tariq Toukan <tariqt@nvidia.com>
---
include/linux/bpf.h | 10 ++++++++++
kernel/bpf/verifier.c | 26 +++++++++++++++-----------
2 files changed, 25 insertions(+), 11 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 7bf441563ffc..914b571bbf3a 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -465,6 +465,16 @@ struct bpf_func_proto {
};
u32 *arg_btf_id[5];
};
+ union {
+ struct {
+ size_t arg1_size;
+ size_t arg2_size;
+ size_t arg3_size;
+ size_t arg4_size;
+ size_t arg5_size;
+ };
+ size_t arg_size[5];
+ };
int *ret_btf_id; /* return value btf_id */
bool (*allowed)(const struct bpf_prog *prog);
};
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 71827d14724a..368fab3dfca5 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -5602,6 +5602,11 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
* next is_mem_size argument below.
*/
meta->raw_mode = (arg_type == ARG_PTR_TO_UNINIT_MEM);
+ if (fn->arg_size[arg]) {
+ err = check_helper_mem_access(env, regno,
+ fn->arg_size[arg], false,
+ meta);
+ }
} else if (arg_type_is_mem_size(arg_type)) {
bool zero_size_allowed = (arg_type == ARG_CONST_SIZE_OR_ZERO);
@@ -5941,13 +5946,12 @@ static bool check_raw_mode_ok(const struct bpf_func_proto *fn)
return count <= 1;
}
-static bool check_args_pair_invalid(enum bpf_arg_type arg_curr,
- enum bpf_arg_type arg_next)
+static bool check_args_pair_invalid(const struct bpf_func_proto *fn, int arg)
{
- return (arg_type_is_mem_ptr(arg_curr) &&
- !arg_type_is_mem_size(arg_next)) ||
- (!arg_type_is_mem_ptr(arg_curr) &&
- arg_type_is_mem_size(arg_next));
+ if (arg_type_is_mem_ptr(fn->arg_type[arg]))
+ return arg_type_is_mem_size(fn->arg_type[arg + 1]) ==
+ !!fn->arg_size[arg];
+ return arg_type_is_mem_size(fn->arg_type[arg + 1]) || fn->arg_size[arg];
}
static bool check_arg_pair_ok(const struct bpf_func_proto *fn)
@@ -5958,11 +5962,11 @@ static bool check_arg_pair_ok(const struct bpf_func_proto *fn)
* helper function specification.
*/
if (arg_type_is_mem_size(fn->arg1_type) ||
- arg_type_is_mem_ptr(fn->arg5_type) ||
- check_args_pair_invalid(fn->arg1_type, fn->arg2_type) ||
- check_args_pair_invalid(fn->arg2_type, fn->arg3_type) ||
- check_args_pair_invalid(fn->arg3_type, fn->arg4_type) ||
- check_args_pair_invalid(fn->arg4_type, fn->arg5_type))
+ (arg_type_is_mem_ptr(fn->arg5_type) && !fn->arg5_size) ||
+ check_args_pair_invalid(fn, 1) ||
+ check_args_pair_invalid(fn, 2) ||
+ check_args_pair_invalid(fn, 3) ||
+ check_args_pair_invalid(fn, 4))
return false;
return true;
--
2.30.2
^ permalink raw reply related
* [PATCH bpf-next v6 2/6] bpf: Fix documentation of th_len in bpf_tcp_{gen,check}_syncookie
From: Maxim Mikityanskiy @ 2022-04-22 17:24 UTC (permalink / raw)
To: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, netdev
Cc: Tariq Toukan, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, David S. Miller, Jakub Kicinski,
Petar Penkov, Lorenz Bauer, Eric Dumazet, Hideaki YOSHIFUJI,
David Ahern, Shuah Khan, Jesper Dangaard Brouer,
Nathan Chancellor, Nick Desaulniers, Joe Stringer, Florent Revest,
linux-kselftest, Toke Høiland-Jørgensen,
Kumar Kartikeya Dwivedi, Florian Westphal, pabeni,
Maxim Mikityanskiy
In-Reply-To: <20220422172422.4037988-1-maximmi@nvidia.com>
bpf_tcp_gen_syncookie expects the full length of the TCP header (with
all options), and bpf_tcp_check_syncookie accepts lengths bigger than
sizeof(struct tcphdr). Fix the documentation that says these lengths
should be exactly sizeof(struct tcphdr).
While at it, fix a typo in the name of struct ipv6hdr.
Signed-off-by: Maxim Mikityanskiy <maximmi@nvidia.com>
Reviewed-by: Tariq Toukan <tariqt@nvidia.com>
---
include/uapi/linux/bpf.h | 10 ++++++----
tools/include/uapi/linux/bpf.h | 10 ++++++----
2 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index d14b10b85e51..5e1679af8282 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -3587,10 +3587,11 @@ union bpf_attr {
*
* *iph* points to the start of the IPv4 or IPv6 header, while
* *iph_len* contains **sizeof**\ (**struct iphdr**) or
- * **sizeof**\ (**struct ip6hdr**).
+ * **sizeof**\ (**struct ipv6hdr**).
*
* *th* points to the start of the TCP header, while *th_len*
- * contains **sizeof**\ (**struct tcphdr**).
+ * contains the length of the TCP header (at least
+ * **sizeof**\ (**struct tcphdr**)).
* Return
* 0 if *iph* and *th* are a valid SYN cookie ACK, or a negative
* error otherwise.
@@ -3773,10 +3774,11 @@ union bpf_attr {
*
* *iph* points to the start of the IPv4 or IPv6 header, while
* *iph_len* contains **sizeof**\ (**struct iphdr**) or
- * **sizeof**\ (**struct ip6hdr**).
+ * **sizeof**\ (**struct ipv6hdr**).
*
* *th* points to the start of the TCP header, while *th_len*
- * contains the length of the TCP header.
+ * contains the length of the TCP header with options (at least
+ * **sizeof**\ (**struct tcphdr**)).
* Return
* On success, lower 32 bits hold the generated SYN cookie in
* followed by 16 bits which hold the MSS value for that cookie,
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index d14b10b85e51..5e1679af8282 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -3587,10 +3587,11 @@ union bpf_attr {
*
* *iph* points to the start of the IPv4 or IPv6 header, while
* *iph_len* contains **sizeof**\ (**struct iphdr**) or
- * **sizeof**\ (**struct ip6hdr**).
+ * **sizeof**\ (**struct ipv6hdr**).
*
* *th* points to the start of the TCP header, while *th_len*
- * contains **sizeof**\ (**struct tcphdr**).
+ * contains the length of the TCP header (at least
+ * **sizeof**\ (**struct tcphdr**)).
* Return
* 0 if *iph* and *th* are a valid SYN cookie ACK, or a negative
* error otherwise.
@@ -3773,10 +3774,11 @@ union bpf_attr {
*
* *iph* points to the start of the IPv4 or IPv6 header, while
* *iph_len* contains **sizeof**\ (**struct iphdr**) or
- * **sizeof**\ (**struct ip6hdr**).
+ * **sizeof**\ (**struct ipv6hdr**).
*
* *th* points to the start of the TCP header, while *th_len*
- * contains the length of the TCP header.
+ * contains the length of the TCP header with options (at least
+ * **sizeof**\ (**struct tcphdr**)).
* Return
* On success, lower 32 bits hold the generated SYN cookie in
* followed by 16 bits which hold the MSS value for that cookie,
--
2.30.2
^ permalink raw reply related
* [PATCH bpf-next v6 0/5] New BPF helpers to accelerate synproxy
From: Maxim Mikityanskiy @ 2022-04-22 17:24 UTC (permalink / raw)
To: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, netdev
Cc: Tariq Toukan, Martin KaFai Lau, Song Liu, Yonghong Song,
John Fastabend, KP Singh, David S. Miller, Jakub Kicinski,
Petar Penkov, Lorenz Bauer, Eric Dumazet, Hideaki YOSHIFUJI,
David Ahern, Shuah Khan, Jesper Dangaard Brouer,
Nathan Chancellor, Nick Desaulniers, Joe Stringer, Florent Revest,
linux-kselftest, Toke Høiland-Jørgensen,
Kumar Kartikeya Dwivedi, Florian Westphal, pabeni,
Maxim Mikityanskiy
The first patch of this series is an improvement to the existing
syncookie BPF helper. The second patch is a documentation fix.
The third patch allows BPF helpers to accept memory regions of fixed
size without doing runtime size checks.
The two last patches add new functionality that allows XDP to
accelerate iptables synproxy.
v1 of this series [1] used to include a patch that exposed conntrack
lookup to BPF using stable helpers. It was superseded by series [2] by
Kumar Kartikeya Dwivedi, which implements this functionality using
unstable helpers.
The fourth patch adds new helpers to issue and check SYN cookies without
binding to a socket, which is useful in the synproxy scenario.
The fifth patch adds a selftest, which consists of a script, an XDP
program and a userspace control application. The XDP program uses
socketless SYN cookie helpers and queries conntrack status instead of
socket status. The userspace control application allows to tune
parameters of the XDP program. This program also serves as a minimal
example of usage of the new functionality.
The draft of the new functionality was presented on Netdev 0x15 [3].
v2 changes:
Split into two series, submitted bugfixes to bpf, dropped the conntrack
patches, implemented the timestamp cookie in BPF using bpf_loop, dropped
the timestamp cookie patch.
v3 changes:
Moved some patches from bpf to bpf-next, dropped the patch that changed
error codes, split the new helpers into IPv4/IPv6, added verifier
functionality to accept memory regions of fixed size.
v4 changes:
Converted the selftest to the test_progs runner. Replaced some
deprecated functions in xdp_synproxy userspace helper.
v5 changes:
Fixed a bug in the selftest. Added questionable functionality to support
new helpers in TC BPF, added selftests for it.
v6 changes:
Wrap the new helpers themselves into #ifdef CONFIG_SYN_COOKIES, replaced
fclose with pclose and fixed the MSS for IPv6 in the selftest.
[1]: https://lore.kernel.org/bpf/20211020095815.GJ28644@breakpoint.cc/t/
[2]: https://lore.kernel.org/bpf/20220114163953.1455836-1-memxor@gmail.com/
[3]: https://netdevconf.info/0x15/session.html?Accelerating-synproxy-with-XDP
Maxim Mikityanskiy (6):
bpf: Use ipv6_only_sock in bpf_tcp_gen_syncookie
bpf: Fix documentation of th_len in bpf_tcp_{gen,check}_syncookie
bpf: Allow helpers to accept pointers with a fixed size
bpf: Add helpers to issue and check SYN cookies in XDP
bpf: Add selftests for raw syncookie helpers
bpf: Allow the new syncookie helpers to work with SKBs
include/linux/bpf.h | 10 +
include/net/tcp.h | 1 +
include/uapi/linux/bpf.h | 88 +-
kernel/bpf/verifier.c | 26 +-
net/core/filter.c | 130 ++-
net/ipv4/tcp_input.c | 3 +-
scripts/bpf_doc.py | 4 +
tools/include/uapi/linux/bpf.h | 88 +-
tools/testing/selftests/bpf/.gitignore | 1 +
tools/testing/selftests/bpf/Makefile | 2 +-
.../selftests/bpf/prog_tests/xdp_synproxy.c | 144 +++
.../selftests/bpf/progs/xdp_synproxy_kern.c | 819 ++++++++++++++++++
tools/testing/selftests/bpf/xdp_synproxy.c | 466 ++++++++++
13 files changed, 1760 insertions(+), 22 deletions(-)
create mode 100644 tools/testing/selftests/bpf/prog_tests/xdp_synproxy.c
create mode 100644 tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c
create mode 100644 tools/testing/selftests/bpf/xdp_synproxy.c
--
2.30.2
^ permalink raw reply
* RE: [PATCH net v3] ice: Fix race during aux device (un)plugging
From: Ertman, David M @ 2022-04-22 17:12 UTC (permalink / raw)
To: ivecera, netdev@vger.kernel.org
Cc: poros, mschmidt, Leon Romanovsky, Brandeburg, Jesse,
Nguyen, Anthony L, David S. Miller, Jakub Kicinski, Paolo Abeni,
Saleem, Shiraz, moderated list:INTEL ETHERNET DRIVERS, open list
In-Reply-To: <20220421060906.1902576-1-ivecera@redhat.com>
> -----Original Message-----
> From: Ivan Vecera <ivecera@redhat.com>
> Sent: Wednesday, April 20, 2022 11:09 PM
> To: netdev@vger.kernel.org
> Cc: poros <poros@redhat.com>; mschmidt <mschmidt@redhat.com>; Leon
> Romanovsky <leon@kernel.org>; Brandeburg, Jesse
> <jesse.brandeburg@intel.com>; Nguyen, Anthony L
> <anthony.l.nguyen@intel.com>; David S. Miller <davem@davemloft.net>;
> Jakub Kicinski <kuba@kernel.org>; Paolo Abeni <pabeni@redhat.com>;
> Ertman, David M <david.m.ertman@intel.com>; Saleem, Shiraz
> <shiraz.saleem@intel.com>; moderated list:INTEL ETHERNET DRIVERS <intel-
> wired-lan@lists.osuosl.org>; open list <linux-kernel@vger.kernel.org>
> Subject: [PATCH net v3] ice: Fix race during aux device (un)plugging
>
> Function ice_plug_aux_dev() assigns pf->adev field too early prior
> aux device initialization and on other side ice_unplug_aux_dev()
> starts aux device deinit and at the end assigns NULL to pf->adev.
> This is wrong because pf->adev should always be non-NULL only when
> aux device is fully initialized and ready. This wrong order causes
> a crash when ice_send_event_to_aux() call occurs because that function
> depends on non-NULL value of pf->adev and does not assume that
> aux device is half-initialized or half-destroyed.
> After order correction the race window is tiny but it is still there,
> as Leon mentioned and manipulation with pf->adev needs to be protected
> by mutex.
>
> Fix (un-)plugging functions so pf->adev field is set after aux device
> init and prior aux device destroy and protect pf->adev assignment by
> new mutex. This mutex is also held during ice_send_event_to_aux()
> call to ensure that aux device is valid during that call. Device
> lock used ice_send_event_to_aux() to avoid its concurrent run can
> be removed as this is secured by that mutex.
>
> Reproducer:
> cycle=1
> while :;do
> echo "#### Cycle: $cycle"
>
> ip link set ens7f0 mtu 9000
> ip link add bond0 type bond mode 1 miimon 100
> ip link set bond0 up
> ifenslave bond0 ens7f0
> ip link set bond0 mtu 9000
> ethtool -L ens7f0 combined 1
> ip link del bond0
> ip link set ens7f0 mtu 1500
> sleep 1
>
> let cycle++
> done
>
> In short when the device is added/removed to/from bond the aux device
> is unplugged/plugged. When MTU of the device is changed an event is
> sent to aux device asynchronously. This can race with (un)plugging
> operation and because pf->adev is set too early (plug) or too late
> (unplug) the function ice_send_event_to_aux() can touch uninitialized
> or destroyed fields. In the case of crash below pf->adev->dev.mutex.
>
> Crash:
> [ 53.372066] bond0: (slave ens7f0): making interface the new active one
> [ 53.378622] bond0: (slave ens7f0): Enslaving as an active interface with an u
> p link
> [ 53.386294] IPv6: ADDRCONF(NETDEV_CHANGE): bond0: link becomes
> ready
> [ 53.549104] bond0: (slave ens7f1): Enslaving as a backup interface with an
> up
> link
> [ 54.118906] ice 0000:ca:00.0 ens7f0: Number of in use tx queues changed
> inval
> idating tc mappings. Priority traffic classification disabled!
> [ 54.233374] ice 0000:ca:00.1 ens7f1: Number of in use tx queues changed
> inval
> idating tc mappings. Priority traffic classification disabled!
> [ 54.248204] bond0: (slave ens7f0): Releasing backup interface
> [ 54.253955] bond0: (slave ens7f1): making interface the new active one
> [ 54.274875] bond0: (slave ens7f1): Releasing backup interface
> [ 54.289153] bond0 (unregistering): Released all slaves
> [ 55.383179] MII link monitoring set to 100 ms
> [ 55.398696] bond0: (slave ens7f0): making interface the new active one
> [ 55.405241] BUG: kernel NULL pointer dereference, address:
> 0000000000000080
> [ 55.405289] bond0: (slave ens7f0): Enslaving as an active interface with an u
> p link
> [ 55.412198] #PF: supervisor write access in kernel mode
> [ 55.412200] #PF: error_code(0x0002) - not-present page
> [ 55.412201] PGD 25d2ad067 P4D 0
> [ 55.412204] Oops: 0002 [#1] PREEMPT SMP NOPTI
> [ 55.412207] CPU: 0 PID: 403 Comm: kworker/0:2 Kdump: loaded Tainted: G
> S
> 5.17.0-13579-g57f2d6540f03 #1
> [ 55.429094] bond0: (slave ens7f1): Enslaving as a backup interface with an
> up
> link
> [ 55.430224] Hardware name: Dell Inc. PowerEdge R750/06V45N, BIOS 1.4.4
> 10/07/
> 2021
> [ 55.430226] Workqueue: ice ice_service_task [ice]
> [ 55.468169] RIP: 0010:mutex_unlock+0x10/0x20
> [ 55.472439] Code: 0f b1 13 74 96 eb e0 4c 89 ee eb d8 e8 79 54 ff ff 66 0f 1f 84
> 00 00 00 00 00 0f 1f 44 00 00 65 48 8b 04 25 40 ef 01 00 31 d2 <f0> 48 0f b1 17 75
> 01 c3 e9 e3 fe ff ff 0f 1f 00 0f 1f 44 00 00 48
> [ 55.491186] RSP: 0018:ff4454230d7d7e28 EFLAGS: 00010246
> [ 55.496413] RAX: ff1a79b208b08000 RBX: ff1a79b2182e8880 RCX:
> 0000000000000001
> [ 55.503545] RDX: 0000000000000000 RSI: ff4454230d7d7db0 RDI:
> 0000000000000080
> [ 55.510678] RBP: ff1a79d1c7e48b68 R08: ff4454230d7d7db0 R09:
> 0000000000000041
> [ 55.517812] R10: 00000000000000a5 R11: 00000000000006e6 R12:
> ff1a79d1c7e48bc0
> [ 55.524945] R13: 0000000000000000 R14: ff1a79d0ffc305c0 R15:
> 0000000000000000
> [ 55.532076] FS: 0000000000000000(0000) GS:ff1a79d0ffc00000(0000)
> knlGS:0000000000000000
> [ 55.540163] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [ 55.545908] CR2: 0000000000000080 CR3: 00000003487ae003 CR4:
> 0000000000771ef0
> [ 55.553041] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
> 0000000000000000
> [ 55.560173] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
> 0000000000000400
> [ 55.567305] PKRU: 55555554
> [ 55.570018] Call Trace:
> [ 55.572474] <TASK>
> [ 55.574579] ice_service_task+0xaab/0xef0 [ice]
> [ 55.579130] process_one_work+0x1c5/0x390
> [ 55.583141] ? process_one_work+0x390/0x390
> [ 55.587326] worker_thread+0x30/0x360
> [ 55.590994] ? process_one_work+0x390/0x390
> [ 55.595180] kthread+0xe6/0x110
> [ 55.598325] ? kthread_complete_and_exit+0x20/0x20
> [ 55.603116] ret_from_fork+0x1f/0x30
> [ 55.606698] </TASK>
>
> Fixes: f9f5301e7e2d ("ice: Register auxiliary device to provide RDMA")
> Cc: Leon Romanovsky <leon@kernel.org>
> Signed-off-by: Ivan Vecera <ivecera@redhat.com>
> ---
> drivers/net/ethernet/intel/ice/ice.h | 1 +
> drivers/net/ethernet/intel/ice/ice_idc.c | 33 ++++++++++++++---------
> drivers/net/ethernet/intel/ice/ice_main.c | 2 ++
> 3 files changed, 23 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/ice/ice.h
> b/drivers/net/ethernet/intel/ice/ice.h
> index 8ed3c9ab7ff7..a895e3a8e988 100644
> --- a/drivers/net/ethernet/intel/ice/ice.h
> +++ b/drivers/net/ethernet/intel/ice/ice.h
> @@ -540,6 +540,7 @@ struct ice_pf {
> struct mutex avail_q_mutex; /* protects access to avail_[rx|tx]qs
> */
> struct mutex sw_mutex; /* lock for protecting VSI alloc
> flow */
> struct mutex tc_mutex; /* lock to protect TC changes
> */
> + struct mutex adev_mutex; /* lock to protect aux device access
> */
> u32 msg_enable;
> struct ice_ptp ptp;
> struct tty_driver *ice_gnss_tty_driver;
> diff --git a/drivers/net/ethernet/intel/ice/ice_idc.c
> b/drivers/net/ethernet/intel/ice/ice_idc.c
> index 25a436d342c2..b9e471137f6a 100644
> --- a/drivers/net/ethernet/intel/ice/ice_idc.c
> +++ b/drivers/net/ethernet/intel/ice/ice_idc.c
> @@ -10,13 +10,15 @@
> * ice_get_auxiliary_drv - retrieve iidc_auxiliary_drv struct
> * @pf: pointer to PF struct
> *
> - * This function has to be called with a device_lock on the
> - * pf->adev.dev to avoid race conditions.
> + * This function has to be called with pf->adev_mutex held
> + * to avoid race conditions.
> */
> static struct iidc_auxiliary_drv *ice_get_auxiliary_drv(struct ice_pf *pf)
> {
> struct auxiliary_device *adev;
>
> + lockdep_assert_held(&pf->adev_mutex);
> +
> adev = pf->adev;
> if (!adev || !adev->dev.driver)
> return NULL;
> @@ -37,14 +39,13 @@ void ice_send_event_to_aux(struct ice_pf *pf, struct
> iidc_event *event)
> if (WARN_ON_ONCE(!in_task()))
> return;
>
> - if (!pf->adev)
> - return;
> + mutex_lock(&pf->adev_mutex);
>
> - device_lock(&pf->adev->dev);
> iadrv = ice_get_auxiliary_drv(pf);
> if (iadrv && iadrv->event_handler)
> iadrv->event_handler(pf, event);
> - device_unlock(&pf->adev->dev);
> +
> + mutex_unlock(&pf->adev_mutex);
> }
>
> /**
> @@ -290,7 +291,6 @@ int ice_plug_aux_dev(struct ice_pf *pf)
> return -ENOMEM;
>
> adev = &iadev->adev;
> - pf->adev = adev;
> iadev->pf = pf;
>
> adev->id = pf->aux_idx;
> @@ -300,18 +300,20 @@ int ice_plug_aux_dev(struct ice_pf *pf)
>
> ret = auxiliary_device_init(adev);
> if (ret) {
> - pf->adev = NULL;
> kfree(iadev);
> return ret;
> }
>
> ret = auxiliary_device_add(adev);
> if (ret) {
> - pf->adev = NULL;
> auxiliary_device_uninit(adev);
> return ret;
> }
>
> + mutex_lock(&pf->adev_mutex);
> + pf->adev = adev;
> + mutex_unlock(&pf->adev_mutex);
> +
> return 0;
> }
>
> @@ -320,12 +322,17 @@ int ice_plug_aux_dev(struct ice_pf *pf)
> */
> void ice_unplug_aux_dev(struct ice_pf *pf)
> {
> - if (!pf->adev)
> - return;
> + struct auxiliary_device *adev;
>
> - auxiliary_device_delete(pf->adev);
> - auxiliary_device_uninit(pf->adev);
> + mutex_lock(&pf->adev_mutex);
> + adev = pf->adev;
> pf->adev = NULL;
> + mutex_unlock(&pf->adev_mutex);
> +
> + if (adev) {
> + auxiliary_device_delete(adev);
> + auxiliary_device_uninit(adev);
> + }
> }
>
> /**
> diff --git a/drivers/net/ethernet/intel/ice/ice_main.c
> b/drivers/net/ethernet/intel/ice/ice_main.c
> index 5b1198859da7..2cbbf7abefc4 100644
> --- a/drivers/net/ethernet/intel/ice/ice_main.c
> +++ b/drivers/net/ethernet/intel/ice/ice_main.c
> @@ -3769,6 +3769,7 @@ u16 ice_get_avail_rxq_count(struct ice_pf *pf)
> static void ice_deinit_pf(struct ice_pf *pf)
> {
> ice_service_task_stop(pf);
> + mutex_destroy(&pf->adev_mutex);
> mutex_destroy(&pf->sw_mutex);
> mutex_destroy(&pf->tc_mutex);
> mutex_destroy(&pf->avail_q_mutex);
> @@ -3847,6 +3848,7 @@ static int ice_init_pf(struct ice_pf *pf)
>
> mutex_init(&pf->sw_mutex);
> mutex_init(&pf->tc_mutex);
> + mutex_init(&pf->adev_mutex);
>
> INIT_HLIST_HEAD(&pf->aq_wait_list);
> spin_lock_init(&pf->aq_wait_lock);
> --
> 2.35.1
ack
^ permalink raw reply
* Re: [PATCH net-next] net: generalize skb freeing deferral to per-cpu lists
From: Jakub Kicinski @ 2022-04-22 17:10 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Eric Dumazet, David S . Miller, Paolo Abeni, netdev
In-Reply-To: <CANn89iLK5i9y5=iAHS=8+SinGkmGgEXR=xk=ATpnXPakD1j-vQ@mail.gmail.com>
On Fri, 22 Apr 2022 09:50:33 -0700 Eric Dumazet wrote:
> The thing is that with a typical number of RX queues (typically 16 or
> 32 queues on a 100Gbit NIC),
> there is enough sharding for this spinlock to be a non-issue.
>
> Also, we could quite easily add some batching in a future patch, for
> the cases where the number of RX queues
> is too small.
>
> (Each cpu could hold up to 8 or 16 skbs in a per-cpu cache, before
> giving them back to alloc_cpu(s))
I was wondering if we want to keep the per-socket queue for the
batching but you're right, per CPU batch is better anyway if needed.
^ permalink raw reply
* Re: [PATCH perf/core 3/5] perf tools: Move libbpf init in libbpf_init function
From: Arnaldo Carvalho de Melo @ 2022-04-22 17:03 UTC (permalink / raw)
To: Jiri Olsa
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
linux-perf-users, netdev, bpf, Ingo Molnar, Namhyung Kim,
Alexander Shishkin, Peter Zijlstra, Martin KaFai Lau, Song Liu,
Yonghong Song, John Fastabend, Ian Rogers
In-Reply-To: <20220422100025.1469207-4-jolsa@kernel.org>
Em Fri, Apr 22, 2022 at 12:00:23PM +0200, Jiri Olsa escreveu:
> Moving the libbpf init code into single function,
> so we have single place doing that.
Cherry picked this one, waiting for Andrii to chime in wrt the libbpf
changes, if its acceptable, how to proceed, i.e. in what tree to carry
these?
- Arnaldo
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> ---
> tools/perf/util/bpf-loader.c | 27 ++++++++++++++++++---------
> 1 file changed, 18 insertions(+), 9 deletions(-)
>
> diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
> index b72cef1ae959..f8ad581ea247 100644
> --- a/tools/perf/util/bpf-loader.c
> +++ b/tools/perf/util/bpf-loader.c
> @@ -99,16 +99,26 @@ static int bpf_perf_object__add(struct bpf_object *obj)
> return perf_obj ? 0 : -ENOMEM;
> }
>
> +static int libbpf_init(void)
> +{
> + if (libbpf_initialized)
> + return 0;
> +
> + libbpf_set_print(libbpf_perf_print);
> + libbpf_initialized = true;
> + return 0;
> +}
> +
> struct bpf_object *
> bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz, const char *name)
> {
> LIBBPF_OPTS(bpf_object_open_opts, opts, .object_name = name);
> struct bpf_object *obj;
> + int err;
>
> - if (!libbpf_initialized) {
> - libbpf_set_print(libbpf_perf_print);
> - libbpf_initialized = true;
> - }
> + err = libbpf_init();
> + if (err)
> + return ERR_PTR(err);
>
> obj = bpf_object__open_mem(obj_buf, obj_buf_sz, &opts);
> if (IS_ERR_OR_NULL(obj)) {
> @@ -135,14 +145,13 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source)
> {
> LIBBPF_OPTS(bpf_object_open_opts, opts, .object_name = filename);
> struct bpf_object *obj;
> + int err;
>
> - if (!libbpf_initialized) {
> - libbpf_set_print(libbpf_perf_print);
> - libbpf_initialized = true;
> - }
> + err = libbpf_init();
> + if (err)
> + return ERR_PTR(err);
>
> if (source) {
> - int err;
> void *obj_buf;
> size_t obj_buf_sz;
>
> --
> 2.35.1
--
- Arnaldo
^ permalink raw reply
* Re: [RFC Patch net-next] net: dsa: ksz: added the generic port_stp_state_set function
From: Vladimir Oltean @ 2022-04-22 17:01 UTC (permalink / raw)
To: Arun Ramadoss
Cc: linux-kernel, netdev, Paolo Abeni, Jakub Kicinski,
David S. Miller, Florian Fainelli, Vivien Didelot, Andrew Lunn,
UNGLinuxDriver, Woojung Huh
In-Reply-To: <20220420072647.22192-1-arun.ramadoss@microchip.com>
On Wed, Apr 20, 2022 at 12:56:47PM +0530, Arun Ramadoss wrote:
> The ksz8795 and ksz9477 uses the same algorithm for the
> port_stp_state_set function except the register address is different. So
> moved the algorithm to the ksz_common.c and used the dev_ops for
> register read and write. This function can also used for the lan937x
> part. Hence making it generic for all the parts.
>
> Signed-off-by: Arun Ramadoss <arun.ramadoss@microchip.com>
> ---
If the entire port STP state change procedure is the same, just a
register offset is different, can you not create a common STP state
procedure that takes the register offset as argument, and gets called
with different offset arguments from ksz8795.c and from ksz9477.c?
^ permalink raw reply
* Re: [PATCH net-next] net: generalize skb freeing deferral to per-cpu lists
From: Eric Dumazet @ 2022-04-22 16:50 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: Eric Dumazet, David S . Miller, Paolo Abeni, netdev
In-Reply-To: <20220422094058.30f34bb4@kernel.org>
On Fri, Apr 22, 2022 at 9:41 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> On Thu, 21 Apr 2022 08:39:20 -0700 Eric Dumazet wrote:
> > diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
> > index 84d78df60453955a8eaf05847f6e2145176a727a..2fe311447fae5e860eee95f6e8772926d4915e9f 100644
> > --- a/include/linux/skbuff.h
> > +++ b/include/linux/skbuff.h
> > @@ -1080,6 +1080,7 @@ struct sk_buff {
> > unsigned int sender_cpu;
> > };
> > #endif
> > + u16 alloc_cpu;
> > #ifdef CONFIG_NETWORK_SECMARK
> > __u32 secmark;
> > #endif
>
> nit: kdoc missing
Yep, I had this covered for v2 already, thanks.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox