diff mbox series

[RFC,09/28] gso: AccECN support

Message ID 1584524612-24470-10-git-send-email-ilpo.jarvinen@helsinki.fi
State RFC
Delegated to: David Miller
Headers show
Series : Accurate ECN for TCP | expand

Commit Message

Ilpo Järvinen March 18, 2020, 9:43 a.m. UTC
From: Ilpo Järvinen <ilpo.jarvinen@cs.helsinki.fi>

Handling the CWR flag differs between RFC 3168 ECN and AccECN.
Take it into account in GSO by not clearing the CWR bit.

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@cs.helsinki.fi>
---
 drivers/net/tun.c               | 3 ++-
 include/linux/netdev_features.h | 3 +++
 include/linux/skbuff.h          | 2 ++
 net/ethtool/common.c            | 1 +
 net/ipv4/tcp_offload.c          | 6 +++++-
 5 files changed, 13 insertions(+), 2 deletions(-)

Comments

Eric Dumazet March 19, 2020, 3:44 a.m. UTC | #1
On 3/18/20 2:43 AM, Ilpo Järvinen wrote:
> From: Ilpo Järvinen <ilpo.jarvinen@cs.helsinki.fi>
> 
> Handling the CWR flag differs between RFC 3168 ECN and AccECN.
> Take it into account in GSO by not clearing the CWR bit.
> 
> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@cs.helsinki.fi>
>

Does it means TCP segmentation offload is disabled on all the NIC
around ?

Why tun driver is changed and not others ?

I believe you need to give much more details in changelog in general,
because many changes are not that obvious.
=?ISO-8859-15?Q?Ilpo_J=E4rvinen?= March 19, 2020, 10:36 p.m. UTC | #2
On Wed, 18 Mar 2020, Eric Dumazet wrote:
> On 3/18/20 2:43 AM, Ilpo Järvinen wrote:
> > From: Ilpo Järvinen <ilpo.jarvinen@cs.helsinki.fi>
> > 
> > Handling the CWR flag differs between RFC 3168 ECN and AccECN.
> > Take it into account in GSO by not clearing the CWR bit.
> > 
> > Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@cs.helsinki.fi>
> >
> 
> Does it means TCP segmentation offload is disabled on all the NIC
> around ?

On general level, yes. HW TSO should be disabled with AccECN (or when CWR 
flag is set for an incoming packet). The reason is how CWR flag is handled 
by RFC 3168 ECN-aware TSO. It splits the segment such that CWR is cleared 
starting from the 2nd segment which is incompatible how AccECN handles the 
CWR flag. With AccECN, CWR flag (or more accurately, the ACE field that 
also includes ECE & AE flags) changes only when new packet(s) with CE mark 
arrives so the flag should not be changed within a super-skb. The new
feature flag is necessary to prevent such TSO engines happily clearing 
CWRs (if the CWR handling feature cannot be turned off).

If NIC is completely unaware of RFC3168 ECN (doesn't support 
NETIF_F_TSO_ECN) or its TSO engine can be set to not touch CWR flag
despite supporting also NETIF_F_TSO_ECN, TSO could be safely used with 
AccECN on such NIC. I've little expertise on TSO HW so I don't know if 
some/what NICs can do it. Nonetheless, there's nothing fundamental 
preventing TSO being enabled with AccECN by NICs (if either of those 
conditions is met).

In the cases, where TSO would fail to keep its hands off CWR flag, it
should fallback to GSO which has always on AccECN support (similar to 
always on ECN support). I think that the current GSO changes are capable 
of handling AccECN skbs. For the other parts of the idea above I'm not 
so sure. There is this NETIF_F_GSO_SOFTWARE with comment that seems to 
indicate it's doing what I want but I'm not fully sure if adding a flag 
there is enough to achieve the desired effect?

On the rx side, supporting both RFC3168 and AccECN style CWR handling
is slightly more complicated (and possibly not worth the effort given
CWRs should be relatively rare with RFC3168-style ECN).

> Why tun driver is changed and not others ?

I think I didn't really understand why tun.c plays with the TSO_ECN flag 
until now (after finding a related comment from tap.c) and so that change 
now doesn't make much sense for me now any more. So I'll just remove that 
part.

> I believe you need to give much more details in changelog in general,
> because many changes are not that obvious.

I'll try to.

Thanks.
diff mbox series

Patch

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 228fe449dc6d..d376a7cb0d63 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -2788,7 +2788,8 @@  static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
 
 		dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST |
 				   TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
-				   NETIF_F_HW_VLAN_STAG_TX;
+				   NETIF_F_HW_VLAN_STAG_TX |
+				   NETIF_F_GSO_ACCECN;
 		dev->features = dev->hw_features | NETIF_F_LLTX;
 		dev->vlan_features = dev->features &
 				     ~(NETIF_F_HW_VLAN_CTAG_TX |
diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h
index 34d050bb1ae6..c7065b468d21 100644
--- a/include/linux/netdev_features.h
+++ b/include/linux/netdev_features.h
@@ -83,6 +83,7 @@  enum {
 	NETIF_F_HW_TLS_RECORD_BIT,	/* Offload TLS record */
 	NETIF_F_GRO_FRAGLIST_BIT,	/* Fraglist GRO */
 
+	NETIF_F_GSO_ACCECN_BIT,		/* ... TCP AccECN support */
 	/*
 	 * Add your fresh new feature above and remember to update
 	 * netdev_features_strings[] in net/core/ethtool.c and maybe
@@ -124,6 +125,7 @@  enum {
 #define NETIF_F_SG		__NETIF_F(SG)
 #define NETIF_F_TSO6		__NETIF_F(TSO6)
 #define NETIF_F_TSO_ECN		__NETIF_F(TSO_ECN)
+#define NETIF_F_GSO_ACCECN	__NETIF_F(GSO_ACCECN)
 #define NETIF_F_TSO		__NETIF_F(TSO)
 #define NETIF_F_VLAN_CHALLENGED	__NETIF_F(VLAN_CHALLENGED)
 #define NETIF_F_RXFCS		__NETIF_F(RXFCS)
@@ -205,6 +207,7 @@  static inline int find_next_netdev_feature(u64 feature, unsigned long start)
 
 /* List of features with software fallbacks. */
 #define NETIF_F_GSO_SOFTWARE	(NETIF_F_ALL_TSO | \
+				 NETIF_F_GSO_ACCECN | \
 				 NETIF_F_GSO_SCTP)
 
 /*
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 21749b2cdc9b..fdd73dc126a2 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -594,6 +594,8 @@  enum {
 	SKB_GSO_UDP_L4 = 1 << 17,
 
 	SKB_GSO_FRAGLIST = 1 << 18,
+
+	SKB_GSO_TCP_ACCECN = 1 << 19,
 };
 
 #if BITS_PER_LONG > 32
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index 7b6969af5ae7..26241b5d62a4 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -27,6 +27,7 @@  const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
 	[NETIF_F_TSO_BIT] =              "tx-tcp-segmentation",
 	[NETIF_F_GSO_ROBUST_BIT] =       "tx-gso-robust",
 	[NETIF_F_TSO_ECN_BIT] =          "tx-tcp-ecn-segmentation",
+	[NETIF_F_GSO_ACCECN_BIT] =       "tx-tcp-accecn-segmentation",
 	[NETIF_F_TSO_MANGLEID_BIT] =	 "tx-tcp-mangleid-segmentation",
 	[NETIF_F_TSO6_BIT] =             "tx-tcp6-segmentation",
 	[NETIF_F_FSO_BIT] =              "tx-fcoe-segmentation",
diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c
index e09147ac9a99..7a81cf438010 100644
--- a/net/ipv4/tcp_offload.c
+++ b/net/ipv4/tcp_offload.c
@@ -65,6 +65,7 @@  struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
 	struct sk_buff *gso_skb = skb;
 	__sum16 newcheck;
 	bool ooo_okay, copy_destructor;
+	bool ecn_cwr_mask;
 
 	th = tcp_hdr(skb);
 	thlen = th->doff * 4;
@@ -121,6 +122,8 @@  struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
 	newcheck = ~csum_fold((__force __wsum)((__force u32)th->check +
 					       (__force u32)delta));
 
+	ecn_cwr_mask = !!(skb_shinfo(gso_skb)->gso_type & SKB_GSO_TCP_ACCECN);
+
 	while (skb->next) {
 		th->fin = th->psh = 0;
 		th->check = newcheck;
@@ -140,7 +143,8 @@  struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
 		th = tcp_hdr(skb);
 
 		th->seq = htonl(seq);
-		th->cwr = 0;
+
+		th->cwr &= ecn_cwr_mask;
 	}
 
 	/* Following permits TCP Small Queues to work well with GSO :