aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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