Эх сурвалжийг харах

rmnet_core: track coalescing usage per descriptor

Descriptors that came from coalesced frames will now carry usage info.
In order to prevent overcoutning, only the first segment from each frame
will report this information; the rest will report 0.

This allows a simple calculation of summing the coal_bytes and coal_bufsize
values reported and dividing to determine the total ratio over a given
period.

These values will be reported in the SKB via a new Control Block struct,
accessable via RMNET_SKB_CB(skb);

Change-Id: I8ea31921afa3afad4d2c570ec5728118bd635b86
Signed-off-by: Sean Tranchetti <[email protected]>
Sean Tranchetti 3 жил өмнө
parent
commit
50a4832e09

+ 29 - 11
core/rmnet_descriptor.c

@@ -35,6 +35,13 @@
 			       sizeof(struct rmnet_map_header) + \
 			       sizeof(struct rmnet_map_control_command_header))
 
+#define rmnet_descriptor_for_each_frag(p, desc) \
+	list_for_each_entry(p, &desc->frags, list)
+#define rmnet_descriptor_for_each_frag_safe(p, tmp, desc) \
+	list_for_each_entry_safe(p, tmp, &desc->frags, list)
+#define rmnet_descriptor_for_each_frag_safe_reverse(p, tmp, desc) \
+	list_for_each_entry_safe_reverse(p, tmp, &desc->frags, list)
+
 typedef void (*rmnet_perf_desc_hook_t)(struct rmnet_frag_descriptor *frag_desc,
 				       struct rmnet_port *port);
 typedef void (*rmnet_perf_chain_hook_t)(void);
@@ -81,7 +88,7 @@ void rmnet_recycle_frag_descriptor(struct rmnet_frag_descriptor *frag_desc,
 
 	list_del(&frag_desc->list);
 
-	list_for_each_entry_safe(frag, tmp, &frag_desc->frags, list) {
+	rmnet_descriptor_for_each_frag_safe(frag, tmp, frag_desc) {
 		struct page *page = skb_frag_page(&frag->frag);
 
 		if (page)
@@ -112,7 +119,7 @@ void *rmnet_frag_pull(struct rmnet_frag_descriptor *frag_desc,
 		return NULL;
 	}
 
-	list_for_each_entry_safe(frag, tmp, &frag_desc->frags, list) {
+	rmnet_descriptor_for_each_frag_safe(frag, tmp, frag_desc) {
 		u32 frag_size = skb_frag_size(&frag->frag);
 
 		if (!size)
@@ -162,7 +169,7 @@ void *rmnet_frag_trim(struct rmnet_frag_descriptor *frag_desc,
 
 	/* Compute number of bytes to remove from the end */
 	eat = frag_desc->len - size;
-	list_for_each_entry_safe_reverse(frag, tmp, &frag_desc->frags, list) {
+	rmnet_descriptor_for_each_frag_safe_reverse(frag, tmp, frag_desc) {
 		u32 frag_size = skb_frag_size(&frag->frag);
 
 		if (!eat)
@@ -206,7 +213,7 @@ static int rmnet_frag_copy_data(struct rmnet_frag_descriptor *frag_desc,
 		return -EINVAL;
 
 	/* Copy 'len' bytes into the bufer starting from 'off' */
-	list_for_each_entry(frag, &frag_desc->frags, list) {
+	rmnet_descriptor_for_each_frag(frag, frag_desc) {
 		if (!len)
 			break;
 
@@ -241,7 +248,7 @@ void *rmnet_frag_header_ptr(struct rmnet_frag_descriptor *frag_desc, u32 off,
 
 	/* Find the starting fragment */
 	offset = off;
-	list_for_each_entry(frag, &frag_desc->frags, list) {
+	rmnet_descriptor_for_each_frag(frag, frag_desc) {
 		frag_size = skb_frag_size(&frag->frag);
 		if (off < frag_size) {
 			start = skb_frag_address(&frag->frag) + off;
@@ -298,7 +305,7 @@ int rmnet_frag_descriptor_add_frags_from(struct rmnet_frag_descriptor *to,
 	if (off > from->len || len > from->len || off + len > from->len)
 		return -EINVAL;
 
-	list_for_each_entry(frag, &from->frags, list) {
+	rmnet_descriptor_for_each_frag(frag, from) {
 		u32 frag_size;
 
 		if (!len)
@@ -798,6 +805,7 @@ static struct sk_buff *rmnet_alloc_skb(struct rmnet_frag_descriptor *frag_desc,
 	struct sk_buff *head_skb, *current_skb, *skb;
 	struct skb_shared_info *shinfo;
 	struct rmnet_fragment *frag, *tmp;
+	struct rmnet_skb_cb *cb;
 
 	/* Use the exact sizes if we know them (i.e. RSB/RSC, rmnet_perf) */
 	if (frag_desc->hdrs_valid) {
@@ -840,7 +848,7 @@ static struct sk_buff *rmnet_alloc_skb(struct rmnet_frag_descriptor *frag_desc,
 	current_skb = head_skb;
 
 	/* Add in the page fragments */
-	list_for_each_entry_safe(frag, tmp, &frag_desc->frags, list) {
+	rmnet_descriptor_for_each_frag_safe(frag, tmp, frag_desc) {
 		struct page *p = skb_frag_page(&frag->frag);
 		u32 frag_size = skb_frag_size(&frag->frag);
 
@@ -874,6 +882,9 @@ add_frag:
 skip_frags:
 	head_skb->dev = frag_desc->dev;
 	rmnet_set_skb_proto(head_skb);
+	cb = RMNET_SKB_CB(head_skb);
+	cb->coal_bytes = frag_desc->coal_bytes;
+	cb->coal_bufsize = frag_desc->coal_bufsize;
 
 	/* Handle any header metadata that needs to be updated after RSB/RSC
 	 * segmentation
@@ -971,7 +982,7 @@ skip_frags:
 	}
 
 	if (frag_desc->flush_shs)
-		head_skb->cb[0] = 1;
+		cb->flush_shs = 1;
 
 	/* Handle coalesced packets */
 	if (frag_desc->gso_segs > 1)
@@ -1150,6 +1161,10 @@ static void __rmnet_frag_segment_data(struct rmnet_frag_descriptor *coal_desc,
 	coal_desc->pkt_id = pkt_id + 1;
 	coal_desc->gso_segs = 0;
 
+	/* Only relevant for the first segment to avoid overcoutning */
+	coal_desc->coal_bytes = 0;
+	coal_desc->coal_bufsize = 0;
+
 	list_add_tail(&new_desc->list, list);
 	return;
 
@@ -1191,9 +1206,7 @@ static bool rmnet_frag_validate_csum(struct rmnet_frag_descriptor *frag_desc)
 	return !csum_fold(csum);
 }
 
-/* Converts the coalesced frame into a list of descriptors.
- * NLOs containing csum erros will not be included.
- */
+/* Converts the coalesced frame into a list of descriptors */
 static void
 rmnet_frag_segment_coal_data(struct rmnet_frag_descriptor *coal_desc,
 			     u64 nlo_err_mask, struct rmnet_port *port,
@@ -1201,6 +1214,7 @@ rmnet_frag_segment_coal_data(struct rmnet_frag_descriptor *coal_desc,
 {
 	struct rmnet_priv *priv = netdev_priv(coal_desc->dev);
 	struct rmnet_map_v5_coal_header coal_hdr;
+	struct rmnet_fragment *frag;
 	u8 *version;
 	u16 pkt_len;
 	u8 pkt, total_pkt = 0;
@@ -1317,6 +1331,10 @@ rmnet_frag_segment_coal_data(struct rmnet_frag_descriptor *coal_desc,
 	}
 
 	coal_desc->hdrs_valid = 1;
+	coal_desc->coal_bytes = coal_desc->len;
+	rmnet_descriptor_for_each_frag(frag, coal_desc)
+		coal_desc->coal_bufsize +=
+			page_size(skb_frag_page(&frag->frag));
 
 	if (rmnet_map_v5_csum_buggy(&coal_hdr) && !zero_csum) {
 		/* Mark the checksum as valid if it checks out */

+ 2 - 0
core/rmnet_descriptor.h

@@ -36,6 +36,8 @@ struct rmnet_frag_descriptor {
 	struct list_head list;
 	struct list_head frags;
 	struct net_device *dev;
+	u32 coal_bufsize;
+	u32 coal_bytes;
 	u32 len;
 	u32 hash;
 	u32 priority;

+ 4 - 2
core/rmnet_handlers.c

@@ -427,6 +427,7 @@ rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb)
 	struct sk_buff *skb = *pskb;
 	struct rmnet_port *port;
 	struct net_device *dev;
+	struct rmnet_skb_cb *cb;
 	int (*rmnet_core_shs_switch)(struct sk_buff *skb,
 				     struct rmnet_shs_clnt_s *cfg);
 
@@ -451,9 +452,10 @@ rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb)
 
 		rcu_read_lock();
 		rmnet_core_shs_switch = rcu_dereference(rmnet_shs_switch);
-		if (rmnet_core_shs_switch && !skb->cb[1] &&
+		cb = RMNET_SKB_CB(skb);
+		if (rmnet_core_shs_switch && !cb->qmap_steer &&
 		    skb->priority != 0xda1a) {
-			skb->cb[1] = 1;
+			cb->qmap_steer = 1;
 			rmnet_core_shs_switch(skb, &port->phy_shs_cfg);
 			rcu_read_unlock();
 			return RX_HANDLER_CONSUMED;

+ 16 - 1
core/rmnet_private.h

@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, 2016-2020 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 2016-2021 The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -13,6 +13,8 @@
 #ifndef _RMNET_PRIVATE_H_
 #define _RMNET_PRIVATE_H_
 
+#include <linux/types.h>
+
 #define RMNET_MAX_PACKET_SIZE      16384
 #define RMNET_DFLT_PACKET_SIZE     1500
 #define RMNET_NEEDED_HEADROOM      16
@@ -45,4 +47,17 @@ RMNET_INGRESS_FORMAT_DL_MARKER_V2)
 /* Pass the frame directly to another device with dev_queue_xmit() */
 #define RMNET_EPMODE_BRIDGE (2)
 
+/* Struct for skb control block use within rmnet driver */
+struct rmnet_skb_cb {
+	/* MUST be the first entries because of legacy reasons */
+	char flush_shs;
+	char qmap_steer;
+
+	/* coalescing stats */
+	u32 coal_bytes;
+	u32 coal_bufsize;
+};
+
+#define RMNET_SKB_CB(skb) ((struct rmnet_skb_cb *)(skb)->cb)
+
 #endif /* _RMNET_PRIVATE_H_ */