* [PATCH net-next v5] net: pppoe: implement GRO/GSO support
@ 2026-03-05 1:38 Qingfang Deng
2026-03-07 1:04 ` Jakub Kicinski
2026-03-26 2:43 ` Qingfang Deng
0 siblings, 2 replies; 10+ messages in thread
From: Qingfang Deng @ 2026-03-05 1:38 UTC (permalink / raw)
To: linux-ppp, Michal Ostrowski, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, David Ahern,
Simon Horman, netdev, linux-kernel
Cc: Felix Fietkau
From: Felix Fietkau <nbd@nbd.name>
Only handles packets where the pppoe header length field matches the exact
packet length. Significantly improves rx throughput.
When running NAT traffic through a MediaTek MT7621 devices from a host
behind PPPoE to a host directly connected via ethernet, the TCP throughput
that the device is able to handle improves from ~130 Mbit/s to ~630 Mbit/s,
using fraglist GRO.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Qingfang Deng <dqfext@gmail.com>
---
v5:
- remove skb_is_gso() check from pppoe_rcv(), as the pppoe length
field is updated in pppoe_gro_complete() to indicate the gso size.
- fix length check in pppoe_gro_receive().
- remove unnecessary check after pppoe_hdr_proto().
- remove some unnecessary const qualifiers.
https://lore.kernel.org/all/20260228032317.146855-1-dqfext@gmail.com/
drivers/net/ppp/pppoe.c | 163 ++++++++++++++++++++++++++++++++++++++++
net/ipv4/af_inet.c | 2 +
net/ipv6/ip6_offload.c | 2 +
3 files changed, 167 insertions(+)
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index 1ac61c273b28..7908262ff2cd 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -77,6 +77,7 @@
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/sock.h>
+#include <net/gro.h>
#include <linux/uaccess.h>
@@ -1097,6 +1098,166 @@ static struct pernet_operations pppoe_net_ops = {
.size = sizeof(struct pppoe_net),
};
+static u16
+compare_pppoe_header(const struct pppoe_hdr *phdr,
+ const struct pppoe_hdr *phdr2)
+{
+ __be16 proto = *(const __be16 *)(phdr + 1);
+ __be16 proto2 = *(const __be16 *)(phdr2 + 1);
+
+ return (__force u16)((phdr->sid ^ phdr2->sid) | (proto ^ proto2));
+}
+
+static __be16 pppoe_hdr_proto(const struct pppoe_hdr *phdr)
+{
+ __be16 proto = *(const __be16 *)(phdr + 1);
+
+ switch (proto) {
+ case cpu_to_be16(PPP_IP):
+ return cpu_to_be16(ETH_P_IP);
+ case cpu_to_be16(PPP_IPV6):
+ return cpu_to_be16(ETH_P_IPV6);
+ default:
+ return 0;
+ }
+}
+
+static struct sk_buff *pppoe_gro_receive(struct list_head *head,
+ struct sk_buff *skb)
+{
+ const struct packet_offload *ptype;
+ unsigned int hlen, off_pppoe;
+ const struct pppoe_hdr *phdr;
+ struct sk_buff *pp = NULL;
+ struct sk_buff *p;
+ int flush = 1;
+ __be16 type;
+
+ off_pppoe = skb_gro_offset(skb);
+ hlen = off_pppoe + sizeof(*phdr);
+ phdr = skb_gro_header(skb, hlen + 2, off_pppoe);
+ if (unlikely(!phdr))
+ goto out;
+
+ /* filter for session packets (type:1, ver:1, code:0) */
+ if (*(const __be16 *)phdr != cpu_to_be16(0x1100))
+ goto out;
+
+ /* ignore packets with padding or invalid length */
+ if (skb_gro_len(skb) != be16_to_cpu(phdr->length) + sizeof(*phdr))
+ goto out;
+
+ type = pppoe_hdr_proto(phdr);
+ ptype = gro_find_receive_by_type(type);
+ if (!ptype)
+ goto out;
+
+ flush = 0;
+
+ list_for_each_entry(p, head, list) {
+ const struct pppoe_hdr *phdr2;
+
+ if (!NAPI_GRO_CB(p)->same_flow)
+ continue;
+
+ phdr2 = (const struct pppoe_hdr *)(p->data + off_pppoe);
+ if (compare_pppoe_header(phdr, phdr2))
+ NAPI_GRO_CB(p)->same_flow = 0;
+ }
+
+ skb_gro_pull(skb, sizeof(*phdr) + 2);
+ skb_gro_postpull_rcsum(skb, phdr, sizeof(*phdr) + 2);
+
+ pp = indirect_call_gro_receive_inet(ptype->callbacks.gro_receive,
+ ipv6_gro_receive, inet_gro_receive,
+ head, skb);
+
+out:
+ skb_gro_flush_final(skb, pp, flush);
+
+ return pp;
+}
+
+static int pppoe_gro_complete(struct sk_buff *skb, int nhoff)
+{
+ struct pppoe_hdr *phdr = (struct pppoe_hdr *)(skb->data + nhoff);
+ __be16 type = pppoe_hdr_proto(phdr);
+ struct packet_offload *ptype;
+ int len, err;
+
+ ptype = gro_find_complete_by_type(type);
+ if (!ptype)
+ return -ENOENT;
+
+ err = INDIRECT_CALL_INET(ptype->callbacks.gro_complete,
+ ipv6_gro_complete, inet_gro_complete,
+ skb, nhoff + sizeof(*phdr) + 2);
+ if (err)
+ return err;
+
+ len = skb->len - (nhoff + sizeof(*phdr));
+ phdr->length = cpu_to_be16(len);
+
+ return 0;
+}
+
+static struct sk_buff *pppoe_gso_segment(struct sk_buff *skb,
+ netdev_features_t features)
+{
+ unsigned int pppoe_hlen = sizeof(struct pppoe_hdr) + 2;
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
+ u16 mac_offset = skb->mac_header;
+ struct packet_offload *ptype;
+ u16 mac_len = skb->mac_len;
+ struct pppoe_hdr *phdr;
+ __be16 orig_type, type;
+ int len, nhoff;
+
+ skb_reset_network_header(skb);
+ nhoff = skb_network_header(skb) - skb_mac_header(skb);
+
+ if (unlikely(!pskb_may_pull(skb, pppoe_hlen)))
+ goto out;
+
+ phdr = (struct pppoe_hdr *)skb_network_header(skb);
+ type = pppoe_hdr_proto(phdr);
+ ptype = gro_find_complete_by_type(type);
+ if (!ptype)
+ goto out;
+
+ orig_type = skb->protocol;
+ __skb_pull(skb, pppoe_hlen);
+ segs = ptype->callbacks.gso_segment(skb, features);
+ if (IS_ERR_OR_NULL(segs)) {
+ skb_gso_error_unwind(skb, orig_type, pppoe_hlen, mac_offset,
+ mac_len);
+ goto out;
+ }
+
+ skb = segs;
+ do {
+ phdr = (struct pppoe_hdr *)(skb_mac_header(skb) + nhoff);
+ len = skb->len - (nhoff + sizeof(*phdr));
+ phdr->length = cpu_to_be16(len);
+ skb->network_header = (u8 *)phdr - skb->head;
+ skb->protocol = orig_type;
+ skb_reset_mac_len(skb);
+ } while ((skb = skb->next));
+
+out:
+ return segs;
+}
+
+static struct packet_offload pppoe_packet_offload __read_mostly = {
+ .type = cpu_to_be16(ETH_P_PPP_SES),
+ .priority = 20,
+ .callbacks = {
+ .gro_receive = pppoe_gro_receive,
+ .gro_complete = pppoe_gro_complete,
+ .gso_segment = pppoe_gso_segment,
+ },
+};
+
static int __init pppoe_init(void)
{
int err;
@@ -1113,6 +1274,7 @@ static int __init pppoe_init(void)
if (err)
goto out_unregister_pppoe_proto;
+ dev_add_offload(&pppoe_packet_offload);
dev_add_pack(&pppoes_ptype);
dev_add_pack(&pppoed_ptype);
register_netdevice_notifier(&pppoe_notifier);
@@ -1132,6 +1294,7 @@ static void __exit pppoe_exit(void)
unregister_netdevice_notifier(&pppoe_notifier);
dev_remove_pack(&pppoed_ptype);
dev_remove_pack(&pppoes_ptype);
+ dev_remove_offload(&pppoe_packet_offload);
unregister_pppox_proto(PX_PROTO_OE);
proto_unregister(&pppoe_sk_proto);
unregister_pernet_device(&pppoe_net_ops);
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index babcd75a08e2..aa3324d819b3 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1532,6 +1532,7 @@ struct sk_buff *inet_gro_receive(struct list_head *head, struct sk_buff *skb)
return pp;
}
+EXPORT_INDIRECT_CALLABLE(inet_gro_receive);
static struct sk_buff *ipip_gro_receive(struct list_head *head,
struct sk_buff *skb)
@@ -1617,6 +1618,7 @@ int inet_gro_complete(struct sk_buff *skb, int nhoff)
out:
return err;
}
+EXPORT_INDIRECT_CALLABLE(inet_gro_complete);
static int ipip_gro_complete(struct sk_buff *skb, int nhoff)
{
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
index bd7f780e37a5..32ba4739cef9 100644
--- a/net/ipv6/ip6_offload.c
+++ b/net/ipv6/ip6_offload.c
@@ -297,6 +297,7 @@ INDIRECT_CALLABLE_SCOPE struct sk_buff *ipv6_gro_receive(struct list_head *head,
return pp;
}
+EXPORT_INDIRECT_CALLABLE(ipv6_gro_receive);
static struct sk_buff *sit_ip6ip6_gro_receive(struct list_head *head,
struct sk_buff *skb)
@@ -359,6 +360,7 @@ INDIRECT_CALLABLE_SCOPE int ipv6_gro_complete(struct sk_buff *skb, int nhoff)
out:
return err;
}
+EXPORT_INDIRECT_CALLABLE(ipv6_gro_complete);
static int sit_gro_complete(struct sk_buff *skb, int nhoff)
{
--
2.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH net-next v5] net: pppoe: implement GRO/GSO support
2026-03-05 1:38 [PATCH net-next v5] net: pppoe: implement GRO/GSO support Qingfang Deng
@ 2026-03-07 1:04 ` Jakub Kicinski
2026-03-09 10:46 ` Qingfang Deng
2026-03-26 2:43 ` Qingfang Deng
1 sibling, 1 reply; 10+ messages in thread
From: Jakub Kicinski @ 2026-03-07 1:04 UTC (permalink / raw)
To: Qingfang Deng
Cc: linux-ppp, Michal Ostrowski, Andrew Lunn, David S. Miller,
Eric Dumazet, Paolo Abeni, David Ahern, Simon Horman, netdev,
linux-kernel, Felix Fietkau
On Thu, 5 Mar 2026 09:38:52 +0800 Qingfang Deng wrote:
> From: Felix Fietkau <nbd@nbd.name>
>
> Only handles packets where the pppoe header length field matches the exact
> packet length. Significantly improves rx throughput.
>
> When running NAT traffic through a MediaTek MT7621 devices from a host
> behind PPPoE to a host directly connected via ethernet, the TCP throughput
> that the device is able to handle improves from ~130 Mbit/s to ~630 Mbit/s,
> using fraglist GRO.
>
> Signed-off-by: Felix Fietkau <nbd@nbd.name>
> Signed-off-by: Qingfang Deng <dqfext@gmail.com>
Please add some selftests.
--
pw-bot: cr
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH net-next v5] net: pppoe: implement GRO/GSO support
2026-03-07 1:04 ` Jakub Kicinski
@ 2026-03-09 10:46 ` Qingfang Deng
2026-03-09 21:01 ` Jakub Kicinski
0 siblings, 1 reply; 10+ messages in thread
From: Qingfang Deng @ 2026-03-09 10:46 UTC (permalink / raw)
To: Jakub Kicinski
Cc: linux-ppp, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, David Ahern, Simon Horman, netdev, linux-kernel,
Felix Fietkau
Hi Jakub,
On Sat, Mar 7, 2026 at 9:04 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> Please add some selftests.
I haven't written a kselftest before. What tests should I include?
I think I can add a local ppp server and client over veth, and test
the connection with ping and iperf3.
> --
> pw-bot: cr
Regards,
- Qingfang
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH net-next v5] net: pppoe: implement GRO/GSO support
2026-03-09 10:46 ` Qingfang Deng
@ 2026-03-09 21:01 ` Jakub Kicinski
2026-03-25 9:23 ` Qingfang Deng
0 siblings, 1 reply; 10+ messages in thread
From: Jakub Kicinski @ 2026-03-09 21:01 UTC (permalink / raw)
To: Qingfang Deng
Cc: linux-ppp, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, David Ahern, Simon Horman, netdev, linux-kernel,
Felix Fietkau, Willem de Bruijn
On Mon, 9 Mar 2026 18:46:59 +0800 Qingfang Deng wrote:
> > Please add some selftests.
>
> I haven't written a kselftest before. What tests should I include?
>
> I think I can add a local ppp server and client over veth, and test
> the connection with ping and iperf3.
We have tools/testing/selftests/drivers/net/gro.c and associated Python
test. (note I have ambiguous feelings about adding ppp cases to this
file vs creating a new test, adding Willem to CC maybe he has some
guidance)
The test itself should send and receive raw packets using packet
sockets. That way you can easily inject arbitrary fragmented frames
on one end and check if they are coalesced correctly on the other.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH net-next v5] net: pppoe: implement GRO/GSO support
2026-03-09 21:01 ` Jakub Kicinski
@ 2026-03-25 9:23 ` Qingfang Deng
2026-03-25 23:59 ` Jakub Kicinski
0 siblings, 1 reply; 10+ messages in thread
From: Qingfang Deng @ 2026-03-25 9:23 UTC (permalink / raw)
To: Jakub Kicinski
Cc: linux-ppp, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, David Ahern, Simon Horman, netdev, linux-kernel,
Felix Fietkau, Willem de Bruijn
On Tue, Mar 10, 2026 at 5:01 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> On Mon, 9 Mar 2026 18:46:59 +0800 Qingfang Deng wrote:
> > > Please add some selftests.
> >
> > I haven't written a kselftest before. What tests should I include?
> >
> > I think I can add a local ppp server and client over veth, and test
> > the connection with ping and iperf3.
>
> We have tools/testing/selftests/drivers/net/gro.c and associated Python
> test. (note I have ambiguous feelings about adding ppp cases to this
> file vs creating a new test, adding Willem to CC maybe he has some
> guidance)
He hasn't replied. What do you think?
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH net-next v5] net: pppoe: implement GRO/GSO support
2026-03-25 9:23 ` Qingfang Deng
@ 2026-03-25 23:59 ` Jakub Kicinski
2026-03-26 2:39 ` Willem de Bruijn
0 siblings, 1 reply; 10+ messages in thread
From: Jakub Kicinski @ 2026-03-25 23:59 UTC (permalink / raw)
To: Qingfang Deng
Cc: linux-ppp, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, David Ahern, Simon Horman, netdev, linux-kernel,
Felix Fietkau, Willem de Bruijn
On Wed, 25 Mar 2026 17:23:39 +0800 Qingfang Deng wrote:
> > > I haven't written a kselftest before. What tests should I include?
> > >
> > > I think I can add a local ppp server and client over veth, and test
> > > the connection with ping and iperf3.
> >
> > We have tools/testing/selftests/drivers/net/gro.c and associated Python
> > test. (note I have ambiguous feelings about adding ppp cases to this
> > file vs creating a new test, adding Willem to CC maybe he has some
> > guidance)
>
> He hasn't replied. What do you think?
He probably missed the mid-thread email. Proceed with whatever you feel
makes sense.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH net-next v5] net: pppoe: implement GRO/GSO support
2026-03-25 23:59 ` Jakub Kicinski
@ 2026-03-26 2:39 ` Willem de Bruijn
0 siblings, 0 replies; 10+ messages in thread
From: Willem de Bruijn @ 2026-03-26 2:39 UTC (permalink / raw)
To: Jakub Kicinski, Qingfang Deng
Cc: linux-ppp, Andrew Lunn, David S. Miller, Eric Dumazet,
Paolo Abeni, David Ahern, Simon Horman, netdev, linux-kernel,
Felix Fietkau, Willem de Bruijn
Jakub Kicinski wrote:
> On Wed, 25 Mar 2026 17:23:39 +0800 Qingfang Deng wrote:
> > > > I haven't written a kselftest before. What tests should I include?
> > > >
> > > > I think I can add a local ppp server and client over veth, and test
> > > > the connection with ping and iperf3.
> > >
> > > We have tools/testing/selftests/drivers/net/gro.c and associated Python
> > > test. (note I have ambiguous feelings about adding ppp cases to this
> > > file vs creating a new test, adding Willem to CC maybe he has some
> > > guidance)
> >
> > He hasn't replied. What do you think?
>
> He probably missed the mid-thread email. Proceed with whatever you feel
> makes sense.
Sorry I missed this.
It's hard to say without seeing the code. Perhaps code it up as an
extension to gro.c. If the code changes are manageable, send that. Else,
consider moving it into a stand-alone test.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH net-next v5] net: pppoe: implement GRO/GSO support
2026-03-05 1:38 [PATCH net-next v5] net: pppoe: implement GRO/GSO support Qingfang Deng
2026-03-07 1:04 ` Jakub Kicinski
@ 2026-03-26 2:43 ` Qingfang Deng
2026-03-26 14:43 ` Xin Long
1 sibling, 1 reply; 10+ messages in thread
From: Qingfang Deng @ 2026-03-26 2:43 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Felix Fietkau, linux-ppp, Andrew Lunn, David S. Miller,
Eric Dumazet, Paolo Abeni, David Ahern, Simon Horman, netdev,
linux-kernel, Xin Long, Richard Gobert
Hi all,
In some cases (such as BIG TCP) a GRO skb length can overflow a u16,
then what should I do with the u16 length field here?
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH net-next v5] net: pppoe: implement GRO/GSO support
2026-03-26 2:43 ` Qingfang Deng
@ 2026-03-26 14:43 ` Xin Long
2026-03-26 14:43 ` Xin Long
0 siblings, 1 reply; 10+ messages in thread
From: Xin Long @ 2026-03-26 14:43 UTC (permalink / raw)
To: Qingfang Deng
Cc: Jakub Kicinski, Felix Fietkau, linux-ppp, Andrew Lunn,
David S. Miller, Eric Dumazet, Paolo Abeni, David Ahern,
Simon Horman, netdev, linux-kernel, Richard Gobert
On Wed, Mar 25, 2026 at 10:43 PM Qingfang Deng <dqfext@gmail.com> wrote:
>
> Hi all,
>
> In some cases (such as BIG TCP) a GRO skb length can overflow a u16,
> then what should I do with the u16 length field here?
I think you can either add a check in pppoe_gro_complete() to ensure
the aggregated size does not exceed U16_MAX, avoiding BIG TCP
behavior; Or, set phdr->length to 0 and rely on skb->len to determine
the actual length, as done in BIG TCP itself.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH net-next v5] net: pppoe: implement GRO/GSO support
2026-03-26 14:43 ` Xin Long
@ 2026-03-26 14:43 ` Xin Long
0 siblings, 0 replies; 10+ messages in thread
From: Xin Long @ 2026-03-26 14:43 UTC (permalink / raw)
To: Qingfang Deng
Cc: Jakub Kicinski, Felix Fietkau, linux-ppp, Andrew Lunn,
David S. Miller, Eric Dumazet, Paolo Abeni, David Ahern,
Simon Horman, netdev, linux-kernel, Richard Gobert
On Thu, Mar 26, 2026 at 10:43 AM Xin Long <lucien.xin@gmail.com> wrote:
>
> On Wed, Mar 25, 2026 at 10:43 PM Qingfang Deng <dqfext@gmail.com> wrote:
> >
> > Hi all,
> >
> > In some cases (such as BIG TCP) a GRO skb length can overflow a u16,
> > then what should I do with the u16 length field here?
>
> I think you can either add a check in pppoe_gro_complete() to ensure
sorry, I meant add a check in pppoe_gro_receive().
> the aggregated size does not exceed U16_MAX, avoiding BIG TCP
> behavior; Or, set phdr->length to 0 and rely on skb->len to determine
> the actual length, as done in BIG TCP itself.
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-03-26 14:44 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-05 1:38 [PATCH net-next v5] net: pppoe: implement GRO/GSO support Qingfang Deng
2026-03-07 1:04 ` Jakub Kicinski
2026-03-09 10:46 ` Qingfang Deng
2026-03-09 21:01 ` Jakub Kicinski
2026-03-25 9:23 ` Qingfang Deng
2026-03-25 23:59 ` Jakub Kicinski
2026-03-26 2:39 ` Willem de Bruijn
2026-03-26 2:43 ` Qingfang Deng
2026-03-26 14:43 ` Xin Long
2026-03-26 14:43 ` Xin Long
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox