Merge branches 'cma', 'cxgb4', 'iser', 'misc', 'mlx4', 'mlx5', 'nes', 'ocrdma', ...
[cascardo/linux.git] / drivers / net / macvtap.c
index 2a89da0..ff111a8 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/wait.h>
 #include <linux/cdev.h>
 #include <linux/idr.h>
@@ -70,6 +69,11 @@ static const struct proto_ops macvtap_socket_ops;
 #define RX_OFFLOADS (NETIF_F_GRO | NETIF_F_LRO)
 #define TAP_FEATURES (NETIF_F_GSO | NETIF_F_SG)
 
+static struct macvlan_dev *macvtap_get_vlan_rcu(const struct net_device *dev)
+{
+       return rcu_dereference(dev->rx_handler_data);
+}
+
 /*
  * RCU usage:
  * The macvtap_queue and the macvlan_dev are loosely coupled, the
@@ -219,7 +223,7 @@ static struct macvtap_queue *macvtap_get_queue(struct net_device *dev,
                goto out;
 
        /* Check if we can use flow to select a queue */
-       rxq = skb_get_rxhash(skb);
+       rxq = skb_get_hash(skb);
        if (rxq) {
                tap = rcu_dereference(vlan->taps[rxq % numvtaps]);
                goto out;
@@ -271,24 +275,27 @@ static void macvtap_del_queues(struct net_device *dev)
                sock_put(&qlist[j]->sk);
 }
 
-/*
- * Forward happens for data that gets sent from one macvlan
- * endpoint to another one in bridge mode. We just take
- * the skb and put it into the receive queue.
- */
-static int macvtap_forward(struct net_device *dev, struct sk_buff *skb)
+static rx_handler_result_t macvtap_handle_frame(struct sk_buff **pskb)
 {
-       struct macvlan_dev *vlan = netdev_priv(dev);
-       struct macvtap_queue *q = macvtap_get_queue(dev, skb);
+       struct sk_buff *skb = *pskb;
+       struct net_device *dev = skb->dev;
+       struct macvlan_dev *vlan;
+       struct macvtap_queue *q;
        netdev_features_t features = TAP_FEATURES;
 
+       vlan = macvtap_get_vlan_rcu(dev);
+       if (!vlan)
+               return RX_HANDLER_PASS;
+
+       q = macvtap_get_queue(dev, skb);
        if (!q)
-               goto drop;
+               return RX_HANDLER_PASS;
 
        if (skb_queue_len(&q->sk.sk_receive_queue) >= dev->tx_queue_len)
                goto drop;
 
-       skb->dev = dev;
+       skb_push(skb, ETH_HLEN);
+
        /* Apply the forward feature mask so that we perform segmentation
         * according to users wishes.  This only works if VNET_HDR is
         * enabled.
@@ -320,22 +327,13 @@ static int macvtap_forward(struct net_device *dev, struct sk_buff *skb)
 
 wake_up:
        wake_up_interruptible_poll(sk_sleep(&q->sk), POLLIN | POLLRDNORM | POLLRDBAND);
-       return NET_RX_SUCCESS;
+       return RX_HANDLER_CONSUMED;
 
 drop:
+       /* Count errors/drops only here, thus don't care about args. */
+       macvlan_count_rx(vlan, 0, 0, 0);
        kfree_skb(skb);
-       return NET_RX_DROP;
-}
-
-/*
- * Receive is for data from the external interface (lowerdev),
- * in case of macvtap, we can treat that the same way as
- * forward, which macvlan cannot.
- */
-static int macvtap_receive(struct sk_buff *skb)
-{
-       skb_push(skb, ETH_HLEN);
-       return macvtap_forward(skb->dev, skb);
+       return RX_HANDLER_CONSUMED;
 }
 
 static int macvtap_get_minor(struct macvlan_dev *vlan)
@@ -385,6 +383,8 @@ static int macvtap_newlink(struct net *src_net,
                           struct nlattr *data[])
 {
        struct macvlan_dev *vlan = netdev_priv(dev);
+       int err;
+
        INIT_LIST_HEAD(&vlan->queue_list);
 
        /* Since macvlan supports all offloads by default, make
@@ -392,16 +392,20 @@ static int macvtap_newlink(struct net *src_net,
         */
        vlan->tap_features = TUN_OFFLOADS;
 
+       err = netdev_rx_handler_register(dev, macvtap_handle_frame, vlan);
+       if (err)
+               return err;
+
        /* Don't put anything that may fail after macvlan_common_newlink
         * because we can't undo what it does.
         */
-       return macvlan_common_newlink(src_net, dev, tb, data,
-                                     macvtap_receive, macvtap_forward);
+       return macvlan_common_newlink(src_net, dev, tb, data);
 }
 
 static void macvtap_dellink(struct net_device *dev,
                            struct list_head *head)
 {
+       netdev_rx_handler_unregister(dev);
        macvtap_del_queues(dev);
        macvlan_dellink(dev, head);
 }
@@ -588,7 +592,7 @@ static int macvtap_skb_from_vnet_hdr(struct sk_buff *skb,
        return 0;
 }
 
-static int macvtap_skb_to_vnet_hdr(const struct sk_buff *skb,
+static void macvtap_skb_to_vnet_hdr(const struct sk_buff *skb,
                                   struct virtio_net_hdr *vnet_hdr)
 {
        memset(vnet_hdr, 0, sizeof(*vnet_hdr));
@@ -619,8 +623,6 @@ static int macvtap_skb_to_vnet_hdr(const struct sk_buff *skb,
        } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
                vnet_hdr->flags = VIRTIO_NET_HDR_F_DATA_VALID;
        } /* else everything is zero */
-
-       return 0;
 }
 
 /* Get packet from user space buffer */
@@ -727,9 +729,8 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
                skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
        }
        if (vlan) {
-               local_bh_disable();
-               macvlan_start_xmit(skb, vlan->dev);
-               local_bh_enable();
+               skb->dev = vlan->dev;
+               dev_queue_xmit(skb);
        } else {
                kfree_skb(skb);
        }
@@ -778,9 +779,7 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q,
                if ((len -= vnet_hdr_len) < 0)
                        return -EINVAL;
 
-               ret = macvtap_skb_to_vnet_hdr(skb, &vnet_hdr);
-               if (ret)
-                       return ret;
+               macvtap_skb_to_vnet_hdr(skb, &vnet_hdr);
 
                if (memcpy_toiovecend(iv, (void *)&vnet_hdr, 0, sizeof(vnet_hdr)))
                        return -EFAULT;
@@ -824,7 +823,7 @@ done:
        return ret ? ret : total;
 }
 
-static ssize_t macvtap_do_read(struct macvtap_queue *q, struct kiocb *iocb,
+static ssize_t macvtap_do_read(struct macvtap_queue *q,
                               const struct iovec *iv, unsigned long len,
                               int noblock)
 {
@@ -875,7 +874,7 @@ static ssize_t macvtap_aio_read(struct kiocb *iocb, const struct iovec *iv,
                goto out;
        }
 
-       ret = macvtap_do_read(q, iocb, iv, len, file->f_flags & O_NONBLOCK);
+       ret = macvtap_do_read(q, iv, len, file->f_flags & O_NONBLOCK);
        ret = min_t(ssize_t, ret, len);
        if (ret > 0)
                iocb->ki_pos = ret;
@@ -1109,7 +1108,7 @@ static int macvtap_recvmsg(struct kiocb *iocb, struct socket *sock,
        int ret;
        if (flags & ~(MSG_DONTWAIT|MSG_TRUNC))
                return -EINVAL;
-       ret = macvtap_do_read(q, iocb, m->msg_iov, total_len,
+       ret = macvtap_do_read(q, m->msg_iov, total_len,
                          flags & MSG_DONTWAIT);
        if (ret > total_len) {
                m->msg_flags |= MSG_TRUNC;