diff options
Diffstat (limited to 'drivers/net/macvlan.c')
-rw-r--r-- | drivers/net/macvlan.c | 113 |
1 files changed, 67 insertions, 46 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 0fc9dc7f20db..6ed577b065df 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c | |||
@@ -38,6 +38,7 @@ struct macvlan_port { | |||
38 | struct hlist_head vlan_hash[MACVLAN_HASH_SIZE]; | 38 | struct hlist_head vlan_hash[MACVLAN_HASH_SIZE]; |
39 | struct list_head vlans; | 39 | struct list_head vlans; |
40 | struct rcu_head rcu; | 40 | struct rcu_head rcu; |
41 | bool passthru; | ||
41 | }; | 42 | }; |
42 | 43 | ||
43 | #define macvlan_port_get_rcu(dev) \ | 44 | #define macvlan_port_get_rcu(dev) \ |
@@ -169,6 +170,7 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) | |||
169 | macvlan_broadcast(skb, port, NULL, | 170 | macvlan_broadcast(skb, port, NULL, |
170 | MACVLAN_MODE_PRIVATE | | 171 | MACVLAN_MODE_PRIVATE | |
171 | MACVLAN_MODE_VEPA | | 172 | MACVLAN_MODE_VEPA | |
173 | MACVLAN_MODE_PASSTHRU| | ||
172 | MACVLAN_MODE_BRIDGE); | 174 | MACVLAN_MODE_BRIDGE); |
173 | else if (src->mode == MACVLAN_MODE_VEPA) | 175 | else if (src->mode == MACVLAN_MODE_VEPA) |
174 | /* flood to everyone except source */ | 176 | /* flood to everyone except source */ |
@@ -185,7 +187,10 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) | |||
185 | return skb; | 187 | return skb; |
186 | } | 188 | } |
187 | 189 | ||
188 | vlan = macvlan_hash_lookup(port, eth->h_dest); | 190 | if (port->passthru) |
191 | vlan = list_first_entry(&port->vlans, struct macvlan_dev, list); | ||
192 | else | ||
193 | vlan = macvlan_hash_lookup(port, eth->h_dest); | ||
189 | if (vlan == NULL) | 194 | if (vlan == NULL) |
190 | return skb; | 195 | return skb; |
191 | 196 | ||
@@ -243,18 +248,22 @@ xmit_world: | |||
243 | netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, | 248 | netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, |
244 | struct net_device *dev) | 249 | struct net_device *dev) |
245 | { | 250 | { |
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; | 251 | unsigned int len = skb->len; |
249 | int ret; | 252 | int ret; |
253 | const struct macvlan_dev *vlan = netdev_priv(dev); | ||
250 | 254 | ||
251 | ret = macvlan_queue_xmit(skb, dev); | 255 | ret = macvlan_queue_xmit(skb, dev); |
252 | if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) { | 256 | if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) { |
253 | txq->tx_packets++; | 257 | struct macvlan_pcpu_stats *pcpu_stats; |
254 | txq->tx_bytes += len; | ||
255 | } else | ||
256 | txq->tx_dropped++; | ||
257 | 258 | ||
259 | pcpu_stats = this_cpu_ptr(vlan->pcpu_stats); | ||
260 | u64_stats_update_begin(&pcpu_stats->syncp); | ||
261 | pcpu_stats->tx_packets++; | ||
262 | pcpu_stats->tx_bytes += len; | ||
263 | u64_stats_update_end(&pcpu_stats->syncp); | ||
264 | } else { | ||
265 | this_cpu_inc(vlan->pcpu_stats->tx_dropped); | ||
266 | } | ||
258 | return ret; | 267 | return ret; |
259 | } | 268 | } |
260 | EXPORT_SYMBOL_GPL(macvlan_start_xmit); | 269 | EXPORT_SYMBOL_GPL(macvlan_start_xmit); |
@@ -284,6 +293,11 @@ static int macvlan_open(struct net_device *dev) | |||
284 | struct net_device *lowerdev = vlan->lowerdev; | 293 | struct net_device *lowerdev = vlan->lowerdev; |
285 | int err; | 294 | int err; |
286 | 295 | ||
296 | if (vlan->port->passthru) { | ||
297 | dev_set_promiscuity(lowerdev, 1); | ||
298 | goto hash_add; | ||
299 | } | ||
300 | |||
287 | err = -EBUSY; | 301 | err = -EBUSY; |
288 | if (macvlan_addr_busy(vlan->port, dev->dev_addr)) | 302 | if (macvlan_addr_busy(vlan->port, dev->dev_addr)) |
289 | goto out; | 303 | goto out; |
@@ -296,6 +310,8 @@ static int macvlan_open(struct net_device *dev) | |||
296 | if (err < 0) | 310 | if (err < 0) |
297 | goto del_unicast; | 311 | goto del_unicast; |
298 | } | 312 | } |
313 | |||
314 | hash_add: | ||
299 | macvlan_hash_add(vlan); | 315 | macvlan_hash_add(vlan); |
300 | return 0; | 316 | return 0; |
301 | 317 | ||
@@ -310,12 +326,18 @@ static int macvlan_stop(struct net_device *dev) | |||
310 | struct macvlan_dev *vlan = netdev_priv(dev); | 326 | struct macvlan_dev *vlan = netdev_priv(dev); |
311 | struct net_device *lowerdev = vlan->lowerdev; | 327 | struct net_device *lowerdev = vlan->lowerdev; |
312 | 328 | ||
329 | if (vlan->port->passthru) { | ||
330 | dev_set_promiscuity(lowerdev, -1); | ||
331 | goto hash_del; | ||
332 | } | ||
333 | |||
313 | dev_mc_unsync(lowerdev, dev); | 334 | dev_mc_unsync(lowerdev, dev); |
314 | if (dev->flags & IFF_ALLMULTI) | 335 | if (dev->flags & IFF_ALLMULTI) |
315 | dev_set_allmulti(lowerdev, -1); | 336 | dev_set_allmulti(lowerdev, -1); |
316 | 337 | ||
317 | dev_uc_del(lowerdev, dev->dev_addr); | 338 | dev_uc_del(lowerdev, dev->dev_addr); |
318 | 339 | ||
340 | hash_del: | ||
319 | macvlan_hash_del(vlan); | 341 | macvlan_hash_del(vlan); |
320 | return 0; | 342 | return 0; |
321 | } | 343 | } |
@@ -414,14 +436,15 @@ static int macvlan_init(struct net_device *dev) | |||
414 | dev->state = (dev->state & ~MACVLAN_STATE_MASK) | | 436 | dev->state = (dev->state & ~MACVLAN_STATE_MASK) | |
415 | (lowerdev->state & MACVLAN_STATE_MASK); | 437 | (lowerdev->state & MACVLAN_STATE_MASK); |
416 | dev->features = lowerdev->features & MACVLAN_FEATURES; | 438 | dev->features = lowerdev->features & MACVLAN_FEATURES; |
439 | dev->features |= NETIF_F_LLTX; | ||
417 | dev->gso_max_size = lowerdev->gso_max_size; | 440 | dev->gso_max_size = lowerdev->gso_max_size; |
418 | dev->iflink = lowerdev->ifindex; | 441 | dev->iflink = lowerdev->ifindex; |
419 | dev->hard_header_len = lowerdev->hard_header_len; | 442 | dev->hard_header_len = lowerdev->hard_header_len; |
420 | 443 | ||
421 | macvlan_set_lockdep_class(dev); | 444 | macvlan_set_lockdep_class(dev); |
422 | 445 | ||
423 | vlan->rx_stats = alloc_percpu(struct macvlan_rx_stats); | 446 | vlan->pcpu_stats = alloc_percpu(struct macvlan_pcpu_stats); |
424 | if (!vlan->rx_stats) | 447 | if (!vlan->pcpu_stats) |
425 | return -ENOMEM; | 448 | return -ENOMEM; |
426 | 449 | ||
427 | return 0; | 450 | return 0; |
@@ -431,7 +454,7 @@ static void macvlan_uninit(struct net_device *dev) | |||
431 | { | 454 | { |
432 | struct macvlan_dev *vlan = netdev_priv(dev); | 455 | struct macvlan_dev *vlan = netdev_priv(dev); |
433 | 456 | ||
434 | free_percpu(vlan->rx_stats); | 457 | free_percpu(vlan->pcpu_stats); |
435 | } | 458 | } |
436 | 459 | ||
437 | static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev, | 460 | static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev, |
@@ -439,33 +462,38 @@ static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev, | |||
439 | { | 462 | { |
440 | struct macvlan_dev *vlan = netdev_priv(dev); | 463 | struct macvlan_dev *vlan = netdev_priv(dev); |
441 | 464 | ||
442 | dev_txq_stats_fold(dev, stats); | 465 | if (vlan->pcpu_stats) { |
443 | 466 | struct macvlan_pcpu_stats *p; | |
444 | if (vlan->rx_stats) { | 467 | u64 rx_packets, rx_bytes, rx_multicast, tx_packets, tx_bytes; |
445 | struct macvlan_rx_stats *p, accum = {0}; | 468 | u32 rx_errors = 0, tx_dropped = 0; |
446 | u64 rx_packets, rx_bytes, rx_multicast; | ||
447 | unsigned int start; | 469 | unsigned int start; |
448 | int i; | 470 | int i; |
449 | 471 | ||
450 | for_each_possible_cpu(i) { | 472 | for_each_possible_cpu(i) { |
451 | p = per_cpu_ptr(vlan->rx_stats, i); | 473 | p = per_cpu_ptr(vlan->pcpu_stats, i); |
452 | do { | 474 | do { |
453 | start = u64_stats_fetch_begin_bh(&p->syncp); | 475 | start = u64_stats_fetch_begin_bh(&p->syncp); |
454 | rx_packets = p->rx_packets; | 476 | rx_packets = p->rx_packets; |
455 | rx_bytes = p->rx_bytes; | 477 | rx_bytes = p->rx_bytes; |
456 | rx_multicast = p->rx_multicast; | 478 | rx_multicast = p->rx_multicast; |
479 | tx_packets = p->tx_packets; | ||
480 | tx_bytes = p->tx_bytes; | ||
457 | } while (u64_stats_fetch_retry_bh(&p->syncp, start)); | 481 | } while (u64_stats_fetch_retry_bh(&p->syncp, start)); |
458 | accum.rx_packets += rx_packets; | 482 | |
459 | accum.rx_bytes += rx_bytes; | 483 | stats->rx_packets += rx_packets; |
460 | accum.rx_multicast += rx_multicast; | 484 | stats->rx_bytes += rx_bytes; |
461 | /* rx_errors is an ulong, updated without syncp protection */ | 485 | stats->multicast += rx_multicast; |
462 | accum.rx_errors += p->rx_errors; | 486 | stats->tx_packets += tx_packets; |
487 | stats->tx_bytes += tx_bytes; | ||
488 | /* rx_errors & tx_dropped are u32, updated | ||
489 | * without syncp protection. | ||
490 | */ | ||
491 | rx_errors += p->rx_errors; | ||
492 | tx_dropped += p->tx_dropped; | ||
463 | } | 493 | } |
464 | stats->rx_packets = accum.rx_packets; | 494 | stats->rx_errors = rx_errors; |
465 | stats->rx_bytes = accum.rx_bytes; | 495 | stats->rx_dropped = rx_errors; |
466 | stats->rx_errors = accum.rx_errors; | 496 | stats->tx_dropped = tx_dropped; |
467 | stats->rx_dropped = accum.rx_errors; | ||
468 | stats->multicast = accum.rx_multicast; | ||
469 | } | 497 | } |
470 | return stats; | 498 | return stats; |
471 | } | 499 | } |
@@ -549,6 +577,7 @@ static int macvlan_port_create(struct net_device *dev) | |||
549 | if (port == NULL) | 577 | if (port == NULL) |
550 | return -ENOMEM; | 578 | return -ENOMEM; |
551 | 579 | ||
580 | port->passthru = false; | ||
552 | port->dev = dev; | 581 | port->dev = dev; |
553 | INIT_LIST_HEAD(&port->vlans); | 582 | INIT_LIST_HEAD(&port->vlans); |
554 | for (i = 0; i < MACVLAN_HASH_SIZE; i++) | 583 | for (i = 0; i < MACVLAN_HASH_SIZE; i++) |
@@ -593,6 +622,7 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) | |||
593 | case MACVLAN_MODE_PRIVATE: | 622 | case MACVLAN_MODE_PRIVATE: |
594 | case MACVLAN_MODE_VEPA: | 623 | case MACVLAN_MODE_VEPA: |
595 | case MACVLAN_MODE_BRIDGE: | 624 | case MACVLAN_MODE_BRIDGE: |
625 | case MACVLAN_MODE_PASSTHRU: | ||
596 | break; | 626 | break; |
597 | default: | 627 | default: |
598 | return -EINVAL; | 628 | return -EINVAL; |
@@ -601,25 +631,6 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) | |||
601 | return 0; | 631 | return 0; |
602 | } | 632 | } |
603 | 633 | ||
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 | int macvlan_common_newlink(struct net *src_net, struct net_device *dev, | 634 | int macvlan_common_newlink(struct net *src_net, struct net_device *dev, |
624 | struct nlattr *tb[], struct nlattr *data[], | 635 | struct nlattr *tb[], struct nlattr *data[], |
625 | int (*receive)(struct sk_buff *skb), | 636 | int (*receive)(struct sk_buff *skb), |
@@ -661,6 +672,10 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, | |||
661 | } | 672 | } |
662 | port = macvlan_port_get(lowerdev); | 673 | port = macvlan_port_get(lowerdev); |
663 | 674 | ||
675 | /* Only 1 macvlan device can be created in passthru mode */ | ||
676 | if (port->passthru) | ||
677 | return -EINVAL; | ||
678 | |||
664 | vlan->lowerdev = lowerdev; | 679 | vlan->lowerdev = lowerdev; |
665 | vlan->dev = dev; | 680 | vlan->dev = dev; |
666 | vlan->port = port; | 681 | vlan->port = port; |
@@ -671,6 +686,13 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, | |||
671 | if (data && data[IFLA_MACVLAN_MODE]) | 686 | if (data && data[IFLA_MACVLAN_MODE]) |
672 | vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); | 687 | vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); |
673 | 688 | ||
689 | if (vlan->mode == MACVLAN_MODE_PASSTHRU) { | ||
690 | if (!list_empty(&port->vlans)) | ||
691 | return -EINVAL; | ||
692 | port->passthru = true; | ||
693 | memcpy(dev->dev_addr, lowerdev->dev_addr, ETH_ALEN); | ||
694 | } | ||
695 | |||
674 | err = register_netdevice(dev); | 696 | err = register_netdevice(dev); |
675 | if (err < 0) | 697 | if (err < 0) |
676 | goto destroy_port; | 698 | goto destroy_port; |
@@ -743,7 +765,6 @@ int macvlan_link_register(struct rtnl_link_ops *ops) | |||
743 | { | 765 | { |
744 | /* common fields */ | 766 | /* common fields */ |
745 | ops->priv_size = sizeof(struct macvlan_dev); | 767 | ops->priv_size = sizeof(struct macvlan_dev); |
746 | ops->get_tx_queues = macvlan_get_tx_queues; | ||
747 | ops->validate = macvlan_validate; | 768 | ops->validate = macvlan_validate; |
748 | ops->maxtype = IFLA_MACVLAN_MAX; | 769 | ops->maxtype = IFLA_MACVLAN_MAX; |
749 | ops->policy = macvlan_policy; | 770 | ops->policy = macvlan_policy; |