Przeglądaj źródła

core: Segment tso packets based on physical device limitations

UDP GSO packets from network stack currently do not honor the
gso_max_size limits set in a driver. As a result, there needs
to be some enforcement done at the driver itself prior to the
transmit to hardware.

Instead of setting the gso_max_size on the rmnet devices, the
gso_max_size is instead set on the physical device. This
ensures that the network stack processing happens with the
maximum gso size possible for the TCP case.

CRs-Fixed: 2981039
Change-Id: I5280ea79f868e2b933f2604f8a33fbf33687f76c
Signed-off-by: Subash Abhinov Kasiviswanathan <[email protected]>
Subash Abhinov Kasiviswanathan 4 lat temu
rodzic
commit
eedd0b9c6d
2 zmienionych plików z 46 dodań i 0 usunięć
  1. 3 0
      core/rmnet_config.h
  2. 43 0
      core/rmnet_vnd.c

+ 3 - 0
core/rmnet_config.h

@@ -188,6 +188,9 @@ struct rmnet_priv_stats {
 	u64 ul_prio;
 	u64 tso_pkts;
 	u64 tso_arriv_errs;
+	u64 tso_segment_success;
+	u64 tso_segment_fail;
+	u64 tso_segment_skip;
 	u64 ll_tso_segs;
 	u64 ll_tso_errs;
 };

+ 43 - 0
core/rmnet_vnd.c

@@ -110,6 +110,46 @@ static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb,
 				priv->stats.ll_tso_segs++;
 				rmnet_egress_handler(skb, low_latency);
 			}
+		} else if (!low_latency && skb_is_gso(skb)) {
+			u64 gso_limit = priv->real_dev->gso_max_size ? : 1;
+			u16 gso_goal = 0;
+			netdev_features_t features = NETIF_F_SG;
+			u16 orig_gso_size = skb_shinfo(skb)->gso_size;
+			unsigned int orig_gso_type = skb_shinfo(skb)->gso_type;
+			struct sk_buff *segs, *tmp;
+
+			features |=  NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+
+			if (skb->len < gso_limit || gso_limit > 65535) {
+				priv->stats.tso_segment_skip++;
+				rmnet_egress_handler(skb, low_latency);
+			} else {
+				do_div(gso_limit, skb_shinfo(skb)->gso_size);
+				gso_goal = gso_limit * skb_shinfo(skb)->gso_size;
+				skb_shinfo(skb)->gso_size = gso_goal;
+
+				segs = __skb_gso_segment(skb, features, false);
+				if (IS_ERR_OR_NULL(segs)) {
+					skb_shinfo(skb)->gso_size = orig_gso_size;
+					skb_shinfo(skb)->gso_type = orig_gso_type;
+
+					priv->stats.tso_segment_fail++;
+					rmnet_egress_handler(skb, low_latency);
+				} else {
+					consume_skb(skb);
+
+					for (skb = segs; skb; skb = tmp) {
+						tmp = skb->next;
+						skb->dev = dev;
+
+						skb_shinfo(skb)->gso_size = orig_gso_size;
+						skb_shinfo(skb)->gso_type = orig_gso_type;
+
+						priv->stats.tso_segment_success++;
+						rmnet_egress_handler(skb, low_latency);
+					}
+				}
+			}
 		} else {
 			rmnet_egress_handler(skb, low_latency);
 		}
@@ -295,6 +335,9 @@ static const char rmnet_gstrings_stats[][ETH_GSTRING_LEN] = {
 	"Uplink priority packets",
 	"TSO packets",
 	"TSO packets arriving incorrectly",
+	"TSO segment success",
+	"TSO segment fail",
+	"TSO segment skip",
 	"LL TSO segment success",
 	"LL TSO segment fail",
 };