diff options
author | Shannon Nelson <shannon.nelson@oracle.com> | 2017-03-14 13:24:40 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-03-16 23:29:54 -0400 |
commit | 0f512c84544b9a8f8de53b6f4bc0c372c45d8693 (patch) | |
tree | 848642bf531b53e4700e226796c091468dcd7f50 | |
parent | 867fa150f8f7ee6e9e5a9ab768e2d0dc675a968b (diff) |
sunvnet: add stats to track ldom to ldom packets and bytes
In this driver, there is a "port" created for the connection to each of
the other ldoms; a netdev queue is mapped to each port, and they are
collected under a single netdev. The generic netdev statistics show
us all the traffic in and out of our network device, but don't show
individual queue/port stats. This patch breaks out the traffic counts
for the individual ports and gives us a little view into the state of
those connections.
Orabug: 25190537
Signed-off-by: Shannon Nelson <shannon.nelson@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/sun/sunvnet.c | 116 | ||||
-rw-r--r-- | drivers/net/ethernet/sun/sunvnet_common.c | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/sun/sunvnet_common.h | 15 |
3 files changed, 136 insertions, 1 deletions
diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c index 4cc2571f71c6..0b95105f7060 100644 --- a/drivers/net/ethernet/sun/sunvnet.c +++ b/drivers/net/ethernet/sun/sunvnet.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* sunvnet.c: Sun LDOM Virtual Network Driver. | 1 | /* sunvnet.c: Sun LDOM Virtual Network Driver. |
2 | * | 2 | * |
3 | * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net> | 3 | * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net> |
4 | * Copyright (C) 2016 Oracle. All rights reserved. | 4 | * Copyright (C) 2016-2017 Oracle. All rights reserved. |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 7 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
@@ -77,11 +77,125 @@ static void vnet_set_msglevel(struct net_device *dev, u32 value) | |||
77 | vp->msg_enable = value; | 77 | vp->msg_enable = value; |
78 | } | 78 | } |
79 | 79 | ||
80 | static const struct { | ||
81 | const char string[ETH_GSTRING_LEN]; | ||
82 | } ethtool_stats_keys[] = { | ||
83 | { "rx_packets" }, | ||
84 | { "tx_packets" }, | ||
85 | { "rx_bytes" }, | ||
86 | { "tx_bytes" }, | ||
87 | { "rx_errors" }, | ||
88 | { "tx_errors" }, | ||
89 | { "rx_dropped" }, | ||
90 | { "tx_dropped" }, | ||
91 | { "multicast" }, | ||
92 | { "rx_length_errors" }, | ||
93 | { "rx_frame_errors" }, | ||
94 | { "rx_missed_errors" }, | ||
95 | { "tx_carrier_errors" }, | ||
96 | { "nports" }, | ||
97 | }; | ||
98 | |||
99 | static int vnet_get_sset_count(struct net_device *dev, int sset) | ||
100 | { | ||
101 | struct vnet *vp = (struct vnet *)netdev_priv(dev); | ||
102 | |||
103 | switch (sset) { | ||
104 | case ETH_SS_STATS: | ||
105 | return ARRAY_SIZE(ethtool_stats_keys) | ||
106 | + (NUM_VNET_PORT_STATS * vp->nports); | ||
107 | default: | ||
108 | return -EOPNOTSUPP; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | static void vnet_get_strings(struct net_device *dev, u32 stringset, u8 *buf) | ||
113 | { | ||
114 | struct vnet *vp = (struct vnet *)netdev_priv(dev); | ||
115 | struct vnet_port *port; | ||
116 | char *p = (char *)buf; | ||
117 | |||
118 | switch (stringset) { | ||
119 | case ETH_SS_STATS: | ||
120 | memcpy(buf, ðtool_stats_keys, sizeof(ethtool_stats_keys)); | ||
121 | p += sizeof(ethtool_stats_keys); | ||
122 | |||
123 | rcu_read_lock(); | ||
124 | list_for_each_entry_rcu(port, &vp->port_list, list) { | ||
125 | snprintf(p, ETH_GSTRING_LEN, "p%u.%s-%pM", | ||
126 | port->q_index, port->switch_port ? "s" : "q", | ||
127 | port->raddr); | ||
128 | p += ETH_GSTRING_LEN; | ||
129 | snprintf(p, ETH_GSTRING_LEN, "p%u.rx_packets", | ||
130 | port->q_index); | ||
131 | p += ETH_GSTRING_LEN; | ||
132 | snprintf(p, ETH_GSTRING_LEN, "p%u.tx_packets", | ||
133 | port->q_index); | ||
134 | p += ETH_GSTRING_LEN; | ||
135 | snprintf(p, ETH_GSTRING_LEN, "p%u.rx_bytes", | ||
136 | port->q_index); | ||
137 | p += ETH_GSTRING_LEN; | ||
138 | snprintf(p, ETH_GSTRING_LEN, "p%u.tx_bytes", | ||
139 | port->q_index); | ||
140 | p += ETH_GSTRING_LEN; | ||
141 | snprintf(p, ETH_GSTRING_LEN, "p%u.event_up", | ||
142 | port->q_index); | ||
143 | p += ETH_GSTRING_LEN; | ||
144 | snprintf(p, ETH_GSTRING_LEN, "p%u.event_reset", | ||
145 | port->q_index); | ||
146 | p += ETH_GSTRING_LEN; | ||
147 | } | ||
148 | rcu_read_unlock(); | ||
149 | break; | ||
150 | default: | ||
151 | WARN_ON(1); | ||
152 | break; | ||
153 | } | ||
154 | } | ||
155 | |||
156 | static void vnet_get_ethtool_stats(struct net_device *dev, | ||
157 | struct ethtool_stats *estats, u64 *data) | ||
158 | { | ||
159 | struct vnet *vp = (struct vnet *)netdev_priv(dev); | ||
160 | struct vnet_port *port; | ||
161 | int i = 0; | ||
162 | |||
163 | data[i++] = dev->stats.rx_packets; | ||
164 | data[i++] = dev->stats.tx_packets; | ||
165 | data[i++] = dev->stats.rx_bytes; | ||
166 | data[i++] = dev->stats.tx_bytes; | ||
167 | data[i++] = dev->stats.rx_errors; | ||
168 | data[i++] = dev->stats.tx_errors; | ||
169 | data[i++] = dev->stats.rx_dropped; | ||
170 | data[i++] = dev->stats.tx_dropped; | ||
171 | data[i++] = dev->stats.multicast; | ||
172 | data[i++] = dev->stats.rx_length_errors; | ||
173 | data[i++] = dev->stats.rx_frame_errors; | ||
174 | data[i++] = dev->stats.rx_missed_errors; | ||
175 | data[i++] = dev->stats.tx_carrier_errors; | ||
176 | data[i++] = vp->nports; | ||
177 | |||
178 | rcu_read_lock(); | ||
179 | list_for_each_entry_rcu(port, &vp->port_list, list) { | ||
180 | data[i++] = port->q_index; | ||
181 | data[i++] = port->stats.rx_packets; | ||
182 | data[i++] = port->stats.tx_packets; | ||
183 | data[i++] = port->stats.rx_bytes; | ||
184 | data[i++] = port->stats.tx_bytes; | ||
185 | data[i++] = port->stats.event_up; | ||
186 | data[i++] = port->stats.event_reset; | ||
187 | } | ||
188 | rcu_read_unlock(); | ||
189 | } | ||
190 | |||
80 | static const struct ethtool_ops vnet_ethtool_ops = { | 191 | static const struct ethtool_ops vnet_ethtool_ops = { |
81 | .get_drvinfo = vnet_get_drvinfo, | 192 | .get_drvinfo = vnet_get_drvinfo, |
82 | .get_msglevel = vnet_get_msglevel, | 193 | .get_msglevel = vnet_get_msglevel, |
83 | .set_msglevel = vnet_set_msglevel, | 194 | .set_msglevel = vnet_set_msglevel, |
84 | .get_link = ethtool_op_get_link, | 195 | .get_link = ethtool_op_get_link, |
196 | .get_sset_count = vnet_get_sset_count, | ||
197 | .get_strings = vnet_get_strings, | ||
198 | .get_ethtool_stats = vnet_get_ethtool_stats, | ||
85 | }; | 199 | }; |
86 | 200 | ||
87 | static LIST_HEAD(vnet_list); | 201 | static LIST_HEAD(vnet_list); |
diff --git a/drivers/net/ethernet/sun/sunvnet_common.c b/drivers/net/ethernet/sun/sunvnet_common.c index fbd0f1e5210e..7e95808f8227 100644 --- a/drivers/net/ethernet/sun/sunvnet_common.c +++ b/drivers/net/ethernet/sun/sunvnet_common.c | |||
@@ -411,6 +411,8 @@ static int vnet_rx_one(struct vnet_port *port, struct vio_net_desc *desc) | |||
411 | 411 | ||
412 | dev->stats.rx_packets++; | 412 | dev->stats.rx_packets++; |
413 | dev->stats.rx_bytes += len; | 413 | dev->stats.rx_bytes += len; |
414 | port->stats.rx_packets++; | ||
415 | port->stats.rx_bytes += len; | ||
414 | napi_gro_receive(&port->napi, skb); | 416 | napi_gro_receive(&port->napi, skb); |
415 | return 0; | 417 | return 0; |
416 | 418 | ||
@@ -768,6 +770,7 @@ static int vnet_event_napi(struct vnet_port *port, int budget) | |||
768 | maybe_tx_wakeup(port); | 770 | maybe_tx_wakeup(port); |
769 | 771 | ||
770 | port->rx_event = 0; | 772 | port->rx_event = 0; |
773 | port->stats.event_reset++; | ||
771 | return 0; | 774 | return 0; |
772 | } | 775 | } |
773 | 776 | ||
@@ -781,6 +784,7 @@ static int vnet_event_napi(struct vnet_port *port, int budget) | |||
781 | 784 | ||
782 | vio_link_state_change(vio, LDC_EVENT_UP); | 785 | vio_link_state_change(vio, LDC_EVENT_UP); |
783 | port->rx_event = 0; | 786 | port->rx_event = 0; |
787 | port->stats.event_up++; | ||
784 | return 0; | 788 | return 0; |
785 | } | 789 | } |
786 | 790 | ||
@@ -1430,6 +1434,8 @@ ldc_start_done: | |||
1430 | 1434 | ||
1431 | dev->stats.tx_packets++; | 1435 | dev->stats.tx_packets++; |
1432 | dev->stats.tx_bytes += port->tx_bufs[txi].skb->len; | 1436 | dev->stats.tx_bytes += port->tx_bufs[txi].skb->len; |
1437 | port->stats.tx_packets++; | ||
1438 | port->stats.tx_bytes += port->tx_bufs[txi].skb->len; | ||
1433 | 1439 | ||
1434 | dr->prod = (dr->prod + 1) & (VNET_TX_RING_SIZE - 1); | 1440 | dr->prod = (dr->prod + 1) & (VNET_TX_RING_SIZE - 1); |
1435 | if (unlikely(vnet_tx_dring_avail(dr) < 1)) { | 1441 | if (unlikely(vnet_tx_dring_avail(dr) < 1)) { |
diff --git a/drivers/net/ethernet/sun/sunvnet_common.h b/drivers/net/ethernet/sun/sunvnet_common.h index b21ef4704bd1..c0fac03cb87a 100644 --- a/drivers/net/ethernet/sun/sunvnet_common.h +++ b/drivers/net/ethernet/sun/sunvnet_common.h | |||
@@ -35,6 +35,19 @@ struct vnet_tx_entry { | |||
35 | 35 | ||
36 | struct vnet; | 36 | struct vnet; |
37 | 37 | ||
38 | struct vnet_port_stats { | ||
39 | /* keep them all the same size */ | ||
40 | u32 rx_bytes; | ||
41 | u32 tx_bytes; | ||
42 | u32 rx_packets; | ||
43 | u32 tx_packets; | ||
44 | u32 event_up; | ||
45 | u32 event_reset; | ||
46 | u32 q_placeholder; | ||
47 | }; | ||
48 | |||
49 | #define NUM_VNET_PORT_STATS (sizeof(struct vnet_port_stats) / sizeof(u32)) | ||
50 | |||
38 | /* Structure to describe a vnet-port or vsw-port in the MD. | 51 | /* Structure to describe a vnet-port or vsw-port in the MD. |
39 | * If the vsw bit is set, this structure represents a vswitch | 52 | * If the vsw bit is set, this structure represents a vswitch |
40 | * port, and the net_device can be found from ->dev. If the | 53 | * port, and the net_device can be found from ->dev. If the |
@@ -44,6 +57,8 @@ struct vnet; | |||
44 | struct vnet_port { | 57 | struct vnet_port { |
45 | struct vio_driver_state vio; | 58 | struct vio_driver_state vio; |
46 | 59 | ||
60 | struct vnet_port_stats stats; | ||
61 | |||
47 | struct hlist_node hash; | 62 | struct hlist_node hash; |
48 | u8 raddr[ETH_ALEN]; | 63 | u8 raddr[ETH_ALEN]; |
49 | unsigned switch_port:1; | 64 | unsigned switch_port:1; |