xdp: allow disable GRO per packet by XDP
Subsystems (12)
cover xdp: allow disable GRO per packet by XDP
Software GRO is currently controlled by a single switch, i.e.
ethtool -K dev gro on|off
However, this is not always desired. When GRO is enabled, even if the kernel cannot GRO certain traffic, it has to run through the GRO receive handlers with no benefit.
There are also scenarios that turning off GRO is a requirement. For example, our production environment has a scenario that a TC egress hook may add multiple encapsulation headers to forwarded skbs for load balancing and isolation purpose. The encapsulation is implemented via BPF. But the problem arises then: there is no way to properly offload a double-encapsulated packet, since skb only has network_header and inner_network_header to track one layer of encapsulation, but not two. On the other hand, not all the traffic through this device needs double encapsulation. But we have to turn off GRO completely for any ingress device as a result.
A natural approach to make this more flexible is to use XDP to control GRO behavior. But current semantic gap between XDP buffer/frame and socket buffer requires some new primitives.
This change set proposes a control bit gro_disabled on skbs to determine if GRO should work on an skb or not. To manipulate this bit, we introduce a new XDP kfunc bpf_xdp_disable_gro as well as generic helpers xdp_frame/buff_fixup_skb_offloading.
The expected working flow is that:
* XDP program examines packets and can call bpf_xdp_disable_gro to disable GRO on a packet
* Device drivers need to call xdp_buff_fixup_skb_offloading (or equivalent version for xdp_frame), to check if skb->gro_disabled needs to be set.
* The kernel will elide GRO later if this bit is used.
Initially we only modified a few drivers for demonstration purpose. The driver side changes is optional and also incremental depending on vendors' agenda. Any suggestions are welcome!
Jesper Dangaard Brouer (1):
mlx5: move xdp_buff scope one level up
Yan Zhai (8):
skb: introduce gro_disabled bit
xdp: add XDP_FLAGS_GRO_DISABLED flag
xdp: implement bpf_xdp_disable_gro kfunc
bnxt: apply XDP offloading fixup when building skb
ice: apply XDP offloading fixup when building skb
veth: apply XDP offloading fixup when building skb
mlx5: apply XDP offloading fixup when building skb
bpf: selftests: test disabling GRO by XDP
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 4 + drivers/net/ethernet/intel/ice/ice_txrx.c | 2 + drivers/net/ethernet/intel/ice/ice_xsk.c | 6 +- drivers/net/ethernet/mellanox/mlx5/core/en.h | 6 +- .../ethernet/mellanox/mlx5/core/en/xsk/rx.c | 10 +- .../ethernet/mellanox/mlx5/core/en/xsk/rx.h | 6 +- .../net/ethernet/mellanox/mlx5/core/en_rx.c | 117 ++++++++++------- drivers/net/veth.c | 4 + include/linux/netdevice.h | 9 +- include/linux/skbuff.h | 10 ++ include/net/xdp.h | 38 +++++- include/net/xdp_sock_drv.h | 2 +- net/Kconfig | 10 ++ net/core/gro.c | 2 +- net/core/gro_cells.c | 2 +- net/core/skbuff.c | 4 + net/core/xdp.c | 27 +++- tools/testing/selftests/bpf/config | 1 + .../selftests/bpf/prog_tests/xdp_offloading.c | 122 ++++++++++++++++++ .../selftests/bpf/progs/xdp_offloading.c | 50 +++++++ 20 files changed, 369 insertions(+), 63 deletions(-) create mode 100644 tools/testing/selftests/bpf/prog_tests/xdp_offloading.c create mode 100644 tools/testing/selftests/bpf/progs/xdp_offloading.c
Signature · 1 line
2.30.2
RFC 1/9 skb: introduce gro_disabled bit
Software GRO is currently controlled by a single switch, i.e.
ethtool -K dev gro on|off
However, this is not always desired. When GRO is enabled, even if the kernel cannot GRO certain traffic, it has to run through the GRO receive handlers with no benefit.
There are also scenarios that turning off GRO is a requirement. For example, our production environment has a scenario that a TC egress hook may add multiple encapsulation headers to forwarded skbs for load balancing and isolation purpose. The encapsulation is implemented via BPF. But the problem arises then: there is no way to properly offload a double-encapsulated packet, since skb only has network_header and inner_network_header to track one layer of encapsulation, but not two. On the other hand, not all the traffic through this device needs double encapsulation. But we have to turn off GRO completely for any ingress device as a result.
Introduce a bit on skb so that GRO engine can be notified to skip GRO on this skb, rather than having to be 0-or-1 for all traffic.
--- include/linux/netdevice.h | 9 +++++++-- include/linux/skbuff.h | 10 ++++++++++ net/Kconfig | 10 ++++++++++ net/core/gro.c | 2 +- net/core/gro_cells.c | 2 +- net/core/skbuff.c | 4 ++++ 6 files changed, 33 insertions(+), 4 deletions(-)
include/linux/netdevice.h +7 -2
@@ -2415,11 +2415,16 @@ struct net_device { ((dev)->devlink_port = (port)); \ }) -static inline bool netif_elide_gro (const struct net_device *dev) +static inline bool netif_elide_gro (const struct sk_buff *skb) { -if (!(dev->features &NETIF_F_GRO ) || dev->xdp_prog) +if (!(skb->dev->features &NETIF_F_GRO ) || skb->dev->xdp_prog)return true; + +#ifdef CONFIG_SKB_GRO_CONTROL +return skb->gro_disabled; +#else return false; +#endif }#define NETDEV_ALIGN 32
include/linux/skbuff.h +10 -0
@@ -1008,6 +1008,9 @@ struct sk_buff {#if IS_ENABLED (CONFIG_IP_SCTP ) __u8 csum_not_inet:1;#endif +#ifdef CONFIG_SKB_GRO_CONTROL + __u8 gro_disabled:1; +#endif #if defined(CONFIG_NET_SCHED ) || defined(CONFIG_NET_XGRESS )__u16 tc_index;/* traffic control index */
@@ -1215,6 +1218,13 @@ static inline bool skb_wifi_acked_valid(const struct sk_buff *skb)#endif } +static inline void skb_disable_gro (struct sk_buff *skb) +{ +#ifdef CONFIG_SKB_GRO_CONTROL + skb->gro_disabled =1 ; +#endif +} +/** * skb_unref - decrement the skb's reference count * @skb: buffer
net/Kconfig +10 -0
@@ -289,6 +289,16 @@ config MAX_SKB_FRAGS and in drivers using build_skb(). If unsure, say 17. +config SKB_GRO_CONTROL + bool "allow disable GRO on per-packet basis" + default y + help + By default GRO can only be enabled or disabled per network device. + This can be cumbersome for certain scenarios. + Toggling this option will allow disabling GRO for selected packets, + e.g. by XDP programs, so that it is more flexibile. + Extra overhead should be minimal. + config RPS bool "Receive packet steering" depends on SMP && SYSFS
net/core/gro.c +1 -1
@@ -476,7 +476,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buffenum gro_result ret;int same_flow; -if (netif_elide_gro (skb->dev)) +if (netif_elide_gro (skb)) goto normal;gro_list_prepare (&gro_list->list, skb);
net/core/gro_cells.c +1 -1
@@ -20,7 +20,7 @@ int gro_cells_receive(struct gro_cells *gcells, struct sk_buff *skb)if (unlikely (!(dev->flags &IFF_UP ))) goto drop; -if (!gcells->cells ||skb_cloned (skb) ||netif_elide_gro (dev)) { +if (!gcells->cells ||skb_cloned (skb) ||netif_elide_gro (skb)) { res =netif_rx (skb); goto unlock; }
net/core/skbuff.c +4 -0
@@ -6030,6 +6030,10 @@ void skb_scrub_packet(struct sk_buff *skb, bool xnet)ipvs_reset (skb); skb->mark =0 ;skb_clear_tstamp (skb); +#ifdef CONFIG_SKB_GRO_CONTROL +/* hand back GRO control to next netns */ + skb->gro_disabled =0 ; +#endif }EXPORT_SYMBOL_GPL (skb_scrub_packet);
Signature · 1 line
2.30.2
Re: [RFC net-next 1/9] skb: introduce gro_disabled bit
From: Yan Zhai <[email protected]>
Date: Thu, 20 Jun 2024 15:19:10 -0700
Quoted 8 lines
Software GRO is currently controlled by a single switch, i.e.
ethtool -K dev gro on|off
However, this is not always desired. When GRO is enabled, even if the kernel cannot GRO certain traffic, it has to run through the GRO receive handlers with no benefit.
Quoted 7 lines
There are also scenarios that turning off GRO is a requirement. For example, our production environment has a scenario that a TC egress hook may add multiple encapsulation headers to forwarded skbs for load balancing and isolation purpose. The encapsulation is implemented via BPF. But the problem arises then: there is no way to properly offload a double-encapsulated packet, since skb only has
network_headerandinner_network_headerto track one layer of encapsulation, but not two.
Implement it in the kernel then? :D
Quoted 75 lines
On the other hand, not all the traffic through this device needs double encapsulation. But we have to turn off GRO completely for any ingress device as a result.
Introduce a bit on skb so that GRO engine can be notified to skip GRO on this skb, rather than having to be 0-or-1 for all traffic.
Signed-off-by Yan Zhai <[email protected]>--- include/linux/netdevice.h | 9 +++++++-- include/linux/skbuff.h | 10 ++++++++++ net/Kconfig | 10 ++++++++++ net/core/gro.c | 2 +- net/core/gro_cells.c | 2 +- net/core/skbuff.c | 4 ++++ 6 files changed, 33 insertions(+), 4 deletions(-)include/linux/netdevice.h +7
-2@@ -2415,11 +2415,16 @@ struct net_device { ((dev)->devlink_port = (port)); \ }) -static inline bool netif_elide_gro (const struct net_device *dev) +static inline bool netif_elide_gro (const struct sk_buff *skb) { -if (!(dev->features &NETIF_F_GRO ) || dev->xdp_prog) +if (!(skb->dev->features &NETIF_F_GRO ) || skb->dev->xdp_prog)return true; + +#ifdef CONFIG_SKB_GRO_CONTROL +return skb->gro_disabled; +#else return false; +#endif }#define NETDEV_ALIGN 32include/linux/skbuff.h +10
-0@@ -1008,6 +1008,9 @@ struct sk_buff {#if IS_ENABLED (CONFIG_IP_SCTP ) __u8 csum_not_inet:1;#endif +#ifdef CONFIG_SKB_GRO_CONTROL + __u8 gro_disabled:1; +#endif #if defined(CONFIG_NET_SCHED ) || defined(CONFIG_NET_XGRESS )__u16 tc_index;/* traffic control index */ @@ -1215,6 +1218,13 @@ static inline bool skb_wifi_acked_valid(const struct sk_buff *skb)#endif } +static inline void skb_disable_gro (struct sk_buff *skb) +{ +#ifdef CONFIG_SKB_GRO_CONTROL + skb->gro_disabled =1 ; +#endif +} +/** * skb_unref - decrement the skb's reference count * @skb: buffer net/Kconfig +0
-0@@ -289,6 +289,16 @@ config MAX_SKB_FRAGS and in drivers using build_skb(). If unsure, say 17.
net/Kconfig config MAX_SKB_FRAGS · line 300
Quoted 10 lines
net/Kconfig +9
-0+config SKB_GRO_CONTROL + bool "allow disable GRO on per-packet basis" + default y + help + By default GRO can only be enabled or disabled per network device. + This can be cumbersome for certain scenarios. + Toggling this option will allow disabling GRO for selected packets, + e.g. by XDP programs, so that it is more flexibile. + Extra overhead should be minimal.
I don't think we need a Kconfig option for that. Can't it be unconditional? Is there any real eye-visible overhead?
Quoted 35 lines
net/Kconfig +1
-0+ config RPS bool "Receive packet steering" depends on SMP && SYSFSnet/core/gro.c +1
-1@@ -476,7 +476,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buffenum gro_result ret;int same_flow; -if (netif_elide_gro (skb->dev)) +if (netif_elide_gro (skb)) goto normal;gro_list_prepare (&gro_list->list, skb);net/core/gro_cells.c +1
-1@@ -20,7 +20,7 @@ int gro_cells_receive(struct gro_cells *gcells, struct sk_buff *skb)if (unlikely (!(dev->flags &IFF_UP ))) goto drop; -if (!gcells->cells ||skb_cloned (skb) ||netif_elide_gro (dev)) { +if (!gcells->cells ||skb_cloned (skb) ||netif_elide_gro (skb)) { res =netif_rx (skb); goto unlock; }net/core/skbuff.c +0
-0
net/core/skbuff.c void skb_scrub_packet(struct sk_buff *skb, bool xnet) · line 6038
Quoted 9 lines
net/core/skbuff.c +4
-0@@ -6030,6 +6030,10 @@ void skb_scrub_packet(struct sk_buff *skb, bool xnet)ipvs_reset (skb); skb->mark =0 ;skb_clear_tstamp (skb); +#ifdef CONFIG_SKB_GRO_CONTROL +/* hand back GRO control to next netns */ + skb->gro_disabled =0 ; +#endif }EXPORT_SYMBOL_GPL (skb_scrub_packet);
Thanks,
Olek
Re: [RFC net-next 1/9] skb: introduce gro_disabled bit
Quoted 20 lines · Alexander Lobakin
From: Yan Zhai <[email protected]>
Date: Thu, 20 Jun 2024 15:19:10 -0700Quoted 8 lines
Software GRO is currently controlled by a single switch, i.e.
ethtool -K dev gro on|off
However, this is not always desired. When GRO is enabled, even if the kernel cannot GRO certain traffic, it has to run through the GRO receive handlers with no benefit.
Quoted 7 lines
There are also scenarios that turning off GRO is a requirement. For example, our production environment has a scenario that a TC egress hook may add multiple encapsulation headers to forwarded skbs for load balancing and isolation purpose. The encapsulation is implemented via BPF. But the problem arises then: there is no way to properly offload a double-encapsulated packet, since skb only has
network_headerandinner_network_headerto track one layer of encapsulation, but not two.
Quoted 2 lines
Implement it in the kernel then? :D
It would be a big commitment that I dare not make :) Out of curiosity, is it something that devices can handle today?
Quoted 76 lines
Quoted 76 lines
On the other hand, not all the traffic through this device needs double encapsulation. But we have to turn off GRO completely for any ingress device as a result.
Introduce a bit on skb so that GRO engine can be notified to skip GRO on this skb, rather than having to be 0-or-1 for all traffic.
Signed-off-by Yan Zhai <[email protected]>--- include/linux/netdevice.h | 9 +++++++-- include/linux/skbuff.h | 10 ++++++++++ net/Kconfig | 10 ++++++++++ net/core/gro.c | 2 +- net/core/gro_cells.c | 2 +- net/core/skbuff.c | 4 ++++ 6 files changed, 33 insertions(+), 4 deletions(-)include/linux/netdevice.h +7
-2@@ -2415,11 +2415,16 @@ struct net_device { ((dev)->devlink_port = (port)); \ }) -static inline bool netif_elide_gro (const struct net_device *dev) +static inline bool netif_elide_gro (const struct sk_buff *skb) { -if (!(dev->features &NETIF_F_GRO ) || dev->xdp_prog) +if (!(skb->dev->features &NETIF_F_GRO ) || skb->dev->xdp_prog)return true; + +#ifdef CONFIG_SKB_GRO_CONTROL +return skb->gro_disabled; +#else return false; +#endif }#define NETDEV_ALIGN 32include/linux/skbuff.h +10
-0@@ -1008,6 +1008,9 @@ struct sk_buff {#if IS_ENABLED (CONFIG_IP_SCTP ) __u8 csum_not_inet:1;#endif +#ifdef CONFIG_SKB_GRO_CONTROL + __u8 gro_disabled:1; +#endif #if defined(CONFIG_NET_SCHED ) || defined(CONFIG_NET_XGRESS )__u16 tc_index;/* traffic control index */ @@ -1215,6 +1218,13 @@ static inline bool skb_wifi_acked_valid(const struct sk_buff *skb)#endif } +static inline void skb_disable_gro (struct sk_buff *skb) +{ +#ifdef CONFIG_SKB_GRO_CONTROL + skb->gro_disabled =1 ; +#endif +} +/** * skb_unref - decrement the skb's reference count * @skb: buffer net/Kconfig +0
-0@@ -289,6 +289,16 @@ config MAX_SKB_FRAGS and in drivers using build_skb(). If unsure, say 17.
Quoted 12 lines
net/Kconfig config MAX_SKB_FRAGS · line 300
Quoted 9 lines
net/Kconfig +9
-0+config SKB_GRO_CONTROL + bool "allow disable GRO on per-packet basis" + default y + help + By default GRO can only be enabled or disabled per network device. + This can be cumbersome for certain scenarios. + Toggling this option will allow disabling GRO for selected packets, + e.g. by XDP programs, so that it is more flexibile. + Extra overhead should be minimal.I don't think we need a
Kconfigoption for that. Can't it be unconditional? Is there any real eye-visible overhead?
Normally if it is a single branch I would not worry about it. But I know I am touching a hot potato here so I just want to be cautious :)
best
Yan
Quoted 3 lines
Thanks,
Olek
Paolo Abeni
maintainerRe: [RFC net-next 1/9] skb: introduce gro_disabled bit
In reply to Yan ZhaiQuoted 42 lines · Yan Zhai
Software GRO is currently controlled by a single switch, i.e.
ethtool -K dev gro on|off
However, this is not always desired. When GRO is enabled, even if the kernel cannot GRO certain traffic, it has to run through the GRO receive handlers with no benefit.
There are also scenarios that turning off GRO is a requirement. For example, our production environment has a scenario that a TC egress hook may add multiple encapsulation headers to forwarded skbs for load balancing and isolation purpose. The encapsulation is implemented via BPF. But the problem arises then: there is no way to properly offload a double-encapsulated packet, since skb only has
network_headerandinner_network_headerto track one layer of encapsulation, but not two. On the other hand, not all the traffic through this device needs double encapsulation. But we have to turn off GRO completely for any ingress device as a result.Introduce a bit on skb so that GRO engine can be notified to skip GRO on this skb, rather than having to be 0-or-1 for all traffic.
Signed-off-by Yan Zhai <[email protected]>--- include/linux/netdevice.h | 9 +++++++-- include/linux/skbuff.h | 10 ++++++++++ net/Kconfig | 10 ++++++++++ net/core/gro.c | 2 +- net/core/gro_cells.c | 2 +- net/core/skbuff.c | 4 ++++ 6 files changed, 33 insertions(+), 4 deletions(-)include/linux/netdevice.h +1
-1@@ -2415,11 +2415,16 @@ struct net_device { ((dev)->devlink_port = (port)); \ }) -static inline bool netif_elide_gro (const struct net_device *dev) +static inline bool netif_elide_gro (const struct sk_buff *skb)
include/linux/netdevice.h struct net_device { · line 2427
Quoted 10 lines
include/linux/netdevice.h +6
-1{ -if (!(dev->features &NETIF_F_GRO ) || dev->xdp_prog) +if (!(skb->dev->features &NETIF_F_GRO ) || skb->dev->xdp_prog)return true; + +#ifdef CONFIG_SKB_GRO_CONTROL +return skb->gro_disabled; +#else return false; +#endif
This will generate OoO if the gro_disabled is flipped in the middle of a stream.
Assuming the above is fine for your use case (I think it's _not_ in general), you could get the same result without an additional costly bit in sk_buff.
Let xdp_frame_fixup_skb_offloading() return a bool - e.g. 'true' when gro should be avoided - and let the NIC driver call netif_receive_skb() instead of the gro rx hook for such packet.
All in all the approach implemented in this series does not look worthy to me.
Thanks,
Paolo
Re: [RFC net-next 1/9] skb: introduce gro_disabled bit
Quoted 58 lines · Paolo Abeni
Quoted 42 lines · Yan Zhai
Software GRO is currently controlled by a single switch, i.e.
ethtool -K dev gro on|off
However, this is not always desired. When GRO is enabled, even if the kernel cannot GRO certain traffic, it has to run through the GRO receive handlers with no benefit.
There are also scenarios that turning off GRO is a requirement. For example, our production environment has a scenario that a TC egress hook may add multiple encapsulation headers to forwarded skbs for load balancing and isolation purpose. The encapsulation is implemented via BPF. But the problem arises then: there is no way to properly offload a double-encapsulated packet, since skb only has
network_headerandinner_network_headerto track one layer of encapsulation, but not two. On the other hand, not all the traffic through this device needs double encapsulation. But we have to turn off GRO completely for any ingress device as a result.Introduce a bit on skb so that GRO engine can be notified to skip GRO on this skb, rather than having to be 0-or-1 for all traffic.
Signed-off-by Yan Zhai <[email protected]>--- include/linux/netdevice.h | 9 +++++++-- include/linux/skbuff.h | 10 ++++++++++ net/Kconfig | 10 ++++++++++ net/core/gro.c | 2 +- net/core/gro_cells.c | 2 +- net/core/skbuff.c | 4 ++++ 6 files changed, 33 insertions(+), 4 deletions(-)include/linux/netdevice.h +1
-1@@ -2415,11 +2415,16 @@ struct net_device { ((dev)->devlink_port = (port)); \ }) -static inline bool netif_elide_gro (const struct net_device *dev) +static inline bool netif_elide_gro (const struct sk_buff *skb)include/linux/netdevice.h struct net_device { · line 2427
Quoted 10 lines
include/linux/netdevice.h +6
-1{ -if (!(dev->features &NETIF_F_GRO ) || dev->xdp_prog) +if (!(skb->dev->features &NETIF_F_GRO ) || skb->dev->xdp_prog)return true; + +#ifdef CONFIG_SKB_GRO_CONTROL +return skb->gro_disabled; +#else return false; +#endif This will generate OoO if the
gro_disabledis flipped in the middle of a stream.
Quoted 3 lines
Assuming the above is fine for your use case (I think it's _not_ in general), you could get the same result without an additional costly bit in
sk_buff.
Calling it per-packet control seems inaccurate here, the motivation is to give users the ability to control per-flow behaviors. OoO is indeed a consequence if users don't do it correctly.
Quoted 5 lines
Let
xdp_frame_fixup_skb_offloading()return a bool - e.g. 'true' when gro should be avoided - and let the NIC driver callnetif_receive_skb()instead of the gro rx hook for such packet.
For rx on a single device, directly calling netif_receive_skb is reasonable. For tunnel receivers it is kinda inconsistent IMHO. For example, we terminate GRE tunnels in a netns, and it is necessary to disable GRO on both the entering veth device and also the GRE tunnel to shutdown GRO. That's why I'd hope to use a bit of skb, to be consistent within the same netns. Let me add a bit more context to clarify why we think this is necessary in another thread.
best,
Yan
Quoted 7 lines
All in all the approach implemented in this series does not look worthy to me.
Thanks,
Paolo
Paolo Abeni
maintainerRe: [RFC net-next 1/9] skb: introduce gro_disabled bit
In reply to Yan ZhaiQuoted 8 lines · Yan Zhai
Software GRO is currently controlled by a single switch, i.e.
ethtool -K dev gro on|off
However, this is not always desired. When GRO is enabled, even if the kernel cannot GRO certain traffic, it has to run through the GRO receive handlers with no benefit.
Quoted 10 lines
There are also scenarios that turning off GRO is a requirement. For example, our production environment has a scenario that a TC egress hook may add multiple encapsulation headers to forwarded skbs for load balancing and isolation purpose. The encapsulation is implemented via BPF. But the problem arises then: there is no way to properly offload a double-encapsulated packet, since skb only has
network_headerandinner_network_headerto track one layer of encapsulation, but not two. On the other hand, not all the traffic through this device needs double encapsulation. But we have to turn off GRO completely for any ingress device as a result.
Could you please add more details WRT this last statement? I'm unsure if I understand your problem. My guess is as follow:
Your device receive some traffic, GRO and forward it, and the multiple encapsulation can happen on such forwarded traffic (since I can't find almost none of the above your message is mainly a wild guess).
Assuming I guessed correctly, I think you could solve the problem with no kernel changes: redirect the to-be-tunneled traffic to some virtual device and all TX offload on top of it and let the encap happen there.
Cheers,
Paolo
Re: [RFC net-next 1/9] skb: introduce gro_disabled bit
Quoted 24 lines · Paolo Abeni
Quoted 8 lines · Yan Zhai
Software GRO is currently controlled by a single switch, i.e.
ethtool -K dev gro on|off
However, this is not always desired. When GRO is enabled, even if the kernel cannot GRO certain traffic, it has to run through the GRO receive handlers with no benefit.
Quoted 10 lines
There are also scenarios that turning off GRO is a requirement. For example, our production environment has a scenario that a TC egress hook may add multiple encapsulation headers to forwarded skbs for load balancing and isolation purpose. The encapsulation is implemented via BPF. But the problem arises then: there is no way to properly offload a double-encapsulated packet, since skb only has
network_headerandinner_network_headerto track one layer of encapsulation, but not two. On the other hand, not all the traffic through this device needs double encapsulation. But we have to turn off GRO completely for any ingress device as a result.Could you please add more details WRT this last statement? I'm unsure if I understand your problem. My guess is as follow:
Quoted 8 lines
Your device receive some traffic, GRO and forward it, and the multiple encapsulation can happen on such forwarded traffic (since I can't find almost none of the above your message is mainly a wild guess).
Assuming I guessed correctly, I think you could solve the problem with no kernel changes: redirect the to-be-tunneled traffic to some virtual device and all TX offload on top of it and let the encap happen there.
Let's say we have a netns to implement network functions like DoS/IDS/Load balancing for IP traffic. The netns has a single veth entrance/exit, and a bunch of ip tunnels, GRE/XFRM, to receive and tunnel traffic from customer's private sites. Some of such traffic could be encapsulated to reach services outside of the netns (but on the same server), for example, customers may also want to use our CDN/Caching functionality. The complication here is that we might have to further tunnel traffic to another data center, because the routing is asymmetric so we can receive client traffic from US but the response may come back to our EU data center, and in order to do layer4/layer7 service, we have to make sure those land on the same server.
It is true that a device like a veth pair or even netkit could allow the kernel segment GRO packets for us. But this does not sound actually right in terms of design: if we know already some packet path should not be GRO-ed, can we enforce this rather than having to aggregate it then chop it down soon after? For our specific case though, it also becomes a headache for analytics and customer rules that rely on ingress device name, we probably need to pair each tunnel with such a virtual device. There could be hundreds of ipsec tunnels, and that seems to be a substantial overhead for both data path and control plane management.
To make this a bit more general, what I'd like to introduce here is:
when we know GRO is either problematic or simply not useful (like to some UDP traffic), can we have more control toggle to skip it?
thanks
Yan
Quoted 4 lines
Cheers,
Paolo
Re: [RFC net-next 1/9] skb: introduce gro_disabled bit
In reply to Yan ZhaiQuoted 42 lines · Yan Zhai
Software GRO is currently controlled by a single switch, i.e.
ethtool -K dev gro on|off
However, this is not always desired. When GRO is enabled, even if the kernel cannot GRO certain traffic, it has to run through the GRO receive handlers with no benefit.
There are also scenarios that turning off GRO is a requirement. For example, our production environment has a scenario that a TC egress hook may add multiple encapsulation headers to forwarded skbs for load balancing and isolation purpose. The encapsulation is implemented via BPF. But the problem arises then: there is no way to properly offload a double-encapsulated packet, since skb only has
network_headerandinner_network_headerto track one layer of encapsulation, but not two. On the other hand, not all the traffic through this device needs double encapsulation. But we have to turn off GRO completely for any ingress device as a result.Introduce a bit on skb so that GRO engine can be notified to skip GRO on this skb, rather than having to be 0-or-1 for all traffic.
Signed-off-by Yan Zhai <[email protected]>--- include/linux/netdevice.h | 9 +++++++-- include/linux/skbuff.h | 10 ++++++++++ net/Kconfig | 10 ++++++++++ net/core/gro.c | 2 +- net/core/gro_cells.c | 2 +- net/core/skbuff.c | 4 ++++ 6 files changed, 33 insertions(+), 4 deletions(-)include/linux/netdevice.h +1
-1@@ -2415,11 +2415,16 @@ struct net_device { ((dev)->devlink_port = (port)); \ }) -static inline bool netif_elide_gro (const struct net_device *dev) +static inline bool netif_elide_gro (const struct sk_buff *skb)
include/linux/netdevice.h struct net_device { · line 2427
Quoted 10 lines
include/linux/netdevice.h +6
-1{ -if (!(dev->features &NETIF_F_GRO ) || dev->xdp_prog) +if (!(skb->dev->features &NETIF_F_GRO ) || skb->dev->xdp_prog)return true; + +#ifdef CONFIG_SKB_GRO_CONTROL +return skb->gro_disabled; +#else return false; +#endif
Yet more branches in the hot path.
Compile time configurability does not help, as that will be enabled by distros.
For a fairly niche use case. Where functionality of GRO already works. So just a performance for a very rare case at the cost of a regression in the common case. A small regression perhaps, but death by a thousand cuts.
Quoted 97 lines
include/linux/netdevice.h +0
-0}#define NETDEV_ALIGN 32include/linux/skbuff.h +10
-0@@ -1008,6 +1008,9 @@ struct sk_buff {#if IS_ENABLED (CONFIG_IP_SCTP ) __u8 csum_not_inet:1;#endif +#ifdef CONFIG_SKB_GRO_CONTROL + __u8 gro_disabled:1; +#endif #if defined(CONFIG_NET_SCHED ) || defined(CONFIG_NET_XGRESS )__u16 tc_index;/* traffic control index */ @@ -1215,6 +1218,13 @@ static inline bool skb_wifi_acked_valid(const struct sk_buff *skb)#endif } +static inline void skb_disable_gro (struct sk_buff *skb) +{ +#ifdef CONFIG_SKB_GRO_CONTROL + skb->gro_disabled =1 ; +#endif +} +/** * skb_unref - decrement the skb's reference count * @skb: buffer net/Kconfig +10
-0@@ -289,6 +289,16 @@ config MAX_SKB_FRAGS and in drivers using build_skb(). If unsure, say 17. +config SKB_GRO_CONTROL + bool "allow disable GRO on per-packet basis" + default y + help + By default GRO can only be enabled or disabled per network device. + This can be cumbersome for certain scenarios. + Toggling this option will allow disabling GRO for selected packets, + e.g. by XDP programs, so that it is more flexibile. + Extra overhead should be minimal. + config RPS bool "Receive packet steering" depends on SMP && SYSFSnet/core/gro.c +1
-1@@ -476,7 +476,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buffenum gro_result ret;int same_flow; -if (netif_elide_gro (skb->dev)) +if (netif_elide_gro (skb)) goto normal;gro_list_prepare (&gro_list->list, skb);net/core/gro_cells.c +1
-1@@ -20,7 +20,7 @@ int gro_cells_receive(struct gro_cells *gcells, struct sk_buff *skb)if (unlikely (!(dev->flags &IFF_UP ))) goto drop; -if (!gcells->cells ||skb_cloned (skb) ||netif_elide_gro (dev)) { +if (!gcells->cells ||skb_cloned (skb) ||netif_elide_gro (skb)) { res =netif_rx (skb); goto unlock; }net/core/skbuff.c +4
-0@@ -6030,6 +6030,10 @@ void skb_scrub_packet(struct sk_buff *skb, bool xnet)ipvs_reset (skb); skb->mark =0 ;skb_clear_tstamp (skb); +#ifdef CONFIG_SKB_GRO_CONTROL +/* hand back GRO control to next netns */ + skb->gro_disabled =0 ; +#endif }EXPORT_SYMBOL_GPL (skb_scrub_packet);Signature · 1 line
2.30.2
Daniel Borkmann
maintainerRe: [RFC net-next 1/9] skb: introduce gro_disabled bit
Quoted 56 lines · Willem de Bruijn
Quoted 42 lines · Yan Zhai
Software GRO is currently controlled by a single switch, i.e.
ethtool -K dev gro on|off
However, this is not always desired. When GRO is enabled, even if the kernel cannot GRO certain traffic, it has to run through the GRO receive handlers with no benefit.
There are also scenarios that turning off GRO is a requirement. For example, our production environment has a scenario that a TC egress hook may add multiple encapsulation headers to forwarded skbs for load balancing and isolation purpose. The encapsulation is implemented via BPF. But the problem arises then: there is no way to properly offload a double-encapsulated packet, since skb only has
network_headerandinner_network_headerto track one layer of encapsulation, but not two. On the other hand, not all the traffic through this device needs double encapsulation. But we have to turn off GRO completely for any ingress device as a result.Introduce a bit on skb so that GRO engine can be notified to skip GRO on this skb, rather than having to be 0-or-1 for all traffic.
Signed-off-by Yan Zhai <[email protected]>--- include/linux/netdevice.h | 9 +++++++-- include/linux/skbuff.h | 10 ++++++++++ net/Kconfig | 10 ++++++++++ net/core/gro.c | 2 +- net/core/gro_cells.c | 2 +- net/core/skbuff.c | 4 ++++ 6 files changed, 33 insertions(+), 4 deletions(-)include/linux/netdevice.h +1
-1@@ -2415,11 +2415,16 @@ struct net_device { ((dev)->devlink_port = (port)); \ }) -static inline bool netif_elide_gro (const struct net_device *dev) +static inline bool netif_elide_gro (const struct sk_buff *skb)include/linux/netdevice.h struct net_device { · line 2427
Quoted 10 lines
include/linux/netdevice.h +6
-1{ -if (!(dev->features &NETIF_F_GRO ) || dev->xdp_prog) +if (!(skb->dev->features &NETIF_F_GRO ) || skb->dev->xdp_prog)return true; + +#ifdef CONFIG_SKB_GRO_CONTROL +return skb->gro_disabled; +#else return false; +#endif Yet more branches in the hot path.
Quoted 7 lines
Compile time configurability does not help, as that will be enabled by distros.
For a fairly niche use case. Where functionality of GRO already works. So just a performance for a very rare case at the cost of a regression in the common case. A small regression perhaps, but death by a thousand cuts.
Mentioning it here b/c it perhaps fits in this context, longer time ago there was the idea mentioned to have BPF operating as GRO engine which might also help to reduce attack surface by only having to handle packets of interest for the concrete production use case. Perhaps here meta data buffer could be used to pass a notification from XDP to exit early w/o aggregation.
Re: [RFC net-next 1/9] skb: introduce gro_disabled bit
Quoted 66 lines · Daniel Borkmann
Quoted 56 lines · Willem de Bruijn
Quoted 42 lines · Yan Zhai
Software GRO is currently controlled by a single switch, i.e.
ethtool -K dev gro on|off
However, this is not always desired. When GRO is enabled, even if the kernel cannot GRO certain traffic, it has to run through the GRO receive handlers with no benefit.
There are also scenarios that turning off GRO is a requirement. For example, our production environment has a scenario that a TC egress hook may add multiple encapsulation headers to forwarded skbs for load balancing and isolation purpose. The encapsulation is implemented via BPF. But the problem arises then: there is no way to properly offload a double-encapsulated packet, since skb only has
network_headerandinner_network_headerto track one layer of encapsulation, but not two. On the other hand, not all the traffic through this device needs double encapsulation. But we have to turn off GRO completely for any ingress device as a result.Introduce a bit on skb so that GRO engine can be notified to skip GRO on this skb, rather than having to be 0-or-1 for all traffic.
Signed-off-by Yan Zhai <[email protected]>--- include/linux/netdevice.h | 9 +++++++-- include/linux/skbuff.h | 10 ++++++++++ net/Kconfig | 10 ++++++++++ net/core/gro.c | 2 +- net/core/gro_cells.c | 2 +- net/core/skbuff.c | 4 ++++ 6 files changed, 33 insertions(+), 4 deletions(-)include/linux/netdevice.h +1
-1@@ -2415,11 +2415,16 @@ struct net_device { ((dev)->devlink_port = (port)); \ }) -static inline bool netif_elide_gro (const struct net_device *dev) +static inline bool netif_elide_gro (const struct sk_buff *skb)include/linux/netdevice.h struct net_device { · line 2427
Quoted 10 lines
include/linux/netdevice.h +6
-1{ -if (!(dev->features &NETIF_F_GRO ) || dev->xdp_prog) +if (!(skb->dev->features &NETIF_F_GRO ) || skb->dev->xdp_prog)return true; + +#ifdef CONFIG_SKB_GRO_CONTROL +return skb->gro_disabled; +#else return false; +#endif Yet more branches in the hot path.
Quoted 7 lines
Compile time configurability does not help, as that will be enabled by distros.
For a fairly niche use case. Where functionality of GRO already works. So just a performance for a very rare case at the cost of a regression in the common case. A small regression perhaps, but death by a thousand cuts.
Quoted 6 lines
Mentioning it here b/c it perhaps fits in this context, longer time ago there was the idea mentioned to have BPF operating as GRO engine which might also help to reduce attack surface by only having to handle packets of interest for the concrete production use case. Perhaps here meta data buffer could be used to pass a notification from XDP to exit early w/o aggregation.
Metadata is in fact one of our interests as well. We discussed using metadata instead of a skb bit to carry this information internally. Since metadata is opaque atm so it seems the only option is to have a GRO control hook before napi_gro_receive, and let BPF decide netif_receive_skb or napi_gro_receive (echo what Paolo said). With BPF it could indeed be more flexible, but the cons is that it could be even more slower than taking a bit on skb. I am actually open to either approach, as long as it gives us more control on when to enable GRO :)
To extend the discussion a bit, putting GRO aside, I think some common hook before GRO would be still valuable moving forward: it is a limited window where the driver code has both access to XDP context and skb. Today we do not have a good way to transfer HW offloading info to skbs if XDP redirect-to-cpu or if XDP encap-and-tx for load balancing purposes. The XDP metadata infrastructure already allows XDP to read this information with driver supports, so to complete that, a place to use it (which I introduced as xdp_buff/frame_fixup_skb_offloading in a later patch) would be beneficial to pass on things like the flow hash, vlan information, etc.
best
Yan
Daniel Borkmann
maintainerRe: [RFC net-next 1/9] skb: introduce gro_disabled bit
Quoted 73 lines · Yan Zhai
Quoted 65 lines · Daniel Borkmann
Quoted 56 lines · Willem de Bruijn
Quoted 42 lines · Yan Zhai
Software GRO is currently controlled by a single switch, i.e.
ethtool -K dev gro on|off
However, this is not always desired. When GRO is enabled, even if the kernel cannot GRO certain traffic, it has to run through the GRO receive handlers with no benefit.
There are also scenarios that turning off GRO is a requirement. For example, our production environment has a scenario that a TC egress hook may add multiple encapsulation headers to forwarded skbs for load balancing and isolation purpose. The encapsulation is implemented via BPF. But the problem arises then: there is no way to properly offload a double-encapsulated packet, since skb only has
network_headerandinner_network_headerto track one layer of encapsulation, but not two. On the other hand, not all the traffic through this device needs double encapsulation. But we have to turn off GRO completely for any ingress device as a result.Introduce a bit on skb so that GRO engine can be notified to skip GRO on this skb, rather than having to be 0-or-1 for all traffic.
Signed-off-by Yan Zhai <[email protected]>--- include/linux/netdevice.h | 9 +++++++-- include/linux/skbuff.h | 10 ++++++++++ net/Kconfig | 10 ++++++++++ net/core/gro.c | 2 +- net/core/gro_cells.c | 2 +- net/core/skbuff.c | 4 ++++ 6 files changed, 33 insertions(+), 4 deletions(-)include/linux/netdevice.h +1
-1@@ -2415,11 +2415,16 @@ struct net_device { ((dev)->devlink_port = (port)); \ }) -static inline bool netif_elide_gro (const struct net_device *dev) +static inline bool netif_elide_gro (const struct sk_buff *skb)include/linux/netdevice.h struct net_device { · line 2427
Quoted 10 lines
include/linux/netdevice.h +6
-1{ -if (!(dev->features &NETIF_F_GRO ) || dev->xdp_prog) +if (!(skb->dev->features &NETIF_F_GRO ) || skb->dev->xdp_prog)return true; + +#ifdef CONFIG_SKB_GRO_CONTROL +return skb->gro_disabled; +#else return false; +#endif Yet more branches in the hot path.
Quoted 7 lines
Compile time configurability does not help, as that will be enabled by distros.
For a fairly niche use case. Where functionality of GRO already works. So just a performance for a very rare case at the cost of a regression in the common case. A small regression perhaps, but death by a thousand cuts.
Quoted 6 lines
Mentioning it here b/c it perhaps fits in this context, longer time ago there was the idea mentioned to have BPF operating as GRO engine which might also help to reduce attack surface by only having to handle packets of interest for the concrete production use case. Perhaps here meta data buffer could be used to pass a notification from XDP to exit early w/o aggregation.
Quoted 9 lines
Metadata is in fact one of our interests as well. We discussed using metadata instead of a skb bit to carry this information internally. Since metadata is opaque atm so it seems the only option is to have a GRO control hook before
napi_gro_receive, and let BPF decidenetif_receive_skbornapi_gro_receive(echo what Paolo said). With BPF it could indeed be more flexible, but the cons is that it could be even more slower than taking a bit on skb. I am actually open to either approach, as long as it gives us more control on when to enable GRO :)
Oh wait, one thing that just came to mind.. have you tried u64 per-CPU counter map in XDP? For packets which should not be GRO-aggregated you add count++ into the meta data area, and this forces GRO to not aggregate since meta data that needs to be transported to tc BPF layer mismatches (and therefore the contract/intent is that tc BPF needs to see the different meta data passed to it).
Thanks,
Daniel
Re: [RFC net-next 1/9] skb: introduce gro_disabled bit
Quoted 85 lines · Daniel Borkmann
Quoted 73 lines · Yan Zhai
Quoted 65 lines · Daniel Borkmann
Quoted 56 lines · Willem de Bruijn
Quoted 42 lines · Yan Zhai
Software GRO is currently controlled by a single switch, i.e.
ethtool -K dev gro on|off
However, this is not always desired. When GRO is enabled, even if the kernel cannot GRO certain traffic, it has to run through the GRO receive handlers with no benefit.
There are also scenarios that turning off GRO is a requirement. For example, our production environment has a scenario that a TC egress hook may add multiple encapsulation headers to forwarded skbs for load balancing and isolation purpose. The encapsulation is implemented via BPF. But the problem arises then: there is no way to properly offload a double-encapsulated packet, since skb only has
network_headerandinner_network_headerto track one layer of encapsulation, but not two. On the other hand, not all the traffic through this device needs double encapsulation. But we have to turn off GRO completely for any ingress device as a result.Introduce a bit on skb so that GRO engine can be notified to skip GRO on this skb, rather than having to be 0-or-1 for all traffic.
Signed-off-by Yan Zhai <[email protected]>--- include/linux/netdevice.h | 9 +++++++-- include/linux/skbuff.h | 10 ++++++++++ net/Kconfig | 10 ++++++++++ net/core/gro.c | 2 +- net/core/gro_cells.c | 2 +- net/core/skbuff.c | 4 ++++ 6 files changed, 33 insertions(+), 4 deletions(-)include/linux/netdevice.h +1
-1@@ -2415,11 +2415,16 @@ struct net_device { ((dev)->devlink_port = (port)); \ }) -static inline bool netif_elide_gro (const struct net_device *dev) +static inline bool netif_elide_gro (const struct sk_buff *skb)include/linux/netdevice.h struct net_device { · line 2427
Quoted 10 lines
include/linux/netdevice.h +6
-1{ -if (!(dev->features &NETIF_F_GRO ) || dev->xdp_prog) +if (!(skb->dev->features &NETIF_F_GRO ) || skb->dev->xdp_prog)return true; + +#ifdef CONFIG_SKB_GRO_CONTROL +return skb->gro_disabled; +#else return false; +#endif Yet more branches in the hot path.
Quoted 7 lines
Compile time configurability does not help, as that will be enabled by distros.
For a fairly niche use case. Where functionality of GRO already works. So just a performance for a very rare case at the cost of a regression in the common case. A small regression perhaps, but death by a thousand cuts.
Quoted 6 lines
Mentioning it here b/c it perhaps fits in this context, longer time ago there was the idea mentioned to have BPF operating as GRO engine which might also help to reduce attack surface by only having to handle packets of interest for the concrete production use case. Perhaps here meta data buffer could be used to pass a notification from XDP to exit early w/o aggregation.
Quoted 9 lines
Metadata is in fact one of our interests as well. We discussed using metadata instead of a skb bit to carry this information internally. Since metadata is opaque atm so it seems the only option is to have a GRO control hook before
napi_gro_receive, and let BPF decidenetif_receive_skbornapi_gro_receive(echo what Paolo said). With BPF it could indeed be more flexible, but the cons is that it could be even more slower than taking a bit on skb. I am actually open to either approach, as long as it gives us more control on when to enable GRO :)
Quoted 7 lines
Oh wait, one thing that just came to mind.. have you tried u64 per-CPU counter map in XDP? For packets which should not be GRO-aggregated you add count++ into the meta data area, and this forces GRO to not aggregate since meta data that needs to be transported to tc BPF layer mismatches (and therefore the contract/intent is that tc BPF needs to see the different meta data passed to it).
Very very sorry to resendx2 :( Not sure why my laptop also decided to switch on html... I removed CCs from the message hopefully it reduces some noises...
We did this before accidentally (we put a timestamp for debugging purposes in metadata) and this actually caused about 20% of OoO for TCP in production: all PSH packets are reordered. GRO does not fire the packet to the upper layer when a diff in metadata is found for a non-PSH packet, instead it is queued as a “new flow” on the GRO list and waits for flushing. When a PSH packet arrives, its semantic is to flush this packet immediately and thus precedes earlier packets of the same flow.
The artifact of this behavior can also cause latency increase and hash degradation since the mismatch does not result in flushing, it results in extra queuing on the same hash list, until the list is flushed. It’s another reason we want to disable GRO when we know metadata can be set differently for tracing purposes (I didn’t mention this though because it seems distracting).
Thanks
Yan
Quoted 2 lines
Thanks,
Daniel
Re: [RFC net-next 1/9] skb: introduce gro_disabled bit
Quoted 94 lines · Yan Zhai
Quoted 85 lines · Daniel Borkmann
Quoted 73 lines · Yan Zhai
Quoted 65 lines · Daniel Borkmann
Quoted 56 lines · Willem de Bruijn
Quoted 42 lines · Yan Zhai
Software GRO is currently controlled by a single switch, i.e.
ethtool -K dev gro on|off
However, this is not always desired. When GRO is enabled, even if the kernel cannot GRO certain traffic, it has to run through the GRO receive handlers with no benefit.
There are also scenarios that turning off GRO is a requirement. For example, our production environment has a scenario that a TC egress hook may add multiple encapsulation headers to forwarded skbs for load balancing and isolation purpose. The encapsulation is implemented via BPF. But the problem arises then: there is no way to properly offload a double-encapsulated packet, since skb only has
network_headerandinner_network_headerto track one layer of encapsulation, but not two. On the other hand, not all the traffic through this device needs double encapsulation. But we have to turn off GRO completely for any ingress device as a result.Introduce a bit on skb so that GRO engine can be notified to skip GRO on this skb, rather than having to be 0-or-1 for all traffic.
Signed-off-by Yan Zhai <[email protected]>--- include/linux/netdevice.h | 9 +++++++-- include/linux/skbuff.h | 10 ++++++++++ net/Kconfig | 10 ++++++++++ net/core/gro.c | 2 +- net/core/gro_cells.c | 2 +- net/core/skbuff.c | 4 ++++ 6 files changed, 33 insertions(+), 4 deletions(-)include/linux/netdevice.h +1
-1@@ -2415,11 +2415,16 @@ struct net_device { ((dev)->devlink_port = (port)); \ }) -static inline bool netif_elide_gro (const struct net_device *dev) +static inline bool netif_elide_gro (const struct sk_buff *skb)include/linux/netdevice.h struct net_device { · line 2427
Quoted 10 lines
include/linux/netdevice.h +6
-1{ -if (!(dev->features &NETIF_F_GRO ) || dev->xdp_prog) +if (!(skb->dev->features &NETIF_F_GRO ) || skb->dev->xdp_prog)return true; + +#ifdef CONFIG_SKB_GRO_CONTROL +return skb->gro_disabled; +#else return false; +#endif Yet more branches in the hot path.
Quoted 7 lines
Compile time configurability does not help, as that will be enabled by distros.
For a fairly niche use case. Where functionality of GRO already works. So just a performance for a very rare case at the cost of a regression in the common case. A small regression perhaps, but death by a thousand cuts.
Quoted 6 lines
Mentioning it here b/c it perhaps fits in this context, longer time ago there was the idea mentioned to have BPF operating as GRO engine which might also help to reduce attack surface by only having to handle packets of interest for the concrete production use case. Perhaps here meta data buffer could be used to pass a notification from XDP to exit early w/o aggregation.
Quoted 9 lines
Metadata is in fact one of our interests as well. We discussed using metadata instead of a skb bit to carry this information internally. Since metadata is opaque atm so it seems the only option is to have a GRO control hook before
napi_gro_receive, and let BPF decidenetif_receive_skbornapi_gro_receive(echo what Paolo said). With BPF it could indeed be more flexible, but the cons is that it could be even more slower than taking a bit on skb. I am actually open to either approach, as long as it gives us more control on when to enable GRO :)Quoted 7 lines
Oh wait, one thing that just came to mind.. have you tried u64 per-CPU counter map in XDP? For packets which should not be GRO-aggregated you add count++ into the meta data area, and this forces GRO to not aggregate since meta data that needs to be transported to tc BPF layer mismatches (and therefore the contract/intent is that tc BPF needs to see the different meta data passed to it).
Quoted 8 lines
We did this before accidentally (we put a timestamp for debugging purposes in metadata) and this actually caused about 20% of OoO for TCP in production: all PSH packets are reordered. GRO does not fire the packet to the upper layer when a diff in metadata is found for a non-PSH packet, instead it is queued as a “new flow” on the GRO list and waits for flushing. When a PSH packet arrives, its semantic is to flush this packet immediately and thus precedes earlier packets of the same flow.
Is that a bug in XDP metadata handling for GRO?
Mismatching metadata should not be taken as separate flows, but as a flush condition.
Daniel Borkmann
maintainerRe: [RFC net-next 1/9] skb: introduce gro_disabled bit
Quoted 102 lines · Willem de Bruijn
Quoted 92 lines · Yan Zhai
Quoted 84 lines · Daniel Borkmann
Quoted 73 lines · Yan Zhai
Quoted 65 lines · Daniel Borkmann
Quoted 56 lines · Willem de Bruijn
Quoted 42 lines · Yan Zhai
Software GRO is currently controlled by a single switch, i.e.
ethtool -K dev gro on|off
However, this is not always desired. When GRO is enabled, even if the kernel cannot GRO certain traffic, it has to run through the GRO receive handlers with no benefit.
There are also scenarios that turning off GRO is a requirement. For example, our production environment has a scenario that a TC egress hook may add multiple encapsulation headers to forwarded skbs for load balancing and isolation purpose. The encapsulation is implemented via BPF. But the problem arises then: there is no way to properly offload a double-encapsulated packet, since skb only has
network_headerandinner_network_headerto track one layer of encapsulation, but not two. On the other hand, not all the traffic through this device needs double encapsulation. But we have to turn off GRO completely for any ingress device as a result.Introduce a bit on skb so that GRO engine can be notified to skip GRO on this skb, rather than having to be 0-or-1 for all traffic.
Signed-off-by Yan Zhai <[email protected]>--- include/linux/netdevice.h | 9 +++++++-- include/linux/skbuff.h | 10 ++++++++++ net/Kconfig | 10 ++++++++++ net/core/gro.c | 2 +- net/core/gro_cells.c | 2 +- net/core/skbuff.c | 4 ++++ 6 files changed, 33 insertions(+), 4 deletions(-)include/linux/netdevice.h +1
-1@@ -2415,11 +2415,16 @@ struct net_device { ((dev)->devlink_port = (port)); \ }) -static inline bool netif_elide_gro (const struct net_device *dev) +static inline bool netif_elide_gro (const struct sk_buff *skb)include/linux/netdevice.h struct net_device { · line 2427
Quoted 10 lines
include/linux/netdevice.h +6
-1{ -if (!(dev->features &NETIF_F_GRO ) || dev->xdp_prog) +if (!(skb->dev->features &NETIF_F_GRO ) || skb->dev->xdp_prog)return true; + +#ifdef CONFIG_SKB_GRO_CONTROL +return skb->gro_disabled; +#else return false; +#endif Yet more branches in the hot path.
Quoted 7 lines
Compile time configurability does not help, as that will be enabled by distros.
For a fairly niche use case. Where functionality of GRO already works. So just a performance for a very rare case at the cost of a regression in the common case. A small regression perhaps, but death by a thousand cuts.
Quoted 6 lines
Mentioning it here b/c it perhaps fits in this context, longer time ago there was the idea mentioned to have BPF operating as GRO engine which might also help to reduce attack surface by only having to handle packets of interest for the concrete production use case. Perhaps here meta data buffer could be used to pass a notification from XDP to exit early w/o aggregation.
Quoted 9 lines
Metadata is in fact one of our interests as well. We discussed using metadata instead of a skb bit to carry this information internally. Since metadata is opaque atm so it seems the only option is to have a GRO control hook before
napi_gro_receive, and let BPF decidenetif_receive_skbornapi_gro_receive(echo what Paolo said). With BPF it could indeed be more flexible, but the cons is that it could be even more slower than taking a bit on skb. I am actually open to either approach, as long as it gives us more control on when to enable GRO :)Quoted 6 lines
Oh wait, one thing that just came to mind.. have you tried u64 per-CPU counter map in XDP? For packets which should not be GRO-aggregated you add count++ into the meta data area, and this forces GRO to not aggregate since meta data that needs to be transported to tc BPF layer mismatches (and therefore the contract/intent is that tc BPF needs to see the different meta data passed to it).
Quoted 8 lines
We did this before accidentally (we put a timestamp for debugging purposes in metadata) and this actually caused about 20% of OoO for TCP in production: all PSH packets are reordered. GRO does not fire the packet to the upper layer when a diff in metadata is found for a non-PSH packet, instead it is queued as a “new flow” on the GRO list and waits for flushing. When a PSH packet arrives, its semantic is to flush this packet immediately and thus precedes earlier packets of the same flow.
Quoted 4 lines
Is that a bug in XDP metadata handling for GRO?
Mismatching metadata should not be taken as separate flows, but as a flush condition.
Definitely a bug as it should flush. If noone is faster I can add it to my backlog todo to fix it, but might probably take a week before I get to it.
Thanks,
Daniel
Re: [RFC net-next 1/9] skb: introduce gro_disabled bit
Quoted 104 lines · Daniel Borkmann
Quoted 102 lines · Willem de Bruijn
Quoted 100 lines · Yan Zhai
Quoted 84 lines · Daniel Borkmann
Quoted 73 lines · Yan Zhai
Quoted 65 lines · Daniel Borkmann
Quoted 56 lines · Willem de Bruijn
Quoted 42 lines · Yan Zhai
Software GRO is currently controlled by a single switch, i.e.
ethtool -K dev gro on|off
However, this is not always desired. When GRO is enabled, even if the kernel cannot GRO certain traffic, it has to run through the GRO receive handlers with no benefit.
There are also scenarios that turning off GRO is a requirement. For example, our production environment has a scenario that a TC egress hook may add multiple encapsulation headers to forwarded skbs for load balancing and isolation purpose. The encapsulation is implemented via BPF. But the problem arises then: there is no way to properly offload a double-encapsulated packet, since skb only has
network_headerandinner_network_headerto track one layer of encapsulation, but not two. On the other hand, not all the traffic through this device needs double encapsulation. But we have to turn off GRO completely for any ingress device as a result.Introduce a bit on skb so that GRO engine can be notified to skip GRO on this skb, rather than having to be 0-or-1 for all traffic.
Signed-off-by Yan Zhai <[email protected]>--- include/linux/netdevice.h | 9 +++++++-- include/linux/skbuff.h | 10 ++++++++++ net/Kconfig | 10 ++++++++++ net/core/gro.c | 2 +- net/core/gro_cells.c | 2 +- net/core/skbuff.c | 4 ++++ 6 files changed, 33 insertions(+), 4 deletions(-)include/linux/netdevice.h +1
-1@@ -2415,11 +2415,16 @@ struct net_device { ((dev)->devlink_port = (port)); \ }) -static inline bool netif_elide_gro (const struct net_device *dev) +static inline bool netif_elide_gro (const struct sk_buff *skb)include/linux/netdevice.h struct net_device { · line 2427
Quoted 10 lines
include/linux/netdevice.h +6
-1{ -if (!(dev->features &NETIF_F_GRO ) || dev->xdp_prog) +if (!(skb->dev->features &NETIF_F_GRO ) || skb->dev->xdp_prog)return true; + +#ifdef CONFIG_SKB_GRO_CONTROL +return skb->gro_disabled; +#else return false; +#endif Yet more branches in the hot path.
Quoted 7 lines
Compile time configurability does not help, as that will be enabled by distros.
For a fairly niche use case. Where functionality of GRO already works. So just a performance for a very rare case at the cost of a regression in the common case. A small regression perhaps, but death by a thousand cuts.
Quoted 6 lines
Mentioning it here b/c it perhaps fits in this context, longer time ago there was the idea mentioned to have BPF operating as GRO engine which might also help to reduce attack surface by only having to handle packets of interest for the concrete production use case. Perhaps here meta data buffer could be used to pass a notification from XDP to exit early w/o aggregation.
Quoted 9 lines
Metadata is in fact one of our interests as well. We discussed using metadata instead of a skb bit to carry this information internally. Since metadata is opaque atm so it seems the only option is to have a GRO control hook before
napi_gro_receive, and let BPF decidenetif_receive_skbornapi_gro_receive(echo what Paolo said). With BPF it could indeed be more flexible, but the cons is that it could be even more slower than taking a bit on skb. I am actually open to either approach, as long as it gives us more control on when to enable GRO :)Quoted 6 lines
Oh wait, one thing that just came to mind.. have you tried u64 per-CPU counter map in XDP? For packets which should not be GRO-aggregated you add count++ into the meta data area, and this forces GRO to not aggregate since meta data that needs to be transported to tc BPF layer mismatches (and therefore the contract/intent is that tc BPF needs to see the different meta data passed to it).
We did this before accidentally (we put a timestamp for debugging purposes in metadata) and this actually caused about 20% of OoO for TCP in production: all PSH packets are reordered. GRO does not fire the packet to the upper layer when a diff in metadata is found for a non-PSH packet, instead it is queued as a “new flow” on the GRO list and waits for flushing. When a PSH packet arrives, its semantic is to flush this packet immediately and thus precedes earlier packets of the same flow.
Quoted 8 lines
Quoted 4 lines
Is that a bug in XDP metadata handling for GRO?
Mismatching metadata should not be taken as separate flows, but as a flush condition.
Definitely a bug as it should flush. If noone is faster I can add it to my backlog todo to fix it, but might probably take a week before I get to it.
In theory we should flush if the same flow has different metadata. However "same flow" is not finally confirmed until GRO proceeds to the TCP layer in this case. So to achieve this flush semantic, metadata should be compared at the leaf protocol handlers instead of initially inside dev_gro_receive. I am not quite sure if it is worthwhile, or just allow skipping GRO from XDP, since it's the XDP program who sets this metadata.
Yan
Quoted 2 lines
Thanks,
Daniel
Re: [RFC net-next 1/9] skb: introduce gro_disabled bit
In reply to Willem de BruijnQuoted 15 lines
include/linux/netdevice.h struct net_device { · line 2427
Quoted 12 lines
include/linux/netdevice.h +7
-2-static inline bool netif_elide_gro (const struct net_device *dev) +static inline bool netif_elide_gro (const struct sk_buff *skb) { -if (!(dev->features &NETIF_F_GRO ) || dev->xdp_prog) +if (!(skb->dev->features &NETIF_F_GRO ) || skb->dev->xdp_prog)return true; + +#ifdef CONFIG_SKB_GRO_CONTROL +return skb->gro_disabled; +#else return false; +#endif Yet more branches in the hot path.
Quoted 8 lines
Compile time configurability does not help, as that will be enabled by distros.
For a fairly niche use case. Where functionality of GRO already works. So just a performance for a very rare case at the cost of a regression in the common case. A small regression perhaps, but death by a thousand cuts.
I share your concern on operating on this hotpath. Will a static_branch + sysctl make it less aggressive? Speaking of performance, I'd hope this can give us more control so we can achieve the best of two worlds: for TCP and some UDP traffic, we can enable GRO, while for some other classes that we know GRO does no good or even harm, let's disable GRO to save more cycles. The key observation is that developers may already know which traffic is blessed by GRO, but lack a way to realize it.
best
Yan
Re: [RFC net-next 1/9] skb: introduce gro_disabled bit
Quoted 18 lines · Yan Zhai
Quoted 18 lines
include/linux/netdevice.h struct net_device { · line 2427
Quoted 12 lines
include/linux/netdevice.h +7
-2-static inline bool netif_elide_gro (const struct net_device *dev) +static inline bool netif_elide_gro (const struct sk_buff *skb) { -if (!(dev->features &NETIF_F_GRO ) || dev->xdp_prog) +if (!(skb->dev->features &NETIF_F_GRO ) || skb->dev->xdp_prog)return true; + +#ifdef CONFIG_SKB_GRO_CONTROL +return skb->gro_disabled; +#else return false; +#endif Yet more branches in the hot path.
Compile time configurability does not help, as that will be enabled by distros.
Quoted 8 lines
Quoted 5 lines
For a fairly niche use case. Where functionality of GRO already works. So just a performance for a very rare case at the cost of a regression in the common case. A small regression perhaps, but death by a thousand cuts.
I share your concern on operating on this hotpath. Will a
static_branch+ sysctl make it less aggressive?
That is always a possibility. But we have to use it judiciously, cannot add a sysctl for every branch.
I'm still of the opinion that Paolo shared that this seems a lot of complexity for a fairly minor performance optimization for a rare case.
Quoted 7 lines
Speaking of
performance, I'd hope this can give us more control so we can achieve the best of two worlds: for TCP and some UDP traffic, we can enable GRO, while for some other classes that we know GRO does no good or even harm, let's disable GRO to save more cycles. The key observation is that developers may already know which traffic is blessed by GRO, but lack a way to realize it.
Following up also on Daniel's point on using BPF as GRO engine. Even earlier I tried to add an option to selectively enable GRO protocols without BPF. Definitely worthwhile to be able to disable GRO handlers to reduce attack surface to bad input.
Quoted 3 lines
best
Yan
Re: [RFC net-next 1/9] skb: introduce gro_disabled bit
Quoted 29 lines · Willem de Bruijn
Quoted 18 lines · Yan Zhai
Quoted 18 lines
include/linux/netdevice.h struct net_device { · line 2427
Quoted 12 lines
include/linux/netdevice.h +7
-2-static inline bool netif_elide_gro (const struct net_device *dev) +static inline bool netif_elide_gro (const struct sk_buff *skb) { -if (!(dev->features &NETIF_F_GRO ) || dev->xdp_prog) +if (!(skb->dev->features &NETIF_F_GRO ) || skb->dev->xdp_prog)return true; + +#ifdef CONFIG_SKB_GRO_CONTROL +return skb->gro_disabled; +#else return false; +#endif Yet more branches in the hot path.
Compile time configurability does not help, as that will be enabled by distros.
Quoted 8 lines
Quoted 5 lines
For a fairly niche use case. Where functionality of GRO already works. So just a performance for a very rare case at the cost of a regression in the common case. A small regression perhaps, but death by a thousand cuts.
I share your concern on operating on this hotpath. Will a
static_branch+ sysctl make it less aggressive?
Quoted 7 lines
That is always a possibility. But we have to use it judiciously, cannot add a sysctl for every branch.
I'm still of the opinion that Paolo shared that this seems a lot of complexity for a fairly minor performance optimization for a rare case.
Actually combining the discussion in this thread, I think it would be more than the corner cases that we encounter. Let me elaborate below.
Quoted 8 lines
Quoted 7 lines
Speaking of
performance, I'd hope this can give us more control so we can achieve the best of two worlds: for TCP and some UDP traffic, we can enable GRO, while for some other classes that we know GRO does no good or even harm, let's disable GRO to save more cycles. The key observation is that developers may already know which traffic is blessed by GRO, but lack a way to realize it.
Quoted 5 lines
Following up also on Daniel's point on using BPF as GRO engine. Even earlier I tried to add an option to selectively enable GRO protocols without BPF. Definitely worthwhile to be able to disable GRO handlers to reduce attack surface to bad input.
I was probably staring too hard at my own things, which is indeed a corner case. But reducing the attack surface is indeed a good motivation for this patch. I checked briefly with our DoS team today, the DoS scenario will definitely benefit from skipping GRO, for example on SYN/RST floods. XDP is our main weapon to drop attack traffic today, but it does not always drop 100% of the floods, and time by time it does need to fall back to iptables due to the delay of XDP program assembly or the BPF limitation on analyzing the packet. I did an ad hoc measurement just now on a mostly idle server, with ~1.3Mpps SYN flood concentrated on one CPU and dropped them early in raw-PREROUTING. w/ GRO this would consume about 35-41% of the CPU time, while w/o GRO the time dropped to 9-12%. This seems a pretty significant breath room under heavy attacks.
But I am not sure I understand "BPF as GRO engine" here, it seems to me that being able to disable GRO by XDP is already good enough. Any more motivations to do more complex work here?
best
Yan
Quoted 6 lines
Quoted 4 lines
best
Yan
Re: [RFC net-next 1/9] skb: introduce gro_disabled bit
Quoted 54 lines · Yan Zhai
Quoted 29 lines · Willem de Bruijn
Quoted 18 lines · Yan Zhai
Quoted 18 lines
include/linux/netdevice.h struct net_device { · line 2427
Quoted 12 lines
include/linux/netdevice.h +7
-2-static inline bool netif_elide_gro (const struct net_device *dev) +static inline bool netif_elide_gro (const struct sk_buff *skb) { -if (!(dev->features &NETIF_F_GRO ) || dev->xdp_prog) +if (!(skb->dev->features &NETIF_F_GRO ) || skb->dev->xdp_prog)return true; + +#ifdef CONFIG_SKB_GRO_CONTROL +return skb->gro_disabled; +#else return false; +#endif Yet more branches in the hot path.
Compile time configurability does not help, as that will be enabled by distros.
Quoted 8 lines
Quoted 5 lines
For a fairly niche use case. Where functionality of GRO already works. So just a performance for a very rare case at the cost of a regression in the common case. A small regression perhaps, but death by a thousand cuts.
I share your concern on operating on this hotpath. Will a
static_branch+ sysctl make it less aggressive?Quoted 7 lines
That is always a possibility. But we have to use it judiciously, cannot add a sysctl for every branch.
I'm still of the opinion that Paolo shared that this seems a lot of complexity for a fairly minor performance optimization for a rare case.
Actually combining the discussion in this thread, I think it would be more than the corner cases that we encounter. Let me elaborate below.
Quoted 8 lines
Quoted 7 lines
Speaking of
performance, I'd hope this can give us more control so we can achieve the best of two worlds: for TCP and some UDP traffic, we can enable GRO, while for some other classes that we know GRO does no good or even harm, let's disable GRO to save more cycles. The key observation is that developers may already know which traffic is blessed by GRO, but lack a way to realize it.Quoted 5 lines
Following up also on Daniel's point on using BPF as GRO engine. Even earlier I tried to add an option to selectively enable GRO protocols without BPF. Definitely worthwhile to be able to disable GRO handlers to reduce attack surface to bad input.
Quoted 13 lines
I was probably staring too hard at my own things, which is indeed a corner case. But reducing the attack surface is indeed a good motivation for this patch. I checked briefly with our DoS team today, the DoS scenario will definitely benefit from skipping GRO, for example on SYN/RST floods. XDP is our main weapon to drop attack traffic today, but it does not always drop 100% of the floods, and time by time it does need to fall back to iptables due to the delay of XDP program assembly or the BPF limitation on analyzing the packet. I did an ad hoc measurement just now on a mostly idle server, with ~1.3Mpps SYN flood concentrated on one CPU and dropped them early in raw-PREROUTING. w/ GRO this would consume about 35-41% of the CPU time, while w/o GRO the time dropped to 9-12%. This seems a pretty significant breath room under heavy attacks.
A GRO opt-out might make sense.
A long time ago I sent a patch that configured GRO protocols using syscalls, selectively (un)registering handlers. The interface was not very nice, so I did not pursue it further. On the upside, the datapath did not introduce any extra code. The intent was to reduce attack surface of packet parsing code.
A few concerns with an XDP based opt-out. It is more work to enable:
requires compiling and load an XDP program. It adds cycles in the hot path. And I do not entirely understand when an XDP program will be able to detect that a packet should not enter the GRO engine, but cannot drop the packet (your netfilter example above).
Quoted 3 lines
But I am not sure I understand "BPF as GRO engine" here, it seems to me that being able to disable GRO by XDP is already good enough. Any more motivations to do more complex work here?
FWIW, we looked into this a few years ago. Analogous to the BPF flow
dissector: if the BPF program is loaded, use that instead of the C code path. But we did not arrive at a practical implementation at the time. Things may have changed, but one issue is how to store and access the list (or table) of outstanding GRO skbs.
Quoted 9 lines
best
YanQuoted 6 lines
Quoted 4 lines
best
Yan
Re: [RFC net-next 1/9] skb: introduce gro_disabled bit
Quoted 78 lines · Willem de Bruijn
Quoted 54 lines · Yan Zhai
Quoted 29 lines · Willem de Bruijn
Quoted 18 lines · Yan Zhai
Quoted 18 lines
include/linux/netdevice.h struct net_device { · line 2427
Quoted 12 lines
include/linux/netdevice.h +7
-2-static inline bool netif_elide_gro (const struct net_device *dev) +static inline bool netif_elide_gro (const struct sk_buff *skb) { -if (!(dev->features &NETIF_F_GRO ) || dev->xdp_prog) +if (!(skb->dev->features &NETIF_F_GRO ) || skb->dev->xdp_prog)return true; + +#ifdef CONFIG_SKB_GRO_CONTROL +return skb->gro_disabled; +#else return false; +#endif Yet more branches in the hot path.
Compile time configurability does not help, as that will be enabled by distros.
Quoted 8 lines
Quoted 5 lines
For a fairly niche use case. Where functionality of GRO already works. So just a performance for a very rare case at the cost of a regression in the common case. A small regression perhaps, but death by a thousand cuts.
I share your concern on operating on this hotpath. Will a
static_branch+ sysctl make it less aggressive?Quoted 7 lines
That is always a possibility. But we have to use it judiciously, cannot add a sysctl for every branch.
I'm still of the opinion that Paolo shared that this seems a lot of complexity for a fairly minor performance optimization for a rare case.
Actually combining the discussion in this thread, I think it would be more than the corner cases that we encounter. Let me elaborate below.
Quoted 8 lines
Quoted 7 lines
Speaking of
performance, I'd hope this can give us more control so we can achieve the best of two worlds: for TCP and some UDP traffic, we can enable GRO, while for some other classes that we know GRO does no good or even harm, let's disable GRO to save more cycles. The key observation is that developers may already know which traffic is blessed by GRO, but lack a way to realize it.Quoted 5 lines
Following up also on Daniel's point on using BPF as GRO engine. Even earlier I tried to add an option to selectively enable GRO protocols without BPF. Definitely worthwhile to be able to disable GRO handlers to reduce attack surface to bad input.
Quoted 13 lines
I was probably staring too hard at my own things, which is indeed a corner case. But reducing the attack surface is indeed a good motivation for this patch. I checked briefly with our DoS team today, the DoS scenario will definitely benefit from skipping GRO, for example on SYN/RST floods. XDP is our main weapon to drop attack traffic today, but it does not always drop 100% of the floods, and time by time it does need to fall back to iptables due to the delay of XDP program assembly or the BPF limitation on analyzing the packet. I did an ad hoc measurement just now on a mostly idle server, with ~1.3Mpps SYN flood concentrated on one CPU and dropped them early in raw-PREROUTING. w/ GRO this would consume about 35-41% of the CPU time, while w/o GRO the time dropped to 9-12%. This seems a pretty significant breath room under heavy attacks.
A GRO opt-out might make sense.
A long time ago I sent a patch that configured GRO protocols using syscalls, selectively (un)registering handlers. The interface was not very nice, so I did not pursue it further. On the upside, the datapath did not introduce any extra code. The intent was to reduce attack surface of packet parsing code.
Quoted 6 lines
A few concerns with an XDP based opt-out. It is more work to enable:
requires compiling and load an XDP program. It adds cycles in the hot path. And I do not entirely understand when an XDP program will be able to detect that a packet should not enter the GRO engine, but cannot drop the packet (your netfilter example above).
Agree that XDP based approach is just offering for XDP users. But given the way GRO works on flows today, it feels really hard to provide an elegant and generic interface.
For DoS scenarios, let me expand it a bit. Packets themselves could be a good indicator that they should not go through GRO, like fragments, or with special flags like SYN/RST/PSH. Under an attack, we sometimes also need conntrack or SYN cookies to help determine if some packets are legit or not. We have a few kfuncs to lookup conntrack entries in XDP today, but I am not sure if we can confidently drop them without completely mirroring full conntrack functionality. Rather, using conntrack as extra heuristics to mark suspicious packets in XDP, like TCP packets out of windows, etc, and still leave verdict to iptables seems a safer thing to do. I did observe a few occurrences in the past where a substantial amount of SYN flood passed through XDP, with some clever tricks in faking flow headers. Those were eventually dealt by SYN cookies, but all of those go through GRO unnecessarily although they all carry a SYN flag. Would be definitely beneficial to save every cycle under attacks.
Quoted 10 lines
Quoted 3 lines
But I am not sure I understand "BPF as GRO engine" here, it seems to me that being able to disable GRO by XDP is already good enough. Any more motivations to do more complex work here?
FWIW, we looked into this a few years ago. Analogous to the BPF flow
dissector: if the BPF program is loaded, use that instead of the C code path. But we did not arrive at a practical implementation at the time. Things may have changed, but one issue is how to store and access the list (or table) of outstanding GRO skbs.
I see, thanks for the explanation.
Yan
Quoted 11 lines
Quoted 9 lines
best
YanQuoted 6 lines
Quoted 4 lines
best
Yan
RFC 2/9 xdp: add XDP_FLAGS_GRO_DISABLED flag
In reply to Yan ZhaiAllow XDP program to set XDP_FLAGS_GRO_DISABLED flag in xdp_buff and xdp_frame, and disable GRO when building an sk_buff if this flag is set.
--- include/net/xdp.h | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-)
include/net/xdp.h +37 -1
@@ -75,6 +75,7 @@ enum xdp_buff_flags {XDP_FLAGS_FRAGS_PF_MEMALLOC =BIT (1 ),/* xdp paged memory is under * pressure */ + XDP_FLAGS_GRO_DISABLED = BIT(2), /* GRO disabled */ }; struct xdp_buff {
@@ -113,12 +114,35 @@ static __always_inline void xdp_buff_set_frag_pfmemalloc(struct xdp_buff *xdp) xdp->flags |=XDP_FLAGS_FRAGS_PF_MEMALLOC ; } +static __always_inline void xdp_buff_disable_gro(struct xdp_buff *xdp) +{ + xdp->flags |=XDP_FLAGS_GRO_DISABLED ; +} + +static __always_inline bool xdp_buff_gro_disabled(struct xdp_buff *xdp) +{ +return !!(xdp->flags &XDP_FLAGS_GRO_DISABLED ); +} + +static __always_inline void +xdp_buff_fixup_skb_offloading (struct xdp_buff *xdp,struct sk_buff *skb) +{ +if (xdp_buff_gro_disabled (xdp)) +skb_disable_gro (skb); +} + +static __always_inline void +xdp_init_buff_minimal (struct xdp_buff *xdp) +{ + xdp->flags =0 ; +} + static __always_inline voidxdp_init_buff (struct xdp_buff *xdp,u32 frame_sz,struct xdp_rxq_info *rxq) { xdp->frame_sz = frame_sz; xdp->rxq = rxq; - xdp->flags =0 ; +xdp_init_buff_minimal (xdp); }static __always_inline void
@@ -187,6 +211,18 @@ static __always_inline bool xdp_frame_is_frag_pfmemalloc(struct xdp_frame *framereturn !!(frame->flags &XDP_FLAGS_FRAGS_PF_MEMALLOC ); } +static __always_inline bool xdp_frame_gro_disabled(struct xdp_frame *frame) +{ +return !!(frame->flags &XDP_FLAGS_GRO_DISABLED ); +} + +static __always_inline void +xdp_frame_fixup_skb_offloading (struct xdp_frame *frame,struct sk_buff *skb) +{ +if (xdp_frame_gro_disabled (frame)) +skb_disable_gro (skb); +} +#define XDP_BULK_QUEUE_SIZE 16struct xdp_frame_bulk {int count;
Signature · 1 line
2.30.2
Re: [RFC net-next 2/9] xdp: add XDP_FLAGS_GRO_DISABLED flag
From: Yan Zhai <[email protected]>
Date: Thu, 20 Jun 2024 15:19:13 -0700
Quoted 13 lines
Allow XDP program to set
XDP_FLAGS_GRO_DISABLEDflag inxdp_buffandxdp_frame, and disable GRO when building ansk_buffif this flag is set.Signed-off-by Yan Zhai <[email protected]>--- include/net/xdp.h | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-)include/net/xdp.h +0
-0
include/net/xdp.h enum xdp_buff_flags { · line 78
Quoted 4 lines
include/net/xdp.h +1
-0@@ -75,6 +75,7 @@ enum xdp_buff_flags {XDP_FLAGS_FRAGS_PF_MEMALLOC =BIT (1 ),/* xdp paged memory is under * pressure */ + XDP_FLAGS_GRO_DISABLED = BIT(2), /* GRO disabled */
There should be tabs, not spaces.
Quoted 13 lines
include/net/xdp.h +6
-0};struct xdp_buff {@@ -113,12 +114,35 @@ static __always_inline void xdp_buff_set_frag_pfmemalloc(struct xdp_buff *xdp) xdp->flags |=XDP_FLAGS_FRAGS_PF_MEMALLOC ; } +static __always_inline void xdp_buff_disable_gro(struct xdp_buff *xdp) +{ + xdp->flags |=XDP_FLAGS_GRO_DISABLED ; +} + +static __always_inline bool xdp_buff_gro_disabled(struct xdp_buff *xdp)
include/net/xdp.h static __always_inline void xdp_buff_set_frag_pfmemalloc(struct xdp_buff *xdp) · line 132
Quoted 10 lines
include/net/xdp.h +10
-0+{ +return !!(xdp->flags &XDP_FLAGS_GRO_DISABLED ); +} + +static __always_inline void +xdp_buff_fixup_skb_offloading (struct xdp_buff *xdp,struct sk_buff *skb) +{ +if (xdp_buff_gro_disabled (xdp)) +skb_disable_gro (skb); +}
I don't think this should be named "fixup". "propagate", "update", "promote", ...?
Maybe if is not needed here?
skb->gro_disabled = xdp_buff_gro_disabled(xdp)
?
include/net/xdp.h static __always_inline void xdp_buff_set_frag_pfmemalloc(struct xdp_buff *xdp) · line 138
Quoted 6 lines
include/net/xdp.h +6
-0+ +static __always_inline void +xdp_init_buff_minimal (struct xdp_buff *xdp) +{ + xdp->flags =0 ; +}
"xdp_buff_clear_flags"?
Quoted 16 lines
include/net/xdp.h +3
-1+ static __always_inline voidxdp_init_buff (struct xdp_buff *xdp,u32 frame_sz,struct xdp_rxq_info *rxq) { xdp->frame_sz = frame_sz; xdp->rxq = rxq; - xdp->flags =0 ; +xdp_init_buff_minimal (xdp); }static __always_inline void@@ -187,6 +211,18 @@ static __always_inline bool xdp_frame_is_frag_pfmemalloc(struct xdp_frame *framereturn !!(frame->flags &XDP_FLAGS_FRAGS_PF_MEMALLOC ); } +static __always_inline bool xdp_frame_gro_disabled(struct xdp_frame *frame)
include/net/xdp.h static __always_inline bool xdp_frame_is_frag_pfmemalloc(struct xdp_frame *frame · line 224
Quoted 10 lines
include/net/xdp.h +10
-0+{ +return !!(frame->flags &XDP_FLAGS_GRO_DISABLED ); +} + +static __always_inline void +xdp_frame_fixup_skb_offloading (struct xdp_frame *frame,struct sk_buff *skb) +{ +if (xdp_frame_gro_disabled (frame)) +skb_disable_gro (skb); +}
(same)
include/net/xdp.h static __always_inline bool xdp_frame_is_frag_pfmemalloc(struct xdp_frame *frame · line 228
Quoted 4 lines
include/net/xdp.h +1
-0+#define XDP_BULK_QUEUE_SIZE 16struct xdp_frame_bulk {int count;
Thanks,
Olek
Re: [RFC net-next 2/9] xdp: add XDP_FLAGS_GRO_DISABLED flag
Quoted 51 lines · Alexander Lobakin
From: Yan Zhai <[email protected]>
Date: Thu, 20 Jun 2024 15:19:13 -0700Quoted 13 lines
Allow XDP program to set
XDP_FLAGS_GRO_DISABLEDflag inxdp_buffandxdp_frame, and disable GRO when building ansk_buffif this flag is set.Signed-off-by Yan Zhai <[email protected]>--- include/net/xdp.h | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-)include/net/xdp.h +0
-0include/net/xdp.h enum xdp_buff_flags { · line 78
Quoted 4 lines
include/net/xdp.h +1
-0@@ -75,6 +75,7 @@ enum xdp_buff_flags {XDP_FLAGS_FRAGS_PF_MEMALLOC =BIT (1 ),/* xdp paged memory is under * pressure */ + XDP_FLAGS_GRO_DISABLED = BIT(2), /* GRO disabled */There should be tabs, not spaces.
Quoted 13 lines
include/net/xdp.h +6
-0};struct xdp_buff {@@ -113,12 +114,35 @@ static __always_inline void xdp_buff_set_frag_pfmemalloc(struct xdp_buff *xdp) xdp->flags |=XDP_FLAGS_FRAGS_PF_MEMALLOC ; } +static __always_inline void xdp_buff_disable_gro(struct xdp_buff *xdp) +{ + xdp->flags |=XDP_FLAGS_GRO_DISABLED ; +} + +static __always_inline bool xdp_buff_gro_disabled(struct xdp_buff *xdp)include/net/xdp.h static __always_inline void xdp_buff_set_frag_pfmemalloc(struct xdp_buff *xdp) · line 132
Quoted 10 lines
include/net/xdp.h +10
-0+{ +return !!(xdp->flags &XDP_FLAGS_GRO_DISABLED ); +} + +static __always_inline void +xdp_buff_fixup_skb_offloading (struct xdp_buff *xdp,struct sk_buff *skb) +{ +if (xdp_buff_gro_disabled (xdp)) +skb_disable_gro (skb); +}I don't think this should be named "fixup". "propagate", "update", "promote", ...?
Quoted 6 lines
Maybe
ifis not needed here?skb->gro_disabled = xdp_buff_gro_disabled(xdp)?
I called it fixup mainly considering current skb fields could be set incorrectly (or maybe not?) For example when XDP load balances traffic, it could encap and send from server A to server B, but that means HW on B may have no good way to calculate the actual flow hash/csum. The original values could be read from A and sent within the encapsulation header, so that B can use this value to "fixup" the things.
But tbh, I am never good at naming, it's too hard for a non-native speaker sometimes... So I am very open on what to use if majority of the participants like it :D
The if is still needed since I added a control config to wrap that bit.
best
Yan
Quoted 45 lines
include/net/xdp.h static __always_inline void xdp_buff_set_frag_pfmemalloc(struct xdp_buff *xdp) · line 138
Quoted 6 lines
include/net/xdp.h +6
-0+ +static __always_inline void +xdp_init_buff_minimal (struct xdp_buff *xdp) +{ + xdp->flags =0 ; +}"
xdp_buff_clear_flags"?Quoted 16 lines
include/net/xdp.h +3
-1+ static __always_inline voidxdp_init_buff (struct xdp_buff *xdp,u32 frame_sz,struct xdp_rxq_info *rxq) { xdp->frame_sz = frame_sz; xdp->rxq = rxq; - xdp->flags =0 ; +xdp_init_buff_minimal (xdp); }static __always_inline void@@ -187,6 +211,18 @@ static __always_inline bool xdp_frame_is_frag_pfmemalloc(struct xdp_frame *framereturn !!(frame->flags &XDP_FLAGS_FRAGS_PF_MEMALLOC ); } +static __always_inline bool xdp_frame_gro_disabled(struct xdp_frame *frame)include/net/xdp.h static __always_inline bool xdp_frame_is_frag_pfmemalloc(struct xdp_frame *frame · line 224
Quoted 10 lines
include/net/xdp.h +10
-0+{ +return !!(frame->flags &XDP_FLAGS_GRO_DISABLED ); +} + +static __always_inline void +xdp_frame_fixup_skb_offloading (struct xdp_frame *frame,struct sk_buff *skb) +{ +if (xdp_frame_gro_disabled (frame)) +skb_disable_gro (skb); +}(same)
include/net/xdp.h static __always_inline bool xdp_frame_is_frag_pfmemalloc(struct xdp_frame *frame · line 228
Quoted 4 lines
include/net/xdp.h +1
-0+#define XDP_BULK_QUEUE_SIZE 16struct xdp_frame_bulk {int count;Thanks,
Olek
RFC 3/9 xdp: implement bpf_xdp_disable_gro kfunc
In reply to Yan ZhaiAdd a kfunc bpf_xdp_disable_gro to toggle XDP_FLAGS_GRO_DISABLED flag.
--- net/core/xdp.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-)
net/core/xdp.c +26 -1
@@ -770,6 +770,20 @@ __bpf_kfunc int bpf_xdp_metadata_rx_vlan_tag(const struct xdp_md *ctx,return -EOPNOTSUPP ; } +/** +* bpf_xdp_disable_gro - Set a flag on underlying XDP buffer, indicating +* the stack to skip this packet for GRO processing. This flag which be +* passed on when the driver builds the skb. +* +* Return: +* * always returns 0 +*/ +__bpf_kfunc int bpf_xdp_disable_gro(struct xdp_md *ctx) +{ +xdp_buff_disable_gro ((struct xdp_buff *)ctx); +return 0 ; +} +__bpf_kfunc_end_defs ();BTF_KFUNCS_START (xdp_metadata_kfunc_ids)
@@ -799,9 +813,20 @@ bool bpf_dev_bound_kfunc_id(u32 btf_id)return btf_id_set8_contains (&xdp_metadata_kfunc_ids, btf_id); } +BTF_KFUNCS_START (xdp_common_kfunc_ids) +BTF_ID_FLAGS (func ,bpf_xdp_disable_gro ,KF_TRUSTED_ARGS ) +BTF_KFUNCS_END (xdp_common_kfunc_ids) + +static const struct btf_kfunc_id_set xdp_common_kfunc_set = { + .owner =THIS_MODULE , + .set = &xdp_common_kfunc_ids, +}; +static int __init xdp_metadata_init (void ) { -return register_btf_kfunc_id_set (BPF_PROG_TYPE_XDP , &xdp_metadata_kfunc_set); +int ret =register_btf_kfunc_id_set (BPF_PROG_TYPE_XDP , &xdp_metadata_kfunc_set); + +return ret ?:register_btf_kfunc_id_set (BPF_PROG_TYPE_XDP , &xdp_common_kfunc_set); }late_initcall (xdp_metadata_init);
Signature · 1 line
2.30.2
kernel test robot
build botRe: [RFC net-next 3/9] xdp: implement bpf_xdp_disable_gro kfunc
kernel test robot noticed the following build warnings:
Hi Yan,
[This is a private test report for your RFC patch.] kernel test robot noticed the following build warnings:
[auto build test WARNING on net-next/main]
url: https://github.com/intel-lab-lkp/linux/commits/Yan-Zhai/skb-introduce-gro_disabled-bit/20240626-052232 base: net-next/main patch link: https://lore.kernel.org/r/e31ce8f27a672e3c0def5a586a9a10f1d71e9948.1718919473.git.yan%40cloudflare.com patch subject: [RFC net-next 3/9] xdp: implement bpf_xdp_disable_gro kfunc config: i386-buildonly-randconfig-001-20240627 (https://download.01.org/0day-ci/archive/20240627/[email protected]/config) compiler: clang version 18.1.5 (https://github.com/llvm/llvm-project 617a15a9eac96088ae5e9134248d8236e34b91b1) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240627/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All warnings (new ones prefixed by >>):
>> net/core/xdp.c:782: warning: Function parameter or struct member 'ctx' not described in 'bpf_xdp_disable_gro'
vim +782 net/core/xdp.c
772
773 /**
774 * bpf_xdp_disable_gro - Set a flag on underlying XDP buffer, indicating
775 * the stack to skip this packet for GRO processing. This flag which be
776 * passed on when the driver builds the skb.
777 *
778 * Return:
779 * * always returns 0
780 */
781 __bpf_kfunc int bpf_xdp_disable_gro(struct xdp_md *ctx)
> 782 { 783 xdp_buff_disable_gro((struct xdp_buff *)ctx);
784 return 0;
785 }
786
Signature · 2 lines
0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
RFC 4/9 bnxt: apply XDP offloading fixup when building skb
In reply to Yan ZhaiAdd a common point to transfer offloading info from XDP context to skb.
--- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +4 -0
@@ -2252,6 +2252,10 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, } } } + +if (xdp_active) +xdp_buff_fixup_skb_offloading (&xdp, skb); +bnxt_deliver_skb (bp, bnapi, skb); rc =1 ;
Signature · 1 line
2.30.2
RFC 5/9 ice: apply XDP offloading fixup when building skb
In reply to Yan ZhaiAdd a common point to transfer offloading info from XDP context to skb.
--- drivers/net/ethernet/intel/ice/ice_txrx.c | 2 ++ drivers/net/ethernet/intel/ice/ice_xsk.c | 6 +++++- include/net/xdp_sock_drv.h | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-)
drivers/net/ethernet/intel/ice/ice_txrx.c +2 -0
@@ -1222,6 +1222,7 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) hard_start =page_address (rx_buf->page) + rx_buf->page_offset - offset; +xdp_init_buff_minimal (xdp);xdp_prepare_buff (xdp, hard_start, offset, size, !!offset);#if (PAGE_SIZE >4096 )/* At larger PAGE_SIZE, frame_sz depend on len size */
@@ -1287,6 +1288,7 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)/* populate checksum, VLAN, and protocol */ ice_process_skb_fields (rx_ring, rx_desc, skb); +xdp_buff_fixup_skb_offloading (xdp, skb);ice_trace (clean_rx_irq_indicate, rx_ring, rx_desc, skb);/* send completed skb up the stack */
drivers/net/ethernet/intel/ice/ice_xsk.c +5 -1
@@ -845,8 +845,10 @@ int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget) xdp_prog =READ_ONCE (rx_ring->xdp_prog); xdp_ring = rx_ring->xdp_ring; -if (ntc != rx_ring->first_desc) +if (ntc != rx_ring->first_desc) { first = *ice_xdp_buf (rx_ring, rx_ring->first_desc); +xdp_init_buff_minimal (first); + }while (likely (total_rx_packets < (unsigned int )budget)) {union ice_32b_rx_flex_desc *rx_desc;
@@ -920,6 +922,7 @@ int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget)break ; } + xdp = first; first =NULL ; rx_ring->first_desc = ntc;
@@ -934,6 +937,7 @@ int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget) vlan_tci =ice_get_vlan_tci (rx_desc);ice_process_skb_fields (rx_ring, rx_desc, skb); +xdp_buff_fixup_skb_offloading (xdp, skb);ice_receive_skb (rx_ring, skb, vlan_tci); }
include/net/xdp_sock_drv.h +1 -1
@@ -181,7 +181,7 @@ static inline void xsk_buff_set_size(struct xdp_buff *xdp, u32 size) xdp->data = xdp->data_hard_start +XDP_PACKET_HEADROOM ; xdp->data_meta = xdp->data; xdp->data_end = xdp->data + size; - xdp->flags =0 ; +xdp_init_buff_minimal (xdp); } static inline dma_addr_t xsk_buff_raw_get_dma(struct xsk_buff_pool *pool,
Signature · 1 line
2.30.2
Re: [RFC net-next 5/9] ice: apply XDP offloading fixup when building skb
From: Yan Zhai <[email protected]>
Date: Thu, 20 Jun 2024 15:19:22 -0700
Quoted 15 lines
Add a common point to transfer offloading info from XDP context to skb.
Signed-off-by Yan Zhai <[email protected]>Signed-off-by Jesper Dangaard Brouer <[email protected]>--- drivers/net/ethernet/intel/ice/ice_txrx.c | 2 ++ drivers/net/ethernet/intel/ice/ice_xsk.c | 6 +++++- include/net/xdp_sock_drv.h | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-)drivers/net/ethernet/intel/ice/ice_txrx.c +0
-0
drivers/net/ethernet/intel/ice/ice_txrx.c int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) · line 1225
Quoted 4 lines
drivers/net/ethernet/intel/ice/ice_txrx.c +1
-0@@ -1222,6 +1222,7 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) hard_start =page_address (rx_buf->page) + rx_buf->page_offset - offset; +xdp_init_buff_minimal (xdp);
Two lines below, you have this:
xdp_buff_clear_frags_flag(xdp);
Which clears frags bit in xdp->flags. I.e. since you always clear flags here, this call becomes redundant.
But I'd say that xdp->flags = 0 really wants to be moved from xdp_init_buff() to xdp_prepare_buff().
Quoted 16 lines
drivers/net/ethernet/intel/ice/ice_txrx.c +1
-0xdp_prepare_buff (xdp, hard_start, offset, size, !!offset);#if (PAGE_SIZE >4096 )/* At larger PAGE_SIZE, frame_sz depend on len size */ @@ -1287,6 +1288,7 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)/* populate checksum, VLAN, and protocol */ ice_process_skb_fields (rx_ring, rx_desc, skb); +xdp_buff_fixup_skb_offloading (xdp, skb);ice_trace (clean_rx_irq_indicate, rx_ring, rx_desc, skb);/* send completed skb up the stack */ drivers/net/ethernet/intel/ice/ice_xsk.c +0
-0
drivers/net/ethernet/intel/ice/ice_xsk.c int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget) · line 850
Quoted 7 lines
drivers/net/ethernet/intel/ice/ice_xsk.c +2
-1@@ -845,8 +845,10 @@ int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget) xdp_prog =READ_ONCE (rx_ring->xdp_prog); xdp_ring = rx_ring->xdp_ring; -if (ntc != rx_ring->first_desc) +if (ntc != rx_ring->first_desc) { first = *ice_xdp_buf (rx_ring, rx_ring->first_desc); +xdp_init_buff_minimal (first);
xdp_buff_set_size() always clears flags, this is redundant.
Quoted 25 lines
drivers/net/ethernet/intel/ice/ice_xsk.c +3
-0+ }while (likely (total_rx_packets < (unsigned int )budget)) {union ice_32b_rx_flex_desc *rx_desc;@@ -920,6 +922,7 @@ int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget)break ; } + xdp = first; first =NULL ; rx_ring->first_desc = ntc;@@ -934,6 +937,7 @@ int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget) vlan_tci =ice_get_vlan_tci (rx_desc);ice_process_skb_fields (rx_ring, rx_desc, skb); +xdp_buff_fixup_skb_offloading (xdp, skb);ice_receive_skb (rx_ring, skb, vlan_tci); }include/net/xdp_sock_drv.h +0
-0
include/net/xdp_sock_drv.h static inline void xsk_buff_set_size(struct xdp_buff *xdp, u32 size) · line 184
Quoted 5 lines
include/net/xdp_sock_drv.h +1
-1@@ -181,7 +181,7 @@ static inline void xsk_buff_set_size(struct xdp_buff *xdp, u32 size) xdp->data = xdp->data_hard_start +XDP_PACKET_HEADROOM ; xdp->data_meta = xdp->data; xdp->data_end = xdp->data + size; - xdp->flags =0 ; +xdp_init_buff_minimal (xdp);
Why is this done in the patch prefixed with "ice:"?
include/net/xdp_sock_drv.h static inline void xsk_buff_set_size(struct xdp_buff *xdp, u32 size) · line 187
Quoted 3 lines
include/net/xdp_sock_drv.h +0
-0} static inline dma_addr_t xsk_buff_raw_get_dma(struct xsk_buff_pool *pool,
Thanks,
Olek
Re: [RFC net-next 5/9] ice: apply XDP offloading fixup when building skb
Quoted 26 lines · Alexander Lobakin
From: Yan Zhai <[email protected]>
Date: Thu, 20 Jun 2024 15:19:22 -0700Quoted 15 lines
Add a common point to transfer offloading info from XDP context to skb.
Signed-off-by Yan Zhai <[email protected]>Signed-off-by Jesper Dangaard Brouer <[email protected]>--- drivers/net/ethernet/intel/ice/ice_txrx.c | 2 ++ drivers/net/ethernet/intel/ice/ice_xsk.c | 6 +++++- include/net/xdp_sock_drv.h | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-)drivers/net/ethernet/intel/ice/ice_txrx.c +0
-0drivers/net/ethernet/intel/ice/ice_txrx.c int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) · line 1225
Quoted 4 lines
drivers/net/ethernet/intel/ice/ice_txrx.c +1
-0@@ -1222,6 +1222,7 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) hard_start =page_address (rx_buf->page) + rx_buf->page_offset - offset; +xdp_init_buff_minimal (xdp);Two lines below, you have this:
Quoted 7 lines
xdp_buff_clear_frags_flag(xdp);Which clears frags bit in
xdp->flags. I.e. since you always clear flags here, this call becomes redundant.
But I'd say thatxdp->flags = 0really wants to be moved fromxdp_init_buff()toxdp_prepare_buff().
You are right, there is some redundancy here. I will fix it if people feel good about the use case in general :)
Quoted 46 lines
Quoted 16 lines
drivers/net/ethernet/intel/ice/ice_txrx.c +1
-0xdp_prepare_buff (xdp, hard_start, offset, size, !!offset);#if (PAGE_SIZE >4096 )/* At larger PAGE_SIZE, frame_sz depend on len size */ @@ -1287,6 +1288,7 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)/* populate checksum, VLAN, and protocol */ ice_process_skb_fields (rx_ring, rx_desc, skb); +xdp_buff_fixup_skb_offloading (xdp, skb);ice_trace (clean_rx_irq_indicate, rx_ring, rx_desc, skb);/* send completed skb up the stack */ drivers/net/ethernet/intel/ice/ice_xsk.c +0
-0drivers/net/ethernet/intel/ice/ice_xsk.c int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget) · line 850
Quoted 7 lines
drivers/net/ethernet/intel/ice/ice_xsk.c +2
-1@@ -845,8 +845,10 @@ int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget) xdp_prog =READ_ONCE (rx_ring->xdp_prog); xdp_ring = rx_ring->xdp_ring; -if (ntc != rx_ring->first_desc) +if (ntc != rx_ring->first_desc) { first = *ice_xdp_buf (rx_ring, rx_ring->first_desc); +xdp_init_buff_minimal (first);
xdp_buff_set_size()always clears flags, this is redundant.Quoted 20 lines
drivers/net/ethernet/intel/ice/ice_xsk.c +3
-0+ }while (likely (total_rx_packets < (unsigned int )budget)) {union ice_32b_rx_flex_desc *rx_desc;@@ -920,6 +922,7 @@ int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget)break ; } + xdp = first; first =NULL ; rx_ring->first_desc = ntc;@@ -934,6 +937,7 @@ int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget) vlan_tci =ice_get_vlan_tci (rx_desc);ice_process_skb_fields (rx_ring, rx_desc, skb); +xdp_buff_fixup_skb_offloading (xdp, skb);ice_receive_skb (rx_ring, skb, vlan_tci); }
Quoted 13 lines
include/net/xdp_sock_drv.h static inline void xsk_buff_set_size(struct xdp_buff *xdp, u32 size) · line 184
Quoted 10 lines
include/net/xdp_sock_drv.h +1
-1@@ -181,7 +181,7 @@ static inline void xsk_buff_set_size(struct xdp_buff *xdp, u32 size) xdp->data = xdp->data_hard_start +XDP_PACKET_HEADROOM ; xdp->data_meta = xdp->data; xdp->data_end = xdp->data + size; - xdp->flags =0 ; +xdp_init_buff_minimal (xdp);Why is this done in the patch prefixed with "ice:"?
Good catch, this should be moved to the previous patch.
thanks
Yan
Quoted 6 lines
include/net/xdp_sock_drv.h static inline void xsk_buff_set_size(struct xdp_buff *xdp, u32 size) · line 187
Quoted 3 lines
include/net/xdp_sock_drv.h +0
-0} static inline dma_addr_t xsk_buff_raw_get_dma(struct xsk_buff_pool *pool,Thanks,
Olek
RFC 6/9 veth: apply XDP offloading fixup when building skb
In reply to Yan ZhaiAdd a common point to transfer offloading info from XDP context to skb.
--- drivers/net/veth.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/veth.c +4 -0
@@ -703,6 +703,8 @@ static void veth_xdp_rcv_bulk_skb(struct veth_rq *rq, void **frames, stats->rx_drops++;continue ; } + +xdp_frame_fixup_skb_offloading (frames[i], skb);napi_gro_receive (&rq->xdp_napi, skb); } }
@@ -855,6 +857,8 @@ static struct sk_buff *veth_xdp_rcv_skb(struct veth_rq *rq, metalen = xdp->data - xdp->data_meta;if (metalen)skb_metadata_set (skb, metalen); + +xdp_buff_fixup_skb_offloading (xdp, skb); out:return skb; drop:
Signature · 1 line
2.30.2
RFC 7/9 mlx5: move xdp_buff scope one level up
In reply to Yan ZhaiThis is in preparation for changes.
--- drivers/net/ethernet/mellanox/mlx5/core/en.h | 6 +- .../ethernet/mellanox/mlx5/core/en/xsk/rx.c | 6 +- .../ethernet/mellanox/mlx5/core/en/xsk/rx.h | 6 +- .../net/ethernet/mellanox/mlx5/core/en_rx.c | 103 +++++++++--------- 4 files changed, 66 insertions(+), 55 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en.h +4 -2
@@ -580,14 +580,16 @@ struct mlx5e_mpw_info {#define MLX5E_MAX_RX_FRAGS 4struct mlx5e_rq ; +struct mlx5e_xdp_buff ;typedef void (*mlx5e_fp_handle_rx_cqe )(struct mlx5e_rq *,struct mlx5_cqe64 *);typedef struct sk_buff * (*mlx5e_fp_skb_from_cqe_mpwrq )(struct mlx5e_rq *rq,struct mlx5e_mpw_info *wi,struct mlx5_cqe64 *cqe,u16 cqe_bcnt, -u32 head_offset,u32 page_idx); +u32 head_offset,u32 page_idx, +struct mlx5e_xdp_buff *mxbuf);typedef struct sk_buff * (*mlx5e_fp_skb_from_cqe )(struct mlx5e_rq *rq,struct mlx5e_wqe_frag_info *wi, -struct mlx5_cqe64 *cqe,u32 cqe_bcnt); +struct mlx5_cqe64 *cqe,u32 cqe_bcnt,struct mlx5e_xdp_buff *mxbuf);typedef bool (*mlx5e_fp_post_rx_wqes )(struct mlx5e_rq *rq);typedef void (*mlx5e_fp_dealloc_wqe )(struct mlx5e_rq *,u16 );typedef void (*mlx5e_fp_shampo_dealloc_hd )(struct mlx5e_rq *,u16 ,u16 ,bool );
drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.c +4 -2
@@ -249,7 +249,8 @@ struct sk_buff *mlx5e_xsk_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq,struct mlx5_cqe64 *cqe, u16 cqe_bcnt, u32 head_offset, - u32 page_idx) + u32 page_idx, + struct mlx5e_xdp_buff *mxbuf_) { struct mlx5e_xdp_buff *mxbuf = xsk_buff_to_mxbuf(wi->alloc_units.xsk_buffs[page_idx]);struct bpf_prog *prog;
@@ -304,7 +305,8 @@ struct sk_buff *mlx5e_xsk_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq,struct sk_buff *mlx5e_xsk_skb_from_cqe_linear (struct mlx5e_rq *rq,struct mlx5e_wqe_frag_info *wi,struct mlx5_cqe64 *cqe, -u32 cqe_bcnt) +u32 cqe_bcnt, +struct mlx5e_xdp_buff *mxbuf_) {struct mlx5e_xdp_buff *mxbuf =xsk_buff_to_mxbuf (*wi->xskp);struct bpf_prog *prog;
drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.h +4 -2
@@ -16,10 +16,12 @@ struct sk_buff *mlx5e_xsk_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq,struct mlx5_cqe64 *cqe, u16 cqe_bcnt, u32 head_offset, - u32 page_idx); + u32 page_idx, + struct mlx5e_xdp_buff *mxbuf_);struct sk_buff *mlx5e_xsk_skb_from_cqe_linear (struct mlx5e_rq *rq,struct mlx5e_wqe_frag_info *wi,struct mlx5_cqe64 *cqe, -u32 cqe_bcnt); +u32 cqe_bcnt, +struct mlx5e_xdp_buff *mxbuf_);#endif /* __MLX5_EN_XSK_RX_H__ */
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +54 -49
342 lines not on this page · raw message
Signature · 1 line
2.30.2
RFC 8/9 mlx5: apply XDP offloading fixup when building skb
In reply to Yan ZhaiAdd a common point to transfer offloading info from XDP context to skb.
--- .../net/ethernet/mellanox/mlx5/core/en/xsk/rx.c | 8 ++++++-- drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.c +6 -2
@@ -250,7 +250,7 @@ struct sk_buff *mlx5e_xsk_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq,u16 cqe_bcnt, u32 head_offset, u32 page_idx, - struct mlx5e_xdp_buff *mxbuf_) + struct mlx5e_xdp_buff *mxbuf_caller) { struct mlx5e_xdp_buff *mxbuf = xsk_buff_to_mxbuf(wi->alloc_units.xsk_buffs[page_idx]);struct bpf_prog *prog;
@@ -270,6 +270,7 @@ struct sk_buff *mlx5e_xsk_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq,/* mxbuf->rq is set on allocation, but cqe is per-packet so set it here */ mxbuf->cqe = cqe; +xdp_init_buff_minimal (&mxbuf->xdp);xsk_buff_set_size (&mxbuf->xdp, cqe_bcnt);xsk_buff_dma_sync_for_cpu (&mxbuf->xdp);net_prefetch (mxbuf->xdp.data);
@@ -295,6 +296,7 @@ struct sk_buff *mlx5e_xsk_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq,__set_bit (page_idx, wi->skip_release_bitmap);/* non-atomic */ return NULL ;/* page/packet was consumed by XDP */ } + mxbuf_caller->xdp.flags = mxbuf->xdp.flags;/* XDP_PASS: copy the data from the UMEM to a new SKB and reuse the * frame. On SKB allocation failure, NULL is returned.
@@ -306,7 +308,7 @@ struct sk_buff *mlx5e_xsk_skb_from_cqe_linear(struct mlx5e_rq *rq,struct mlx5e_wqe_frag_info *wi, struct mlx5_cqe64 *cqe, u32 cqe_bcnt, - struct mlx5e_xdp_buff *mxbuf_) + struct mlx5e_xdp_buff *mxbuf_caller) { struct mlx5e_xdp_buff *mxbuf = xsk_buff_to_mxbuf(*wi->xskp);struct bpf_prog *prog;
@@ -320,6 +322,7 @@ struct sk_buff *mlx5e_xsk_skb_from_cqe_linear(struct mlx5e_rq *rq,/* mxbuf->rq is set on allocation, but cqe is per-packet so set it here */ mxbuf->cqe = cqe; +xdp_init_buff_minimal (&mxbuf->xdp);xsk_buff_set_size (&mxbuf->xdp, cqe_bcnt);xsk_buff_dma_sync_for_cpu (&mxbuf->xdp);net_prefetch (mxbuf->xdp.data);
@@ -330,6 +333,7 @@ struct sk_buff *mlx5e_xsk_skb_from_cqe_linear(struct mlx5e_rq *rq, wi->flags |=BIT (MLX5E_WQE_FRAG_SKIP_RELEASE );return NULL ;/* page/packet was consumed by XDP */ } + mxbuf_caller->xdp.flags = mxbuf->xdp.flags;/* XDP_PASS: copy the data from the UMEM to a new SKB. The frame reuse * will be handled by mlx5e_free_rx_wqe.
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +14 -0
@@ -1670,6 +1670,8 @@ mlx5e_skb_from_cqe_linear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi,dma_addr_t addr;u32 frag_size; +xdp_init_buff_minimal (&mxbuf->xdp); + va =page_address (frag_page->page) + wi->offset; data = va + rx_headroom; frag_size =MLX5_SKB_FRAG_SZ (rx_headroom + cqe_bcnt);
@@ -1721,6 +1723,7 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wivoid *va; frag_page = wi->frag_page; +xdp_init_buff_minimal (&mxbuf->xdp); va =page_address (frag_page->page) + wi->offset; frag_consumed_bytes =min_t (u32, frag_info->frag_size, cqe_bcnt);
@@ -1837,6 +1840,7 @@ static void mlx5e_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe) }mlx5e_complete_rx_cqe (rq, cqe, cqe_bcnt, skb); +xdp_buff_fixup_skb_offloading (&mxbuf.xdp, skb);if (mlx5e_cqe_regb_chain (cqe))if (!mlx5e_tc_update_skb_nic (cqe, skb)) {
@@ -1885,6 +1889,7 @@ static void mlx5e_handle_rx_cqe_rep(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe) }mlx5e_complete_rx_cqe (rq, cqe, cqe_bcnt, skb); +xdp_buff_fixup_skb_offloading (&mxbuf.xdp, skb);if (rep->vlan &&skb_vlan_tag_present (skb))skb_vlan_pop (skb);
@@ -1935,6 +1940,7 @@ static void mlx5e_handle_rx_cqe_mpwrq_rep(struct mlx5e_rq *rq, struct mlx5_cqe64 goto mpwrq_cqe_out;mlx5e_complete_rx_cqe (rq, cqe, cqe_bcnt, skb); +xdp_buff_fixup_skb_offloading (&mxbuf.xdp, skb);mlx5e_rep_tc_receive (cqe, rq, skb);
@@ -2138,6 +2144,8 @@ mlx5e_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,return NULL ; } +xdp_init_buff_minimal (&mxbuf->xdp); + va =page_address (frag_page->page) + head_offset; data = va + rx_headroom; frag_size =MLX5_SKB_FRAG_SZ (rx_headroom + cqe_bcnt);
@@ -2345,6 +2353,8 @@ static void mlx5e_handle_rx_cqe_mpwrq_shampo(struct mlx5e_rq *rq, struct mlx5_cq }mlx5e_shampo_complete_rx_cqe (rq, cqe, cqe_bcnt, *skb); +xdp_buff_fixup_skb_offloading (&mxbuf.xdp, *skb); +if (flush && rq->hw_gro_data->skb)mlx5e_shampo_flush_skb (rq, cqe, match); free_hd_entry:
@@ -2404,6 +2414,7 @@ static void mlx5e_handle_rx_cqe_mpwrq(struct mlx5e_rq *rq, struct mlx5_cqe64 *cq goto mpwrq_cqe_out;mlx5e_complete_rx_cqe (rq, cqe, cqe_bcnt, skb); +xdp_buff_fixup_skb_offloading (&mxbuf.xdp, skb);if (mlx5e_cqe_regb_chain (cqe))if (!mlx5e_tc_update_skb_nic (cqe, skb)) {
@@ -2649,6 +2660,8 @@ static void mlx5i_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe) goto wq_cyc_pop;mlx5i_complete_rx_cqe (rq, cqe, cqe_bcnt, skb); +xdp_buff_fixup_skb_offloading (&mxbuf.xdp, skb); +if (unlikely (!skb->dev)) {dev_kfree_skb_any (skb); goto wq_cyc_pop;
@@ -2740,6 +2753,7 @@ static void mlx5e_trap_handle_rx_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqemlx5e_complete_rx_cqe (rq, cqe, cqe_bcnt, skb);skb_push (skb,ETH_HLEN ); +xdp_buff_fixup_skb_offloading (&mxbuf.xdp, skb);mlx5_devlink_trap_report (rq->mdev, trap_id, skb, rq->netdev->devlink_port);
Signature · 1 line
2.30.2
RFC 9/9 bpf: selftests: test disabling GRO by XDP
In reply to Yan ZhaiTest the case when XDP disables GRO for a packet, the effect is actually reflected on the receiving side.
--- tools/testing/selftests/bpf/config | 1 + .../selftests/bpf/prog_tests/xdp_offloading.c | 122 ++++++++++++++++++ .../selftests/bpf/progs/xdp_offloading.c | 50 +++++++ 3 files changed, 173 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/xdp_offloading.c create mode 100644 tools/testing/selftests/bpf/progs/xdp_offloading.c
tools/testing/selftests/bpf/config +1 -0
@@ -96,3 +96,4 @@ CONFIG_XDP_SOCKETS=y CONFIG_XFRM_INTERFACE=y CONFIG_TCP_CONG_DCTCP=y CONFIG_TCP_CONG_BBR=y +CONFIG_SKB_GRO_CONTROL=y
tools/testing/selftests/bpf/prog_tests/xdp_offloading.c new file +122 -0
122 lines not on this page · raw message
tools/testing/selftests/bpf/progs/xdp_offloading.c new file +50 -0
50 lines not on this page · raw message
Signature · 1 line
2.30.2