summaryrefslogtreecommitdiffstats
path: root/drivers/net/macvlan.c
diff options
context:
space:
mode:
authorAlexander Duyck <alexander.h.duyck@intel.com>2018-04-03 17:16:09 -0400
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2018-04-25 11:26:19 -0400
commit81d4e91cd599ed7fd378ca5463d6d9b05214b8b2 (patch)
treec02f50fca0ed14ab028413f16abd79967d82ad93 /drivers/net/macvlan.c
parent7d775f63470c3b6ddf34c770c973293ab925a7bb (diff)
macvlan: Use software path for offloaded local, broadcast, and multicast traffic
This change makes it so that we use a software path for packets that are going to be locally switched between two macvlan interfaces on the same device. In addition we resort to software replication of broadcast and multicast packets instead of offloading that to hardware. The general idea is that using the device for east/west traffic local to the system is extremely inefficient. We can only support up to whatever the PCIe limit is for any given device so this caps us at somewhere around 20G for devices supported by ixgbe. This is compounded even further when you take broadcast and multicast into account as a single 10G port can come to a crawl as a packet is replicated up to 60+ times in some cases. In order to get away from that I am implementing changes so that we handle broadcast/multicast replication and east/west local traffic all in software. Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com> Tested-by: Andrew Bowers <andrewx.bowers@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/macvlan.c')
-rw-r--r--drivers/net/macvlan.c47
1 files changed, 21 insertions, 26 deletions
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 7ddc94ff4109..adde8fc45588 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -514,6 +514,7 @@ static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
514 const struct macvlan_dev *vlan = netdev_priv(dev); 514 const struct macvlan_dev *vlan = netdev_priv(dev);
515 const struct macvlan_port *port = vlan->port; 515 const struct macvlan_port *port = vlan->port;
516 const struct macvlan_dev *dest; 516 const struct macvlan_dev *dest;
517 void *accel_priv = NULL;
517 518
518 if (vlan->mode == MACVLAN_MODE_BRIDGE) { 519 if (vlan->mode == MACVLAN_MODE_BRIDGE) {
519 const struct ethhdr *eth = (void *)skb->data; 520 const struct ethhdr *eth = (void *)skb->data;
@@ -533,9 +534,14 @@ static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
533 } 534 }
534 } 535 }
535 536
537 /* For packets that are non-multicast and not bridged we will pass
538 * the necessary information so that the lowerdev can distinguish
539 * the source of the packets via the accel_priv value.
540 */
541 accel_priv = vlan->accel_priv;
536xmit_world: 542xmit_world:
537 skb->dev = vlan->lowerdev; 543 skb->dev = vlan->lowerdev;
538 return dev_queue_xmit(skb); 544 return dev_queue_xmit_accel(skb, accel_priv);
539} 545}
540 546
541static inline netdev_tx_t macvlan_netpoll_send_skb(struct macvlan_dev *vlan, struct sk_buff *skb) 547static inline netdev_tx_t macvlan_netpoll_send_skb(struct macvlan_dev *vlan, struct sk_buff *skb)
@@ -552,19 +558,14 @@ static inline netdev_tx_t macvlan_netpoll_send_skb(struct macvlan_dev *vlan, str
552static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, 558static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
553 struct net_device *dev) 559 struct net_device *dev)
554{ 560{
561 struct macvlan_dev *vlan = netdev_priv(dev);
555 unsigned int len = skb->len; 562 unsigned int len = skb->len;
556 int ret; 563 int ret;
557 struct macvlan_dev *vlan = netdev_priv(dev);
558 564
559 if (unlikely(netpoll_tx_running(dev))) 565 if (unlikely(netpoll_tx_running(dev)))
560 return macvlan_netpoll_send_skb(vlan, skb); 566 return macvlan_netpoll_send_skb(vlan, skb);
561 567
562 if (vlan->accel_priv) { 568 ret = macvlan_queue_xmit(skb, dev);
563 skb->dev = vlan->lowerdev;
564 ret = dev_queue_xmit_accel(skb, vlan->accel_priv);
565 } else {
566 ret = macvlan_queue_xmit(skb, dev);
567 }
568 569
569 if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) { 570 if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
570 struct vlan_pcpu_stats *pcpu_stats; 571 struct vlan_pcpu_stats *pcpu_stats;
@@ -620,26 +621,20 @@ static int macvlan_open(struct net_device *dev)
620 /* Attempt to populate accel_priv which is used to offload the L2 621 /* Attempt to populate accel_priv which is used to offload the L2
621 * forwarding requests for unicast packets. 622 * forwarding requests for unicast packets.
622 */ 623 */
623 if (lowerdev->features & NETIF_F_HW_L2FW_DOFFLOAD) { 624 if (lowerdev->features & NETIF_F_HW_L2FW_DOFFLOAD)
624 vlan->accel_priv = 625 vlan->accel_priv =
625 lowerdev->netdev_ops->ndo_dfwd_add_station(lowerdev, dev); 626 lowerdev->netdev_ops->ndo_dfwd_add_station(lowerdev, dev);
626 627
627 /* If we get a NULL pointer back, or if we get an error 628 /* If earlier attempt to offload failed, or accel_priv is not
628 * then we should just fall through to the non accelerated path 629 * populated we must add the unicast address to the lower device.
629 */ 630 */
630 if (IS_ERR_OR_NULL(vlan->accel_priv)) 631 if (IS_ERR_OR_NULL(vlan->accel_priv)) {
631 vlan->accel_priv = NULL; 632 vlan->accel_priv = NULL;
632 else 633 err = dev_uc_add(lowerdev, dev->dev_addr);
633 return 0; 634 if (err < 0)
635 goto out;
634 } 636 }
635 637
636 err = -EBUSY;
637 if (macvlan_addr_busy(vlan->port, dev->dev_addr))
638 goto out;
639
640 err = dev_uc_add(lowerdev, dev->dev_addr);
641 if (err < 0)
642 goto out;
643 if (dev->flags & IFF_ALLMULTI) { 638 if (dev->flags & IFF_ALLMULTI) {
644 err = dev_set_allmulti(lowerdev, 1); 639 err = dev_set_allmulti(lowerdev, 1);
645 if (err < 0) 640 if (err < 0)
@@ -660,13 +655,14 @@ clear_multi:
660 if (dev->flags & IFF_ALLMULTI) 655 if (dev->flags & IFF_ALLMULTI)
661 dev_set_allmulti(lowerdev, -1); 656 dev_set_allmulti(lowerdev, -1);
662del_unicast: 657del_unicast:
663 dev_uc_del(lowerdev, dev->dev_addr);
664out:
665 if (vlan->accel_priv) { 658 if (vlan->accel_priv) {
666 lowerdev->netdev_ops->ndo_dfwd_del_station(lowerdev, 659 lowerdev->netdev_ops->ndo_dfwd_del_station(lowerdev,
667 vlan->accel_priv); 660 vlan->accel_priv);
668 vlan->accel_priv = NULL; 661 vlan->accel_priv = NULL;
662 } else {
663 dev_uc_del(lowerdev, dev->dev_addr);
669 } 664 }
665out:
670 return err; 666 return err;
671} 667}
672 668
@@ -679,7 +675,6 @@ static int macvlan_stop(struct net_device *dev)
679 lowerdev->netdev_ops->ndo_dfwd_del_station(lowerdev, 675 lowerdev->netdev_ops->ndo_dfwd_del_station(lowerdev,
680 vlan->accel_priv); 676 vlan->accel_priv);
681 vlan->accel_priv = NULL; 677 vlan->accel_priv = NULL;
682 return 0;
683 } 678 }
684 679
685 dev_uc_unsync(lowerdev, dev); 680 dev_uc_unsync(lowerdev, dev);