]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/net/macvlan.c
macvlan: Use software path for offloaded local, broadcast, and multicast traffic
[linux.git] / drivers / net / macvlan.c
index 7ddc94ff4109c689e79fcbf4f106d0ffd7f2e6fd..adde8fc45588ba12c82bd79cf830e3ed99b907e3 100644 (file)
@@ -514,6 +514,7 @@ static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
        const struct macvlan_dev *vlan = netdev_priv(dev);
        const struct macvlan_port *port = vlan->port;
        const struct macvlan_dev *dest;
+       void *accel_priv = NULL;
 
        if (vlan->mode == MACVLAN_MODE_BRIDGE) {
                const struct ethhdr *eth = (void *)skb->data;
@@ -533,9 +534,14 @@ static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
                }
        }
 
+       /* For packets that are non-multicast and not bridged we will pass
+        * the necessary information so that the lowerdev can distinguish
+        * the source of the packets via the accel_priv value.
+        */
+       accel_priv = vlan->accel_priv;
 xmit_world:
        skb->dev = vlan->lowerdev;
-       return dev_queue_xmit(skb);
+       return dev_queue_xmit_accel(skb, accel_priv);
 }
 
 static 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
 static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
                                      struct net_device *dev)
 {
+       struct macvlan_dev *vlan = netdev_priv(dev);
        unsigned int len = skb->len;
        int ret;
-       struct macvlan_dev *vlan = netdev_priv(dev);
 
        if (unlikely(netpoll_tx_running(dev)))
                return macvlan_netpoll_send_skb(vlan, skb);
 
-       if (vlan->accel_priv) {
-               skb->dev = vlan->lowerdev;
-               ret = dev_queue_xmit_accel(skb, vlan->accel_priv);
-       } else {
-               ret = macvlan_queue_xmit(skb, dev);
-       }
+       ret = macvlan_queue_xmit(skb, dev);
 
        if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
                struct vlan_pcpu_stats *pcpu_stats;
@@ -620,26 +621,20 @@ static int macvlan_open(struct net_device *dev)
        /* Attempt to populate accel_priv which is used to offload the L2
         * forwarding requests for unicast packets.
         */
-       if (lowerdev->features & NETIF_F_HW_L2FW_DOFFLOAD) {
+       if (lowerdev->features & NETIF_F_HW_L2FW_DOFFLOAD)
                vlan->accel_priv =
                      lowerdev->netdev_ops->ndo_dfwd_add_station(lowerdev, dev);
 
-               /* If we get a NULL pointer back, or if we get an error
-                * then we should just fall through to the non accelerated path
-                */
-               if (IS_ERR_OR_NULL(vlan->accel_priv))
-                       vlan->accel_priv = NULL;
-               else
-                       return 0;
+       /* If earlier attempt to offload failed, or accel_priv is not
+        * populated we must add the unicast address to the lower device.
+        */
+       if (IS_ERR_OR_NULL(vlan->accel_priv)) {
+               vlan->accel_priv = NULL;
+               err = dev_uc_add(lowerdev, dev->dev_addr);
+               if (err < 0)
+                       goto out;
        }
 
-       err = -EBUSY;
-       if (macvlan_addr_busy(vlan->port, dev->dev_addr))
-               goto out;
-
-       err = dev_uc_add(lowerdev, dev->dev_addr);
-       if (err < 0)
-               goto out;
        if (dev->flags & IFF_ALLMULTI) {
                err = dev_set_allmulti(lowerdev, 1);
                if (err < 0)
@@ -660,13 +655,14 @@ static int macvlan_open(struct net_device *dev)
        if (dev->flags & IFF_ALLMULTI)
                dev_set_allmulti(lowerdev, -1);
 del_unicast:
-       dev_uc_del(lowerdev, dev->dev_addr);
-out:
        if (vlan->accel_priv) {
                lowerdev->netdev_ops->ndo_dfwd_del_station(lowerdev,
                                                           vlan->accel_priv);
                vlan->accel_priv = NULL;
+       } else {
+               dev_uc_del(lowerdev, dev->dev_addr);
        }
+out:
        return err;
 }
 
@@ -679,7 +675,6 @@ static int macvlan_stop(struct net_device *dev)
                lowerdev->netdev_ops->ndo_dfwd_del_station(lowerdev,
                                                           vlan->accel_priv);
                vlan->accel_priv = NULL;
-               return 0;
        }
 
        dev_uc_unsync(lowerdev, dev);