aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/macvlan.c
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2010-11-10 16:14:04 -0500
committerDavid S. Miller <davem@davemloft.net>2010-11-16 13:58:30 -0500
commit8ffab51b3dfc54876f145f15b351c41f3f703195 (patch)
tree0455321fbdb953e77fecff62345f8414553bc394 /drivers/net/macvlan.c
parent0e3125c755445664f00ad036e4fc2cd32fd52877 (diff)
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>
Diffstat (limited to 'drivers/net/macvlan.c')
-rw-r--r--drivers/net/macvlan.c80
1 files changed, 35 insertions, 45 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 0fc9dc7f20db..93f0ba25c808 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -243,18 +243,22 @@ xmit_world:
243netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, 243netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
244 struct net_device *dev) 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 unsigned int len = skb->len; 246 unsigned int len = skb->len;
249 int ret; 247 int ret;
248 const struct macvlan_dev *vlan = netdev_priv(dev);
250 249
251 ret = macvlan_queue_xmit(skb, dev); 250 ret = macvlan_queue_xmit(skb, dev);
252 if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) { 251 if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
253 txq->tx_packets++; 252 struct macvlan_pcpu_stats *pcpu_stats;
254 txq->tx_bytes += len;
255 } else
256 txq->tx_dropped++;
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 return ret; 262 return ret;
259} 263}
260EXPORT_SYMBOL_GPL(macvlan_start_xmit); 264EXPORT_SYMBOL_GPL(macvlan_start_xmit);
@@ -414,14 +418,15 @@ static int macvlan_init(struct net_device *dev)
414 dev->state = (dev->state & ~MACVLAN_STATE_MASK) | 418 dev->state = (dev->state & ~MACVLAN_STATE_MASK) |
415 (lowerdev->state & MACVLAN_STATE_MASK); 419 (lowerdev->state & MACVLAN_STATE_MASK);
416 dev->features = lowerdev->features & MACVLAN_FEATURES; 420 dev->features = lowerdev->features & MACVLAN_FEATURES;
421 dev->features |= NETIF_F_LLTX;
417 dev->gso_max_size = lowerdev->gso_max_size; 422 dev->gso_max_size = lowerdev->gso_max_size;
418 dev->iflink = lowerdev->ifindex; 423 dev->iflink = lowerdev->ifindex;
419 dev->hard_header_len = lowerdev->hard_header_len; 424 dev->hard_header_len = lowerdev->hard_header_len;
420 425
421 macvlan_set_lockdep_class(dev); 426 macvlan_set_lockdep_class(dev);
422 427
423 vlan->rx_stats = alloc_percpu(struct macvlan_rx_stats); 428 vlan->pcpu_stats = alloc_percpu(struct macvlan_pcpu_stats);
424 if (!vlan->rx_stats) 429 if (!vlan->pcpu_stats)
425 return -ENOMEM; 430 return -ENOMEM;
426 431
427 return 0; 432 return 0;
@@ -431,7 +436,7 @@ static void macvlan_uninit(struct net_device *dev)
431{ 436{
432 struct macvlan_dev *vlan = netdev_priv(dev); 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
437static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev, 442static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev,
@@ -439,33 +444,38 @@ static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev,
439{ 444{
440 struct macvlan_dev *vlan = netdev_priv(dev); 445 struct macvlan_dev *vlan = netdev_priv(dev);
441 446
442 dev_txq_stats_fold(dev, stats); 447 if (vlan->pcpu_stats) {
443 448 struct macvlan_pcpu_stats *p;
444 if (vlan->rx_stats) { 449 u64 rx_packets, rx_bytes, rx_multicast, tx_packets, tx_bytes;
445 struct macvlan_rx_stats *p, accum = {0}; 450 u32 rx_errors = 0, tx_dropped = 0;
446 u64 rx_packets, rx_bytes, rx_multicast;
447 unsigned int start; 451 unsigned int start;
448 int i; 452 int i;
449 453
450 for_each_possible_cpu(i) { 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 do { 456 do {
453 start = u64_stats_fetch_begin_bh(&p->syncp); 457 start = u64_stats_fetch_begin_bh(&p->syncp);
454 rx_packets = p->rx_packets; 458 rx_packets = p->rx_packets;
455 rx_bytes = p->rx_bytes; 459 rx_bytes = p->rx_bytes;
456 rx_multicast = p->rx_multicast; 460 rx_multicast = p->rx_multicast;
461 tx_packets = p->tx_packets;
462 tx_bytes = p->tx_bytes;
457 } while (u64_stats_fetch_retry_bh(&p->syncp, start)); 463 } while (u64_stats_fetch_retry_bh(&p->syncp, start));
458 accum.rx_packets += rx_packets; 464
459 accum.rx_bytes += rx_bytes; 465 stats->rx_packets += rx_packets;
460 accum.rx_multicast += rx_multicast; 466 stats->rx_bytes += rx_bytes;
461 /* rx_errors is an ulong, updated without syncp protection */ 467 stats->multicast += rx_multicast;
462 accum.rx_errors += p->rx_errors; 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; 476 stats->rx_errors = rx_errors;
465 stats->rx_bytes = accum.rx_bytes; 477 stats->rx_dropped = rx_errors;
466 stats->rx_errors = accum.rx_errors; 478 stats->tx_dropped = tx_dropped;
467 stats->rx_dropped = accum.rx_errors;
468 stats->multicast = accum.rx_multicast;
469 } 479 }
470 return stats; 480 return stats;
471} 481}
@@ -601,25 +611,6 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
601 return 0; 611 return 0;
602} 612}
603 613
604static 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
623int macvlan_common_newlink(struct net *src_net, struct net_device *dev, 614int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
624 struct nlattr *tb[], struct nlattr *data[], 615 struct nlattr *tb[], struct nlattr *data[],
625 int (*receive)(struct sk_buff *skb), 616 int (*receive)(struct sk_buff *skb),
@@ -743,7 +734,6 @@ int macvlan_link_register(struct rtnl_link_ops *ops)
743{ 734{
744 /* common fields */ 735 /* common fields */
745 ops->priv_size = sizeof(struct macvlan_dev); 736 ops->priv_size = sizeof(struct macvlan_dev);
746 ops->get_tx_queues = macvlan_get_tx_queues;
747 ops->validate = macvlan_validate; 737 ops->validate = macvlan_validate;
748 ops->maxtype = IFLA_MACVLAN_MAX; 738 ops->maxtype = IFLA_MACVLAN_MAX;
749 ops->policy = macvlan_policy; 739 ops->policy = macvlan_policy;