Commit 8ffab51b3dfc54876f145f15b351c41f3f703195

Authored by Eric Dumazet
Committed by David S. Miller
1 parent 0e3125c755

macvlan: lockless tx path

macvlan is a stacked device, like tunnels. We should use the lockless
mechanism we are using in tunnels and loopback.

This patch completely removes locking in TX path.

tx stat counters are added into existing percpu stat structure, renamed
from rx_stats to pcpu_stats.

Note : this reverts commit 2c11455321f37 (macvlan: add multiqueue
capability)

Note : rx_errors converted to a 32bit counter, like tx_dropped, since
they dont need 64bit range.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Patrick McHardy <kaber@trash.net>
Cc: Ben Greear <greearb@candelatech.com>
Cc: Ben Hutchings <bhutchings@solarflare.com>
Acked-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 2 changed files with 55 additions and 59 deletions Side-by-side Diff

drivers/net/macvlan.c
... ... @@ -243,18 +243,22 @@
243 243 netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
244 244 struct net_device *dev)
245 245 {
246   - int i = skb_get_queue_mapping(skb);
247   - struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
248 246 unsigned int len = skb->len;
249 247 int ret;
  248 + const struct macvlan_dev *vlan = netdev_priv(dev);
250 249  
251 250 ret = macvlan_queue_xmit(skb, dev);
252 251 if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
253   - txq->tx_packets++;
254   - txq->tx_bytes += len;
255   - } else
256   - txq->tx_dropped++;
  252 + struct macvlan_pcpu_stats *pcpu_stats;
257 253  
  254 + pcpu_stats = this_cpu_ptr(vlan->pcpu_stats);
  255 + u64_stats_update_begin(&pcpu_stats->syncp);
  256 + pcpu_stats->tx_packets++;
  257 + pcpu_stats->tx_bytes += len;
  258 + u64_stats_update_end(&pcpu_stats->syncp);
  259 + } else {
  260 + this_cpu_inc(vlan->pcpu_stats->tx_dropped);
  261 + }
258 262 return ret;
259 263 }
260 264 EXPORT_SYMBOL_GPL(macvlan_start_xmit);
261 265  
... ... @@ -414,14 +418,15 @@
414 418 dev->state = (dev->state & ~MACVLAN_STATE_MASK) |
415 419 (lowerdev->state & MACVLAN_STATE_MASK);
416 420 dev->features = lowerdev->features & MACVLAN_FEATURES;
  421 + dev->features |= NETIF_F_LLTX;
417 422 dev->gso_max_size = lowerdev->gso_max_size;
418 423 dev->iflink = lowerdev->ifindex;
419 424 dev->hard_header_len = lowerdev->hard_header_len;
420 425  
421 426 macvlan_set_lockdep_class(dev);
422 427  
423   - vlan->rx_stats = alloc_percpu(struct macvlan_rx_stats);
424   - if (!vlan->rx_stats)
  428 + vlan->pcpu_stats = alloc_percpu(struct macvlan_pcpu_stats);
  429 + if (!vlan->pcpu_stats)
425 430 return -ENOMEM;
426 431  
427 432 return 0;
... ... @@ -431,7 +436,7 @@
431 436 {
432 437 struct macvlan_dev *vlan = netdev_priv(dev);
433 438  
434   - free_percpu(vlan->rx_stats);
  439 + free_percpu(vlan->pcpu_stats);
435 440 }
436 441  
437 442 static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev,
438 443  
439 444  
440 445  
441 446  
... ... @@ -439,33 +444,38 @@
439 444 {
440 445 struct macvlan_dev *vlan = netdev_priv(dev);
441 446  
442   - dev_txq_stats_fold(dev, stats);
443   -
444   - if (vlan->rx_stats) {
445   - struct macvlan_rx_stats *p, accum = {0};
446   - u64 rx_packets, rx_bytes, rx_multicast;
  447 + if (vlan->pcpu_stats) {
  448 + struct macvlan_pcpu_stats *p;
  449 + u64 rx_packets, rx_bytes, rx_multicast, tx_packets, tx_bytes;
  450 + u32 rx_errors = 0, tx_dropped = 0;
447 451 unsigned int start;
448 452 int i;
449 453  
450 454 for_each_possible_cpu(i) {
451   - p = per_cpu_ptr(vlan->rx_stats, i);
  455 + p = per_cpu_ptr(vlan->pcpu_stats, i);
452 456 do {
453 457 start = u64_stats_fetch_begin_bh(&p->syncp);
454 458 rx_packets = p->rx_packets;
455 459 rx_bytes = p->rx_bytes;
456 460 rx_multicast = p->rx_multicast;
  461 + tx_packets = p->tx_packets;
  462 + tx_bytes = p->tx_bytes;
457 463 } while (u64_stats_fetch_retry_bh(&p->syncp, start));
458   - accum.rx_packets += rx_packets;
459   - accum.rx_bytes += rx_bytes;
460   - accum.rx_multicast += rx_multicast;
461   - /* rx_errors is an ulong, updated without syncp protection */
462   - accum.rx_errors += p->rx_errors;
  464 +
  465 + stats->rx_packets += rx_packets;
  466 + stats->rx_bytes += rx_bytes;
  467 + stats->multicast += rx_multicast;
  468 + stats->tx_packets += tx_packets;
  469 + stats->tx_bytes += tx_bytes;
  470 + /* rx_errors & tx_dropped are u32, updated
  471 + * without syncp protection.
  472 + */
  473 + rx_errors += p->rx_errors;
  474 + tx_dropped += p->tx_dropped;
463 475 }
464   - stats->rx_packets = accum.rx_packets;
465   - stats->rx_bytes = accum.rx_bytes;
466   - stats->rx_errors = accum.rx_errors;
467   - stats->rx_dropped = accum.rx_errors;
468   - stats->multicast = accum.rx_multicast;
  476 + stats->rx_errors = rx_errors;
  477 + stats->rx_dropped = rx_errors;
  478 + stats->tx_dropped = tx_dropped;
469 479 }
470 480 return stats;
471 481 }
... ... @@ -601,25 +611,6 @@
601 611 return 0;
602 612 }
603 613  
604   -static int macvlan_get_tx_queues(struct net *net,
605   - struct nlattr *tb[],
606   - unsigned int *num_tx_queues,
607   - unsigned int *real_num_tx_queues)
608   -{
609   - struct net_device *real_dev;
610   -
611   - if (!tb[IFLA_LINK])
612   - return -EINVAL;
613   -
614   - real_dev = __dev_get_by_index(net, nla_get_u32(tb[IFLA_LINK]));
615   - if (!real_dev)
616   - return -ENODEV;
617   -
618   - *num_tx_queues = real_dev->num_tx_queues;
619   - *real_num_tx_queues = real_dev->real_num_tx_queues;
620   - return 0;
621   -}
622   -
623 614 int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
624 615 struct nlattr *tb[], struct nlattr *data[],
625 616 int (*receive)(struct sk_buff *skb),
... ... @@ -743,7 +734,6 @@
743 734 {
744 735 /* common fields */
745 736 ops->priv_size = sizeof(struct macvlan_dev);
746   - ops->get_tx_queues = macvlan_get_tx_queues;
747 737 ops->validate = macvlan_validate;
748 738 ops->maxtype = IFLA_MACVLAN_MAX;
749 739 ops->policy = macvlan_policy;
include/linux/if_macvlan.h
... ... @@ -25,19 +25,25 @@
25 25 struct macvtap_queue;
26 26  
27 27 /**
28   - * struct macvlan_rx_stats - MACVLAN percpu rx stats
  28 + * struct macvlan_pcpu_stats - MACVLAN percpu stats
29 29 * @rx_packets: number of received packets
30 30 * @rx_bytes: number of received bytes
31 31 * @rx_multicast: number of received multicast packets
  32 + * @tx_packets: number of transmitted packets
  33 + * @tx_bytes: number of transmitted bytes
32 34 * @syncp: synchronization point for 64bit counters
33   - * @rx_errors: number of errors
  35 + * @rx_errors: number of rx errors
  36 + * @tx_dropped: number of tx dropped packets
34 37 */
35   -struct macvlan_rx_stats {
  38 +struct macvlan_pcpu_stats {
36 39 u64 rx_packets;
37 40 u64 rx_bytes;
38 41 u64 rx_multicast;
  42 + u64 tx_packets;
  43 + u64 tx_bytes;
39 44 struct u64_stats_sync syncp;
40   - unsigned long rx_errors;
  45 + u32 rx_errors;
  46 + u32 tx_dropped;
41 47 };
42 48  
43 49 /*
... ... @@ -52,7 +58,7 @@
52 58 struct hlist_node hlist;
53 59 struct macvlan_port *port;
54 60 struct net_device *lowerdev;
55   - struct macvlan_rx_stats __percpu *rx_stats;
  61 + struct macvlan_pcpu_stats __percpu *pcpu_stats;
56 62 enum macvlan_mode mode;
57 63 int (*receive)(struct sk_buff *skb);
58 64 int (*forward)(struct net_device *dev, struct sk_buff *skb);
59 65  
60 66  
61 67  
... ... @@ -64,18 +70,18 @@
64 70 unsigned int len, bool success,
65 71 bool multicast)
66 72 {
67   - struct macvlan_rx_stats *rx_stats;
68   -
69   - rx_stats = this_cpu_ptr(vlan->rx_stats);
70 73 if (likely(success)) {
71   - u64_stats_update_begin(&rx_stats->syncp);
72   - rx_stats->rx_packets++;
73   - rx_stats->rx_bytes += len;
  74 + struct macvlan_pcpu_stats *pcpu_stats;
  75 +
  76 + pcpu_stats = this_cpu_ptr(vlan->pcpu_stats);
  77 + u64_stats_update_begin(&pcpu_stats->syncp);
  78 + pcpu_stats->rx_packets++;
  79 + pcpu_stats->rx_bytes += len;
74 80 if (multicast)
75   - rx_stats->rx_multicast++;
76   - u64_stats_update_end(&rx_stats->syncp);
  81 + pcpu_stats->rx_multicast++;
  82 + u64_stats_update_end(&pcpu_stats->syncp);
77 83 } else {
78   - rx_stats->rx_errors++;
  84 + this_cpu_inc(vlan->pcpu_stats->rx_errors);
79 85 }
80 86 }
81 87