kernel: bump 6.1 to 6.1.90

This commit is contained in:
DHDAXCW
2024-05-06 11:12:28 +08:00
parent d98b5e2116
commit bffabe88ef
85 changed files with 2220 additions and 981 deletions

View File

@@ -1,2 +1,2 @@
LINUX_VERSION-6.1 = .87
LINUX_KERNEL_HASH-6.1.87 = fc7af16a72e8aee4790b796f1bf5003cb0de6095ea1ffd7d7c7c9a5678d95124
LINUX_VERSION-6.1 = .90
LINUX_KERNEL_HASH-6.1.90 = 83a3d72e764fceda2c1fc68a4ea6b91253a28da56a688a2b61776b0d19788e1d

View File

@@ -0,0 +1,107 @@
From: Richard Gobert <richardbgobert@gmail.com>
Date: Wed, 3 Jan 2024 15:44:21 +0100
Subject: [PATCH] net: gro: parse ipv6 ext headers without frag0 invalidation
The existing code always pulls the IPv6 header and sets the transport
offset initially. Then optionally again pulls any extension headers in
ipv6_gso_pull_exthdrs and sets the transport offset again on return from
that call. skb->data is set at the start of the first extension header
before calling ipv6_gso_pull_exthdrs, and must disable the frag0
optimization because that function uses pskb_may_pull/pskb_pull instead of
skb_gro_ helpers. It sets the GRO offset to the TCP header with
skb_gro_pull and sets the transport header. Then returns skb->data to its
position before this block.
This commit introduces a new helper function - ipv6_gro_pull_exthdrs -
which is used in ipv6_gro_receive to pull ipv6 ext headers instead of
ipv6_gso_pull_exthdrs. Thus, there is no modification of skb->data, all
operations use skb_gro_* helpers, and the frag0 fast path can be taken for
IPv6 packets with ext headers.
Signed-off-by: Richard Gobert <richardbgobert@gmail.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://lore.kernel.org/r/504130f6-b56c-4dcc-882c-97942c59f5b7@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
--- a/net/ipv6/ip6_offload.c
+++ b/net/ipv6/ip6_offload.c
@@ -36,6 +36,40 @@
INDIRECT_CALL_L4(cb, f2, f1, head, skb); \
})
+static int ipv6_gro_pull_exthdrs(struct sk_buff *skb, int off, int proto)
+{
+ const struct net_offload *ops = NULL;
+ struct ipv6_opt_hdr *opth;
+
+ for (;;) {
+ int len;
+
+ ops = rcu_dereference(inet6_offloads[proto]);
+
+ if (unlikely(!ops))
+ break;
+
+ if (!(ops->flags & INET6_PROTO_GSO_EXTHDR))
+ break;
+
+ opth = skb_gro_header(skb, off + sizeof(*opth), off);
+ if (unlikely(!opth))
+ break;
+
+ len = ipv6_optlen(opth);
+
+ opth = skb_gro_header(skb, off + len, off);
+ if (unlikely(!opth))
+ break;
+ proto = opth->nexthdr;
+
+ off += len;
+ }
+
+ skb_gro_pull(skb, off - skb_network_offset(skb));
+ return proto;
+}
+
static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto)
{
const struct net_offload *ops = NULL;
@@ -224,28 +258,25 @@ INDIRECT_CALLABLE_SCOPE struct sk_buff *
goto out;
skb_set_network_header(skb, off);
- skb_gro_pull(skb, sizeof(*iph));
- skb_set_transport_header(skb, skb_gro_offset(skb));
- flush += ntohs(iph->payload_len) != skb_gro_len(skb);
+ flush += ntohs(iph->payload_len) != skb->len - hlen;
proto = iph->nexthdr;
ops = rcu_dereference(inet6_offloads[proto]);
if (!ops || !ops->callbacks.gro_receive) {
- pskb_pull(skb, skb_gro_offset(skb));
- skb_gro_frag0_invalidate(skb);
- proto = ipv6_gso_pull_exthdrs(skb, proto);
- skb_gro_pull(skb, -skb_transport_offset(skb));
- skb_reset_transport_header(skb);
- __skb_push(skb, skb_gro_offset(skb));
+ proto = ipv6_gro_pull_exthdrs(skb, hlen, proto);
ops = rcu_dereference(inet6_offloads[proto]);
if (!ops || !ops->callbacks.gro_receive)
goto out;
- iph = ipv6_hdr(skb);
+ iph = skb_gro_network_header(skb);
+ } else {
+ skb_gro_pull(skb, sizeof(*iph));
}
+ skb_set_transport_header(skb, skb_gro_offset(skb));
+
NAPI_GRO_CB(skb)->proto = proto;
flush--;

View File

@@ -0,0 +1,48 @@
From: Richard Gobert <richardbgobert@gmail.com>
Date: Tue, 30 Apr 2024 16:35:55 +0200
Subject: [PATCH] net: gro: add flush check in udp_gro_receive_segment
GRO-GSO path is supposed to be transparent and as such L3 flush checks are
relevant to all UDP flows merging in GRO. This patch uses the same logic
and code from tcp_gro_receive, terminating merge if flush is non zero.
Fixes: e20cf8d3f1f7 ("udp: implement GRO for plain UDP sockets.")
Signed-off-by: Richard Gobert <richardbgobert@gmail.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -463,6 +463,7 @@ static struct sk_buff *udp_gro_receive_s
struct sk_buff *p;
unsigned int ulen;
int ret = 0;
+ int flush;
/* requires non zero csum, for symmetry with GSO */
if (!uh->check) {
@@ -496,13 +497,22 @@ static struct sk_buff *udp_gro_receive_s
return p;
}
+ flush = NAPI_GRO_CB(p)->flush;
+
+ if (NAPI_GRO_CB(p)->flush_id != 1 ||
+ NAPI_GRO_CB(p)->count != 1 ||
+ !NAPI_GRO_CB(p)->is_atomic)
+ flush |= NAPI_GRO_CB(p)->flush_id;
+ else
+ NAPI_GRO_CB(p)->is_atomic = false;
+
/* Terminate the flow on len mismatch or if it grow "too much".
* Under small packet flood GRO count could elsewhere grow a lot
* leading to excessive truesize values.
* On len mismatch merge the first packet shorter than gso_size,
* otherwise complete the GRO packet.
*/
- if (ulen > ntohs(uh2->len)) {
+ if (ulen > ntohs(uh2->len) || flush) {
pp = p;
} else {
if (NAPI_GRO_CB(skb)->is_flist) {

View File

@@ -1,87 +0,0 @@
From: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Thu, 11 Apr 2024 13:28:59 +0200
Subject: [PATCH] netfilter: flowtable: validate pppoe header
Ensure there is sufficient room to access the protocol field of the
PPPoe header. Validate it once before the flowtable lookup, then use a
helper function to access protocol field.
Reported-by: syzbot+b6f07e1c07ef40199081@syzkaller.appspotmail.com
Fixes: 72efd585f714 ("netfilter: flowtable: add pppoe support")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -335,7 +335,7 @@ int nf_flow_rule_route_ipv6(struct net *
int nf_flow_table_offload_init(void);
void nf_flow_table_offload_exit(void);
-static inline __be16 nf_flow_pppoe_proto(const struct sk_buff *skb)
+static inline __be16 __nf_flow_pppoe_proto(const struct sk_buff *skb)
{
__be16 proto;
@@ -351,6 +351,16 @@ static inline __be16 nf_flow_pppoe_proto
return 0;
}
+static inline bool nf_flow_pppoe_proto(struct sk_buff *skb, __be16 *inner_proto)
+{
+ if (!pskb_may_pull(skb, PPPOE_SES_HLEN))
+ return false;
+
+ *inner_proto = __nf_flow_pppoe_proto(skb);
+
+ return true;
+}
+
#define NF_FLOW_TABLE_STAT_INC(net, count) __this_cpu_inc((net)->ft.stat->count)
#define NF_FLOW_TABLE_STAT_DEC(net, count) __this_cpu_dec((net)->ft.stat->count)
#define NF_FLOW_TABLE_STAT_INC_ATOMIC(net, count) \
--- a/net/netfilter/nf_flow_table_inet.c
+++ b/net/netfilter/nf_flow_table_inet.c
@@ -21,7 +21,8 @@ nf_flow_offload_inet_hook(void *priv, st
proto = veth->h_vlan_encapsulated_proto;
break;
case htons(ETH_P_PPP_SES):
- proto = nf_flow_pppoe_proto(skb);
+ if (!nf_flow_pppoe_proto(skb, &proto))
+ return NF_ACCEPT;
break;
default:
proto = skb->protocol;
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -267,10 +267,11 @@ static unsigned int nf_flow_xmit_xfrm(st
return NF_STOLEN;
}
-static bool nf_flow_skb_encap_protocol(const struct sk_buff *skb, __be16 proto,
+static bool nf_flow_skb_encap_protocol(struct sk_buff *skb, __be16 proto,
u32 *offset)
{
struct vlan_ethhdr *veth;
+ __be16 inner_proto;
switch (skb->protocol) {
case htons(ETH_P_8021Q):
@@ -281,7 +282,8 @@ static bool nf_flow_skb_encap_protocol(c
}
break;
case htons(ETH_P_PPP_SES):
- if (nf_flow_pppoe_proto(skb) == proto) {
+ if (nf_flow_pppoe_proto(skb, &inner_proto) &&
+ inner_proto == proto) {
*offset += PPPOE_SES_HLEN;
return true;
}
@@ -310,7 +312,7 @@ static void nf_flow_encap_pop(struct sk_
skb_reset_network_header(skb);
break;
case htons(ETH_P_PPP_SES):
- skb->protocol = nf_flow_pppoe_proto(skb);
+ skb->protocol = __nf_flow_pppoe_proto(skb);
skb_pull(skb, PPPOE_SES_HLEN);
skb_reset_network_header(skb);
break;

View File

@@ -1,24 +0,0 @@
From: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Thu, 11 Apr 2024 13:29:00 +0200
Subject: [PATCH] netfilter: flowtable: incorrect pppoe tuple
pppoe traffic reaching ingress path does not match the flowtable entry
because the pppoe header is expected to be at the network header offset.
This bug causes a mismatch in the flow table lookup, so pppoe packets
enter the classical forwarding path.
Fixes: 72efd585f714 ("netfilter: flowtable: add pppoe support")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -156,7 +156,7 @@ static void nf_flow_tuple_encap(struct s
tuple->encap[i].proto = skb->protocol;
break;
case htons(ETH_P_PPP_SES):
- phdr = (struct pppoe_hdr *)skb_mac_header(skb);
+ phdr = (struct pppoe_hdr *)skb_network_header(skb);
tuple->encap[i].id = ntohs(phdr->sid);
tuple->encap[i].proto = skb->protocol;
break;

View File

@@ -81,7 +81,7 @@ Tested-by: Frank Wunderlich <frank-w@public-files.de>
#include <linux/phylink.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
@@ -2812,128 +2813,11 @@ static int mt7531_rgmii_setup(struct mt7
@@ -2839,128 +2840,11 @@ static int mt7531_rgmii_setup(struct mt7
return 0;
}
@@ -210,7 +210,7 @@ Tested-by: Frank Wunderlich <frank-w@public-files.de>
static int
mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
phy_interface_t interface)
@@ -2956,11 +2840,11 @@ mt7531_mac_config(struct dsa_switch *ds,
@@ -2983,11 +2867,11 @@ mt7531_mac_config(struct dsa_switch *ds,
phydev = dp->slave->phydev;
return mt7531_rgmii_setup(priv, port, interface, phydev);
case PHY_INTERFACE_MODE_SGMII:
@@ -224,7 +224,7 @@ Tested-by: Frank Wunderlich <frank-w@public-files.de>
default:
return -EINVAL;
}
@@ -2985,11 +2869,11 @@ mt753x_phylink_mac_select_pcs(struct dsa
@@ -3012,11 +2896,11 @@ mt753x_phylink_mac_select_pcs(struct dsa
switch (interface) {
case PHY_INTERFACE_MODE_TRGMII:
@@ -238,7 +238,7 @@ Tested-by: Frank Wunderlich <frank-w@public-files.de>
default:
return NULL;
}
@@ -3230,86 +3114,6 @@ static void mt7530_pcs_get_state(struct
@@ -3257,86 +3141,6 @@ static void mt7530_pcs_get_state(struct
state->pause |= MLO_PAUSE_TX;
}
@@ -325,7 +325,7 @@ Tested-by: Frank Wunderlich <frank-w@public-files.de>
static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
phy_interface_t interface,
const unsigned long *advertising,
@@ -3329,18 +3133,57 @@ static const struct phylink_pcs_ops mt75
@@ -3356,18 +3160,57 @@ static const struct phylink_pcs_ops mt75
.pcs_an_restart = mt7530_pcs_an_restart,
};
@@ -389,7 +389,7 @@ Tested-by: Frank Wunderlich <frank-w@public-files.de>
int i, ret;
/* Initialise the PCS devices */
@@ -3348,8 +3191,6 @@ mt753x_setup(struct dsa_switch *ds)
@@ -3375,8 +3218,6 @@ mt753x_setup(struct dsa_switch *ds)
priv->pcs[i].pcs.ops = priv->info->pcs_ops;
priv->pcs[i].priv = priv;
priv->pcs[i].port = i;
@@ -398,7 +398,7 @@ Tested-by: Frank Wunderlich <frank-w@public-files.de>
}
ret = priv->info->sw_setup(ds);
@@ -3364,6 +3205,16 @@ mt753x_setup(struct dsa_switch *ds)
@@ -3391,6 +3232,16 @@ mt753x_setup(struct dsa_switch *ds)
if (ret && priv->irq)
mt7530_free_irq_common(priv);
@@ -415,7 +415,7 @@ Tested-by: Frank Wunderlich <frank-w@public-files.de>
return ret;
}
@@ -3455,7 +3306,7 @@ static const struct mt753x_info mt753x_t
@@ -3483,7 +3334,7 @@ static const struct mt753x_info mt753x_t
},
[ID_MT7531] = {
.id = ID_MT7531,
@@ -424,7 +424,7 @@ Tested-by: Frank Wunderlich <frank-w@public-files.de>
.sw_setup = mt7531_setup,
.phy_read = mt7531_ind_phy_read,
.phy_write = mt7531_ind_phy_write,
@@ -3563,7 +3414,7 @@ static void
@@ -3591,7 +3442,7 @@ static void
mt7530_remove(struct mdio_device *mdiodev)
{
struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
@@ -433,7 +433,7 @@ Tested-by: Frank Wunderlich <frank-w@public-files.de>
if (!priv)
return;
@@ -3582,6 +3433,10 @@ mt7530_remove(struct mdio_device *mdiode
@@ -3610,6 +3461,10 @@ mt7530_remove(struct mdio_device *mdiode
mt7530_free_irq(priv);
dsa_unregister_switch(priv->ds);
@@ -446,7 +446,7 @@ Tested-by: Frank Wunderlich <frank-w@public-files.de>
--- a/drivers/net/dsa/mt7530.h
+++ b/drivers/net/dsa/mt7530.h
@@ -396,47 +396,8 @@ enum mt7530_vlan_port_acc_frm {
@@ -401,47 +401,8 @@ enum mt7530_vlan_port_acc_frm {
CCR_TX_OCT_CNT_BAD)
/* MT7531 SGMII register group */
@@ -496,7 +496,7 @@ Tested-by: Frank Wunderlich <frank-w@public-files.de>
/* Register for system reset */
#define MT7530_SYS_CTRL 0x7000
@@ -735,13 +696,13 @@ struct mt7530_fdb {
@@ -741,13 +702,13 @@ struct mt7530_fdb {
* @pm: The matrix used to show all connections with the port.
* @pvid: The VLAN specified is to be considered a PVID at ingress. Any
* untagged frames will be assigned to the related VLAN.

View File

@@ -18,7 +18,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -3165,26 +3165,56 @@ static const struct regmap_bus mt7531_re
@@ -3192,26 +3192,56 @@ static const struct regmap_bus mt7531_re
.reg_update_bits = mt7530_regmap_update_bits,
};
@@ -88,7 +88,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
int i, ret;
/* Initialise the PCS devices */
@@ -3206,15 +3236,11 @@ mt753x_setup(struct dsa_switch *ds)
@@ -3233,15 +3263,11 @@ mt753x_setup(struct dsa_switch *ds)
if (ret && priv->irq)
mt7530_free_irq_common(priv);

View File

@@ -19,7 +19,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -3138,7 +3138,7 @@ static int mt7530_regmap_read(void *cont
@@ -3165,7 +3165,7 @@ static int mt7530_regmap_read(void *cont
{
struct mt7530_priv *priv = context;
@@ -28,7 +28,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
return 0;
};
@@ -3146,23 +3146,25 @@ static int mt7530_regmap_write(void *con
@@ -3173,23 +3173,25 @@ static int mt7530_regmap_write(void *con
{
struct mt7530_priv *priv = context;
@@ -62,7 +62,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
};
static int
@@ -3188,6 +3190,9 @@ mt7531_create_sgmii(struct mt7530_priv *
@@ -3215,6 +3217,9 @@ mt7531_create_sgmii(struct mt7530_priv *
mt7531_pcs_config[i]->reg_stride = 4;
mt7531_pcs_config[i]->reg_base = MT7531_SGMII_REG_BASE(5 + i);
mt7531_pcs_config[i]->max_register = 0x17c;

View File

@@ -133,7 +133,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
}
static void
@@ -3134,22 +3155,6 @@ static const struct phylink_pcs_ops mt75
@@ -3161,22 +3182,6 @@ static const struct phylink_pcs_ops mt75
.pcs_an_restart = mt7530_pcs_an_restart,
};
@@ -156,7 +156,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
static void
mt7530_mdio_regmap_lock(void *mdio_lock)
{
@@ -3162,7 +3167,7 @@ mt7530_mdio_regmap_unlock(void *mdio_loc
@@ -3189,7 +3194,7 @@ mt7530_mdio_regmap_unlock(void *mdio_loc
mutex_unlock(mdio_lock);
}
@@ -165,7 +165,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
.reg_write = mt7530_regmap_write,
.reg_read = mt7530_regmap_read,
};
@@ -3195,7 +3200,7 @@ mt7531_create_sgmii(struct mt7530_priv *
@@ -3222,7 +3227,7 @@ mt7531_create_sgmii(struct mt7530_priv *
mt7531_pcs_config[i]->lock_arg = &priv->bus->mdio_lock;
regmap = devm_regmap_init(priv->dev,
@@ -174,7 +174,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
mt7531_pcs_config[i]);
if (IS_ERR(regmap)) {
ret = PTR_ERR(regmap);
@@ -3360,6 +3365,7 @@ MODULE_DEVICE_TABLE(of, mt7530_of_match)
@@ -3388,6 +3393,7 @@ MODULE_DEVICE_TABLE(of, mt7530_of_match)
static int
mt7530_probe(struct mdio_device *mdiodev)
{
@@ -182,7 +182,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
struct mt7530_priv *priv;
struct device_node *dn;
@@ -3439,6 +3445,21 @@ mt7530_probe(struct mdio_device *mdiodev
@@ -3467,6 +3473,21 @@ mt7530_probe(struct mdio_device *mdiodev
mutex_init(&priv->reg_mutex);
dev_set_drvdata(&mdiodev->dev, priv);
@@ -206,7 +206,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
--- a/drivers/net/dsa/mt7530.h
+++ b/drivers/net/dsa/mt7530.h
@@ -779,6 +779,7 @@ struct mt753x_info {
@@ -785,6 +785,7 @@ struct mt753x_info {
* @dev: The device pointer
* @ds: The pointer to the dsa core structure
* @bus: The bus used for the device and built-in PHY
@@ -214,7 +214,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
* @rstc: The pointer to reset control used by MCM
* @core_pwr: The power supplied into the core
* @io_pwr: The power supplied into the I/O
@@ -799,6 +800,7 @@ struct mt7530_priv {
@@ -805,6 +806,7 @@ struct mt7530_priv {
struct device *dev;
struct dsa_switch *ds;
struct mii_bus *bus;

View File

@@ -18,7 +18,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -3246,12 +3246,6 @@ mt753x_setup(struct dsa_switch *ds)
@@ -3273,12 +3273,6 @@ mt753x_setup(struct dsa_switch *ds)
if (ret && priv->irq)
mt7530_free_irq_common(priv);
@@ -31,7 +31,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
return ret;
}
@@ -3368,6 +3362,7 @@ mt7530_probe(struct mdio_device *mdiodev
@@ -3396,6 +3390,7 @@ mt7530_probe(struct mdio_device *mdiodev
static struct regmap_config *regmap_config;
struct mt7530_priv *priv;
struct device_node *dn;
@@ -39,7 +39,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
dn = mdiodev->dev.of_node;
@@ -3460,6 +3455,12 @@ mt7530_probe(struct mdio_device *mdiodev
@@ -3488,6 +3483,12 @@ mt7530_probe(struct mdio_device *mdiodev
if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap);

View File

@@ -114,7 +114,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
}
static void
@@ -645,14 +649,13 @@ static int
@@ -659,14 +663,13 @@ static int
mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
int regnum)
{
@@ -130,7 +130,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
@@ -685,7 +688,7 @@ mt7531_ind_c45_phy_read(struct mt7530_pr
@@ -699,7 +702,7 @@ mt7531_ind_c45_phy_read(struct mt7530_pr
ret = val & MT7531_MDIO_RW_DATA_MASK;
out:
@@ -139,7 +139,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
return ret;
}
@@ -694,14 +697,13 @@ static int
@@ -708,14 +711,13 @@ static int
mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
int regnum, u32 data)
{
@@ -155,7 +155,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
@@ -733,7 +735,7 @@ mt7531_ind_c45_phy_write(struct mt7530_p
@@ -747,7 +749,7 @@ mt7531_ind_c45_phy_write(struct mt7530_p
}
out:
@@ -164,7 +164,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
return ret;
}
@@ -741,14 +743,13 @@ out:
@@ -755,14 +757,13 @@ out:
static int
mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)
{
@@ -180,7 +180,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
@@ -771,7 +772,7 @@ mt7531_ind_c22_phy_read(struct mt7530_pr
@@ -785,7 +786,7 @@ mt7531_ind_c22_phy_read(struct mt7530_pr
ret = val & MT7531_MDIO_RW_DATA_MASK;
out:
@@ -189,7 +189,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
return ret;
}
@@ -780,14 +781,13 @@ static int
@@ -794,14 +795,13 @@ static int
mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,
u16 data)
{
@@ -205,7 +205,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
!(reg & MT7531_PHY_ACS_ST), 20, 100000);
@@ -809,7 +809,7 @@ mt7531_ind_c22_phy_write(struct mt7530_p
@@ -823,7 +823,7 @@ mt7531_ind_c22_phy_write(struct mt7530_p
}
out:
@@ -214,7 +214,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
return ret;
}
@@ -1322,7 +1322,6 @@ static int
@@ -1343,7 +1343,6 @@ static int
mt7530_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
{
struct mt7530_priv *priv = ds->priv;
@@ -222,7 +222,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
int length;
u32 val;
@@ -1333,7 +1332,7 @@ mt7530_port_change_mtu(struct dsa_switch
@@ -1354,7 +1353,7 @@ mt7530_port_change_mtu(struct dsa_switch
if (!dsa_is_cpu_port(ds, port))
return 0;
@@ -231,7 +231,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
val = mt7530_mii_read(priv, MT7530_GMACCR);
val &= ~MAX_RX_PKT_LEN_MASK;
@@ -1354,7 +1353,7 @@ mt7530_port_change_mtu(struct dsa_switch
@@ -1375,7 +1374,7 @@ mt7530_port_change_mtu(struct dsa_switch
mt7530_mii_write(priv, MT7530_GMACCR, val);
@@ -240,7 +240,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
return 0;
}
@@ -2155,10 +2154,10 @@ mt7530_irq_thread_fn(int irq, void *dev_
@@ -2176,10 +2175,10 @@ mt7530_irq_thread_fn(int irq, void *dev_
u32 val;
int p;
@@ -253,7 +253,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
for (p = 0; p < MT7530_NUM_PHYS; p++) {
if (BIT(p) & val) {
@@ -2194,7 +2193,7 @@ mt7530_irq_bus_lock(struct irq_data *d)
@@ -2215,7 +2214,7 @@ mt7530_irq_bus_lock(struct irq_data *d)
{
struct mt7530_priv *priv = irq_data_get_irq_chip_data(d);
@@ -262,7 +262,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
}
static void
@@ -2203,7 +2202,7 @@ mt7530_irq_bus_sync_unlock(struct irq_da
@@ -2224,7 +2223,7 @@ mt7530_irq_bus_sync_unlock(struct irq_da
struct mt7530_priv *priv = irq_data_get_irq_chip_data(d);
mt7530_mii_write(priv, MT7530_SYS_INT_EN, priv->irq_enable);

View File

@@ -21,7 +21,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -950,6 +950,24 @@ mt7530_set_ageing_time(struct dsa_switch
@@ -964,6 +964,24 @@ mt7530_set_ageing_time(struct dsa_switch
return 0;
}
@@ -48,7 +48,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
struct mt7530_priv *priv = ds->priv;
--- a/drivers/net/dsa/mt7530.h
+++ b/drivers/net/dsa/mt7530.h
@@ -714,24 +714,6 @@ enum p5_interface_select {
@@ -720,24 +720,6 @@ enum p5_interface_select {
P5_INTF_SEL_GMAC5_SGMII,
};

View File

@@ -17,7 +17,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -3374,44 +3374,21 @@ static const struct of_device_id mt7530_
@@ -3402,44 +3402,21 @@ static const struct of_device_id mt7530_
MODULE_DEVICE_TABLE(of, mt7530_of_match);
static int
@@ -67,7 +67,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
if (!priv->info)
return -EINVAL;
@@ -3425,23 +3402,53 @@ mt7530_probe(struct mdio_device *mdiodev
@@ -3453,23 +3430,53 @@ mt7530_probe(struct mdio_device *mdiodev
return -EINVAL;
priv->id = priv->info->id;
@@ -131,7 +131,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
priv->reset = devm_gpiod_get_optional(&mdiodev->dev, "reset",
GPIOD_OUT_LOW);
if (IS_ERR(priv->reset)) {
@@ -3450,12 +3457,15 @@ mt7530_probe(struct mdio_device *mdiodev
@@ -3478,12 +3485,15 @@ mt7530_probe(struct mdio_device *mdiodev
}
}

View File

@@ -17,7 +17,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -3492,6 +3492,17 @@ mt7530_probe(struct mdio_device *mdiodev
@@ -3520,6 +3520,17 @@ mt7530_probe(struct mdio_device *mdiodev
}
static void
@@ -35,7 +35,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
mt7530_remove(struct mdio_device *mdiodev)
{
struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
@@ -3510,15 +3521,10 @@ mt7530_remove(struct mdio_device *mdiode
@@ -3538,15 +3549,10 @@ mt7530_remove(struct mdio_device *mdiode
dev_err(priv->dev, "Failed to disable io pwr: %d\n",
ret);

View File

@@ -416,7 +416,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
static u32
mt7530_mii_read(struct mt7530_priv *priv, u32 reg)
{
@@ -3172,72 +3123,6 @@ static const struct phylink_pcs_ops mt75
@@ -3199,72 +3150,6 @@ static const struct phylink_pcs_ops mt75
.pcs_an_restart = mt7530_pcs_an_restart,
};
@@ -489,7 +489,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
static int
mt753x_setup(struct dsa_switch *ds)
{
@@ -3296,7 +3181,7 @@ static int mt753x_set_mac_eee(struct dsa
@@ -3323,7 +3208,7 @@ static int mt753x_set_mac_eee(struct dsa
return 0;
}
@@ -497,8 +497,8 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
+const struct dsa_switch_ops mt7530_switch_ops = {
.get_tag_protocol = mtk_get_tag_protocol,
.setup = mt753x_setup,
.get_strings = mt7530_get_strings,
@@ -3330,8 +3215,9 @@ static const struct dsa_switch_ops mt753
.preferred_default_local_cpu_port = mt753x_preferred_default_local_cpu_port,
@@ -3358,8 +3243,9 @@ static const struct dsa_switch_ops mt753
.get_mac_eee = mt753x_get_mac_eee,
.set_mac_eee = mt753x_set_mac_eee,
};
@@ -509,7 +509,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
[ID_MT7621] = {
.id = ID_MT7621,
.pcs_ops = &mt7530_pcs_ops,
@@ -3364,16 +3250,9 @@ static const struct mt753x_info mt753x_t
@@ -3392,16 +3278,9 @@ static const struct mt753x_info mt753x_t
.mac_port_config = mt7531_mac_config,
},
};
@@ -528,7 +528,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
mt7530_probe_common(struct mt7530_priv *priv)
{
struct device *dev = priv->dev;
@@ -3410,88 +3289,9 @@ mt7530_probe_common(struct mt7530_priv *
@@ -3438,88 +3317,9 @@ mt7530_probe_common(struct mt7530_priv *
return 0;
}
@@ -619,7 +619,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
mt7530_remove_common(struct mt7530_priv *priv)
{
if (priv->irq)
@@ -3501,55 +3301,7 @@ mt7530_remove_common(struct mt7530_priv
@@ -3529,55 +3329,7 @@ mt7530_remove_common(struct mt7530_priv
mutex_destroy(&priv->reg_mutex);
}
@@ -678,7 +678,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch");
--- a/drivers/net/dsa/mt7530.h
+++ b/drivers/net/dsa/mt7530.h
@@ -839,4 +839,10 @@ static inline void INIT_MT7530_DUMMY_POL
@@ -845,4 +845,10 @@ static inline void INIT_MT7530_DUMMY_POL
p->reg = reg;
}

View File

@@ -184,7 +184,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
+MODULE_LICENSE("GPL");
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -2202,6 +2202,47 @@ static const struct irq_domain_ops mt753
@@ -2223,6 +2223,47 @@ static const struct irq_domain_ops mt753
};
static void
@@ -232,7 +232,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
mt7530_setup_mdio_irq(struct mt7530_priv *priv)
{
struct dsa_switch *ds = priv->ds;
@@ -2235,8 +2276,15 @@ mt7530_setup_irq(struct mt7530_priv *pri
@@ -2256,8 +2297,15 @@ mt7530_setup_irq(struct mt7530_priv *pri
return priv->irq ? : -EINVAL;
}
@@ -250,7 +250,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
if (!priv->irq_domain) {
dev_err(dev, "failed to create IRQ domain\n");
return -ENOMEM;
@@ -2735,6 +2783,25 @@ static void mt7531_mac_port_get_caps(str
@@ -2762,6 +2810,25 @@ static void mt7531_mac_port_get_caps(str
}
}
@@ -276,7 +276,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
static int
mt753x_pad_setup(struct dsa_switch *ds, const struct phylink_link_state *state)
{
@@ -2811,6 +2878,17 @@ static bool mt753x_is_mac_port(u32 port)
@@ -2838,6 +2905,17 @@ static bool mt753x_is_mac_port(u32 port)
}
static int
@@ -294,7 +294,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
phy_interface_t interface)
{
@@ -2880,7 +2958,8 @@ mt753x_phylink_mac_config(struct dsa_swi
@@ -2907,7 +2985,8 @@ mt753x_phylink_mac_config(struct dsa_swi
switch (port) {
case 0 ... 4: /* Internal phy */
@@ -304,7 +304,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
goto unsupported;
break;
case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */
@@ -2958,7 +3037,8 @@ static void mt753x_phylink_mac_link_up(s
@@ -2985,7 +3064,8 @@ static void mt753x_phylink_mac_link_up(s
/* MT753x MAC works in 1G full duplex mode for all up-clocked
* variants.
*/
@@ -314,7 +314,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
(phy_interface_mode_is_8023z(interface))) {
speed = SPEED_1000;
duplex = DUPLEX_FULL;
@@ -3038,6 +3118,21 @@ mt7531_cpu_port_config(struct dsa_switch
@@ -3065,6 +3145,21 @@ mt7531_cpu_port_config(struct dsa_switch
return 0;
}
@@ -336,7 +336,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port,
struct phylink_config *config)
{
@@ -3183,6 +3278,27 @@ static int mt753x_set_mac_eee(struct dsa
@@ -3210,6 +3305,27 @@ static int mt753x_set_mac_eee(struct dsa
return 0;
}
@@ -364,7 +364,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
const struct dsa_switch_ops mt7530_switch_ops = {
.get_tag_protocol = mtk_get_tag_protocol,
.setup = mt753x_setup,
@@ -3251,6 +3367,17 @@ const struct mt753x_info mt753x_table[]
@@ -3279,6 +3395,17 @@ const struct mt753x_info mt753x_table[]
.mac_port_get_caps = mt7531_mac_port_get_caps,
.mac_port_config = mt7531_mac_config,
},
@@ -392,9 +392,9 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
};
#define NUM_TRGMII_CTRL 5
@@ -54,11 +55,11 @@ enum mt753x_id {
#define MT7531_MIRROR_PORT_SET(x) (((x) & MIRROR_MASK) << 16)
@@ -59,11 +60,11 @@ enum mt753x_id {
#define MT7531_CPU_PMAP_MASK GENMASK(7, 0)
#define MT7531_CPU_PMAP(x) FIELD_PREP(MT7531_CPU_PMAP_MASK, x)
-#define MT753X_MIRROR_REG(id) (((id) == ID_MT7531) ? \
+#define MT753X_MIRROR_REG(id) ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \
@@ -407,7 +407,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
MT7531_MIRROR_MASK : MIRROR_MASK)
/* Registers for BPDU and PAE frame control*/
@@ -327,9 +328,8 @@ enum mt7530_vlan_port_acc_frm {
@@ -332,9 +333,8 @@ enum mt7530_vlan_port_acc_frm {
MT7531_FORCE_DPX | \
MT7531_FORCE_RX_FC | \
MT7531_FORCE_TX_FC)

View File

@@ -73,7 +73,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
}
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -3245,6 +3245,12 @@ mt753x_setup(struct dsa_switch *ds)
@@ -3272,6 +3272,12 @@ mt753x_setup(struct dsa_switch *ds)
if (ret && priv->irq)
mt7530_free_irq_common(priv);
@@ -88,7 +88,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
--- a/drivers/net/dsa/mt7530.h
+++ b/drivers/net/dsa/mt7530.h
@@ -773,10 +773,10 @@ struct mt753x_info {
@@ -779,10 +779,10 @@ struct mt753x_info {
* registers
* @p6_interface Holding the current port 6 interface
* @p5_intf_sel: Holding the current port 5 interface select
@@ -100,7 +100,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
*/
struct mt7530_priv {
struct device *dev;
@@ -795,7 +795,6 @@ struct mt7530_priv {
@@ -801,7 +801,6 @@ struct mt7530_priv {
unsigned int p5_intf_sel;
u8 mirror_rx;
u8 mirror_tx;
@@ -108,7 +108,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
struct mt7530_port ports[MT7530_NUM_PORTS];
struct mt753x_pcs pcs[MT7530_NUM_PORTS];
/* protect among processes for registers access*/
@@ -803,6 +802,7 @@ struct mt7530_priv {
@@ -809,6 +808,7 @@ struct mt7530_priv {
int irq;
struct irq_domain *irq_domain;
u32 irq_enable;

View File

@@ -0,0 +1,107 @@
From: Richard Gobert <richardbgobert@gmail.com>
Date: Wed, 3 Jan 2024 15:44:21 +0100
Subject: [PATCH] net: gro: parse ipv6 ext headers without frag0 invalidation
The existing code always pulls the IPv6 header and sets the transport
offset initially. Then optionally again pulls any extension headers in
ipv6_gso_pull_exthdrs and sets the transport offset again on return from
that call. skb->data is set at the start of the first extension header
before calling ipv6_gso_pull_exthdrs, and must disable the frag0
optimization because that function uses pskb_may_pull/pskb_pull instead of
skb_gro_ helpers. It sets the GRO offset to the TCP header with
skb_gro_pull and sets the transport header. Then returns skb->data to its
position before this block.
This commit introduces a new helper function - ipv6_gro_pull_exthdrs -
which is used in ipv6_gro_receive to pull ipv6 ext headers instead of
ipv6_gso_pull_exthdrs. Thus, there is no modification of skb->data, all
operations use skb_gro_* helpers, and the frag0 fast path can be taken for
IPv6 packets with ext headers.
Signed-off-by: Richard Gobert <richardbgobert@gmail.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://lore.kernel.org/r/504130f6-b56c-4dcc-882c-97942c59f5b7@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
--- a/net/ipv6/ip6_offload.c
+++ b/net/ipv6/ip6_offload.c
@@ -37,6 +37,40 @@
INDIRECT_CALL_L4(cb, f2, f1, head, skb); \
})
+static int ipv6_gro_pull_exthdrs(struct sk_buff *skb, int off, int proto)
+{
+ const struct net_offload *ops = NULL;
+ struct ipv6_opt_hdr *opth;
+
+ for (;;) {
+ int len;
+
+ ops = rcu_dereference(inet6_offloads[proto]);
+
+ if (unlikely(!ops))
+ break;
+
+ if (!(ops->flags & INET6_PROTO_GSO_EXTHDR))
+ break;
+
+ opth = skb_gro_header(skb, off + sizeof(*opth), off);
+ if (unlikely(!opth))
+ break;
+
+ len = ipv6_optlen(opth);
+
+ opth = skb_gro_header(skb, off + len, off);
+ if (unlikely(!opth))
+ break;
+ proto = opth->nexthdr;
+
+ off += len;
+ }
+
+ skb_gro_pull(skb, off - skb_network_offset(skb));
+ return proto;
+}
+
static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto)
{
const struct net_offload *ops = NULL;
@@ -206,28 +240,25 @@ INDIRECT_CALLABLE_SCOPE struct sk_buff *
goto out;
skb_set_network_header(skb, off);
- skb_gro_pull(skb, sizeof(*iph));
- skb_set_transport_header(skb, skb_gro_offset(skb));
- flush += ntohs(iph->payload_len) != skb_gro_len(skb);
+ flush += ntohs(iph->payload_len) != skb->len - hlen;
proto = iph->nexthdr;
ops = rcu_dereference(inet6_offloads[proto]);
if (!ops || !ops->callbacks.gro_receive) {
- pskb_pull(skb, skb_gro_offset(skb));
- skb_gro_frag0_invalidate(skb);
- proto = ipv6_gso_pull_exthdrs(skb, proto);
- skb_gro_pull(skb, -skb_transport_offset(skb));
- skb_reset_transport_header(skb);
- __skb_push(skb, skb_gro_offset(skb));
+ proto = ipv6_gro_pull_exthdrs(skb, hlen, proto);
ops = rcu_dereference(inet6_offloads[proto]);
if (!ops || !ops->callbacks.gro_receive)
goto out;
- iph = ipv6_hdr(skb);
+ iph = skb_gro_network_header(skb);
+ } else {
+ skb_gro_pull(skb, sizeof(*iph));
}
+ skb_set_transport_header(skb, skb_gro_offset(skb));
+
NAPI_GRO_CB(skb)->proto = proto;
flush--;

View File

@@ -0,0 +1,178 @@
From: Richard Gobert <richardbgobert@gmail.com>
Date: Tue, 30 Apr 2024 16:35:54 +0200
Subject: [PATCH] net: gro: fix udp bad offset in socket lookup by adding
{inner_}network_offset to napi_gro_cb
Commits a602456 ("udp: Add GRO functions to UDP socket") and 57c67ff ("udp:
additional GRO support") introduce incorrect usage of {ip,ipv6}_hdr in the
complete phase of gro. The functions always return skb->network_header,
which in the case of encapsulated packets at the gro complete phase, is
always set to the innermost L3 of the packet. That means that calling
{ip,ipv6}_hdr for skbs which completed the GRO receive phase (both in
gro_list and *_gro_complete) when parsing an encapsulated packet's _outer_
L3/L4 may return an unexpected value.
This incorrect usage leads to a bug in GRO's UDP socket lookup.
udp{4,6}_lib_lookup_skb functions use ip_hdr/ipv6_hdr respectively. These
*_hdr functions return network_header which will point to the innermost L3,
resulting in the wrong offset being used in __udp{4,6}_lib_lookup with
encapsulated packets.
This patch adds network_offset and inner_network_offset to napi_gro_cb, and
makes sure both are set correctly.
To fix the issue, network_offsets union is used inside napi_gro_cb, in
which both the outer and the inner network offsets are saved.
Reproduction example:
Endpoint configuration example (fou + local address bind)
# ip fou add port 6666 ipproto 4
# ip link add name tun1 type ipip remote 2.2.2.1 local 2.2.2.2 encap fou encap-dport 5555 encap-sport 6666 mode ipip
# ip link set tun1 up
# ip a add 1.1.1.2/24 dev tun1
Netperf TCP_STREAM result on net-next before patch is applied:
net-next main, GRO enabled:
$ netperf -H 1.1.1.2 -t TCP_STREAM -l 5
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
131072 16384 16384 5.28 2.37
net-next main, GRO disabled:
$ netperf -H 1.1.1.2 -t TCP_STREAM -l 5
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
131072 16384 16384 5.01 2745.06
patch applied, GRO enabled:
$ netperf -H 1.1.1.2 -t TCP_STREAM -l 5
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
131072 16384 16384 5.01 2877.38
Fixes: a6024562ffd7 ("udp: Add GRO functions to UDP socket")
Signed-off-by: Richard Gobert <richardbgobert@gmail.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
--- a/include/net/gro.h
+++ b/include/net/gro.h
@@ -86,6 +86,15 @@ struct napi_gro_cb {
/* used to support CHECKSUM_COMPLETE for tunneling protocols */
__wsum csum;
+
+ /* L3 offsets */
+ union {
+ struct {
+ u16 network_offset;
+ u16 inner_network_offset;
+ };
+ u16 network_offsets[2];
+ };
};
#define NAPI_GRO_CB(skb) ((struct napi_gro_cb *)(skb)->cb)
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -478,6 +478,8 @@ static struct sk_buff *vlan_gro_receive(
if (unlikely(!vhdr))
goto out;
+ NAPI_GRO_CB(skb)->network_offsets[NAPI_GRO_CB(skb)->encap_mark] = hlen;
+
type = vhdr->h_vlan_encapsulated_proto;
ptype = gro_find_receive_by_type(type);
--- a/net/core/gro.c
+++ b/net/core/gro.c
@@ -373,6 +373,7 @@ static inline void skb_gro_reset_offset(
const struct skb_shared_info *pinfo = skb_shinfo(skb);
const skb_frag_t *frag0 = &pinfo->frags[0];
+ NAPI_GRO_CB(skb)->network_offset = 0;
NAPI_GRO_CB(skb)->data_offset = 0;
NAPI_GRO_CB(skb)->frag0 = NULL;
NAPI_GRO_CB(skb)->frag0_len = 0;
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1571,6 +1571,7 @@ struct sk_buff *inet_gro_receive(struct
/* The above will be needed by the transport layer if there is one
* immediately following this IP hdr.
*/
+ NAPI_GRO_CB(skb)->inner_network_offset = off;
/* Note : No need to call skb_gro_postpull_rcsum() here,
* as we already checked checksum over ipv4 header was 0
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -534,7 +534,8 @@ static inline struct sock *__udp4_lib_lo
struct sock *udp4_lib_lookup_skb(const struct sk_buff *skb,
__be16 sport, __be16 dport)
{
- const struct iphdr *iph = ip_hdr(skb);
+ const u16 offset = NAPI_GRO_CB(skb)->network_offsets[skb->encapsulation];
+ const struct iphdr *iph = (struct iphdr *)(skb->data + offset);
struct net *net = dev_net(skb->dev);
int iif, sdif;
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -718,7 +718,8 @@ EXPORT_SYMBOL(udp_gro_complete);
INDIRECT_CALLABLE_SCOPE int udp4_gro_complete(struct sk_buff *skb, int nhoff)
{
- const struct iphdr *iph = ip_hdr(skb);
+ const u16 offset = NAPI_GRO_CB(skb)->network_offsets[skb->encapsulation];
+ const struct iphdr *iph = (struct iphdr *)(skb->data + offset);
struct udphdr *uh = (struct udphdr *)(skb->data + nhoff);
/* do fraglist only if there is no outer UDP encap (or we already processed it) */
--- a/net/ipv6/ip6_offload.c
+++ b/net/ipv6/ip6_offload.c
@@ -240,6 +240,7 @@ INDIRECT_CALLABLE_SCOPE struct sk_buff *
goto out;
skb_set_network_header(skb, off);
+ NAPI_GRO_CB(skb)->inner_network_offset = off;
flush += ntohs(iph->payload_len) != skb->len - hlen;
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -275,7 +275,8 @@ static struct sock *__udp6_lib_lookup_sk
struct sock *udp6_lib_lookup_skb(const struct sk_buff *skb,
__be16 sport, __be16 dport)
{
- const struct ipv6hdr *iph = ipv6_hdr(skb);
+ const u16 offset = NAPI_GRO_CB(skb)->network_offsets[skb->encapsulation];
+ const struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + offset);
struct net *net = dev_net(skb->dev);
int iif, sdif;
--- a/net/ipv6/udp_offload.c
+++ b/net/ipv6/udp_offload.c
@@ -164,7 +164,8 @@ flush:
INDIRECT_CALLABLE_SCOPE int udp6_gro_complete(struct sk_buff *skb, int nhoff)
{
- const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+ const u16 offset = NAPI_GRO_CB(skb)->network_offsets[skb->encapsulation];
+ const struct ipv6hdr *ipv6h = (struct ipv6hdr *)(skb->data + offset);
struct udphdr *uh = (struct udphdr *)(skb->data + nhoff);
/* do fraglist only if there is no outer UDP encap (or we already processed it) */

View File

@@ -0,0 +1,48 @@
From: Richard Gobert <richardbgobert@gmail.com>
Date: Tue, 30 Apr 2024 16:35:55 +0200
Subject: [PATCH] net: gro: add flush check in udp_gro_receive_segment
GRO-GSO path is supposed to be transparent and as such L3 flush checks are
relevant to all UDP flows merging in GRO. This patch uses the same logic
and code from tcp_gro_receive, terminating merge if flush is non zero.
Fixes: e20cf8d3f1f7 ("udp: implement GRO for plain UDP sockets.")
Signed-off-by: Richard Gobert <richardbgobert@gmail.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -471,6 +471,7 @@ static struct sk_buff *udp_gro_receive_s
struct sk_buff *p;
unsigned int ulen;
int ret = 0;
+ int flush;
/* requires non zero csum, for symmetry with GSO */
if (!uh->check) {
@@ -504,13 +505,22 @@ static struct sk_buff *udp_gro_receive_s
return p;
}
+ flush = NAPI_GRO_CB(p)->flush;
+
+ if (NAPI_GRO_CB(p)->flush_id != 1 ||
+ NAPI_GRO_CB(p)->count != 1 ||
+ !NAPI_GRO_CB(p)->is_atomic)
+ flush |= NAPI_GRO_CB(p)->flush_id;
+ else
+ NAPI_GRO_CB(p)->is_atomic = false;
+
/* Terminate the flow on len mismatch or if it grow "too much".
* Under small packet flood GRO count could elsewhere grow a lot
* leading to excessive truesize values.
* On len mismatch merge the first packet shorter than gso_size,
* otherwise complete the GRO packet.
*/
- if (ulen > ntohs(uh2->len)) {
+ if (ulen > ntohs(uh2->len) || flush) {
pp = p;
} else {
if (NAPI_GRO_CB(skb)->is_flist) {

View File

@@ -1,87 +0,0 @@
From: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Thu, 11 Apr 2024 13:28:59 +0200
Subject: [PATCH] netfilter: flowtable: validate pppoe header
Ensure there is sufficient room to access the protocol field of the
PPPoe header. Validate it once before the flowtable lookup, then use a
helper function to access protocol field.
Reported-by: syzbot+b6f07e1c07ef40199081@syzkaller.appspotmail.com
Fixes: 72efd585f714 ("netfilter: flowtable: add pppoe support")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -335,7 +335,7 @@ int nf_flow_rule_route_ipv6(struct net *
int nf_flow_table_offload_init(void);
void nf_flow_table_offload_exit(void);
-static inline __be16 nf_flow_pppoe_proto(const struct sk_buff *skb)
+static inline __be16 __nf_flow_pppoe_proto(const struct sk_buff *skb)
{
__be16 proto;
@@ -351,6 +351,16 @@ static inline __be16 nf_flow_pppoe_proto
return 0;
}
+static inline bool nf_flow_pppoe_proto(struct sk_buff *skb, __be16 *inner_proto)
+{
+ if (!pskb_may_pull(skb, PPPOE_SES_HLEN))
+ return false;
+
+ *inner_proto = __nf_flow_pppoe_proto(skb);
+
+ return true;
+}
+
#define NF_FLOW_TABLE_STAT_INC(net, count) __this_cpu_inc((net)->ft.stat->count)
#define NF_FLOW_TABLE_STAT_DEC(net, count) __this_cpu_dec((net)->ft.stat->count)
#define NF_FLOW_TABLE_STAT_INC_ATOMIC(net, count) \
--- a/net/netfilter/nf_flow_table_inet.c
+++ b/net/netfilter/nf_flow_table_inet.c
@@ -21,7 +21,8 @@ nf_flow_offload_inet_hook(void *priv, st
proto = veth->h_vlan_encapsulated_proto;
break;
case htons(ETH_P_PPP_SES):
- proto = nf_flow_pppoe_proto(skb);
+ if (!nf_flow_pppoe_proto(skb, &proto))
+ return NF_ACCEPT;
break;
default:
proto = skb->protocol;
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -273,10 +273,11 @@ static unsigned int nf_flow_xmit_xfrm(st
return NF_STOLEN;
}
-static bool nf_flow_skb_encap_protocol(const struct sk_buff *skb, __be16 proto,
+static bool nf_flow_skb_encap_protocol(struct sk_buff *skb, __be16 proto,
u32 *offset)
{
struct vlan_ethhdr *veth;
+ __be16 inner_proto;
switch (skb->protocol) {
case htons(ETH_P_8021Q):
@@ -287,7 +288,8 @@ static bool nf_flow_skb_encap_protocol(c
}
break;
case htons(ETH_P_PPP_SES):
- if (nf_flow_pppoe_proto(skb) == proto) {
+ if (nf_flow_pppoe_proto(skb, &inner_proto) &&
+ inner_proto == proto) {
*offset += PPPOE_SES_HLEN;
return true;
}
@@ -316,7 +318,7 @@ static void nf_flow_encap_pop(struct sk_
skb_reset_network_header(skb);
break;
case htons(ETH_P_PPP_SES):
- skb->protocol = nf_flow_pppoe_proto(skb);
+ skb->protocol = __nf_flow_pppoe_proto(skb);
skb_pull(skb, PPPOE_SES_HLEN);
skb_reset_network_header(skb);
break;

View File

@@ -1,24 +0,0 @@
From: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Thu, 11 Apr 2024 13:29:00 +0200
Subject: [PATCH] netfilter: flowtable: incorrect pppoe tuple
pppoe traffic reaching ingress path does not match the flowtable entry
because the pppoe header is expected to be at the network header offset.
This bug causes a mismatch in the flow table lookup, so pppoe packets
enter the classical forwarding path.
Fixes: 72efd585f714 ("netfilter: flowtable: add pppoe support")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -157,7 +157,7 @@ static void nf_flow_tuple_encap(struct s
tuple->encap[i].proto = skb->protocol;
break;
case htons(ETH_P_PPP_SES):
- phdr = (struct pppoe_hdr *)skb_mac_header(skb);
+ phdr = (struct pppoe_hdr *)skb_network_header(skb);
tuple->encap[i].id = ntohs(phdr->sid);
tuple->encap[i].proto = skb->protocol;
break;

View File

@@ -14,7 +14,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
--- a/drivers/net/ethernet/mediatek/mtk_wed.c
+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
@@ -1713,19 +1713,20 @@ mtk_wed_irq_set_mask(struct mtk_wed_devi
@@ -1709,19 +1709,20 @@ mtk_wed_irq_set_mask(struct mtk_wed_devi
int mtk_wed_flow_add(int index)
{
struct mtk_wed_hw *hw = hw_list[index];
@@ -44,7 +44,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
goto out;
}
@@ -1744,14 +1745,15 @@ void mtk_wed_flow_remove(int index)
@@ -1740,14 +1741,15 @@ void mtk_wed_flow_remove(int index)
{
struct mtk_wed_hw *hw = hw_list[index];

View File

@@ -52,15 +52,15 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
wdma_clr(dev, MTK_WDMA_GLO_CFG,
MTK_WDMA_GLO_CFG_RX_INFO3_PRERES);
@@ -606,7 +606,7 @@ mtk_wed_stop(struct mtk_wed_device *dev)
wdma_w32(dev, MTK_WDMA_INT_MASK, 0);
wdma_w32(dev, MTK_WDMA_INT_GRP2, 0);
wed_w32(dev, MTK_WED_WPDMA_INT_MASK, 0);
- if (dev->hw->version == 1)
+ if (mtk_wed_is_v1(dev->hw))
return;
wed_w32(dev, MTK_WED_EXT_INT_MASK1, 0);
@@ -625,7 +625,7 @@ mtk_wed_deinit(struct mtk_wed_device *de
@@ -624,7 +624,7 @@ mtk_wed_deinit(struct mtk_wed_device *de
MTK_WED_CTRL_WED_TX_BM_EN |
MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
@@ -69,7 +69,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
return;
wed_clr(dev, MTK_WED_CTRL,
@@ -731,7 +731,7 @@ mtk_wed_bus_init(struct mtk_wed_device *
@@ -730,7 +730,7 @@ mtk_wed_bus_init(struct mtk_wed_device *
static void
mtk_wed_set_wpdma(struct mtk_wed_device *dev)
{
@@ -78,7 +78,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_phys);
} else {
mtk_wed_bus_init(dev);
@@ -762,7 +762,7 @@ mtk_wed_hw_init_early(struct mtk_wed_dev
@@ -761,7 +761,7 @@ mtk_wed_hw_init_early(struct mtk_wed_dev
MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY;
wed_m32(dev, MTK_WED_WDMA_GLO_CFG, mask, set);
@@ -87,7 +87,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
u32 offset = dev->hw->index ? 0x04000400 : 0;
wdma_set(dev, MTK_WDMA_GLO_CFG,
@@ -935,7 +935,7 @@ mtk_wed_hw_init(struct mtk_wed_device *d
@@ -934,7 +934,7 @@ mtk_wed_hw_init(struct mtk_wed_device *d
wed_w32(dev, MTK_WED_TX_BM_BUF_LEN, MTK_WED_PKT_SIZE);
@@ -96,7 +96,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
wed_w32(dev, MTK_WED_TX_BM_TKID,
FIELD_PREP(MTK_WED_TX_BM_TKID_START,
dev->wlan.token_start) |
@@ -968,7 +968,7 @@ mtk_wed_hw_init(struct mtk_wed_device *d
@@ -967,7 +967,7 @@ mtk_wed_hw_init(struct mtk_wed_device *d
mtk_wed_reset(dev, MTK_WED_RESET_TX_BM);
@@ -105,7 +105,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
wed_set(dev, MTK_WED_CTRL,
MTK_WED_CTRL_WED_TX_BM_EN |
MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
@@ -1218,7 +1218,7 @@ mtk_wed_reset_dma(struct mtk_wed_device
@@ -1217,7 +1217,7 @@ mtk_wed_reset_dma(struct mtk_wed_device
}
dev->init_done = false;
@@ -114,7 +114,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
return;
if (!busy) {
@@ -1344,7 +1344,7 @@ mtk_wed_configure_irq(struct mtk_wed_dev
@@ -1343,7 +1343,7 @@ mtk_wed_configure_irq(struct mtk_wed_dev
MTK_WED_CTRL_WED_TX_BM_EN |
MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
@@ -123,7 +123,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER,
MTK_WED_PCIE_INT_TRIGGER_STATUS);
@@ -1417,7 +1417,7 @@ mtk_wed_dma_enable(struct mtk_wed_device
@@ -1416,7 +1416,7 @@ mtk_wed_dma_enable(struct mtk_wed_device
MTK_WDMA_GLO_CFG_RX_INFO1_PRERES |
MTK_WDMA_GLO_CFG_RX_INFO2_PRERES);
@@ -132,7 +132,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
wdma_set(dev, MTK_WDMA_GLO_CFG,
MTK_WDMA_GLO_CFG_RX_INFO3_PRERES);
} else {
@@ -1466,7 +1466,7 @@ mtk_wed_start(struct mtk_wed_device *dev
@@ -1465,7 +1465,7 @@ mtk_wed_start(struct mtk_wed_device *dev
mtk_wed_set_ext_int(dev, true);
@@ -141,7 +141,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
u32 val = dev->wlan.wpdma_phys | MTK_PCIE_MIRROR_MAP_EN |
FIELD_PREP(MTK_PCIE_MIRROR_MAP_WED_ID,
dev->hw->index);
@@ -1551,7 +1551,7 @@ mtk_wed_attach(struct mtk_wed_device *de
@@ -1550,7 +1550,7 @@ mtk_wed_attach(struct mtk_wed_device *de
}
mtk_wed_hw_init_early(dev);
@@ -150,7 +150,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP,
BIT(hw->index), 0);
} else {
@@ -1619,7 +1619,7 @@ static int
@@ -1618,7 +1618,7 @@ static int
mtk_wed_txfree_ring_setup(struct mtk_wed_device *dev, void __iomem *regs)
{
struct mtk_wed_ring *ring = &dev->txfree_ring;
@@ -159,7 +159,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
/*
* For txfree event handling, the same DMA ring is shared between WED
@@ -1677,7 +1677,7 @@ mtk_wed_irq_get(struct mtk_wed_device *d
@@ -1676,7 +1676,7 @@ mtk_wed_irq_get(struct mtk_wed_device *d
{
u32 val, ext_mask = MTK_WED_EXT_INT_STATUS_ERROR_MASK;
@@ -168,7 +168,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
ext_mask |= MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR;
else
ext_mask |= MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH |
@@ -1844,7 +1844,7 @@ mtk_wed_setup_tc(struct mtk_wed_device *
@@ -1840,7 +1840,7 @@ mtk_wed_setup_tc(struct mtk_wed_device *
{
struct mtk_wed_hw *hw = wed->hw;
@@ -177,7 +177,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
return -EOPNOTSUPP;
switch (type) {
@@ -1918,9 +1918,9 @@ void mtk_wed_add_hw(struct device_node *
@@ -1914,9 +1914,9 @@ void mtk_wed_add_hw(struct device_node *
hw->wdma = wdma;
hw->index = index;
hw->irq = irq;

View File

@@ -16,15 +16,15 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
--- a/drivers/net/ethernet/mediatek/mtk_wed.c
+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
@@ -606,7 +606,7 @@ mtk_wed_stop(struct mtk_wed_device *dev)
wdma_w32(dev, MTK_WDMA_INT_MASK, 0);
wdma_w32(dev, MTK_WDMA_INT_GRP2, 0);
wed_w32(dev, MTK_WED_WPDMA_INT_MASK, 0);
- if (mtk_wed_is_v1(dev->hw))
+ if (!mtk_wed_get_rx_capa(dev))
return;
wed_w32(dev, MTK_WED_EXT_INT_MASK1, 0);
@@ -733,16 +733,21 @@ mtk_wed_set_wpdma(struct mtk_wed_device
@@ -732,16 +732,21 @@ mtk_wed_set_wpdma(struct mtk_wed_device
{
if (mtk_wed_is_v1(dev->hw)) {
wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_phys);
@@ -55,7 +55,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
}
static void
@@ -974,15 +979,17 @@ mtk_wed_hw_init(struct mtk_wed_device *d
@@ -973,15 +978,17 @@ mtk_wed_hw_init(struct mtk_wed_device *d
MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
} else {
wed_clr(dev, MTK_WED_TX_TKID_CTRL, MTK_WED_TX_TKID_CTRL_PAUSE);
@@ -82,7 +82,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
}
wed_clr(dev, MTK_WED_TX_BM_CTRL, MTK_WED_TX_BM_CTRL_PAUSE);
@@ -1354,8 +1361,6 @@ mtk_wed_configure_irq(struct mtk_wed_dev
@@ -1353,8 +1360,6 @@ mtk_wed_configure_irq(struct mtk_wed_dev
wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask);
} else {
@@ -91,7 +91,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
/* initail tx interrupt trigger */
wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX,
MTK_WED_WPDMA_INT_CTRL_TX0_DONE_EN |
@@ -1374,15 +1379,20 @@ mtk_wed_configure_irq(struct mtk_wed_dev
@@ -1373,15 +1378,20 @@ mtk_wed_configure_irq(struct mtk_wed_dev
FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_TRIG,
dev->wlan.txfree_tbit));
@@ -121,7 +121,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
wed_w32(dev, MTK_WED_WDMA_INT_CLR, wdma_mask);
wed_set(dev, MTK_WED_WDMA_INT_CTRL,
@@ -1401,6 +1411,8 @@ mtk_wed_configure_irq(struct mtk_wed_dev
@@ -1400,6 +1410,8 @@ mtk_wed_configure_irq(struct mtk_wed_dev
static void
mtk_wed_dma_enable(struct mtk_wed_device *dev)
{
@@ -130,7 +130,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
wed_set(dev, MTK_WED_WPDMA_INT_CTRL, MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV);
wed_set(dev, MTK_WED_GLO_CFG,
@@ -1420,33 +1432,33 @@ mtk_wed_dma_enable(struct mtk_wed_device
@@ -1419,33 +1431,33 @@ mtk_wed_dma_enable(struct mtk_wed_device
if (mtk_wed_is_v1(dev->hw)) {
wdma_set(dev, MTK_WDMA_GLO_CFG,
MTK_WDMA_GLO_CFG_RX_INFO3_PRERES);
@@ -186,7 +186,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
}
static void
@@ -1473,7 +1485,7 @@ mtk_wed_start(struct mtk_wed_device *dev
@@ -1472,7 +1484,7 @@ mtk_wed_start(struct mtk_wed_device *dev
val |= BIT(0) | (BIT(1) * !!dev->hw->index);
regmap_write(dev->hw->mirror, dev->hw->index * 4, val);
@@ -195,7 +195,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
/* driver set mid ready and only once */
wed_w32(dev, MTK_WED_EXT_INT_MASK1,
MTK_WED_EXT_INT_STATUS_WPDMA_MID_RDY);
@@ -1485,7 +1497,6 @@ mtk_wed_start(struct mtk_wed_device *dev
@@ -1484,7 +1496,6 @@ mtk_wed_start(struct mtk_wed_device *dev
if (mtk_wed_rro_cfg(dev))
return;
@@ -203,7 +203,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
}
mtk_wed_set_512_support(dev, dev->wlan.wcid_512);
@@ -1551,13 +1562,14 @@ mtk_wed_attach(struct mtk_wed_device *de
@@ -1550,13 +1561,14 @@ mtk_wed_attach(struct mtk_wed_device *de
}
mtk_wed_hw_init_early(dev);

View File

@@ -38,7 +38,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
static void
wed_m32(struct mtk_wed_device *dev, u32 reg, u32 mask, u32 val)
{
@@ -747,7 +767,7 @@ mtk_wed_set_wpdma(struct mtk_wed_device
@@ -746,7 +766,7 @@ mtk_wed_set_wpdma(struct mtk_wed_device
return;
wed_w32(dev, MTK_WED_WPDMA_RX_GLO_CFG, dev->wlan.wpdma_rx_glo);
@@ -47,7 +47,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
}
static void
@@ -941,22 +961,10 @@ mtk_wed_hw_init(struct mtk_wed_device *d
@@ -940,22 +960,10 @@ mtk_wed_hw_init(struct mtk_wed_device *d
wed_w32(dev, MTK_WED_TX_BM_BUF_LEN, MTK_WED_PKT_SIZE);
if (mtk_wed_is_v1(dev->hw)) {
@@ -70,7 +70,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
wed_w32(dev, MTK_WED_TX_BM_DYN_THR,
FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO_V2, 0) |
MTK_WED_TX_BM_DYN_THR_HI_V2);
@@ -971,6 +979,11 @@ mtk_wed_hw_init(struct mtk_wed_device *d
@@ -970,6 +978,11 @@ mtk_wed_hw_init(struct mtk_wed_device *d
MTK_WED_TX_TKID_DYN_THR_HI);
}
@@ -82,7 +82,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
mtk_wed_reset(dev, MTK_WED_RESET_TX_BM);
if (mtk_wed_is_v1(dev->hw)) {
@@ -1105,13 +1118,8 @@ mtk_wed_rx_reset(struct mtk_wed_device *
@@ -1104,13 +1117,8 @@ mtk_wed_rx_reset(struct mtk_wed_device *
if (ret) {
mtk_wed_reset(dev, MTK_WED_RESET_WED_RX_DMA);
} else {
@@ -98,7 +98,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
wed_w32(dev, MTK_WED_RESET_IDX, 0);
}
@@ -1164,7 +1172,8 @@ mtk_wed_reset_dma(struct mtk_wed_device
@@ -1163,7 +1171,8 @@ mtk_wed_reset_dma(struct mtk_wed_device
if (busy) {
mtk_wed_reset(dev, MTK_WED_RESET_WED_TX_DMA);
} else {
@@ -108,7 +108,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
wed_w32(dev, MTK_WED_RESET_IDX, 0);
}
@@ -1256,7 +1265,6 @@ static int
@@ -1255,7 +1264,6 @@ static int
mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev, int idx, int size,
bool reset)
{
@@ -116,7 +116,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
struct mtk_wed_ring *wdma;
if (idx >= ARRAY_SIZE(dev->rx_wdma))
@@ -1264,7 +1272,7 @@ mtk_wed_wdma_rx_ring_setup(struct mtk_we
@@ -1263,7 +1271,7 @@ mtk_wed_wdma_rx_ring_setup(struct mtk_we
wdma = &dev->rx_wdma[idx];
if (!reset && mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
@@ -125,7 +125,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
return -ENOMEM;
wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_BASE,
@@ -1285,7 +1293,6 @@ static int
@@ -1284,7 +1292,6 @@ static int
mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev, int idx, int size,
bool reset)
{
@@ -133,7 +133,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
struct mtk_wed_ring *wdma;
if (idx >= ARRAY_SIZE(dev->tx_wdma))
@@ -1293,7 +1300,7 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_we
@@ -1292,7 +1299,7 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_we
wdma = &dev->tx_wdma[idx];
if (!reset && mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
@@ -142,7 +142,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
return -ENOMEM;
wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_BASE,
@@ -1932,7 +1939,12 @@ void mtk_wed_add_hw(struct device_node *
@@ -1928,7 +1935,12 @@ void mtk_wed_add_hw(struct device_node *
hw->irq = irq;
hw->version = eth->soc->version;
@@ -156,7 +156,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
hw->mirror = syscon_regmap_lookup_by_phandle(eth_np,
"mediatek,pcie-mirror");
hw->hifsys = syscon_regmap_lookup_by_phandle(eth_np,
@@ -1946,6 +1958,8 @@ void mtk_wed_add_hw(struct device_node *
@@ -1942,6 +1954,8 @@ void mtk_wed_add_hw(struct device_node *
regmap_write(hw->mirror, 0, 0);
regmap_write(hw->mirror, 4, 0);
}

View File

@@ -302,7 +302,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
}
mtk_wed_set_512_support(dev, false);
@@ -652,6 +699,14 @@ mtk_wed_deinit(struct mtk_wed_device *de
@@ -651,6 +698,14 @@ mtk_wed_deinit(struct mtk_wed_device *de
MTK_WED_CTRL_RX_ROUTE_QM_EN |
MTK_WED_CTRL_WED_RX_BM_EN |
MTK_WED_CTRL_RX_RRO_QM_EN);
@@ -317,7 +317,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
}
static void
@@ -701,21 +756,37 @@ mtk_wed_detach(struct mtk_wed_device *de
@@ -700,21 +755,37 @@ mtk_wed_detach(struct mtk_wed_device *de
mutex_unlock(&hw_lock);
}
@@ -362,7 +362,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
wed_w32(dev, MTK_WED_PCIE_INT_CTRL,
FIELD_PREP(MTK_WED_PCIE_INT_CTRL_POLL_EN, 2));
@@ -723,19 +794,9 @@ mtk_wed_bus_init(struct mtk_wed_device *
@@ -722,19 +793,9 @@ mtk_wed_bus_init(struct mtk_wed_device *
/* pcie interrupt control: pola/source selection */
wed_set(dev, MTK_WED_PCIE_INT_CTRL,
MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA |
@@ -385,7 +385,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
break;
}
case MTK_WED_BUS_AXI:
@@ -773,18 +834,19 @@ mtk_wed_set_wpdma(struct mtk_wed_device
@@ -772,18 +833,19 @@ mtk_wed_set_wpdma(struct mtk_wed_device
static void
mtk_wed_hw_init_early(struct mtk_wed_device *dev)
{
@@ -412,7 +412,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
wed_m32(dev, MTK_WED_WDMA_GLO_CFG, mask, set);
if (mtk_wed_is_v1(dev->hw)) {
@@ -932,11 +994,18 @@ mtk_wed_route_qm_hw_init(struct mtk_wed_
@@ -931,11 +993,18 @@ mtk_wed_route_qm_hw_init(struct mtk_wed_
}
/* configure RX_ROUTE_QM */
@@ -436,7 +436,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
/* enable RX_ROUTE_QM */
wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_ROUTE_QM_EN);
}
@@ -949,22 +1018,30 @@ mtk_wed_hw_init(struct mtk_wed_device *d
@@ -948,22 +1017,30 @@ mtk_wed_hw_init(struct mtk_wed_device *d
dev->init_done = true;
mtk_wed_set_ext_int(dev, false);
@@ -475,7 +475,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
wed_w32(dev, MTK_WED_TX_BM_DYN_THR,
FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO_V2, 0) |
MTK_WED_TX_BM_DYN_THR_HI_V2);
@@ -974,9 +1051,6 @@ mtk_wed_hw_init(struct mtk_wed_device *d
@@ -973,9 +1050,6 @@ mtk_wed_hw_init(struct mtk_wed_device *d
dev->tx_buf_ring.size / 128) |
FIELD_PREP(MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM,
dev->tx_buf_ring.size / 128));
@@ -485,7 +485,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
}
wed_w32(dev, dev->hw->soc->regmap.tx_bm_tkid,
@@ -986,26 +1060,62 @@ mtk_wed_hw_init(struct mtk_wed_device *d
@@ -985,26 +1059,62 @@ mtk_wed_hw_init(struct mtk_wed_device *d
mtk_wed_reset(dev, MTK_WED_RESET_TX_BM);
@@ -561,7 +561,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
}
static void
@@ -1303,6 +1413,24 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_we
@@ -1302,6 +1412,24 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_we
dev->hw->soc->wdma_desc_size, true))
return -ENOMEM;
@@ -586,7 +586,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_BASE,
wdma->desc_phys);
wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_COUNT,
@@ -1368,6 +1496,9 @@ mtk_wed_configure_irq(struct mtk_wed_dev
@@ -1367,6 +1495,9 @@ mtk_wed_configure_irq(struct mtk_wed_dev
wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask);
} else {
@@ -596,7 +596,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
/* initail tx interrupt trigger */
wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX,
MTK_WED_WPDMA_INT_CTRL_TX0_DONE_EN |
@@ -1420,33 +1551,60 @@ mtk_wed_dma_enable(struct mtk_wed_device
@@ -1419,33 +1550,60 @@ mtk_wed_dma_enable(struct mtk_wed_device
{
int i;
@@ -668,7 +668,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP |
MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV);
@@ -1458,11 +1616,22 @@ mtk_wed_dma_enable(struct mtk_wed_device
@@ -1457,11 +1615,22 @@ mtk_wed_dma_enable(struct mtk_wed_device
MTK_WED_WDMA_GLO_CFG_TX_DRV_EN |
MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK);
@@ -693,7 +693,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
for (i = 0; i < MTK_WED_RX_QUEUES; i++)
mtk_wed_check_wfdma_rx_fill(dev, i);
@@ -1502,6 +1671,12 @@ mtk_wed_start(struct mtk_wed_device *dev
@@ -1501,6 +1670,12 @@ mtk_wed_start(struct mtk_wed_device *dev
wed_r32(dev, MTK_WED_EXT_INT_MASK1);
wed_r32(dev, MTK_WED_EXT_INT_MASK2);
@@ -706,7 +706,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
if (mtk_wed_rro_cfg(dev))
return;
}
@@ -1553,6 +1728,7 @@ mtk_wed_attach(struct mtk_wed_device *de
@@ -1552,6 +1727,7 @@ mtk_wed_attach(struct mtk_wed_device *de
dev->irq = hw->irq;
dev->wdma_idx = hw->index;
dev->version = hw->version;
@@ -714,7 +714,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
if (hw->eth->dma_dev == hw->eth->dev &&
of_dma_is_coherent(hw->eth->dev->of_node))
@@ -1620,6 +1796,23 @@ mtk_wed_tx_ring_setup(struct mtk_wed_dev
@@ -1619,6 +1795,23 @@ mtk_wed_tx_ring_setup(struct mtk_wed_dev
ring->reg_base = MTK_WED_RING_TX(idx);
ring->wpdma = regs;
@@ -738,7 +738,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
/* WED -> WPDMA */
wpdma_tx_w32(dev, idx, MTK_WED_RING_OFS_BASE, ring->desc_phys);
wpdma_tx_w32(dev, idx, MTK_WED_RING_OFS_COUNT, MTK_WED_TX_RING_SIZE);
@@ -1694,15 +1887,13 @@ mtk_wed_rx_ring_setup(struct mtk_wed_dev
@@ -1693,15 +1886,13 @@ mtk_wed_rx_ring_setup(struct mtk_wed_dev
static u32
mtk_wed_irq_get(struct mtk_wed_device *dev, u32 mask)
{
@@ -759,7 +759,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
val = wed_r32(dev, MTK_WED_EXT_INT_STATUS);
wed_w32(dev, MTK_WED_EXT_INT_STATUS, val);
@@ -1943,6 +2134,9 @@ void mtk_wed_add_hw(struct device_node *
@@ -1939,6 +2130,9 @@ void mtk_wed_add_hw(struct device_node *
case 2:
hw->soc = &mt7986_data;
break;

View File

@@ -56,7 +56,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
}
static void
@@ -1546,6 +1537,7 @@ mtk_wed_configure_irq(struct mtk_wed_dev
@@ -1545,6 +1536,7 @@ mtk_wed_configure_irq(struct mtk_wed_dev
wed_w32(dev, MTK_WED_INT_MASK, irq_mask);
}
@@ -64,7 +64,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
static void
mtk_wed_dma_enable(struct mtk_wed_device *dev)
{
@@ -1633,8 +1625,26 @@ mtk_wed_dma_enable(struct mtk_wed_device
@@ -1632,8 +1624,26 @@ mtk_wed_dma_enable(struct mtk_wed_device
wdma_set(dev, MTK_WDMA_WRBK_TX_CFG, MTK_WDMA_WRBK_TX_CFG_WRBK_EN);
}

View File

@@ -248,7 +248,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
{
u32 desc_size = dev->hw->soc->tx_ring_desc_size;
@@ -709,6 +840,7 @@ __mtk_wed_detach(struct mtk_wed_device *
@@ -708,6 +839,7 @@ __mtk_wed_detach(struct mtk_wed_device *
mtk_wdma_rx_reset(dev);
mtk_wed_reset(dev, MTK_WED_RESET_WED);
@@ -256,7 +256,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
mtk_wed_free_tx_buffer(dev);
mtk_wed_free_tx_rings(dev);
@@ -1129,23 +1261,6 @@ mtk_wed_ring_reset(struct mtk_wed_ring *
@@ -1128,23 +1260,6 @@ mtk_wed_ring_reset(struct mtk_wed_ring *
}
}
@@ -280,7 +280,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
static int
mtk_wed_rx_reset(struct mtk_wed_device *dev)
{
@@ -1692,6 +1807,7 @@ mtk_wed_start(struct mtk_wed_device *dev
@@ -1691,6 +1806,7 @@ mtk_wed_start(struct mtk_wed_device *dev
}
mtk_wed_set_512_support(dev, dev->wlan.wcid_512);
@@ -288,7 +288,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
mtk_wed_dma_enable(dev);
dev->running = true;
@@ -1748,6 +1864,10 @@ mtk_wed_attach(struct mtk_wed_device *de
@@ -1747,6 +1863,10 @@ mtk_wed_attach(struct mtk_wed_device *de
if (ret)
goto out;

View File

@@ -173,7 +173,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
}
static void
@@ -935,6 +1056,8 @@ mtk_wed_bus_init(struct mtk_wed_device *
@@ -934,6 +1055,8 @@ mtk_wed_bus_init(struct mtk_wed_device *
static void
mtk_wed_set_wpdma(struct mtk_wed_device *dev)
{
@@ -182,7 +182,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
if (mtk_wed_is_v1(dev->hw)) {
wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_phys);
return;
@@ -952,6 +1075,15 @@ mtk_wed_set_wpdma(struct mtk_wed_device
@@ -951,6 +1074,15 @@ mtk_wed_set_wpdma(struct mtk_wed_device
wed_w32(dev, MTK_WED_WPDMA_RX_GLO_CFG, dev->wlan.wpdma_rx_glo);
wed_w32(dev, dev->hw->soc->regmap.wpdma_rx_ring0, dev->wlan.wpdma_rx);
@@ -198,7 +198,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
}
static void
@@ -1763,6 +1895,165 @@ mtk_wed_dma_enable(struct mtk_wed_device
@@ -1762,6 +1894,165 @@ mtk_wed_dma_enable(struct mtk_wed_device
}
static void
@@ -364,7 +364,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
{
int i;
@@ -2216,6 +2507,10 @@ void mtk_wed_add_hw(struct device_node *
@@ -2212,6 +2503,10 @@ void mtk_wed_add_hw(struct device_node *
.detach = mtk_wed_detach,
.ppe_check = mtk_wed_ppe_check,
.setup_tc = mtk_wed_setup_tc,

View File

@@ -205,7 +205,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_TX);
wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
@@ -1406,13 +1570,33 @@ mtk_wed_rx_reset(struct mtk_wed_device *
@@ -1405,13 +1569,33 @@ mtk_wed_rx_reset(struct mtk_wed_device *
if (ret)
return ret;
@@ -239,7 +239,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
MTK_WED_WPDMA_RX_D_RST_CRX_IDX |
MTK_WED_WPDMA_RX_D_RST_DRV_IDX);
@@ -1440,23 +1624,52 @@ mtk_wed_rx_reset(struct mtk_wed_device *
@@ -1439,23 +1623,52 @@ mtk_wed_rx_reset(struct mtk_wed_device *
wed_w32(dev, MTK_WED_RROQM_RST_IDX, 0);
}
@@ -298,7 +298,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
mtk_wed_reset(dev, MTK_WED_RESET_WDMA_TX_DRV);
/* reset wed rx dma */
@@ -1477,6 +1690,14 @@ mtk_wed_rx_reset(struct mtk_wed_device *
@@ -1476,6 +1689,14 @@ mtk_wed_rx_reset(struct mtk_wed_device *
MTK_WED_CTRL_WED_RX_BM_BUSY);
mtk_wed_reset(dev, MTK_WED_RESET_RX_BM);
@@ -313,7 +313,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
/* wo change to enable state */
val = MTK_WED_WO_STATE_ENABLE;
ret = mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO,
@@ -1494,6 +1715,7 @@ mtk_wed_rx_reset(struct mtk_wed_device *
@@ -1493,6 +1714,7 @@ mtk_wed_rx_reset(struct mtk_wed_device *
false);
}
mtk_wed_free_rx_buffer(dev);
@@ -321,7 +321,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
return 0;
}
@@ -1527,15 +1749,41 @@ mtk_wed_reset_dma(struct mtk_wed_device
@@ -1526,15 +1748,41 @@ mtk_wed_reset_dma(struct mtk_wed_device
/* 2. reset WDMA rx DMA */
busy = !!mtk_wdma_rx_reset(dev);
@@ -364,7 +364,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
wed_w32(dev, MTK_WED_WDMA_RESET_IDX,
MTK_WED_WDMA_RESET_IDX_RX | MTK_WED_WDMA_RESET_IDX_DRV);
wed_w32(dev, MTK_WED_WDMA_RESET_IDX, 0);
@@ -1551,8 +1799,13 @@ mtk_wed_reset_dma(struct mtk_wed_device
@@ -1550,8 +1798,13 @@ mtk_wed_reset_dma(struct mtk_wed_device
wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
for (i = 0; i < 100; i++) {
@@ -380,7 +380,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
break;
}
@@ -1574,6 +1827,8 @@ mtk_wed_reset_dma(struct mtk_wed_device
@@ -1573,6 +1826,8 @@ mtk_wed_reset_dma(struct mtk_wed_device
mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT);
mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_TX_DRV);
mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_RX_DRV);
@@ -389,7 +389,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
} else {
wed_w32(dev, MTK_WED_WPDMA_RESET_IDX,
MTK_WED_WPDMA_RESET_IDX_TX |
@@ -1590,7 +1845,14 @@ mtk_wed_reset_dma(struct mtk_wed_device
@@ -1589,7 +1844,14 @@ mtk_wed_reset_dma(struct mtk_wed_device
wed_w32(dev, MTK_WED_RESET_IDX, 0);
}
@@ -405,7 +405,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
}
static int
@@ -1842,6 +2104,7 @@ mtk_wed_dma_enable(struct mtk_wed_device
@@ -1841,6 +2103,7 @@ mtk_wed_dma_enable(struct mtk_wed_device
MTK_WED_WPDMA_GLO_CFG_RX_DRV_UNS_VER_FORCE_4);
wdma_set(dev, MTK_WDMA_PREF_RX_CFG, MTK_WDMA_PREF_RX_CFG_PREF_EN);
@@ -413,7 +413,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
}
wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
@@ -1905,6 +2168,12 @@ mtk_wed_start_hw_rro(struct mtk_wed_devi
@@ -1904,6 +2167,12 @@ mtk_wed_start_hw_rro(struct mtk_wed_devi
if (!mtk_wed_get_rx_capa(dev) || !dev->wlan.hw_rro)
return;

View File

@@ -46,7 +46,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -3003,13 +3003,25 @@ static void stmmac_tx_timer_arm(struct s
@@ -2988,13 +2988,25 @@ static void stmmac_tx_timer_arm(struct s
{
struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue];
u32 tx_coal_timer = priv->tx_coal_timer[queue];

View File

@@ -18,7 +18,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2551,9 +2551,13 @@ static void stmmac_bump_dma_threshold(st
@@ -2536,9 +2536,13 @@ static void stmmac_bump_dma_threshold(st
* @priv: driver private structure
* @budget: napi budget limiting this functions packet handling
* @queue: TX queue index
@@ -33,7 +33,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
{
struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue];
struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[queue];
@@ -2713,7 +2717,7 @@ static int stmmac_tx_clean(struct stmmac
@@ -2698,7 +2702,7 @@ static int stmmac_tx_clean(struct stmmac
/* We still have pending packets, let's call for a new scheduling */
if (tx_q->dirty_tx != tx_q->cur_tx)
@@ -42,7 +42,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
u64_stats_update_begin(&txq_stats->napi_syncp);
u64_stats_add(&txq_stats->napi.tx_packets, tx_packets);
@@ -5605,6 +5609,7 @@ static int stmmac_napi_poll_tx(struct na
@@ -5590,6 +5594,7 @@ static int stmmac_napi_poll_tx(struct na
container_of(napi, struct stmmac_channel, tx_napi);
struct stmmac_priv *priv = ch->priv_data;
struct stmmac_txq_stats *txq_stats;
@@ -50,7 +50,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
u32 chan = ch->index;
int work_done;
@@ -5613,7 +5618,7 @@ static int stmmac_napi_poll_tx(struct na
@@ -5598,7 +5603,7 @@ static int stmmac_napi_poll_tx(struct na
u64_stats_inc(&txq_stats->napi.poll);
u64_stats_update_end(&txq_stats->napi_syncp);
@@ -59,7 +59,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
work_done = min(work_done, budget);
if (work_done < budget && napi_complete_done(napi, work_done)) {
@@ -5624,6 +5629,10 @@ static int stmmac_napi_poll_tx(struct na
@@ -5609,6 +5614,10 @@ static int stmmac_napi_poll_tx(struct na
spin_unlock_irqrestore(&ch->lock, flags);
}
@@ -70,7 +70,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
return work_done;
}
@@ -5632,6 +5641,7 @@ static int stmmac_napi_poll_rxtx(struct
@@ -5617,6 +5626,7 @@ static int stmmac_napi_poll_rxtx(struct
struct stmmac_channel *ch =
container_of(napi, struct stmmac_channel, rxtx_napi);
struct stmmac_priv *priv = ch->priv_data;
@@ -78,7 +78,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
int rx_done, tx_done, rxtx_done;
struct stmmac_rxq_stats *rxq_stats;
struct stmmac_txq_stats *txq_stats;
@@ -5647,7 +5657,7 @@ static int stmmac_napi_poll_rxtx(struct
@@ -5632,7 +5642,7 @@ static int stmmac_napi_poll_rxtx(struct
u64_stats_inc(&txq_stats->napi.poll);
u64_stats_update_end(&txq_stats->napi_syncp);
@@ -87,7 +87,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
tx_done = min(tx_done, budget);
rx_done = stmmac_rx_zc(priv, budget, chan);
@@ -5672,6 +5682,10 @@ static int stmmac_napi_poll_rxtx(struct
@@ -5657,6 +5667,10 @@ static int stmmac_napi_poll_rxtx(struct
spin_unlock_irqrestore(&ch->lock, flags);
}

View File

@@ -179,7 +179,7 @@ Subject: [PATCH] net/bridge: add bridge offload
static int
br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb)
@@ -189,6 +190,7 @@ int br_handle_frame_finish(struct net *n
@@ -194,6 +195,7 @@ int br_handle_frame_finish(struct net *n
dst->used = now;
br_forward(dst->dst, skb, local_rcv, false);
} else {
@@ -187,7 +187,7 @@ Subject: [PATCH] net/bridge: add bridge offload
if (!mcast_hit)
br_flood(br, skb, pkt_type, local_rcv, false);
else
@@ -322,6 +324,9 @@ static rx_handler_result_t br_handle_fra
@@ -327,6 +329,9 @@ static rx_handler_result_t br_handle_fra
memset(skb->cb, 0, sizeof(struct br_input_skb_cb));
p = br_port_get_rcu(skb->dev);
@@ -686,7 +686,7 @@ Subject: [PATCH] net/bridge: add bridge offload
#ifdef CONFIG_NET_SWITCHDEV
/* Counter used to make sure that hardware domains get unique
* identifiers in case a bridge spans multiple switchdev instances.
@@ -565,6 +581,10 @@ struct br_input_skb_cb {
@@ -566,6 +582,10 @@ struct br_input_skb_cb {
#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
u8 br_netfilter_broute:1;
#endif

View File

@@ -0,0 +1,24 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Tue, 23 Apr 2024 12:35:21 +0200
Subject: [PATCH] net: enable fraglist GRO by default
This can significantly improve performance for packet forwarding/bridging
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/linux/netdev_features.h
+++ b/include/linux/netdev_features.h
@@ -242,10 +242,10 @@ static inline int find_next_netdev_featu
#define NETIF_F_UPPER_DISABLES NETIF_F_LRO
/* changeable features with no special hardware requirements */
-#define NETIF_F_SOFT_FEATURES (NETIF_F_GSO | NETIF_F_GRO)
+#define NETIF_F_SOFT_FEATURES (NETIF_F_GSO | NETIF_F_GRO | NETIF_F_GRO_FRAGLIST)
/* Changeable features with no special hardware requirements that defaults to off. */
-#define NETIF_F_SOFT_FEATURES_OFF (NETIF_F_GRO_FRAGLIST | NETIF_F_GRO_UDP_FWD)
+#define NETIF_F_SOFT_FEATURES_OFF (NETIF_F_GRO_UDP_FWD)
#define NETIF_F_VLAN_FEATURES (NETIF_F_HW_VLAN_CTAG_FILTER | \
NETIF_F_HW_VLAN_CTAG_RX | \

View File

@@ -11,7 +11,7 @@ Submitted-by: Yousong Zhou <yszhou4tech@gmail.com>
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -531,6 +531,63 @@ int eth_platform_get_mac_address(struct
@@ -505,6 +505,63 @@ int eth_platform_get_mac_address(struct
}
EXPORT_SYMBOL(eth_platform_get_mac_address);
@@ -75,7 +75,7 @@ Submitted-by: Yousong Zhou <yszhou4tech@gmail.com>
/**
* platform_get_ethdev_address - Set netdev's MAC address from a given device
* @dev: Pointer to the device
@@ -564,19 +621,23 @@ int nvmem_get_mac_address(struct device
@@ -538,19 +595,23 @@ int nvmem_get_mac_address(struct device
{
struct nvmem_cell *cell;
const void *mac;

View File

@@ -47,7 +47,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
const struct header_ops *header_ops;
unsigned char operstate;
@@ -2184,6 +2191,10 @@ struct net_device {
@@ -2182,6 +2189,10 @@ struct net_device {
struct mctp_dev __rcu *mctp_ptr;
#endif
@@ -60,7 +60,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
*/
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3046,6 +3046,10 @@ static inline int pskb_trim(struct sk_bu
@@ -3045,6 +3045,10 @@ static inline int pskb_trim(struct sk_bu
return (len < skb->len) ? __pskb_trim(skb, len) : 0;
}
@@ -71,7 +71,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
/**
* pskb_trim_unique - remove end from a paged unique (not cloned) buffer
* @skb: buffer to alter
@@ -3195,16 +3199,6 @@ static inline struct sk_buff *dev_alloc_
@@ -3194,16 +3198,6 @@ static inline struct sk_buff *dev_alloc_
}
@@ -152,7 +152,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
{
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -171,6 +171,12 @@ __be16 eth_type_trans(struct sk_buff *sk
@@ -159,6 +159,12 @@ __be16 eth_type_trans(struct sk_buff *sk
const struct ethhdr *eth;
skb->dev = dev;

View File

@@ -43,7 +43,7 @@ Subject: [PATCH] net/usb/qmi_wwan: add MeigLink modem support
#define QUECTEL_VENDOR_ID 0x2c7c
/* These Quectel products use Quectel's vendor ID */
@@ -1152,6 +1157,11 @@ static const struct usb_device_id option
@@ -1156,6 +1161,11 @@ static const struct usb_device_id option
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000), /* SIMCom SIM5218 */
.driver_info = NCTRL(0) | NCTRL(1) | NCTRL(2) | NCTRL(3) | RSVD(4) },
@@ -55,7 +55,7 @@ Subject: [PATCH] net/usb/qmi_wwan: add MeigLink modem support
/* Quectel products using Qualcomm vendor ID */
{ USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC15)},
{ USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC20),
@@ -1193,6 +1203,11 @@ static const struct usb_device_id option
@@ -1197,6 +1207,11 @@ static const struct usb_device_id option
.driver_info = ZLP },
{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96),
.driver_info = RSVD(4) },

View File

@@ -60,7 +60,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
static void sock_def_write_space_wfree(struct sock *sk);
static void sock_def_write_space(struct sock *sk);
@@ -585,6 +587,18 @@ discard_and_relse:
@@ -586,6 +588,18 @@ discard_and_relse:
}
EXPORT_SYMBOL(__sk_receive_skb);
@@ -79,7 +79,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
INDIRECT_CALLABLE_DECLARE(struct dst_entry *ip6_dst_check(struct dst_entry *,
u32));
INDIRECT_CALLABLE_DECLARE(struct dst_entry *ipv4_dst_check(struct dst_entry *,
@@ -2188,9 +2202,11 @@ static void __sk_free(struct sock *sk)
@@ -2189,9 +2203,11 @@ static void __sk_free(struct sock *sk)
if (likely(sk->sk_net_refcnt))
sock_inuse_add(sock_net(sk), -1);

View File

@@ -330,7 +330,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -4114,6 +4114,8 @@ static __net_initdata struct pernet_oper
@@ -4115,6 +4115,8 @@ static __net_initdata struct pernet_oper
static int __init proto_init(void)
{

View File

@@ -1,6 +1,6 @@
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -642,6 +642,7 @@ static void option_instat_callback(struc
@@ -646,6 +646,7 @@ static void option_instat_callback(struc
static const struct usb_device_id option_ids[] = {
@@ -8,7 +8,7 @@
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_LIGHT) },
@@ -2385,6 +2386,15 @@ static int option_probe(struct usb_seria
@@ -2423,6 +2424,15 @@ static int option_probe(struct usb_seria
if (device_flags & NUMEP2 && iface_desc->bNumEndpoints != 2)
return -ENODEV;

View File

@@ -12,7 +12,7 @@
struct list_head *br_ip_list);
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -990,6 +990,10 @@ struct sk_buff {
@@ -989,6 +989,10 @@ struct sk_buff {
__u8 csum_not_inet:1;
__u8 scm_io_uring:1;

View File

@@ -0,0 +1,24 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Tue, 23 Apr 2024 12:35:21 +0200
Subject: [PATCH] net: enable fraglist GRO by default
This can significantly improve performance for packet forwarding/bridging
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/linux/netdev_features.h
+++ b/include/linux/netdev_features.h
@@ -242,10 +242,10 @@ static inline int find_next_netdev_featu
#define NETIF_F_UPPER_DISABLES NETIF_F_LRO
/* changeable features with no special hardware requirements */
-#define NETIF_F_SOFT_FEATURES (NETIF_F_GSO | NETIF_F_GRO)
+#define NETIF_F_SOFT_FEATURES (NETIF_F_GSO | NETIF_F_GRO | NETIF_F_GRO_FRAGLIST)
/* Changeable features with no special hardware requirements that defaults to off. */
-#define NETIF_F_SOFT_FEATURES_OFF (NETIF_F_GRO_FRAGLIST | NETIF_F_GRO_UDP_FWD)
+#define NETIF_F_SOFT_FEATURES_OFF (NETIF_F_GRO_UDP_FWD)
#define NETIF_F_VLAN_FEATURES (NETIF_F_HW_VLAN_CTAG_FILTER | \
NETIF_F_HW_VLAN_CTAG_RX | \

View File

@@ -9,7 +9,7 @@ Subject: [PATCH] net/dsa/mv88e6xxx: disable ATU violation
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -3305,6 +3305,9 @@ static int mv88e6xxx_setup_port(struct m
@@ -3353,6 +3353,9 @@ static int mv88e6xxx_setup_port(struct m
else
reg = 1 << port;

View File

@@ -43,7 +43,7 @@ Subject: [PATCH] net/usb/qmi_wwan: add MeigLink modem support
#define QUECTEL_VENDOR_ID 0x2c7c
/* These Quectel products use Quectel's vendor ID */
@@ -1152,6 +1157,11 @@ static const struct usb_device_id option
@@ -1156,6 +1161,11 @@ static const struct usb_device_id option
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000), /* SIMCom SIM5218 */
.driver_info = NCTRL(0) | NCTRL(1) | NCTRL(2) | NCTRL(3) | RSVD(4) },
@@ -55,7 +55,7 @@ Subject: [PATCH] net/usb/qmi_wwan: add MeigLink modem support
/* Quectel products using Qualcomm vendor ID */
{ USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC15)},
{ USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC20),
@@ -1193,6 +1203,11 @@ static const struct usb_device_id option
@@ -1197,6 +1207,11 @@ static const struct usb_device_id option
.driver_info = ZLP },
{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96),
.driver_info = RSVD(4) },

View File

@@ -61,7 +61,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
static void sock_def_write_space_wfree(struct sock *sk);
static void sock_def_write_space(struct sock *sk);
@@ -589,6 +591,21 @@ discard_and_relse:
@@ -590,6 +592,21 @@ discard_and_relse:
}
EXPORT_SYMBOL(__sk_receive_skb);
@@ -83,7 +83,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
INDIRECT_CALLABLE_DECLARE(struct dst_entry *ip6_dst_check(struct dst_entry *,
u32));
INDIRECT_CALLABLE_DECLARE(struct dst_entry *ipv4_dst_check(struct dst_entry *,
@@ -2246,9 +2263,11 @@ static void __sk_free(struct sock *sk)
@@ -2247,9 +2264,11 @@ static void __sk_free(struct sock *sk)
if (likely(sk->sk_net_refcnt))
sock_inuse_add(sock_net(sk), -1);

View File

@@ -330,7 +330,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -4144,6 +4144,8 @@ static __net_initdata struct pernet_oper
@@ -4145,6 +4145,8 @@ static __net_initdata struct pernet_oper
static int __init proto_init(void)
{

View File

@@ -1,6 +1,6 @@
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -642,6 +642,7 @@ static void option_instat_callback(struc
@@ -646,6 +646,7 @@ static void option_instat_callback(struc
static const struct usb_device_id option_ids[] = {
@@ -8,7 +8,7 @@
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_LIGHT) },
@@ -2379,6 +2380,15 @@ static int option_probe(struct usb_seria
@@ -2423,6 +2424,15 @@ static int option_probe(struct usb_seria
if (device_flags & NUMEP2 && iface_desc->bNumEndpoints != 2)
return -ENODEV;

View File

@@ -15,7 +15,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -222,6 +222,9 @@ static void __br_handle_local_finish(str
@@ -227,6 +227,9 @@ static void __br_handle_local_finish(str
/* note: already called with rcu_read_lock */
static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
@@ -25,7 +25,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
__br_handle_local_finish(skb);
/* return 1 to signal the okfn() was called so it's ok to use the skb */
@@ -390,6 +393,17 @@ forward:
@@ -397,6 +400,17 @@ forward:
goto defer_stp_filtering;
switch (p->state) {

View File

@@ -1,151 +0,0 @@
From: Felix Fietkau <nbd@nbd.name>
Subject: net: replace GRO optimization patch with a new one that supports VLANs/bridges with different MAC addresses
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
include/linux/netdevice.h | 2 ++
include/linux/skbuff.h | 3 ++-
net/core/dev.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++
net/ethernet/eth.c | 18 +++++++++++++++++-
4 files changed, 69 insertions(+), 2 deletions(-)
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2135,6 +2135,8 @@ struct net_device {
struct netdev_hw_addr_list mc;
struct netdev_hw_addr_list dev_addrs;
+ unsigned char local_addr_mask[MAX_ADDR_LEN];
+
#ifdef CONFIG_SYSFS
struct kset *queues_kset;
#endif
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -967,6 +967,7 @@ struct sk_buff {
#ifdef CONFIG_IPV6_NDISC_NODETYPE
__u8 ndisc_nodetype:2;
#endif
+ __u8 gro_skip:1;
__u8 ipvs_property:1;
__u8 inner_protocol_type:1;
--- a/net/core/gro.c
+++ b/net/core/gro.c
@@ -492,6 +492,9 @@ static enum gro_result dev_gro_receive(s
int same_flow;
int grow;
+ if (skb->gro_skip)
+ goto normal;
+
if (netif_elide_gro(skb->dev))
goto normal;
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -7643,6 +7643,48 @@ static void __netdev_adjacent_dev_unlink
&upper_dev->adj_list.lower);
}
+static void __netdev_addr_mask(unsigned char *mask, const unsigned char *addr,
+ struct net_device *dev)
+{
+ int i;
+
+ for (i = 0; i < dev->addr_len; i++)
+ mask[i] |= addr[i] ^ dev->dev_addr[i];
+}
+
+static void __netdev_upper_mask(unsigned char *mask, struct net_device *dev,
+ struct net_device *lower)
+{
+ struct net_device *cur;
+ struct list_head *iter;
+
+ netdev_for_each_upper_dev_rcu(dev, cur, iter) {
+ __netdev_addr_mask(mask, cur->dev_addr, lower);
+ __netdev_upper_mask(mask, cur, lower);
+ }
+}
+
+static void __netdev_update_addr_mask(struct net_device *dev)
+{
+ unsigned char mask[MAX_ADDR_LEN];
+ struct net_device *cur;
+ struct list_head *iter;
+
+ memset(mask, 0, sizeof(mask));
+ __netdev_upper_mask(mask, dev, dev);
+ memcpy(dev->local_addr_mask, mask, dev->addr_len);
+
+ netdev_for_each_lower_dev(dev, cur, iter)
+ __netdev_update_addr_mask(cur);
+}
+
+static void netdev_update_addr_mask(struct net_device *dev)
+{
+ rcu_read_lock();
+ __netdev_update_addr_mask(dev);
+ rcu_read_unlock();
+}
+
static int __netdev_upper_dev_link(struct net_device *dev,
struct net_device *upper_dev, bool master,
void *upper_priv, void *upper_info,
@@ -7694,6 +7736,7 @@ static int __netdev_upper_dev_link(struc
if (ret)
return ret;
+ netdev_update_addr_mask(dev);
ret = call_netdevice_notifiers_info(NETDEV_CHANGEUPPER,
&changeupper_info.info);
ret = notifier_to_errno(ret);
@@ -7790,6 +7833,7 @@ static void __netdev_upper_dev_unlink(st
__netdev_adjacent_dev_unlink_neighbour(dev, upper_dev);
+ netdev_update_addr_mask(dev);
call_netdevice_notifiers_info(NETDEV_CHANGEUPPER,
&changeupper_info.info);
@@ -8842,6 +8886,7 @@ int dev_set_mac_address(struct net_devic
if (err)
return err;
dev->addr_assign_type = NET_ADDR_SET;
+ netdev_update_addr_mask(dev);
call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
add_device_randomness(dev->dev_addr, dev->addr_len);
return 0;
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -143,6 +143,18 @@ u32 eth_get_headlen(const struct net_dev
}
EXPORT_SYMBOL(eth_get_headlen);
+static inline bool
+eth_check_local_mask(const void *addr1, const void *addr2, const void *mask)
+{
+ const u16 *a1 = addr1;
+ const u16 *a2 = addr2;
+ const u16 *m = mask;
+
+ return (((a1[0] ^ a2[0]) & ~m[0]) |
+ ((a1[1] ^ a2[1]) & ~m[1]) |
+ ((a1[2] ^ a2[2]) & ~m[2]));
+}
+
/**
* eth_type_trans - determine the packet's protocol ID.
* @skb: received socket data
@@ -174,6 +186,10 @@ __be16 eth_type_trans(struct sk_buff *sk
} else {
skb->pkt_type = PACKET_OTHERHOST;
}
+
+ if (eth_check_local_mask(eth->h_dest, dev->dev_addr,
+ dev->local_addr_mask))
+ skb->gro_skip = 1;
}
/*

View File

@@ -0,0 +1,627 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Tue, 23 Apr 2024 11:23:03 +0200
Subject: [PATCH] net: add TCP fraglist GRO support
When forwarding TCP after GRO, software segmentation is very expensive,
especially when the checksum needs to be recalculated.
One case where that's currently unavoidable is when routing packets over
PPPoE. Performance improves significantly when using fraglist GRO
implemented in the same way as for UDP.
Here's a measurement of running 2 TCP streams through a MediaTek MT7622
device (2-core Cortex-A53), which runs NAT with flow offload enabled from
one ethernet port to PPPoE on another ethernet port + cake qdisc set to
1Gbps.
rx-gro-list off: 630 Mbit/s, CPU 35% idle
rx-gro-list on: 770 Mbit/s, CPU 40% idle
Signe-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/net/gro.h
+++ b/include/net/gro.h
@@ -424,6 +424,7 @@ static inline __wsum ip6_gro_compute_pse
}
int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb);
+int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb);
/* Pass the currently batched GRO_NORMAL SKBs up to the stack. */
static inline void gro_normal_list(struct napi_struct *napi)
@@ -446,5 +447,48 @@ static inline void gro_normal_one(struct
gro_normal_list(napi);
}
+/* This function is the alternative of 'inet_iif' and 'inet_sdif'
+ * functions in case we can not rely on fields of IPCB.
+ *
+ * The caller must verify skb_valid_dst(skb) is false and skb->dev is initialized.
+ * The caller must hold the RCU read lock.
+ */
+static inline void inet_get_iif_sdif(const struct sk_buff *skb, int *iif, int *sdif)
+{
+ *iif = inet_iif(skb) ?: skb->dev->ifindex;
+ *sdif = 0;
+
+#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
+ if (netif_is_l3_slave(skb->dev)) {
+ struct net_device *master = netdev_master_upper_dev_get_rcu(skb->dev);
+
+ *sdif = *iif;
+ *iif = master ? master->ifindex : 0;
+ }
+#endif
+}
+
+/* This function is the alternative of 'inet6_iif' and 'inet6_sdif'
+ * functions in case we can not rely on fields of IP6CB.
+ *
+ * The caller must verify skb_valid_dst(skb) is false and skb->dev is initialized.
+ * The caller must hold the RCU read lock.
+ */
+static inline void inet6_get_iif_sdif(const struct sk_buff *skb, int *iif, int *sdif)
+{
+ /* using skb->dev->ifindex because skb_dst(skb) is not initialized */
+ *iif = skb->dev->ifindex;
+ *sdif = 0;
+
+#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
+ if (netif_is_l3_slave(skb->dev)) {
+ struct net_device *master = netdev_master_upper_dev_get_rcu(skb->dev);
+
+ *sdif = *iif;
+ *iif = master ? master->ifindex : 0;
+ }
+#endif
+}
+
#endif /* _NET_IPV6_GRO_H */
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -2057,7 +2057,10 @@ void tcp_v4_destroy_sock(struct sock *sk
struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
netdev_features_t features);
-struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb);
+struct tcphdr *tcp_gro_pull_header(struct sk_buff *skb);
+struct sk_buff *tcp_gro_lookup(struct list_head *head, struct tcphdr *th);
+struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb,
+ struct tcphdr *th);
INDIRECT_CALLABLE_DECLARE(int tcp4_gro_complete(struct sk_buff *skb, int thoff));
INDIRECT_CALLABLE_DECLARE(struct sk_buff *tcp4_gro_receive(struct list_head *head, struct sk_buff *skb));
INDIRECT_CALLABLE_DECLARE(int tcp6_gro_complete(struct sk_buff *skb, int thoff));
--- a/net/core/gro.c
+++ b/net/core/gro.c
@@ -290,6 +290,33 @@ done:
return 0;
}
+int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb)
+{
+ if (unlikely(p->len + skb->len >= 65536))
+ return -E2BIG;
+
+ if (NAPI_GRO_CB(p)->last == p)
+ skb_shinfo(p)->frag_list = skb;
+ else
+ NAPI_GRO_CB(p)->last->next = skb;
+
+ skb_pull(skb, skb_gro_offset(skb));
+
+ NAPI_GRO_CB(p)->last = skb;
+ NAPI_GRO_CB(p)->count++;
+ p->data_len += skb->len;
+
+ /* sk ownership - if any - completely transferred to the aggregated packet */
+ skb->destructor = NULL;
+ skb->sk = NULL;
+ p->truesize += skb->truesize;
+ p->len += skb->len;
+
+ NAPI_GRO_CB(skb)->same_flow = 1;
+
+ return 0;
+}
+
static void napi_gro_complete(struct napi_struct *napi, struct sk_buff *skb)
{
--- a/net/ipv4/tcp_offload.c
+++ b/net/ipv4/tcp_offload.c
@@ -27,6 +27,70 @@ static void tcp_gso_tstamp(struct sk_buf
}
}
+static void __tcpv4_gso_segment_csum(struct sk_buff *seg,
+ __be32 *oldip, __be32 newip,
+ __be16 *oldport, __be16 newport)
+{
+ struct tcphdr *th;
+ struct iphdr *iph;
+
+ if (*oldip == newip && *oldport == newport)
+ return;
+
+ th = tcp_hdr(seg);
+ iph = ip_hdr(seg);
+
+ inet_proto_csum_replace4(&th->check, seg, *oldip, newip, true);
+ inet_proto_csum_replace2(&th->check, seg, *oldport, newport, false);
+ *oldport = newport;
+
+ csum_replace4(&iph->check, *oldip, newip);
+ *oldip = newip;
+}
+
+static struct sk_buff *__tcpv4_gso_segment_list_csum(struct sk_buff *segs)
+{
+ const struct tcphdr *th;
+ const struct iphdr *iph;
+ struct sk_buff *seg;
+ struct tcphdr *th2;
+ struct iphdr *iph2;
+
+ seg = segs;
+ th = tcp_hdr(seg);
+ iph = ip_hdr(seg);
+ th2 = tcp_hdr(seg->next);
+ iph2 = ip_hdr(seg->next);
+
+ if (!(*(const u32 *)&th->source ^ *(const u32 *)&th2->source) &&
+ iph->daddr == iph2->daddr && iph->saddr == iph2->saddr)
+ return segs;
+
+ while ((seg = seg->next)) {
+ th2 = tcp_hdr(seg);
+ iph2 = ip_hdr(seg);
+
+ __tcpv4_gso_segment_csum(seg,
+ &iph2->saddr, iph->saddr,
+ &th2->source, th->source);
+ __tcpv4_gso_segment_csum(seg,
+ &iph2->daddr, iph->daddr,
+ &th2->dest, th->dest);
+ }
+
+ return segs;
+}
+
+static struct sk_buff *__tcp4_gso_segment_list(struct sk_buff *skb,
+ netdev_features_t features)
+{
+ skb = skb_segment_list(skb, features, skb_mac_header_len(skb));
+ if (IS_ERR(skb))
+ return skb;
+
+ return __tcpv4_gso_segment_list_csum(skb);
+}
+
static struct sk_buff *tcp4_gso_segment(struct sk_buff *skb,
netdev_features_t features)
{
@@ -36,6 +100,9 @@ static struct sk_buff *tcp4_gso_segment(
if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
return ERR_PTR(-EINVAL);
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST)
+ return __tcp4_gso_segment_list(skb, features);
+
if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) {
const struct iphdr *iph = ip_hdr(skb);
struct tcphdr *th = tcp_hdr(skb);
@@ -177,61 +244,76 @@ out:
return segs;
}
-struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb)
+struct sk_buff *tcp_gro_lookup(struct list_head *head, struct tcphdr *th)
{
- struct sk_buff *pp = NULL;
+ struct tcphdr *th2;
struct sk_buff *p;
+
+ list_for_each_entry(p, head, list) {
+ if (!NAPI_GRO_CB(p)->same_flow)
+ continue;
+
+ th2 = tcp_hdr(p);
+ if (*(u32 *)&th->source ^ *(u32 *)&th2->source) {
+ NAPI_GRO_CB(p)->same_flow = 0;
+ continue;
+ }
+
+ return p;
+ }
+
+ return NULL;
+}
+
+struct tcphdr *tcp_gro_pull_header(struct sk_buff *skb)
+{
+ unsigned int thlen, hlen, off;
struct tcphdr *th;
- struct tcphdr *th2;
- unsigned int len;
- unsigned int thlen;
- __be32 flags;
- unsigned int mss = 1;
- unsigned int hlen;
- unsigned int off;
- int flush = 1;
- int i;
off = skb_gro_offset(skb);
hlen = off + sizeof(*th);
th = skb_gro_header(skb, hlen, off);
if (unlikely(!th))
- goto out;
+ return NULL;
thlen = th->doff * 4;
if (thlen < sizeof(*th))
- goto out;
+ return NULL;
hlen = off + thlen;
if (skb_gro_header_hard(skb, hlen)) {
th = skb_gro_header_slow(skb, hlen, off);
if (unlikely(!th))
- goto out;
+ return NULL;
}
skb_gro_pull(skb, thlen);
- len = skb_gro_len(skb);
- flags = tcp_flag_word(th);
-
- list_for_each_entry(p, head, list) {
- if (!NAPI_GRO_CB(p)->same_flow)
- continue;
+ return th;
+}
- th2 = tcp_hdr(p);
+struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb,
+ struct tcphdr *th)
+{
+ unsigned int thlen = th->doff * 4;
+ struct sk_buff *pp = NULL;
+ struct sk_buff *p;
+ struct tcphdr *th2;
+ unsigned int len;
+ __be32 flags;
+ unsigned int mss = 1;
+ int flush = 1;
+ int i;
- if (*(u32 *)&th->source ^ *(u32 *)&th2->source) {
- NAPI_GRO_CB(p)->same_flow = 0;
- continue;
- }
+ len = skb_gro_len(skb);
+ flags = tcp_flag_word(th);
- goto found;
- }
- p = NULL;
- goto out_check_final;
+ p = tcp_gro_lookup(head, th);
+ if (!p)
+ goto out_check_final;
-found:
/* Include the IP ID check below from the inner most IP hdr */
+ th2 = tcp_hdr(p);
flush = NAPI_GRO_CB(p)->flush;
flush |= (__force int)(flags & TCP_FLAG_CWR);
flush |= (__force int)((flags ^ tcp_flag_word(th2)) &
@@ -268,6 +350,19 @@ found:
flush |= p->decrypted ^ skb->decrypted;
#endif
+ if (unlikely(NAPI_GRO_CB(p)->is_flist)) {
+ flush |= (__force int)(flags ^ tcp_flag_word(th2));
+ flush |= skb->ip_summed != p->ip_summed;
+ flush |= skb->csum_level != p->csum_level;
+ flush |= !pskb_may_pull(skb, skb_gro_offset(skb));
+ flush |= NAPI_GRO_CB(p)->count >= 64;
+
+ if (flush || skb_gro_receive_list(p, skb))
+ mss = 1;
+
+ goto out_check_final;
+ }
+
if (flush || skb_gro_receive(p, skb)) {
mss = 1;
goto out_check_final;
@@ -289,7 +384,6 @@ out_check_final:
if (p && (!NAPI_GRO_CB(skb)->same_flow || flush))
pp = p;
-out:
NAPI_GRO_CB(skb)->flush |= (flush != 0);
return pp;
@@ -315,18 +409,58 @@ int tcp_gro_complete(struct sk_buff *skb
}
EXPORT_SYMBOL(tcp_gro_complete);
+static void tcp4_check_fraglist_gro(struct list_head *head, struct sk_buff *skb,
+ struct tcphdr *th)
+{
+ const struct iphdr *iph;
+ struct sk_buff *p;
+ struct sock *sk;
+ struct net *net;
+ int iif, sdif;
+
+ if (!(skb->dev->features & NETIF_F_GRO_FRAGLIST))
+ return;
+
+ p = tcp_gro_lookup(head, th);
+ if (p) {
+ NAPI_GRO_CB(skb)->is_flist = NAPI_GRO_CB(p)->is_flist;
+ return;
+ }
+
+ inet_get_iif_sdif(skb, &iif, &sdif);
+ iph = skb_gro_network_header(skb);
+ net = dev_net(skb->dev);
+ sk = __inet_lookup_established(net, net->ipv4.tcp_death_row.hashinfo,
+ iph->saddr, th->source,
+ iph->daddr, ntohs(th->dest),
+ iif, sdif);
+ NAPI_GRO_CB(skb)->is_flist = !sk;
+ if (sk)
+ sock_put(sk);
+}
+
INDIRECT_CALLABLE_SCOPE
struct sk_buff *tcp4_gro_receive(struct list_head *head, struct sk_buff *skb)
{
+ struct tcphdr *th;
+
/* Don't bother verifying checksum if we're going to flush anyway. */
if (!NAPI_GRO_CB(skb)->flush &&
skb_gro_checksum_validate(skb, IPPROTO_TCP,
- inet_gro_compute_pseudo)) {
- NAPI_GRO_CB(skb)->flush = 1;
- return NULL;
- }
+ inet_gro_compute_pseudo))
+ goto flush;
+
+ th = tcp_gro_pull_header(skb);
+ if (!th)
+ goto flush;
- return tcp_gro_receive(head, skb);
+ tcp4_check_fraglist_gro(head, skb, th);
+
+ return tcp_gro_receive(head, skb, th);
+
+flush:
+ NAPI_GRO_CB(skb)->flush = 1;
+ return NULL;
}
INDIRECT_CALLABLE_SCOPE int tcp4_gro_complete(struct sk_buff *skb, int thoff)
@@ -334,6 +468,15 @@ INDIRECT_CALLABLE_SCOPE int tcp4_gro_com
const struct iphdr *iph = ip_hdr(skb);
struct tcphdr *th = tcp_hdr(skb);
+ if (unlikely(NAPI_GRO_CB(skb)->is_flist)) {
+ skb_shinfo(skb)->gso_type |= SKB_GSO_FRAGLIST | SKB_GSO_TCPV4;
+ skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count;
+
+ __skb_incr_checksum_unnecessary(skb);
+
+ return 0;
+ }
+
th->check = ~tcp_v4_check(skb->len - thoff, iph->saddr,
iph->daddr, 0);
skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV4;
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -425,33 +425,6 @@ out:
return segs;
}
-static int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb)
-{
- if (unlikely(p->len + skb->len >= 65536))
- return -E2BIG;
-
- if (NAPI_GRO_CB(p)->last == p)
- skb_shinfo(p)->frag_list = skb;
- else
- NAPI_GRO_CB(p)->last->next = skb;
-
- skb_pull(skb, skb_gro_offset(skb));
-
- NAPI_GRO_CB(p)->last = skb;
- NAPI_GRO_CB(p)->count++;
- p->data_len += skb->len;
-
- /* sk ownership - if any - completely transferred to the aggregated packet */
- skb->destructor = NULL;
- skb->sk = NULL;
- p->truesize += skb->truesize;
- p->len += skb->len;
-
- NAPI_GRO_CB(skb)->same_flow = 1;
-
- return 0;
-}
-
#define UDP_GRO_CNT_MAX 64
static struct sk_buff *udp_gro_receive_segment(struct list_head *head,
--- a/net/ipv6/tcpv6_offload.c
+++ b/net/ipv6/tcpv6_offload.c
@@ -7,24 +7,67 @@
*/
#include <linux/indirect_call_wrapper.h>
#include <linux/skbuff.h>
+#include <net/inet6_hashtables.h>
#include <net/gro.h>
#include <net/protocol.h>
#include <net/tcp.h>
#include <net/ip6_checksum.h>
#include "ip6_offload.h"
+static void tcp6_check_fraglist_gro(struct list_head *head, struct sk_buff *skb,
+ struct tcphdr *th)
+{
+#if IS_ENABLED(CONFIG_IPV6)
+ const struct ipv6hdr *hdr;
+ struct sk_buff *p;
+ struct sock *sk;
+ struct net *net;
+ int iif, sdif;
+
+ if (!(skb->dev->features & NETIF_F_GRO_FRAGLIST))
+ return;
+
+ p = tcp_gro_lookup(head, th);
+ if (p) {
+ NAPI_GRO_CB(skb)->is_flist = NAPI_GRO_CB(p)->is_flist;
+ return;
+ }
+
+ inet6_get_iif_sdif(skb, &iif, &sdif);
+ hdr = skb_gro_network_header(skb);
+ net = dev_net(skb->dev);
+ sk = __inet6_lookup_established(net, net->ipv4.tcp_death_row.hashinfo,
+ &hdr->saddr, th->source,
+ &hdr->daddr, ntohs(th->dest),
+ iif, sdif);
+ NAPI_GRO_CB(skb)->is_flist = !sk;
+ if (sk)
+ sock_put(sk);
+#endif /* IS_ENABLED(CONFIG_IPV6) */
+}
+
INDIRECT_CALLABLE_SCOPE
struct sk_buff *tcp6_gro_receive(struct list_head *head, struct sk_buff *skb)
{
+ struct tcphdr *th;
+
/* Don't bother verifying checksum if we're going to flush anyway. */
if (!NAPI_GRO_CB(skb)->flush &&
skb_gro_checksum_validate(skb, IPPROTO_TCP,
- ip6_gro_compute_pseudo)) {
- NAPI_GRO_CB(skb)->flush = 1;
- return NULL;
- }
+ ip6_gro_compute_pseudo))
+ goto flush;
- return tcp_gro_receive(head, skb);
+ th = tcp_gro_pull_header(skb);
+ if (!th)
+ goto flush;
+
+ tcp6_check_fraglist_gro(head, skb, th);
+
+ return tcp_gro_receive(head, skb, th);
+
+flush:
+ NAPI_GRO_CB(skb)->flush = 1;
+ return NULL;
}
INDIRECT_CALLABLE_SCOPE int tcp6_gro_complete(struct sk_buff *skb, int thoff)
@@ -32,6 +75,15 @@ INDIRECT_CALLABLE_SCOPE int tcp6_gro_com
const struct ipv6hdr *iph = ipv6_hdr(skb);
struct tcphdr *th = tcp_hdr(skb);
+ if (unlikely(NAPI_GRO_CB(skb)->is_flist)) {
+ skb_shinfo(skb)->gso_type |= SKB_GSO_FRAGLIST | SKB_GSO_TCPV6;
+ skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count;
+
+ __skb_incr_checksum_unnecessary(skb);
+
+ return 0;
+ }
+
th->check = ~tcp_v6_check(skb->len - thoff, &iph->saddr,
&iph->daddr, 0);
skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV6;
@@ -39,6 +91,61 @@ INDIRECT_CALLABLE_SCOPE int tcp6_gro_com
return tcp_gro_complete(skb);
}
+static void __tcpv6_gso_segment_csum(struct sk_buff *seg,
+ __be16 *oldport, __be16 newport)
+{
+ struct tcphdr *th;
+
+ if (*oldport == newport)
+ return;
+
+ th = tcp_hdr(seg);
+ inet_proto_csum_replace2(&th->check, seg, *oldport, newport, false);
+ *oldport = newport;
+}
+
+static struct sk_buff *__tcpv6_gso_segment_list_csum(struct sk_buff *segs)
+{
+ const struct tcphdr *th;
+ const struct ipv6hdr *iph;
+ struct sk_buff *seg;
+ struct tcphdr *th2;
+ struct ipv6hdr *iph2;
+
+ seg = segs;
+ th = tcp_hdr(seg);
+ iph = ipv6_hdr(seg);
+ th2 = tcp_hdr(seg->next);
+ iph2 = ipv6_hdr(seg->next);
+
+ if (!(*(const u32 *)&th->source ^ *(const u32 *)&th2->source) &&
+ ipv6_addr_equal(&iph->saddr, &iph2->saddr) &&
+ ipv6_addr_equal(&iph->daddr, &iph2->daddr))
+ return segs;
+
+ while ((seg = seg->next)) {
+ th2 = tcp_hdr(seg);
+ iph2 = ipv6_hdr(seg);
+
+ iph2->saddr = iph->saddr;
+ iph2->daddr = iph->daddr;
+ __tcpv6_gso_segment_csum(seg, &th2->source, th->source);
+ __tcpv6_gso_segment_csum(seg, &th2->dest, th->dest);
+ }
+
+ return segs;
+}
+
+static struct sk_buff *__tcp6_gso_segment_list(struct sk_buff *skb,
+ netdev_features_t features)
+{
+ skb = skb_segment_list(skb, features, skb_mac_header_len(skb));
+ if (IS_ERR(skb))
+ return skb;
+
+ return __tcpv6_gso_segment_list_csum(skb);
+}
+
static struct sk_buff *tcp6_gso_segment(struct sk_buff *skb,
netdev_features_t features)
{
@@ -50,6 +157,9 @@ static struct sk_buff *tcp6_gso_segment(
if (!pskb_may_pull(skb, sizeof(*th)))
return ERR_PTR(-EINVAL);
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST)
+ return __tcp6_gso_segment_list(skb, features);
+
if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) {
const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
struct tcphdr *th = tcp_hdr(skb);

View File

@@ -0,0 +1,23 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Sat, 27 Apr 2024 18:54:25 +0200
Subject: [PATCH] net: bridge: fix multicast-to-unicast with fraglist GSO
Calling skb_copy on a SKB_GSO_FRAGLIST skb is not valid, since it returns
an invalid linearized skb. This code only needs to change the ethernet
header, so pskb_copy is the right function to call here.
Fixes: 6db6f0eae605 ("bridge: multicast to unicast")
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -261,7 +261,7 @@ static void maybe_deliver_addr(struct ne
if (skb->dev == p->dev && ether_addr_equal(src, addr))
return;
- skb = skb_copy(skb, GFP_ATOMIC);
+ skb = pskb_copy(skb, GFP_ATOMIC);
if (!skb) {
DEV_STATS_INC(dev, tx_dropped);
return;

View File

@@ -0,0 +1,59 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Sat, 27 Apr 2024 19:29:45 +0200
Subject: [PATCH] net: core: reject skb_copy(_expand) for fraglist GSO skbs
SKB_GSO_FRAGLIST skbs must not be linearized, otherwise they become
invalid. Return NULL if such an skb is passed to skb_copy or
skb_copy_expand, in order to prevent a crash on a potential later
call to skb_gso_segment.
Fixes: 3a1296a38d0c ("net: Support GRO/GSO fraglist chaining.")
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -1720,11 +1720,17 @@ static inline int skb_alloc_rx_flag(cons
struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask)
{
- int headerlen = skb_headroom(skb);
- unsigned int size = skb_end_offset(skb) + skb->data_len;
- struct sk_buff *n = __alloc_skb(size, gfp_mask,
- skb_alloc_rx_flag(skb), NUMA_NO_NODE);
+ struct sk_buff *n;
+ unsigned int size;
+ int headerlen;
+ if (WARN_ON_ONCE(skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST))
+ return NULL;
+
+ headerlen = skb_headroom(skb);
+ size = skb_end_offset(skb) + skb->data_len;
+ n = __alloc_skb(size, gfp_mask,
+ skb_alloc_rx_flag(skb), NUMA_NO_NODE);
if (!n)
return NULL;
@@ -2037,12 +2043,17 @@ struct sk_buff *skb_copy_expand(const st
/*
* Allocate the copy buffer
*/
- struct sk_buff *n = __alloc_skb(newheadroom + skb->len + newtailroom,
- gfp_mask, skb_alloc_rx_flag(skb),
- NUMA_NO_NODE);
- int oldheadroom = skb_headroom(skb);
int head_copy_len, head_copy_off;
+ struct sk_buff *n;
+ int oldheadroom;
+
+ if (WARN_ON_ONCE(skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST))
+ return NULL;
+ oldheadroom = skb_headroom(skb);
+ n = __alloc_skb(newheadroom + skb->len + newtailroom,
+ gfp_mask, skb_alloc_rx_flag(skb),
+ NUMA_NO_NODE);
if (!n)
return NULL;

View File

@@ -1,90 +0,0 @@
From 844c273286f328acf0dab5fbd5d864366b4904dc Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Tue, 30 Mar 2021 18:21:14 +0200
Subject: [PATCH] of_net: add mac-address-increment support
Lots of embedded devices use the mac-address of other interface
extracted from nvmem cells and increments it by one or two. Add two
bindings to integrate this and directly use the right mac-address for
the interface. Some example are some routers that use the gmac
mac-address stored in the art partition and increments it by one for the
wifi. mac-address-increment-byte bindings is used to tell what byte of
the mac-address has to be increased (if not defined the last byte is
increased) and mac-address-increment tells how much the byte decided
early has to be increased.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
net/core/of_net.c | 43 +++++++++++++++++++++++++++++++++++++++----
1 file changed, 39 insertions(+), 4 deletions(-)
--- a/net/core/of_net.c
+++ b/net/core/of_net.c
@@ -119,28 +119,63 @@ static int of_get_mac_addr_nvmem(struct
* this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
* but is all zeros.
*
+ * DT can tell the system to increment the mac-address after is extracted by
+ * using:
+ * - mac-address-increment-byte to decide what byte to increase
+ * (if not defined is increased the last byte)
+ * - mac-address-increment to decide how much to increase. The value WILL
+ * overflow to other bytes if the increment is over 255 or the total
+ * increment will exceed 255 of the current byte.
+ * (example 00:01:02:03:04:ff + 1 == 00:01:02:03:05:00)
+ * (example 00:01:02:03:04:fe + 5 == 00:01:02:03:05:03)
+ *
* Return: 0 on success and errno in case of error.
*/
int of_get_mac_address(struct device_node *np, u8 *addr)
{
+ u32 inc_idx, mac_inc, mac_val;
int ret;
+ /* Check first if the increment byte is present and valid.
+ * If not set assume to increment the last byte if found.
+ */
+ if (of_property_read_u32(np, "mac-address-increment-byte", &inc_idx))
+ inc_idx = 5;
+ if (inc_idx < 3 || inc_idx > 5)
+ return -EINVAL;
+
if (!np)
return -ENODEV;
ret = of_get_mac_addr(np, "mac-address", addr);
if (!ret)
- return 0;
+ goto found;
ret = of_get_mac_addr(np, "local-mac-address", addr);
if (!ret)
- return 0;
+ goto found;
ret = of_get_mac_addr(np, "address", addr);
if (!ret)
- return 0;
+ goto found;
+
+ ret = of_get_mac_addr_nvmem(np, addr);
+ if (ret)
+ return ret;
+
+found:
+ if (!of_property_read_u32(np, "mac-address-increment", &mac_inc)) {
+ /* Convert to a contiguous value */
+ mac_val = (addr[3] << 16) + (addr[4] << 8) + addr[5];
+ mac_val += mac_inc << 8 * (5-inc_idx);
+
+ /* Apply the incremented value handling overflow case */
+ addr[3] = (mac_val >> 16) & 0xff;
+ addr[4] = (mac_val >> 8) & 0xff;
+ addr[5] = (mac_val >> 0) & 0xff;
+ }
- return of_get_mac_addr_nvmem(np, addr);
+ return ret;
}
EXPORT_SYMBOL(of_get_mac_address);

View File

@@ -45,11 +45,31 @@ property. This way, the MAC address can be accessed using procfs.
/**
* of_get_mac_address()
* @np: Caller's Device Node
@@ -175,6 +196,7 @@ found:
addr[5] = (mac_val >> 0) & 0xff;
}
@@ -130,17 +151,23 @@ int of_get_mac_address(struct device_nod
+ of_add_mac_address(np, addr);
return ret;
ret = of_get_mac_addr(np, "mac-address", addr);
if (!ret)
- return 0;
+ goto found;
ret = of_get_mac_addr(np, "local-mac-address", addr);
if (!ret)
- return 0;
+ goto found;
ret = of_get_mac_addr(np, "address", addr);
if (!ret)
- return 0;
+ goto found;
- return of_get_mac_addr_nvmem(np, addr);
+ ret = of_get_mac_addr_nvmem(np, addr);
+ if (ret)
+ return ret;
+
+found:
+ ret = of_add_mac_address(np, addr);
+ return ret;
}
EXPORT_SYMBOL(of_get_mac_address);

View File

@@ -1,31 +0,0 @@
From dd07dd394d8bfdb5d527fab18ca54f20815ec4e4 Mon Sep 17 00:00:00 2001
From: Will Moss <willormos@gmail.com>
Date: Wed, 3 Aug 2022 13:48:55 +0000
Subject: [PATCH] of_net: do mac-address-increment only once
Remove mac-address-increment and mac-address-increment-byte
DT property after incrementing process to make sure MAC address
would not get incremented more if this function is stared again.
It could happen if device initialization is deferred after
unsuccessful attempt.
Signed-off-by: Will Moss <willormos@gmail.com>
---
drivers/of/of_net.c | 6 ++++++
1 file changed, 6 insertions(+)
--- a/net/core/of_net.c
+++ b/net/core/of_net.c
@@ -194,6 +194,12 @@ found:
addr[3] = (mac_val >> 16) & 0xff;
addr[4] = (mac_val >> 8) & 0xff;
addr[5] = (mac_val >> 0) & 0xff;
+
+ /* Remove mac-address-increment and mac-address-increment-byte
+ * DT property to make sure MAC address would not get incremented
+ * more if this function is stared again. */
+ of_remove_property(np, of_find_property(np, "mac-address-increment", NULL));
+ of_remove_property(np, of_find_property(np, "mac-address-increment-byte", NULL));
}
of_add_mac_address(np, addr);

View File

@@ -45,7 +45,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
if (!(p->flags & BR_BCAST_FLOOD) && skb->dev != br->dev)
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -344,6 +344,8 @@ static rx_handler_result_t br_handle_fra
@@ -349,6 +349,8 @@ static rx_handler_result_t br_handle_fra
fwd_mask |= p->group_fwd_mask;
switch (dest[5]) {
case 0x00: /* Bridge Group Address */

View File

@@ -15,7 +15,7 @@ Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -2449,6 +2449,10 @@ mt7530_setup(struct dsa_switch *ds)
@@ -2470,6 +2470,10 @@ mt7530_setup(struct dsa_switch *ds)
return -ENODEV;
}

View File

@@ -17,7 +17,7 @@ Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2170,7 +2170,7 @@ struct net_device {
@@ -2168,7 +2168,7 @@ struct net_device {
#if IS_ENABLED(CONFIG_AX25)
void *ax25_ptr;
#endif

View File

@@ -20,7 +20,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
/**
* napi_disable - prevent NAPI from scheduling
@@ -3130,6 +3131,7 @@ struct softnet_data {
@@ -3128,6 +3129,7 @@ struct softnet_data {
unsigned int processed;
unsigned int time_squeeze;
unsigned int received_rps;
@@ -157,7 +157,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
void netif_napi_add_weight(struct net_device *dev, struct napi_struct *napi,
int (*poll)(struct napi_struct *, int), int weight)
{
@@ -11186,6 +11257,9 @@ static int dev_cpu_dead(unsigned int old
@@ -11141,6 +11212,9 @@ static int dev_cpu_dead(unsigned int old
raise_softirq_irqoff(NET_TX_SOFTIRQ);
local_irq_enable();
@@ -167,7 +167,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
#ifdef CONFIG_RPS
remsd = oldsd->rps_ipi_list;
oldsd->rps_ipi_list = NULL;
@@ -11498,6 +11572,7 @@ static int __init net_dev_init(void)
@@ -11453,6 +11527,7 @@ static int __init net_dev_init(void)
INIT_CSD(&sd->defer_csd, trigger_rx_softirq, sd);
spin_lock_init(&sd->defer_lock);
@@ -177,15 +177,15 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
sd->backlog.weight = weight_p;
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -29,6 +29,7 @@ static int int_3600 = 3600;
static int min_sndbuf = SOCK_MIN_SNDBUF;
@@ -30,6 +30,7 @@ static int min_sndbuf = SOCK_MIN_SNDBUF;
static int min_rcvbuf = SOCK_MIN_RCVBUF;
static int max_skb_frags = MAX_SKB_FRAGS;
static int min_mem_pcpu_rsv = SK_MEMORY_PCPU_RESERVE;
+static int backlog_threaded;
static int net_msg_warn; /* Unused, but still a sysctl */
@@ -112,6 +113,23 @@ static int rps_sock_flow_sysctl(struct c
@@ -113,6 +114,23 @@ static int rps_sock_flow_sysctl(struct c
}
#endif /* CONFIG_RPS */
@@ -209,7 +209,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
#ifdef CONFIG_NET_FLOW_LIMIT
static DEFINE_MUTEX(flow_limit_update_mutex);
@@ -473,6 +491,15 @@ static struct ctl_table net_core_table[]
@@ -482,6 +500,15 @@ static struct ctl_table net_core_table[]
.proc_handler = rps_sock_flow_sysctl
},
#endif

View File

@@ -16,7 +16,7 @@ Signed-off-by: David Bauer <mail@david-bauer.net>
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -2339,10 +2339,13 @@ mt7530_setup_mdio(struct mt7530_priv *pr
@@ -2360,10 +2360,13 @@ mt7530_setup_mdio(struct mt7530_priv *pr
{
struct dsa_switch *ds = priv->ds;
struct device *dev = priv->dev;
@@ -30,7 +30,7 @@ Signed-off-by: David Bauer <mail@david-bauer.net>
bus = devm_mdiobus_alloc(dev);
if (!bus)
return -ENOMEM;
@@ -2359,7 +2362,9 @@ mt7530_setup_mdio(struct mt7530_priv *pr
@@ -2380,7 +2383,9 @@ mt7530_setup_mdio(struct mt7530_priv *pr
if (priv->irq)
mt7530_setup_mdio_irq(priv);

View File

@@ -19,7 +19,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
static struct amd_chipset_info {
struct pci_dev *nb_dev;
struct pci_dev *smbus_dev;
@@ -633,6 +635,10 @@ bool usb_amd_pt_check_port(struct device
@@ -631,6 +633,10 @@ bool usb_amd_pt_check_port(struct device
}
EXPORT_SYMBOL_GPL(usb_amd_pt_check_port);
@@ -30,7 +30,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
/*
* Make sure the controller is completely inactive, unable to
* generate interrupts or do DMA.
@@ -712,8 +718,17 @@ reset_needed:
@@ -710,8 +716,17 @@ reset_needed:
uhci_reset_hc(pdev, base);
return 1;
}
@@ -48,7 +48,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask)
{
u16 cmd;
@@ -1285,3 +1300,4 @@ static void quirk_usb_early_handoff(stru
@@ -1283,3 +1298,4 @@ static void quirk_usb_early_handoff(stru
}
DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff);
@@ -98,7 +98,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
#endif /* __LINUX_USB_PCI_QUIRKS_H */
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -483,7 +483,14 @@ extern int usb_hcd_pci_probe(struct pci_
@@ -484,7 +484,14 @@ extern int usb_hcd_pci_probe(struct pci_
extern void usb_hcd_pci_remove(struct pci_dev *dev);
extern void usb_hcd_pci_shutdown(struct pci_dev *dev);

View File

@@ -12,16 +12,17 @@
{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -2277,6 +2277,12 @@ static const struct usb_device_id option
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x01a3, 0xff) }, /* Fibocom FM101-GL (laptop MBIM) */
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x01a4, 0xff), /* Fibocom FM101-GL (laptop MBIM) */
.driver_info = RSVD(4) },
+ { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0a04, 0xff), /* Fibocom FM650 ECM */
+ .driver_info = RSVD(5) },
+ { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0a05, 0xff), /* Fibocom FM650 NCM */
+ .driver_info = RSVD(6) },
+ { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0a06, 0xff), /* Fibocom FM650 RNDIS */
+ .driver_info = RSVD(6) },
@@ -2310,9 +2310,13 @@ static const struct usb_device_id option
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0a06, 0xff) }, /* Fibocom FM650-CN (RNDIS mode) */
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0a07, 0xff) }, /* Fibocom FM650-CN (MBIM mode) */
{ USB_DEVICE_INTERFACE_CLASS(0x2df3, 0x9d03, 0xff) }, /* LongSung M5710 */
+ { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1402, 0xff) }, /* GosunCn GM800 (Download mode) */
+ { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1403, 0xff) }, /* GosunCn GM800 (rmnet, old) */
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1404, 0xff) }, /* GosunCn GM500 RNDIS */
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1405, 0xff) }, /* GosunCn GM500 MBIM */
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1406, 0xff) }, /* GosunCn GM500 ECM/NCM */
+ { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1421, 0xff) }, /* GosunCn GM800 (rmnet) */
+ { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1422, 0xff) }, /* GosunCn GM800 (EAP) */
{ USB_DEVICE(0x33f8, 0x0104), /* Rolling RW101-GL (laptop RMNET) */
.driver_info = RSVD(4) | RSVD(5) },
{ USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x01a2, 0xff) }, /* Rolling RW101-GL (laptop MBIM) */

View File

@@ -61,7 +61,7 @@ Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
/*
* We need to store the untouched command line for future reference.
* We also need to store the touched command line since the parameter
@@ -959,6 +982,7 @@ asmlinkage __visible void __init __no_sa
@@ -961,6 +984,7 @@ asmlinkage __visible void __init __no_sa
pr_notice("%s", linux_banner);
early_security_init();
setup_arch(&command_line);

View File

@@ -15,7 +15,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -239,6 +239,9 @@ static void __br_handle_local_finish(str
@@ -244,6 +244,9 @@ static void __br_handle_local_finish(str
/* note: already called with rcu_read_lock */
static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
@@ -25,7 +25,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
__br_handle_local_finish(skb);
/* return 1 to signal the okfn() was called so it's ok to use the skb */
@@ -408,6 +411,17 @@ forward:
@@ -415,6 +418,17 @@ forward:
goto defer_stp_filtering;
switch (p->state) {

View File

@@ -1,151 +0,0 @@
From: Felix Fietkau <nbd@nbd.name>
Subject: net: replace GRO optimization patch with a new one that supports VLANs/bridges with different MAC addresses
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
include/linux/netdevice.h | 2 ++
include/linux/skbuff.h | 3 ++-
net/core/dev.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++
net/ethernet/eth.c | 18 +++++++++++++++++-
4 files changed, 69 insertions(+), 2 deletions(-)
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2210,6 +2210,8 @@ struct net_device {
struct netdev_hw_addr_list mc;
struct netdev_hw_addr_list dev_addrs;
+ unsigned char local_addr_mask[MAX_ADDR_LEN];
+
#ifdef CONFIG_SYSFS
struct kset *queues_kset;
#endif
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -959,6 +959,7 @@ struct sk_buff {
#ifdef CONFIG_IPV6_NDISC_NODETYPE
__u8 ndisc_nodetype:2;
#endif
+ __u8 gro_skip:1;
#if IS_ENABLED(CONFIG_IP_VS)
__u8 ipvs_property:1;
--- a/net/core/gro.c
+++ b/net/core/gro.c
@@ -446,6 +446,9 @@ static enum gro_result dev_gro_receive(s
enum gro_result ret;
int same_flow;
+ if (skb->gro_skip)
+ goto normal;
+
if (netif_elide_gro(skb->dev))
goto normal;
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -7689,6 +7689,48 @@ static void __netdev_adjacent_dev_unlink
&upper_dev->adj_list.lower);
}
+static void __netdev_addr_mask(unsigned char *mask, const unsigned char *addr,
+ struct net_device *dev)
+{
+ int i;
+
+ for (i = 0; i < dev->addr_len; i++)
+ mask[i] |= addr[i] ^ dev->dev_addr[i];
+}
+
+static void __netdev_upper_mask(unsigned char *mask, struct net_device *dev,
+ struct net_device *lower)
+{
+ struct net_device *cur;
+ struct list_head *iter;
+
+ netdev_for_each_upper_dev_rcu(dev, cur, iter) {
+ __netdev_addr_mask(mask, cur->dev_addr, lower);
+ __netdev_upper_mask(mask, cur, lower);
+ }
+}
+
+static void __netdev_update_addr_mask(struct net_device *dev)
+{
+ unsigned char mask[MAX_ADDR_LEN];
+ struct net_device *cur;
+ struct list_head *iter;
+
+ memset(mask, 0, sizeof(mask));
+ __netdev_upper_mask(mask, dev, dev);
+ memcpy(dev->local_addr_mask, mask, dev->addr_len);
+
+ netdev_for_each_lower_dev(dev, cur, iter)
+ __netdev_update_addr_mask(cur);
+}
+
+static void netdev_update_addr_mask(struct net_device *dev)
+{
+ rcu_read_lock();
+ __netdev_update_addr_mask(dev);
+ rcu_read_unlock();
+}
+
static int __netdev_upper_dev_link(struct net_device *dev,
struct net_device *upper_dev, bool master,
void *upper_priv, void *upper_info,
@@ -7740,6 +7782,7 @@ static int __netdev_upper_dev_link(struc
if (ret)
return ret;
+ netdev_update_addr_mask(dev);
ret = call_netdevice_notifiers_info(NETDEV_CHANGEUPPER,
&changeupper_info.info);
ret = notifier_to_errno(ret);
@@ -7836,6 +7879,7 @@ static void __netdev_upper_dev_unlink(st
__netdev_adjacent_dev_unlink_neighbour(dev, upper_dev);
+ netdev_update_addr_mask(dev);
call_netdevice_notifiers_info(NETDEV_CHANGEUPPER,
&changeupper_info.info);
@@ -8892,6 +8936,7 @@ int dev_set_mac_address(struct net_devic
return err;
}
dev->addr_assign_type = NET_ADDR_SET;
+ netdev_update_addr_mask(dev);
call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
add_device_randomness(dev->dev_addr, dev->addr_len);
return 0;
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -143,6 +143,18 @@ u32 eth_get_headlen(const struct net_dev
}
EXPORT_SYMBOL(eth_get_headlen);
+static inline bool
+eth_check_local_mask(const void *addr1, const void *addr2, const void *mask)
+{
+ const u16 *a1 = addr1;
+ const u16 *a2 = addr2;
+ const u16 *m = mask;
+
+ return (((a1[0] ^ a2[0]) & ~m[0]) |
+ ((a1[1] ^ a2[1]) & ~m[1]) |
+ ((a1[2] ^ a2[2]) & ~m[2]));
+}
+
/**
* eth_type_trans - determine the packet's protocol ID.
* @skb: received socket data
@@ -174,6 +186,10 @@ __be16 eth_type_trans(struct sk_buff *sk
} else {
skb->pkt_type = PACKET_OTHERHOST;
}
+
+ if (eth_check_local_mask(eth->h_dest, dev->dev_addr,
+ dev->local_addr_mask))
+ skb->gro_skip = 1;
}
/*

View File

@@ -0,0 +1,578 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Tue, 23 Apr 2024 11:23:03 +0200
Subject: [PATCH] net: add TCP fraglist GRO support
When forwarding TCP after GRO, software segmentation is very expensive,
especially when the checksum needs to be recalculated.
One case where that's currently unavoidable is when routing packets over
PPPoE. Performance improves significantly when using fraglist GRO
implemented in the same way as for UDP.
Here's a measurement of running 2 TCP streams through a MediaTek MT7622
device (2-core Cortex-A53), which runs NAT with flow offload enabled from
one ethernet port to PPPoE on another ethernet port + cake qdisc set to
1Gbps.
rx-gro-list off: 630 Mbit/s, CPU 35% idle
rx-gro-list on: 770 Mbit/s, CPU 40% idle
Signe-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/net/gro.h
+++ b/include/net/gro.h
@@ -439,6 +439,7 @@ static inline __wsum ip6_gro_compute_pse
}
int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb);
+int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb);
/* Pass the currently batched GRO_NORMAL SKBs up to the stack. */
static inline void gro_normal_list(struct napi_struct *napi)
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -2082,7 +2082,10 @@ void tcp_v4_destroy_sock(struct sock *sk
struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
netdev_features_t features);
-struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb);
+struct tcphdr *tcp_gro_pull_header(struct sk_buff *skb);
+struct sk_buff *tcp_gro_lookup(struct list_head *head, struct tcphdr *th);
+struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb,
+ struct tcphdr *th);
INDIRECT_CALLABLE_DECLARE(int tcp4_gro_complete(struct sk_buff *skb, int thoff));
INDIRECT_CALLABLE_DECLARE(struct sk_buff *tcp4_gro_receive(struct list_head *head, struct sk_buff *skb));
INDIRECT_CALLABLE_DECLARE(int tcp6_gro_complete(struct sk_buff *skb, int thoff));
--- a/net/core/gro.c
+++ b/net/core/gro.c
@@ -233,6 +233,33 @@ done:
return 0;
}
+int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb)
+{
+ if (unlikely(p->len + skb->len >= 65536))
+ return -E2BIG;
+
+ if (NAPI_GRO_CB(p)->last == p)
+ skb_shinfo(p)->frag_list = skb;
+ else
+ NAPI_GRO_CB(p)->last->next = skb;
+
+ skb_pull(skb, skb_gro_offset(skb));
+
+ NAPI_GRO_CB(p)->last = skb;
+ NAPI_GRO_CB(p)->count++;
+ p->data_len += skb->len;
+
+ /* sk ownership - if any - completely transferred to the aggregated packet */
+ skb->destructor = NULL;
+ skb->sk = NULL;
+ p->truesize += skb->truesize;
+ p->len += skb->len;
+
+ NAPI_GRO_CB(skb)->same_flow = 1;
+
+ return 0;
+}
+
static void napi_gro_complete(struct napi_struct *napi, struct sk_buff *skb)
{
--- a/net/ipv4/tcp_offload.c
+++ b/net/ipv4/tcp_offload.c
@@ -28,6 +28,70 @@ static void tcp_gso_tstamp(struct sk_buf
}
}
+static void __tcpv4_gso_segment_csum(struct sk_buff *seg,
+ __be32 *oldip, __be32 newip,
+ __be16 *oldport, __be16 newport)
+{
+ struct tcphdr *th;
+ struct iphdr *iph;
+
+ if (*oldip == newip && *oldport == newport)
+ return;
+
+ th = tcp_hdr(seg);
+ iph = ip_hdr(seg);
+
+ inet_proto_csum_replace4(&th->check, seg, *oldip, newip, true);
+ inet_proto_csum_replace2(&th->check, seg, *oldport, newport, false);
+ *oldport = newport;
+
+ csum_replace4(&iph->check, *oldip, newip);
+ *oldip = newip;
+}
+
+static struct sk_buff *__tcpv4_gso_segment_list_csum(struct sk_buff *segs)
+{
+ const struct tcphdr *th;
+ const struct iphdr *iph;
+ struct sk_buff *seg;
+ struct tcphdr *th2;
+ struct iphdr *iph2;
+
+ seg = segs;
+ th = tcp_hdr(seg);
+ iph = ip_hdr(seg);
+ th2 = tcp_hdr(seg->next);
+ iph2 = ip_hdr(seg->next);
+
+ if (!(*(const u32 *)&th->source ^ *(const u32 *)&th2->source) &&
+ iph->daddr == iph2->daddr && iph->saddr == iph2->saddr)
+ return segs;
+
+ while ((seg = seg->next)) {
+ th2 = tcp_hdr(seg);
+ iph2 = ip_hdr(seg);
+
+ __tcpv4_gso_segment_csum(seg,
+ &iph2->saddr, iph->saddr,
+ &th2->source, th->source);
+ __tcpv4_gso_segment_csum(seg,
+ &iph2->daddr, iph->daddr,
+ &th2->dest, th->dest);
+ }
+
+ return segs;
+}
+
+static struct sk_buff *__tcp4_gso_segment_list(struct sk_buff *skb,
+ netdev_features_t features)
+{
+ skb = skb_segment_list(skb, features, skb_mac_header_len(skb));
+ if (IS_ERR(skb))
+ return skb;
+
+ return __tcpv4_gso_segment_list_csum(skb);
+}
+
static struct sk_buff *tcp4_gso_segment(struct sk_buff *skb,
netdev_features_t features)
{
@@ -37,6 +101,9 @@ static struct sk_buff *tcp4_gso_segment(
if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
return ERR_PTR(-EINVAL);
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST)
+ return __tcp4_gso_segment_list(skb, features);
+
if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) {
const struct iphdr *iph = ip_hdr(skb);
struct tcphdr *th = tcp_hdr(skb);
@@ -178,61 +245,76 @@ out:
return segs;
}
-struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb)
+struct sk_buff *tcp_gro_lookup(struct list_head *head, struct tcphdr *th)
{
- struct sk_buff *pp = NULL;
+ struct tcphdr *th2;
struct sk_buff *p;
+
+ list_for_each_entry(p, head, list) {
+ if (!NAPI_GRO_CB(p)->same_flow)
+ continue;
+
+ th2 = tcp_hdr(p);
+ if (*(u32 *)&th->source ^ *(u32 *)&th2->source) {
+ NAPI_GRO_CB(p)->same_flow = 0;
+ continue;
+ }
+
+ return p;
+ }
+
+ return NULL;
+}
+
+struct tcphdr *tcp_gro_pull_header(struct sk_buff *skb)
+{
+ unsigned int thlen, hlen, off;
struct tcphdr *th;
- struct tcphdr *th2;
- unsigned int len;
- unsigned int thlen;
- __be32 flags;
- unsigned int mss = 1;
- unsigned int hlen;
- unsigned int off;
- int flush = 1;
- int i;
off = skb_gro_offset(skb);
hlen = off + sizeof(*th);
th = skb_gro_header(skb, hlen, off);
if (unlikely(!th))
- goto out;
+ return NULL;
thlen = th->doff * 4;
if (thlen < sizeof(*th))
- goto out;
+ return NULL;
hlen = off + thlen;
if (skb_gro_header_hard(skb, hlen)) {
th = skb_gro_header_slow(skb, hlen, off);
if (unlikely(!th))
- goto out;
+ return NULL;
}
skb_gro_pull(skb, thlen);
- len = skb_gro_len(skb);
- flags = tcp_flag_word(th);
-
- list_for_each_entry(p, head, list) {
- if (!NAPI_GRO_CB(p)->same_flow)
- continue;
+ return th;
+}
- th2 = tcp_hdr(p);
+struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb,
+ struct tcphdr *th)
+{
+ unsigned int thlen = th->doff * 4;
+ struct sk_buff *pp = NULL;
+ struct sk_buff *p;
+ struct tcphdr *th2;
+ unsigned int len;
+ __be32 flags;
+ unsigned int mss = 1;
+ int flush = 1;
+ int i;
- if (*(u32 *)&th->source ^ *(u32 *)&th2->source) {
- NAPI_GRO_CB(p)->same_flow = 0;
- continue;
- }
+ len = skb_gro_len(skb);
+ flags = tcp_flag_word(th);
- goto found;
- }
- p = NULL;
- goto out_check_final;
+ p = tcp_gro_lookup(head, th);
+ if (!p)
+ goto out_check_final;
-found:
/* Include the IP ID check below from the inner most IP hdr */
+ th2 = tcp_hdr(p);
flush = NAPI_GRO_CB(p)->flush;
flush |= (__force int)(flags & TCP_FLAG_CWR);
flush |= (__force int)((flags ^ tcp_flag_word(th2)) &
@@ -269,6 +351,19 @@ found:
flush |= p->decrypted ^ skb->decrypted;
#endif
+ if (unlikely(NAPI_GRO_CB(p)->is_flist)) {
+ flush |= (__force int)(flags ^ tcp_flag_word(th2));
+ flush |= skb->ip_summed != p->ip_summed;
+ flush |= skb->csum_level != p->csum_level;
+ flush |= !pskb_may_pull(skb, skb_gro_offset(skb));
+ flush |= NAPI_GRO_CB(p)->count >= 64;
+
+ if (flush || skb_gro_receive_list(p, skb))
+ mss = 1;
+
+ goto out_check_final;
+ }
+
if (flush || skb_gro_receive(p, skb)) {
mss = 1;
goto out_check_final;
@@ -290,7 +385,6 @@ out_check_final:
if (p && (!NAPI_GRO_CB(skb)->same_flow || flush))
pp = p;
-out:
NAPI_GRO_CB(skb)->flush |= (flush != 0);
return pp;
@@ -314,18 +408,58 @@ void tcp_gro_complete(struct sk_buff *sk
}
EXPORT_SYMBOL(tcp_gro_complete);
+static void tcp4_check_fraglist_gro(struct list_head *head, struct sk_buff *skb,
+ struct tcphdr *th)
+{
+ const struct iphdr *iph;
+ struct sk_buff *p;
+ struct sock *sk;
+ struct net *net;
+ int iif, sdif;
+
+ if (!(skb->dev->features & NETIF_F_GRO_FRAGLIST))
+ return;
+
+ p = tcp_gro_lookup(head, th);
+ if (p) {
+ NAPI_GRO_CB(skb)->is_flist = NAPI_GRO_CB(p)->is_flist;
+ return;
+ }
+
+ inet_get_iif_sdif(skb, &iif, &sdif);
+ iph = skb_gro_network_header(skb);
+ net = dev_net(skb->dev);
+ sk = __inet_lookup_established(net, net->ipv4.tcp_death_row.hashinfo,
+ iph->saddr, th->source,
+ iph->daddr, ntohs(th->dest),
+ iif, sdif);
+ NAPI_GRO_CB(skb)->is_flist = !sk;
+ if (sk)
+ sock_put(sk);
+}
+
INDIRECT_CALLABLE_SCOPE
struct sk_buff *tcp4_gro_receive(struct list_head *head, struct sk_buff *skb)
{
+ struct tcphdr *th;
+
/* Don't bother verifying checksum if we're going to flush anyway. */
if (!NAPI_GRO_CB(skb)->flush &&
skb_gro_checksum_validate(skb, IPPROTO_TCP,
- inet_gro_compute_pseudo)) {
- NAPI_GRO_CB(skb)->flush = 1;
- return NULL;
- }
+ inet_gro_compute_pseudo))
+ goto flush;
+
+ th = tcp_gro_pull_header(skb);
+ if (!th)
+ goto flush;
- return tcp_gro_receive(head, skb);
+ tcp4_check_fraglist_gro(head, skb, th);
+
+ return tcp_gro_receive(head, skb, th);
+
+flush:
+ NAPI_GRO_CB(skb)->flush = 1;
+ return NULL;
}
INDIRECT_CALLABLE_SCOPE int tcp4_gro_complete(struct sk_buff *skb, int thoff)
@@ -333,6 +467,15 @@ INDIRECT_CALLABLE_SCOPE int tcp4_gro_com
const struct iphdr *iph = ip_hdr(skb);
struct tcphdr *th = tcp_hdr(skb);
+ if (unlikely(NAPI_GRO_CB(skb)->is_flist)) {
+ skb_shinfo(skb)->gso_type |= SKB_GSO_FRAGLIST | SKB_GSO_TCPV4;
+ skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count;
+
+ __skb_incr_checksum_unnecessary(skb);
+
+ return 0;
+ }
+
th->check = ~tcp_v4_check(skb->len - thoff, iph->saddr,
iph->daddr, 0);
skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV4;
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -433,33 +433,6 @@ out:
return segs;
}
-static int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb)
-{
- if (unlikely(p->len + skb->len >= 65536))
- return -E2BIG;
-
- if (NAPI_GRO_CB(p)->last == p)
- skb_shinfo(p)->frag_list = skb;
- else
- NAPI_GRO_CB(p)->last->next = skb;
-
- skb_pull(skb, skb_gro_offset(skb));
-
- NAPI_GRO_CB(p)->last = skb;
- NAPI_GRO_CB(p)->count++;
- p->data_len += skb->len;
-
- /* sk ownership - if any - completely transferred to the aggregated packet */
- skb->destructor = NULL;
- skb->sk = NULL;
- p->truesize += skb->truesize;
- p->len += skb->len;
-
- NAPI_GRO_CB(skb)->same_flow = 1;
-
- return 0;
-}
-
#define UDP_GRO_CNT_MAX 64
static struct sk_buff *udp_gro_receive_segment(struct list_head *head,
--- a/net/ipv6/tcpv6_offload.c
+++ b/net/ipv6/tcpv6_offload.c
@@ -7,24 +7,67 @@
*/
#include <linux/indirect_call_wrapper.h>
#include <linux/skbuff.h>
+#include <net/inet6_hashtables.h>
#include <net/gro.h>
#include <net/protocol.h>
#include <net/tcp.h>
#include <net/ip6_checksum.h>
#include "ip6_offload.h"
+static void tcp6_check_fraglist_gro(struct list_head *head, struct sk_buff *skb,
+ struct tcphdr *th)
+{
+#if IS_ENABLED(CONFIG_IPV6)
+ const struct ipv6hdr *hdr;
+ struct sk_buff *p;
+ struct sock *sk;
+ struct net *net;
+ int iif, sdif;
+
+ if (!(skb->dev->features & NETIF_F_GRO_FRAGLIST))
+ return;
+
+ p = tcp_gro_lookup(head, th);
+ if (p) {
+ NAPI_GRO_CB(skb)->is_flist = NAPI_GRO_CB(p)->is_flist;
+ return;
+ }
+
+ inet6_get_iif_sdif(skb, &iif, &sdif);
+ hdr = skb_gro_network_header(skb);
+ net = dev_net(skb->dev);
+ sk = __inet6_lookup_established(net, net->ipv4.tcp_death_row.hashinfo,
+ &hdr->saddr, th->source,
+ &hdr->daddr, ntohs(th->dest),
+ iif, sdif);
+ NAPI_GRO_CB(skb)->is_flist = !sk;
+ if (sk)
+ sock_put(sk);
+#endif /* IS_ENABLED(CONFIG_IPV6) */
+}
+
INDIRECT_CALLABLE_SCOPE
struct sk_buff *tcp6_gro_receive(struct list_head *head, struct sk_buff *skb)
{
+ struct tcphdr *th;
+
/* Don't bother verifying checksum if we're going to flush anyway. */
if (!NAPI_GRO_CB(skb)->flush &&
skb_gro_checksum_validate(skb, IPPROTO_TCP,
- ip6_gro_compute_pseudo)) {
- NAPI_GRO_CB(skb)->flush = 1;
- return NULL;
- }
+ ip6_gro_compute_pseudo))
+ goto flush;
- return tcp_gro_receive(head, skb);
+ th = tcp_gro_pull_header(skb);
+ if (!th)
+ goto flush;
+
+ tcp6_check_fraglist_gro(head, skb, th);
+
+ return tcp_gro_receive(head, skb, th);
+
+flush:
+ NAPI_GRO_CB(skb)->flush = 1;
+ return NULL;
}
INDIRECT_CALLABLE_SCOPE int tcp6_gro_complete(struct sk_buff *skb, int thoff)
@@ -32,6 +75,15 @@ INDIRECT_CALLABLE_SCOPE int tcp6_gro_com
const struct ipv6hdr *iph = ipv6_hdr(skb);
struct tcphdr *th = tcp_hdr(skb);
+ if (unlikely(NAPI_GRO_CB(skb)->is_flist)) {
+ skb_shinfo(skb)->gso_type |= SKB_GSO_FRAGLIST | SKB_GSO_TCPV6;
+ skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count;
+
+ __skb_incr_checksum_unnecessary(skb);
+
+ return 0;
+ }
+
th->check = ~tcp_v6_check(skb->len - thoff, &iph->saddr,
&iph->daddr, 0);
skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV6;
@@ -40,6 +92,61 @@ INDIRECT_CALLABLE_SCOPE int tcp6_gro_com
return 0;
}
+static void __tcpv6_gso_segment_csum(struct sk_buff *seg,
+ __be16 *oldport, __be16 newport)
+{
+ struct tcphdr *th;
+
+ if (*oldport == newport)
+ return;
+
+ th = tcp_hdr(seg);
+ inet_proto_csum_replace2(&th->check, seg, *oldport, newport, false);
+ *oldport = newport;
+}
+
+static struct sk_buff *__tcpv6_gso_segment_list_csum(struct sk_buff *segs)
+{
+ const struct tcphdr *th;
+ const struct ipv6hdr *iph;
+ struct sk_buff *seg;
+ struct tcphdr *th2;
+ struct ipv6hdr *iph2;
+
+ seg = segs;
+ th = tcp_hdr(seg);
+ iph = ipv6_hdr(seg);
+ th2 = tcp_hdr(seg->next);
+ iph2 = ipv6_hdr(seg->next);
+
+ if (!(*(const u32 *)&th->source ^ *(const u32 *)&th2->source) &&
+ ipv6_addr_equal(&iph->saddr, &iph2->saddr) &&
+ ipv6_addr_equal(&iph->daddr, &iph2->daddr))
+ return segs;
+
+ while ((seg = seg->next)) {
+ th2 = tcp_hdr(seg);
+ iph2 = ipv6_hdr(seg);
+
+ iph2->saddr = iph->saddr;
+ iph2->daddr = iph->daddr;
+ __tcpv6_gso_segment_csum(seg, &th2->source, th->source);
+ __tcpv6_gso_segment_csum(seg, &th2->dest, th->dest);
+ }
+
+ return segs;
+}
+
+static struct sk_buff *__tcp6_gso_segment_list(struct sk_buff *skb,
+ netdev_features_t features)
+{
+ skb = skb_segment_list(skb, features, skb_mac_header_len(skb));
+ if (IS_ERR(skb))
+ return skb;
+
+ return __tcpv6_gso_segment_list_csum(skb);
+}
+
static struct sk_buff *tcp6_gso_segment(struct sk_buff *skb,
netdev_features_t features)
{
@@ -51,6 +158,9 @@ static struct sk_buff *tcp6_gso_segment(
if (!pskb_may_pull(skb, sizeof(*th)))
return ERR_PTR(-EINVAL);
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST)
+ return __tcp6_gso_segment_list(skb, features);
+
if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) {
const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
struct tcphdr *th = tcp_hdr(skb);

View File

@@ -0,0 +1,23 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Sat, 27 Apr 2024 18:54:25 +0200
Subject: [PATCH] net: bridge: fix multicast-to-unicast with fraglist GSO
Calling skb_copy on a SKB_GSO_FRAGLIST skb is not valid, since it returns
an invalid linearized skb. This code only needs to change the ethernet
header, so pskb_copy is the right function to call here.
Fixes: 6db6f0eae605 ("bridge: multicast to unicast")
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -266,7 +266,7 @@ static void maybe_deliver_addr(struct ne
if (skb->dev == p->dev && ether_addr_equal(src, addr))
return;
- skb = skb_copy(skb, GFP_ATOMIC);
+ skb = pskb_copy(skb, GFP_ATOMIC);
if (!skb) {
DEV_STATS_INC(dev, tx_dropped);
return;

View File

@@ -0,0 +1,59 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Sat, 27 Apr 2024 19:29:45 +0200
Subject: [PATCH] net: core: reject skb_copy(_expand) for fraglist GSO skbs
SKB_GSO_FRAGLIST skbs must not be linearized, otherwise they become
invalid. Return NULL if such an skb is passed to skb_copy or
skb_copy_expand, in order to prevent a crash on a potential later
call to skb_gso_segment.
Fixes: 3a1296a38d0c ("net: Support GRO/GSO fraglist chaining.")
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -1971,11 +1971,17 @@ static inline int skb_alloc_rx_flag(cons
struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask)
{
- int headerlen = skb_headroom(skb);
- unsigned int size = skb_end_offset(skb) + skb->data_len;
- struct sk_buff *n = __alloc_skb(size, gfp_mask,
- skb_alloc_rx_flag(skb), NUMA_NO_NODE);
+ struct sk_buff *n;
+ unsigned int size;
+ int headerlen;
+ if (WARN_ON_ONCE(skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST))
+ return NULL;
+
+ headerlen = skb_headroom(skb);
+ size = skb_end_offset(skb) + skb->data_len;
+ n = __alloc_skb(size, gfp_mask,
+ skb_alloc_rx_flag(skb), NUMA_NO_NODE);
if (!n)
return NULL;
@@ -2303,12 +2309,17 @@ struct sk_buff *skb_copy_expand(const st
/*
* Allocate the copy buffer
*/
- struct sk_buff *n = __alloc_skb(newheadroom + skb->len + newtailroom,
- gfp_mask, skb_alloc_rx_flag(skb),
- NUMA_NO_NODE);
- int oldheadroom = skb_headroom(skb);
int head_copy_len, head_copy_off;
+ struct sk_buff *n;
+ int oldheadroom;
+
+ if (WARN_ON_ONCE(skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST))
+ return NULL;
+ oldheadroom = skb_headroom(skb);
+ n = __alloc_skb(newheadroom + skb->len + newtailroom,
+ gfp_mask, skb_alloc_rx_flag(skb),
+ NUMA_NO_NODE);
if (!n)
return NULL;

View File

@@ -1,90 +0,0 @@
From 844c273286f328acf0dab5fbd5d864366b4904dc Mon Sep 17 00:00:00 2001
From: Ansuel Smith <ansuelsmth@gmail.com>
Date: Tue, 30 Mar 2021 18:21:14 +0200
Subject: [PATCH] of_net: add mac-address-increment support
Lots of embedded devices use the mac-address of other interface
extracted from nvmem cells and increments it by one or two. Add two
bindings to integrate this and directly use the right mac-address for
the interface. Some example are some routers that use the gmac
mac-address stored in the art partition and increments it by one for the
wifi. mac-address-increment-byte bindings is used to tell what byte of
the mac-address has to be increased (if not defined the last byte is
increased) and mac-address-increment tells how much the byte decided
early has to be increased.
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
net/core/of_net.c | 43 +++++++++++++++++++++++++++++++++++++++----
1 file changed, 39 insertions(+), 4 deletions(-)
--- a/net/core/of_net.c
+++ b/net/core/of_net.c
@@ -121,28 +121,63 @@ EXPORT_SYMBOL(of_get_mac_address_nvmem);
* this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
* but is all zeros.
*
+ * DT can tell the system to increment the mac-address after is extracted by
+ * using:
+ * - mac-address-increment-byte to decide what byte to increase
+ * (if not defined is increased the last byte)
+ * - mac-address-increment to decide how much to increase. The value WILL
+ * overflow to other bytes if the increment is over 255 or the total
+ * increment will exceed 255 of the current byte.
+ * (example 00:01:02:03:04:ff + 1 == 00:01:02:03:05:00)
+ * (example 00:01:02:03:04:fe + 5 == 00:01:02:03:05:03)
+ *
* Return: 0 on success and errno in case of error.
*/
int of_get_mac_address(struct device_node *np, u8 *addr)
{
+ u32 inc_idx, mac_inc, mac_val;
int ret;
+ /* Check first if the increment byte is present and valid.
+ * If not set assume to increment the last byte if found.
+ */
+ if (of_property_read_u32(np, "mac-address-increment-byte", &inc_idx))
+ inc_idx = 5;
+ if (inc_idx < 3 || inc_idx > 5)
+ return -EINVAL;
+
if (!np)
return -ENODEV;
ret = of_get_mac_addr(np, "mac-address", addr);
if (!ret)
- return 0;
+ goto found;
ret = of_get_mac_addr(np, "local-mac-address", addr);
if (!ret)
- return 0;
+ goto found;
ret = of_get_mac_addr(np, "address", addr);
if (!ret)
- return 0;
+ goto found;
+
+ ret = of_get_mac_address_nvmem(np, addr);
+ if (ret)
+ return ret;
+
+found:
+ if (!of_property_read_u32(np, "mac-address-increment", &mac_inc)) {
+ /* Convert to a contiguous value */
+ mac_val = (addr[3] << 16) + (addr[4] << 8) + addr[5];
+ mac_val += mac_inc << 8 * (5-inc_idx);
+
+ /* Apply the incremented value handling overflow case */
+ addr[3] = (mac_val >> 16) & 0xff;
+ addr[4] = (mac_val >> 8) & 0xff;
+ addr[5] = (mac_val >> 0) & 0xff;
+ }
- return of_get_mac_address_nvmem(np, addr);
+ return ret;
}
EXPORT_SYMBOL(of_get_mac_address);

View File

@@ -45,11 +45,31 @@ property. This way, the MAC address can be accessed using procfs.
/**
* of_get_mac_address()
* @np: Caller's Device Node
@@ -177,6 +198,7 @@ found:
addr[5] = (mac_val >> 0) & 0xff;
}
@@ -132,17 +153,23 @@ int of_get_mac_address(struct device_nod
+ of_add_mac_address(np, addr);
return ret;
ret = of_get_mac_addr(np, "mac-address", addr);
if (!ret)
- return 0;
+ goto found;
ret = of_get_mac_addr(np, "local-mac-address", addr);
if (!ret)
- return 0;
+ goto found;
ret = of_get_mac_addr(np, "address", addr);
if (!ret)
- return 0;
+ goto found;
- return of_get_mac_address_nvmem(np, addr);
+ ret = of_get_mac_address_nvmem(np, addr);
+ if (ret)
+ return ret;
+
+found:
+ ret = of_add_mac_address(np, addr);
+ return ret;
}
EXPORT_SYMBOL(of_get_mac_address);

View File

@@ -18,7 +18,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -8260,7 +8260,7 @@ static int nft_register_flowtable_net_ho
@@ -8268,7 +8268,7 @@ static int nft_register_flowtable_net_ho
err = flowtable->data.type->setup(&flowtable->data,
hook->ops.dev,
FLOW_BLOCK_BIND);

View File

@@ -45,7 +45,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
if (!(p->flags & BR_BCAST_FLOOD) && skb->dev != br->dev)
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -362,6 +362,8 @@ static rx_handler_result_t br_handle_fra
@@ -367,6 +367,8 @@ static rx_handler_result_t br_handle_fra
fwd_mask |= p->group_fwd_mask;
switch (dest[5]) {
case 0x00: /* Bridge Group Address */

View File

@@ -15,7 +15,7 @@ Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -2465,6 +2465,10 @@ mt7530_setup(struct dsa_switch *ds)
@@ -2467,6 +2467,10 @@ mt7530_setup(struct dsa_switch *ds)
return -ENODEV;
}

View File

@@ -177,15 +177,15 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
sd->backlog.weight = weight_p;
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -30,6 +30,7 @@ static int int_3600 = 3600;
static int min_sndbuf = SOCK_MIN_SNDBUF;
@@ -31,6 +31,7 @@ static int min_sndbuf = SOCK_MIN_SNDBUF;
static int min_rcvbuf = SOCK_MIN_RCVBUF;
static int max_skb_frags = MAX_SKB_FRAGS;
static int min_mem_pcpu_rsv = SK_MEMORY_PCPU_RESERVE;
+static int backlog_threaded;
static int net_msg_warn; /* Unused, but still a sysctl */
@@ -188,6 +189,23 @@ static int rps_sock_flow_sysctl(struct c
@@ -189,6 +190,23 @@ static int rps_sock_flow_sysctl(struct c
}
#endif /* CONFIG_RPS */
@@ -209,7 +209,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
#ifdef CONFIG_NET_FLOW_LIMIT
static DEFINE_MUTEX(flow_limit_update_mutex);
@@ -532,6 +550,15 @@ static struct ctl_table net_core_table[]
@@ -541,6 +559,15 @@ static struct ctl_table net_core_table[]
.proc_handler = rps_sock_flow_sysctl
},
#endif

View File

@@ -17,7 +17,7 @@ Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -6887,6 +6887,7 @@ static int mv88e6xxx_register_switch(str
@@ -6935,6 +6935,7 @@ static int mv88e6xxx_register_switch(str
ds->ops = &mv88e6xxx_switch_ops;
ds->ageing_time_min = chip->info->age_time_coeff;
ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX;

View File

@@ -16,7 +16,7 @@ Signed-off-by: David Bauer <mail@david-bauer.net>
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -2353,10 +2353,13 @@ mt7530_setup_mdio(struct mt7530_priv *pr
@@ -2355,10 +2355,13 @@ mt7530_setup_mdio(struct mt7530_priv *pr
{
struct dsa_switch *ds = priv->ds;
struct device *dev = priv->dev;
@@ -30,7 +30,7 @@ Signed-off-by: David Bauer <mail@david-bauer.net>
bus = devm_mdiobus_alloc(dev);
if (!bus)
return -ENOMEM;
@@ -2375,7 +2378,9 @@ mt7530_setup_mdio(struct mt7530_priv *pr
@@ -2377,7 +2380,9 @@ mt7530_setup_mdio(struct mt7530_priv *pr
if (priv->irq)
mt7530_setup_mdio_irq(priv);

View File

@@ -98,7 +98,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
#endif /* __LINUX_USB_PCI_QUIRKS_H */
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -484,7 +484,14 @@ extern int usb_hcd_pci_probe(struct pci_
@@ -485,7 +485,14 @@ extern int usb_hcd_pci_probe(struct pci_
extern void usb_hcd_pci_remove(struct pci_dev *dev);
extern void usb_hcd_pci_shutdown(struct pci_dev *dev);

View File

@@ -0,0 +1,28 @@
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -1431,6 +1431,9 @@ static const struct usb_device_id produc
{QMI_FIXED_INTF(0x2692, 0x9025, 4)}, /* Cellient MPL200 (rebranded Qualcomm 05c6:9025) */
{QMI_QUIRK_SET_DTR(0x1546, 0x1312, 4)}, /* u-blox LARA-R6 01B */
{QMI_QUIRK_SET_DTR(0x1546, 0x1342, 4)}, /* u-blox LARA-L6 */
+ {QMI_FIXED_INTF(0x2077, 0x2002, 4)}, /* T&W TW04C */
+ {QMI_FIXED_INTF(0x2077, 0x2003, 4)}, /* T&W TW12G */
+ {QMI_FIXED_INTF(0x2077, 0x2004, 4)}, /* T&W TW510M */
/* 4. Gobi 1000 devices */
{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -2310,9 +2310,13 @@ static const struct usb_device_id option
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0a06, 0xff) }, /* Fibocom FM650-CN (RNDIS mode) */
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0a07, 0xff) }, /* Fibocom FM650-CN (MBIM mode) */
{ USB_DEVICE_INTERFACE_CLASS(0x2df3, 0x9d03, 0xff) }, /* LongSung M5710 */
+ { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1402, 0xff) }, /* GosunCn GM800 (Download mode) */
+ { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1403, 0xff) }, /* GosunCn GM800 (rmnet, old) */
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1404, 0xff) }, /* GosunCn GM500 RNDIS */
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1405, 0xff) }, /* GosunCn GM500 MBIM */
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1406, 0xff) }, /* GosunCn GM500 ECM/NCM */
+ { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1421, 0xff) }, /* GosunCn GM800 (rmnet) */
+ { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1422, 0xff) }, /* GosunCn GM800 (EAP) */
{ USB_DEVICE(0x33f8, 0x0104), /* Rolling RW101-GL (laptop RMNET) */
.driver_info = RSVD(4) | RSVD(5) },
{ USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x01a2, 0xff) }, /* Rolling RW101-GL (laptop MBIM) */

View File

@@ -61,7 +61,7 @@ Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
/*
* We need to store the untouched command line for future reference.
* We also need to store the touched command line since the parameter
@@ -896,6 +919,7 @@ void start_kernel(void)
@@ -898,6 +921,7 @@ void start_kernel(void)
pr_notice("%s", linux_banner);
early_security_init();
setup_arch(&command_line);

View File

@@ -105,7 +105,7 @@ Link: https://lore.kernel.org/r/20230418142109.49762-2-sebastian.reichel@collabo
if (!(tmp & GICR_PENDBASER_SHAREABILITY_MASK)) {
/*
* The HW reports non-shareable, we must remove the
@@ -4731,6 +4742,19 @@ static bool __maybe_unused its_enable_qu
@@ -4726,6 +4737,19 @@ static bool __maybe_unused its_enable_qu
return true;
}
@@ -125,7 +125,7 @@ Link: https://lore.kernel.org/r/20230418142109.49762-2-sebastian.reichel@collabo
static const struct gic_quirk its_quirks[] = {
#ifdef CONFIG_CAVIUM_ERRATUM_22375
{
@@ -4777,6 +4801,14 @@ static const struct gic_quirk its_quirks
@@ -4772,6 +4796,14 @@ static const struct gic_quirk its_quirks
.init = its_enable_quirk_hip07_161600802,
},
#endif
@@ -140,7 +140,7 @@ Link: https://lore.kernel.org/r/20230418142109.49762-2-sebastian.reichel@collabo
{
}
};
@@ -5116,6 +5148,9 @@ static int __init its_probe_one(struct r
@@ -5111,6 +5143,9 @@ static int __init its_probe_one(struct r
gits_write_cbaser(baser, its->base + GITS_CBASER);
tmp = gits_read_cbaser(its->base + GITS_CBASER);

View File

@@ -21,7 +21,7 @@ Link: https://lore.kernel.org/r/20230703164129.193991-1-sebastian.reichel@collab
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -4746,7 +4746,8 @@ static bool __maybe_unused its_enable_rk
@@ -4741,7 +4741,8 @@ static bool __maybe_unused its_enable_rk
{
struct its_node *its = data;

View File

@@ -25,7 +25,7 @@ Change-Id: I6624b6af2ede3c2fca61c0f753a08a33ce69a6d2
#define GRF_PCIE30PHY_CON6 0x18
#define GRF_PCIE30PHY_CON9 0x24
#define GRF_PCIE30PHY_DA_OCM (BIT(15) | BIT(31))
@@ -63,6 +64,10 @@ struct rockchip_p3phy_ops {
@@ -65,6 +66,10 @@ struct rockchip_p3phy_ops {
int (*phy_init)(struct rockchip_p3phy_priv *priv);
};
@@ -36,7 +36,7 @@ Change-Id: I6624b6af2ede3c2fca61c0f753a08a33ce69a6d2
static int rockchip_p3phy_set_mode(struct phy *phy, enum phy_mode mode, int submode)
{
struct rockchip_p3phy_priv *priv = phy_get_drvdata(phy);
@@ -87,13 +92,14 @@ static int rockchip_p3phy_rk3568_init(st
@@ -89,13 +94,14 @@ static int rockchip_p3phy_rk3568_init(st
{
struct phy *phy = priv->phy;
bool bifurcation = false;
@@ -52,7 +52,7 @@ Change-Id: I6624b6af2ede3c2fca61c0f753a08a33ce69a6d2
dev_info(&phy->dev, "lane number %d, val %d\n", i, priv->lanes[i]);
if (priv->lanes[i] > 1)
bifurcation = true;
@@ -112,16 +118,35 @@ static int rockchip_p3phy_rk3568_init(st
@@ -114,16 +120,35 @@ static int rockchip_p3phy_rk3568_init(st
GRF_PCIE30PHY_WR_EN & ~RK3568_BIFURCATION_LANE_0_1);
}

View File

@@ -1,6 +1,6 @@
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -4750,7 +4750,9 @@ static bool __maybe_unused its_enable_rk
@@ -4745,7 +4745,9 @@ static bool __maybe_unused its_enable_rk
{
struct its_node *its = data;

View File

@@ -83,7 +83,7 @@ Signed-off-by: XiaoDong Huang <derrick.huang@rock-chips.com>
if (alloc_lpis) {
lpi_map = its_lpi_alloc(nvecs, &lpi_base, &nr_lpis);
if (lpi_map)
@@ -5071,6 +5087,7 @@ static int __init its_probe_one(struct r
@@ -5066,6 +5082,7 @@ static int __init its_probe_one(struct r
struct page *page;
u32 ctlr;
int err;
@@ -91,7 +91,7 @@ Signed-off-by: XiaoDong Huang <derrick.huang@rock-chips.com>
its_base = its_map_one(res, &err);
if (!its_base)
@@ -5124,7 +5141,10 @@ static int __init its_probe_one(struct r
@@ -5119,7 +5136,10 @@ static int __init its_probe_one(struct r
its->numa_node = numa_node;