aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/macvlan.c
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2009-11-17 03:53:49 -0500
committerDavid S. Miller <davem@davemloft.net>2009-11-18 02:51:57 -0500
commitfccaf71011b171883efee5bae321eac4760584d1 (patch)
treea44bb3d88d778891b29049700bd9611d255f8045 /drivers/net/macvlan.c
parent9793241fe92f7d9303fb221e43fc598eb065f267 (diff)
macvlan: Precise RX stats accounting
With multi queue devices, its possible that several cpus call macvlan RX routines simultaneously for the same macvlan device. We update RX stats counter without any locking, so we can get slightly wrong counters. One possible fix is to use percpu counters, to get precise accounting and also get guarantee of no cache line ping pongs between cpus. Note: this adds 16 bytes (32 bytes on 64bit arches) of percpu data per macvlan device. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/macvlan.c')
-rw-r--r--drivers/net/macvlan.c76
1 files changed, 66 insertions, 10 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 271aa7e1d033..ae2b5c79c55e 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -38,12 +38,27 @@ struct macvlan_port {
38 struct list_head vlans; 38 struct list_head vlans;
39}; 39};
40 40
41/**
42 * struct macvlan_rx_stats - MACVLAN percpu rx stats
43 * @rx_packets: number of received packets
44 * @rx_bytes: number of received bytes
45 * @multicast: number of received multicast packets
46 * @rx_errors: number of errors
47 */
48struct macvlan_rx_stats {
49 unsigned long rx_packets;
50 unsigned long rx_bytes;
51 unsigned long multicast;
52 unsigned long rx_errors;
53};
54
41struct macvlan_dev { 55struct macvlan_dev {
42 struct net_device *dev; 56 struct net_device *dev;
43 struct list_head list; 57 struct list_head list;
44 struct hlist_node hlist; 58 struct hlist_node hlist;
45 struct macvlan_port *port; 59 struct macvlan_port *port;
46 struct net_device *lowerdev; 60 struct net_device *lowerdev;
61 struct macvlan_rx_stats *rx_stats;
47}; 62};
48 63
49 64
@@ -110,6 +125,7 @@ static void macvlan_broadcast(struct sk_buff *skb,
110 struct net_device *dev; 125 struct net_device *dev;
111 struct sk_buff *nskb; 126 struct sk_buff *nskb;
112 unsigned int i; 127 unsigned int i;
128 struct macvlan_rx_stats *rx_stats;
113 129
114 if (skb->protocol == htons(ETH_P_PAUSE)) 130 if (skb->protocol == htons(ETH_P_PAUSE))
115 return; 131 return;
@@ -117,17 +133,17 @@ static void macvlan_broadcast(struct sk_buff *skb,
117 for (i = 0; i < MACVLAN_HASH_SIZE; i++) { 133 for (i = 0; i < MACVLAN_HASH_SIZE; i++) {
118 hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[i], hlist) { 134 hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[i], hlist) {
119 dev = vlan->dev; 135 dev = vlan->dev;
136 rx_stats = per_cpu_ptr(vlan->rx_stats, smp_processor_id());
120 137
121 nskb = skb_clone(skb, GFP_ATOMIC); 138 nskb = skb_clone(skb, GFP_ATOMIC);
122 if (nskb == NULL) { 139 if (nskb == NULL) {
123 dev->stats.rx_errors++; 140 rx_stats->rx_errors++;
124 dev->stats.rx_dropped++;
125 continue; 141 continue;
126 } 142 }
127 143
128 dev->stats.rx_bytes += skb->len + ETH_HLEN; 144 rx_stats->rx_bytes += skb->len + ETH_HLEN;
129 dev->stats.rx_packets++; 145 rx_stats->rx_packets++;
130 dev->stats.multicast++; 146 rx_stats->multicast++;
131 147
132 nskb->dev = dev; 148 nskb->dev = dev;
133 if (!compare_ether_addr_64bits(eth->h_dest, dev->broadcast)) 149 if (!compare_ether_addr_64bits(eth->h_dest, dev->broadcast))
@@ -147,6 +163,7 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
147 const struct macvlan_port *port; 163 const struct macvlan_port *port;
148 const struct macvlan_dev *vlan; 164 const struct macvlan_dev *vlan;
149 struct net_device *dev; 165 struct net_device *dev;
166 struct macvlan_rx_stats *rx_stats;
150 167
151 port = rcu_dereference(skb->dev->macvlan_port); 168 port = rcu_dereference(skb->dev->macvlan_port);
152 if (port == NULL) 169 if (port == NULL)
@@ -166,16 +183,15 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
166 kfree_skb(skb); 183 kfree_skb(skb);
167 return NULL; 184 return NULL;
168 } 185 }
169 186 rx_stats = per_cpu_ptr(vlan->rx_stats, smp_processor_id());
170 skb = skb_share_check(skb, GFP_ATOMIC); 187 skb = skb_share_check(skb, GFP_ATOMIC);
171 if (skb == NULL) { 188 if (skb == NULL) {
172 dev->stats.rx_errors++; 189 rx_stats->rx_errors++;
173 dev->stats.rx_dropped++;
174 return NULL; 190 return NULL;
175 } 191 }
176 192
177 dev->stats.rx_bytes += skb->len + ETH_HLEN; 193 rx_stats->rx_bytes += skb->len + ETH_HLEN;
178 dev->stats.rx_packets++; 194 rx_stats->rx_packets++;
179 195
180 skb->dev = dev; 196 skb->dev = dev;
181 skb->pkt_type = PACKET_HOST; 197 skb->pkt_type = PACKET_HOST;
@@ -365,9 +381,47 @@ static int macvlan_init(struct net_device *dev)
365 381
366 macvlan_set_lockdep_class(dev); 382 macvlan_set_lockdep_class(dev);
367 383
384 vlan->rx_stats = alloc_percpu(struct macvlan_rx_stats);
385 if (!vlan->rx_stats)
386 return -ENOMEM;
387
368 return 0; 388 return 0;
369} 389}
370 390
391static void macvlan_uninit(struct net_device *dev)
392{
393 struct macvlan_dev *vlan = netdev_priv(dev);
394
395 free_percpu(vlan->rx_stats);
396}
397
398static struct net_device_stats *macvlan_dev_get_stats(struct net_device *dev)
399{
400 struct net_device_stats *stats = &dev->stats;
401 struct macvlan_dev *vlan = netdev_priv(dev);
402
403 dev_txq_stats_fold(dev, stats);
404
405 if (vlan->rx_stats) {
406 struct macvlan_rx_stats *p, rx = {0};
407 int i;
408
409 for_each_possible_cpu(i) {
410 p = per_cpu_ptr(vlan->rx_stats, i);
411 rx.rx_packets += p->rx_packets;
412 rx.rx_bytes += p->rx_bytes;
413 rx.rx_errors += p->rx_errors;
414 rx.multicast += p->multicast;
415 }
416 stats->rx_packets = rx.rx_packets;
417 stats->rx_bytes = rx.rx_bytes;
418 stats->rx_errors = rx.rx_errors;
419 stats->rx_dropped = rx.rx_errors;
420 stats->multicast = rx.multicast;
421 }
422 return stats;
423}
424
371static void macvlan_ethtool_get_drvinfo(struct net_device *dev, 425static void macvlan_ethtool_get_drvinfo(struct net_device *dev,
372 struct ethtool_drvinfo *drvinfo) 426 struct ethtool_drvinfo *drvinfo)
373{ 427{
@@ -404,6 +458,7 @@ static const struct ethtool_ops macvlan_ethtool_ops = {
404 458
405static const struct net_device_ops macvlan_netdev_ops = { 459static const struct net_device_ops macvlan_netdev_ops = {
406 .ndo_init = macvlan_init, 460 .ndo_init = macvlan_init,
461 .ndo_uninit = macvlan_uninit,
407 .ndo_open = macvlan_open, 462 .ndo_open = macvlan_open,
408 .ndo_stop = macvlan_stop, 463 .ndo_stop = macvlan_stop,
409 .ndo_start_xmit = macvlan_start_xmit, 464 .ndo_start_xmit = macvlan_start_xmit,
@@ -411,6 +466,7 @@ static const struct net_device_ops macvlan_netdev_ops = {
411 .ndo_change_rx_flags = macvlan_change_rx_flags, 466 .ndo_change_rx_flags = macvlan_change_rx_flags,
412 .ndo_set_mac_address = macvlan_set_mac_address, 467 .ndo_set_mac_address = macvlan_set_mac_address,
413 .ndo_set_multicast_list = macvlan_set_multicast_list, 468 .ndo_set_multicast_list = macvlan_set_multicast_list,
469 .ndo_get_stats = macvlan_dev_get_stats,
414 .ndo_validate_addr = eth_validate_addr, 470 .ndo_validate_addr = eth_validate_addr,
415}; 471};
416 472