diff options
-rw-r--r-- | drivers/net/macvlan.c | 76 |
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 | */ | ||
48 | struct macvlan_rx_stats { | ||
49 | unsigned long rx_packets; | ||
50 | unsigned long rx_bytes; | ||
51 | unsigned long multicast; | ||
52 | unsigned long rx_errors; | ||
53 | }; | ||
54 | |||
41 | struct macvlan_dev { | 55 | struct 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 | ||
391 | static 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 | |||
398 | static 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 | |||
371 | static void macvlan_ethtool_get_drvinfo(struct net_device *dev, | 425 | static 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 | ||
405 | static const struct net_device_ops macvlan_netdev_ops = { | 459 | static 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 | ||