Skip to content

Commit beeecd4

Browse files
bmorkdavem330
authored andcommitted
net: cdc_ncm/cdc_mbim: adding NCM protocol statistics
To have an idea of the effects of the protocol coalescing it's useful to have some counters showing the different aspects. Due to the asymmetrical usbnet interface the netdev rx_bytes counter has been counting real received payload, while the tx_bytes counter has included the NCM/MBIM framing overhead. This overhead can be many times the payload because of the aggressive padding strategy of this driver, and will vary a lot depending on device and traffic. With very few exceptions, users are only interested in the payload size. Having an somewhat accurate payload byte counter is particularly important for mobile broadband devices, which many NCM devices and of course all MBIM devices are. Users and userspace applications will use this counter to monitor account quotas. Having protocol specific counters for the overhead, we are now able to correct the tx_bytes netdev counter so that it shows the real payload Signed-off-by: Bjørn Mork <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 43e4c6d commit beeecd4

File tree

3 files changed

+108
-0
lines changed

3 files changed

+108
-0
lines changed

drivers/net/usb/cdc_mbim.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,7 @@ static int cdc_mbim_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
420420
struct usb_cdc_ncm_dpe16 *dpe16;
421421
int ndpoffset;
422422
int loopcount = 50; /* arbitrary max preventing infinite loop */
423+
u32 payload = 0;
423424
u8 *c;
424425
u16 tci;
425426

@@ -482,6 +483,7 @@ static int cdc_mbim_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
482483
if (!skb)
483484
goto error;
484485
usbnet_skb_return(dev, skb);
486+
payload += len; /* count payload bytes in this NTB */
485487
}
486488
}
487489
err_ndp:
@@ -490,6 +492,10 @@ static int cdc_mbim_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
490492
if (ndpoffset && loopcount--)
491493
goto next_ndp;
492494

495+
/* update stats */
496+
ctx->rx_overhead += skb_in->len - payload;
497+
ctx->rx_ntbs++;
498+
493499
return 1;
494500
error:
495501
return 0;

drivers/net/usb/cdc_ncm.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,68 @@ static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx);
6565
static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *hr_timer);
6666
static struct usb_driver cdc_ncm_driver;
6767

68+
struct cdc_ncm_stats {
69+
char stat_string[ETH_GSTRING_LEN];
70+
int sizeof_stat;
71+
int stat_offset;
72+
};
73+
74+
#define CDC_NCM_STAT(str, m) { \
75+
.stat_string = str, \
76+
.sizeof_stat = sizeof(((struct cdc_ncm_ctx *)0)->m), \
77+
.stat_offset = offsetof(struct cdc_ncm_ctx, m) }
78+
#define CDC_NCM_SIMPLE_STAT(m) CDC_NCM_STAT(__stringify(m), m)
79+
80+
static const struct cdc_ncm_stats cdc_ncm_gstrings_stats[] = {
81+
CDC_NCM_SIMPLE_STAT(tx_reason_ntb_full),
82+
CDC_NCM_SIMPLE_STAT(tx_reason_ndp_full),
83+
CDC_NCM_SIMPLE_STAT(tx_reason_timeout),
84+
CDC_NCM_SIMPLE_STAT(tx_reason_max_datagram),
85+
CDC_NCM_SIMPLE_STAT(tx_overhead),
86+
CDC_NCM_SIMPLE_STAT(tx_ntbs),
87+
CDC_NCM_SIMPLE_STAT(rx_overhead),
88+
CDC_NCM_SIMPLE_STAT(rx_ntbs),
89+
};
90+
91+
static int cdc_ncm_get_sset_count(struct net_device __always_unused *netdev, int sset)
92+
{
93+
switch (sset) {
94+
case ETH_SS_STATS:
95+
return ARRAY_SIZE(cdc_ncm_gstrings_stats);
96+
default:
97+
return -EOPNOTSUPP;
98+
}
99+
}
100+
101+
static void cdc_ncm_get_ethtool_stats(struct net_device *netdev,
102+
struct ethtool_stats __always_unused *stats,
103+
u64 *data)
104+
{
105+
struct usbnet *dev = netdev_priv(netdev);
106+
struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
107+
int i;
108+
char *p = NULL;
109+
110+
for (i = 0; i < ARRAY_SIZE(cdc_ncm_gstrings_stats); i++) {
111+
p = (char *)ctx + cdc_ncm_gstrings_stats[i].stat_offset;
112+
data[i] = (cdc_ncm_gstrings_stats[i].sizeof_stat == sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
113+
}
114+
}
115+
116+
static void cdc_ncm_get_strings(struct net_device __always_unused *netdev, u32 stringset, u8 *data)
117+
{
118+
u8 *p = data;
119+
int i;
120+
121+
switch (stringset) {
122+
case ETH_SS_STATS:
123+
for (i = 0; i < ARRAY_SIZE(cdc_ncm_gstrings_stats); i++) {
124+
memcpy(p, cdc_ncm_gstrings_stats[i].stat_string, ETH_GSTRING_LEN);
125+
p += ETH_GSTRING_LEN;
126+
}
127+
}
128+
}
129+
68130
static int cdc_ncm_get_coalesce(struct net_device *netdev,
69131
struct ethtool_coalesce *ec)
70132
{
@@ -122,6 +184,9 @@ static const struct ethtool_ops cdc_ncm_ethtool_ops = {
122184
.get_msglevel = usbnet_get_msglevel,
123185
.set_msglevel = usbnet_set_msglevel,
124186
.get_ts_info = ethtool_op_get_ts_info,
187+
.get_sset_count = cdc_ncm_get_sset_count,
188+
.get_strings = cdc_ncm_get_strings,
189+
.get_ethtool_stats = cdc_ncm_get_ethtool_stats,
125190
.get_coalesce = cdc_ncm_get_coalesce,
126191
.set_coalesce = cdc_ncm_set_coalesce,
127192
};
@@ -862,6 +927,9 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
862927

863928
/* count total number of frames in this NTB */
864929
ctx->tx_curr_frame_num = 0;
930+
931+
/* recent payload counter for this skb_out */
932+
ctx->tx_curr_frame_payload = 0;
865933
}
866934

867935
for (n = ctx->tx_curr_frame_num; n < ctx->tx_max_datagrams; n++) {
@@ -899,6 +967,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
899967
ctx->tx_rem_sign = sign;
900968
skb = NULL;
901969
ready2send = 1;
970+
ctx->tx_reason_ntb_full++; /* count reason for transmitting */
902971
}
903972
break;
904973
}
@@ -912,12 +981,14 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
912981
ndp16->dpe16[index].wDatagramIndex = cpu_to_le16(skb_out->len);
913982
ndp16->wLength = cpu_to_le16(ndplen + sizeof(struct usb_cdc_ncm_dpe16));
914983
memcpy(skb_put(skb_out, skb->len), skb->data, skb->len);
984+
ctx->tx_curr_frame_payload += skb->len; /* count real tx payload data */
915985
dev_kfree_skb_any(skb);
916986
skb = NULL;
917987

918988
/* send now if this NDP is full */
919989
if (index >= CDC_NCM_DPT_DATAGRAMS_MAX) {
920990
ready2send = 1;
991+
ctx->tx_reason_ndp_full++; /* count reason for transmitting */
921992
break;
922993
}
923994
}
@@ -947,6 +1018,8 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
9471018
goto exit_no_skb;
9481019

9491020
} else {
1021+
if (n == ctx->tx_max_datagrams)
1022+
ctx->tx_reason_max_datagram++; /* count reason for transmitting */
9501023
/* frame goes out */
9511024
/* variables will be reset at next call */
9521025
}
@@ -974,6 +1047,17 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
9741047
/* return skb */
9751048
ctx->tx_curr_skb = NULL;
9761049
dev->net->stats.tx_packets += ctx->tx_curr_frame_num;
1050+
1051+
/* keep private stats: framing overhead and number of NTBs */
1052+
ctx->tx_overhead += skb_out->len - ctx->tx_curr_frame_payload;
1053+
ctx->tx_ntbs++;
1054+
1055+
/* usbnet has already counted all the framing overhead.
1056+
* Adjust the stats so that the tx_bytes counter show real
1057+
* payload data instead.
1058+
*/
1059+
dev->net->stats.tx_bytes -= skb_out->len - ctx->tx_curr_frame_payload;
1060+
9771061
return skb_out;
9781062

9791063
exit_no_skb:
@@ -1014,6 +1098,7 @@ static void cdc_ncm_txpath_bh(unsigned long param)
10141098
cdc_ncm_tx_timeout_start(ctx);
10151099
spin_unlock_bh(&ctx->mtx);
10161100
} else if (dev->net != NULL) {
1101+
ctx->tx_reason_timeout++; /* count reason for transmitting */
10171102
spin_unlock_bh(&ctx->mtx);
10181103
netif_tx_lock_bh(dev->net);
10191104
usbnet_start_xmit(NULL, dev->net);
@@ -1149,6 +1234,7 @@ int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
11491234
struct usb_cdc_ncm_dpe16 *dpe16;
11501235
int ndpoffset;
11511236
int loopcount = 50; /* arbitrary max preventing infinite loop */
1237+
u32 payload = 0;
11521238

11531239
ndpoffset = cdc_ncm_rx_verify_nth16(ctx, skb_in);
11541240
if (ndpoffset < 0)
@@ -1201,6 +1287,7 @@ int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
12011287
skb->data = ((u8 *)skb_in->data) + offset;
12021288
skb_set_tail_pointer(skb, len);
12031289
usbnet_skb_return(dev, skb);
1290+
payload += len; /* count payload bytes in this NTB */
12041291
}
12051292
}
12061293
err_ndp:
@@ -1209,6 +1296,10 @@ int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
12091296
if (ndpoffset && loopcount--)
12101297
goto next_ndp;
12111298

1299+
/* update stats */
1300+
ctx->rx_overhead += skb_in->len - payload;
1301+
ctx->rx_ntbs++;
1302+
12121303
return 1;
12131304
error:
12141305
return 0;

include/linux/usb/cdc_ncm.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,17 @@ struct cdc_ncm_ctx {
116116
u16 rx_seq;
117117
u16 connected;
118118
u16 min_tx_pkt;
119+
120+
/* statistics */
121+
u32 tx_curr_frame_payload;
122+
u32 tx_reason_ntb_full;
123+
u32 tx_reason_ndp_full;
124+
u32 tx_reason_timeout;
125+
u32 tx_reason_max_datagram;
126+
u64 tx_overhead;
127+
u64 tx_ntbs;
128+
u64 rx_overhead;
129+
u64 rx_ntbs;
119130
};
120131

121132
u8 cdc_ncm_select_altsetting(struct usb_interface *intf);

0 commit comments

Comments
 (0)