Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Eric Dumazet and committed by
David S. Miller
8ffab51b 0e3125c7

+55 -59
+35 -45
drivers/net/macvlan.c
··· 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); ··· 418 414 dev->state = (dev->state & ~MACVLAN_STATE_MASK) | 419 415 (lowerdev->state & MACVLAN_STATE_MASK); 420 416 dev->features = lowerdev->features & MACVLAN_FEATURES; 417 + dev->features |= NETIF_F_LLTX; 421 418 dev->gso_max_size = lowerdev->gso_max_size; 422 419 dev->iflink = lowerdev->ifindex; 423 420 dev->hard_header_len = lowerdev->hard_header_len; 424 421 425 422 macvlan_set_lockdep_class(dev); 426 423 427 - vlan->rx_stats = alloc_percpu(struct macvlan_rx_stats); 428 - if (!vlan->rx_stats) 424 + vlan->pcpu_stats = alloc_percpu(struct macvlan_pcpu_stats); 425 + if (!vlan->pcpu_stats) 429 426 return -ENOMEM; 430 427 431 428 return 0; ··· 436 431 { 437 432 struct macvlan_dev *vlan = netdev_priv(dev); 438 433 439 - free_percpu(vlan->rx_stats); 434 + free_percpu(vlan->pcpu_stats); 440 435 } 441 436 442 437 static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev, ··· 444 439 { 445 440 struct macvlan_dev *vlan = netdev_priv(dev); 446 441 447 - dev_txq_stats_fold(dev, stats); 448 - 449 - if (vlan->rx_stats) { 450 - struct macvlan_rx_stats *p, accum = {0}; 451 - u64 rx_packets, rx_bytes, rx_multicast; 442 + if (vlan->pcpu_stats) { 443 + struct macvlan_pcpu_stats *p; 444 + u64 rx_packets, rx_bytes, rx_multicast, tx_packets, tx_bytes; 445 + u32 rx_errors = 0, tx_dropped = 0; 452 446 unsigned int start; 453 447 int i; 454 448 455 449 for_each_possible_cpu(i) { 456 - p = per_cpu_ptr(vlan->rx_stats, i); 450 + p = per_cpu_ptr(vlan->pcpu_stats, i); 457 451 do { 458 452 start = u64_stats_fetch_begin_bh(&p->syncp); 459 453 rx_packets = p->rx_packets; 460 454 rx_bytes = p->rx_bytes; 461 455 rx_multicast = p->rx_multicast; 456 + tx_packets = p->tx_packets; 457 + tx_bytes = p->tx_bytes; 462 458 } while (u64_stats_fetch_retry_bh(&p->syncp, start)); 463 - accum.rx_packets += rx_packets; 464 - accum.rx_bytes += rx_bytes; 465 - accum.rx_multicast += rx_multicast; 466 - /* rx_errors is an ulong, updated without syncp protection */ 467 - accum.rx_errors += p->rx_errors; 459 + 460 + stats->rx_packets += rx_packets; 461 + stats->rx_bytes += rx_bytes; 462 + stats->multicast += rx_multicast; 463 + stats->tx_packets += tx_packets; 464 + stats->tx_bytes += tx_bytes; 465 + /* rx_errors & tx_dropped are u32, updated 466 + * without syncp protection. 467 + */ 468 + rx_errors += p->rx_errors; 469 + tx_dropped += p->tx_dropped; 468 470 } 469 - stats->rx_packets = accum.rx_packets; 470 - stats->rx_bytes = accum.rx_bytes; 471 - stats->rx_errors = accum.rx_errors; 472 - stats->rx_dropped = accum.rx_errors; 473 - stats->multicast = accum.rx_multicast; 471 + stats->rx_errors = rx_errors; 472 + stats->rx_dropped = rx_errors; 473 + stats->tx_dropped = tx_dropped; 474 474 } 475 475 return stats; 476 476 } ··· 611 601 return 0; 612 602 } 613 603 614 - static int macvlan_get_tx_queues(struct net *net, 615 - struct nlattr *tb[], 616 - unsigned int *num_tx_queues, 617 - unsigned int *real_num_tx_queues) 618 - { 619 - struct net_device *real_dev; 620 - 621 - if (!tb[IFLA_LINK]) 622 - return -EINVAL; 623 - 624 - real_dev = __dev_get_by_index(net, nla_get_u32(tb[IFLA_LINK])); 625 - if (!real_dev) 626 - return -ENODEV; 627 - 628 - *num_tx_queues = real_dev->num_tx_queues; 629 - *real_num_tx_queues = real_dev->real_num_tx_queues; 630 - return 0; 631 - } 632 - 633 604 int macvlan_common_newlink(struct net *src_net, struct net_device *dev, 634 605 struct nlattr *tb[], struct nlattr *data[], 635 606 int (*receive)(struct sk_buff *skb), ··· 734 743 { 735 744 /* common fields */ 736 745 ops->priv_size = sizeof(struct macvlan_dev); 737 - ops->get_tx_queues = macvlan_get_tx_queues; 738 746 ops->validate = macvlan_validate; 739 747 ops->maxtype = IFLA_MACVLAN_MAX; 740 748 ops->policy = macvlan_policy;
+20 -14
include/linux/if_macvlan.h
··· 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 /* ··· 58 52 struct hlist_node hlist; 59 53 struct macvlan_port *port; 60 54 struct net_device *lowerdev; 61 - struct macvlan_rx_stats __percpu *rx_stats; 55 + struct macvlan_pcpu_stats __percpu *pcpu_stats; 62 56 enum macvlan_mode mode; 63 57 int (*receive)(struct sk_buff *skb); 64 58 int (*forward)(struct net_device *dev, struct sk_buff *skb); ··· 70 64 unsigned int len, bool success, 71 65 bool multicast) 72 66 { 73 - struct macvlan_rx_stats *rx_stats; 74 - 75 - rx_stats = this_cpu_ptr(vlan->rx_stats); 76 67 if (likely(success)) { 77 - u64_stats_update_begin(&rx_stats->syncp); 78 - rx_stats->rx_packets++; 79 - rx_stats->rx_bytes += len; 68 + struct macvlan_pcpu_stats *pcpu_stats; 69 + 70 + pcpu_stats = this_cpu_ptr(vlan->pcpu_stats); 71 + u64_stats_update_begin(&pcpu_stats->syncp); 72 + pcpu_stats->rx_packets++; 73 + pcpu_stats->rx_bytes += len; 80 74 if (multicast) 81 - rx_stats->rx_multicast++; 82 - u64_stats_update_end(&rx_stats->syncp); 75 + pcpu_stats->rx_multicast++; 76 + u64_stats_update_end(&pcpu_stats->syncp); 83 77 } else { 84 - rx_stats->rx_errors++; 78 + this_cpu_inc(vlan->pcpu_stats->rx_errors); 85 79 } 86 80 } 87 81