Merge tag 'iommu-fix-v5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / drivers / net / tun.c
index fed8544..276a0e4 100644 (file)
@@ -1058,6 +1058,7 @@ static unsigned int run_ebpf_filter(struct tun_struct *tun,
 static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct tun_struct *tun = netdev_priv(dev);
+       enum skb_drop_reason drop_reason;
        int txq = skb->queue_mapping;
        struct netdev_queue *queue;
        struct tun_file *tfile;
@@ -1067,8 +1068,10 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
        tfile = rcu_dereference(tun->tfiles[txq]);
 
        /* Drop packet if interface is not attached */
-       if (!tfile)
+       if (!tfile) {
+               drop_reason = SKB_DROP_REASON_DEV_READY;
                goto drop;
+       }
 
        if (!rcu_dereference(tun->steering_prog))
                tun_automq_xmit(tun, skb);
@@ -1078,19 +1081,32 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Drop if the filter does not like it.
         * This is a noop if the filter is disabled.
         * Filter can be enabled only for the TAP devices. */
-       if (!check_filter(&tun->txflt, skb))
+       if (!check_filter(&tun->txflt, skb)) {
+               drop_reason = SKB_DROP_REASON_TAP_TXFILTER;
                goto drop;
+       }
 
        if (tfile->socket.sk->sk_filter &&
-           sk_filter(tfile->socket.sk, skb))
+           sk_filter(tfile->socket.sk, skb)) {
+               drop_reason = SKB_DROP_REASON_SOCKET_FILTER;
                goto drop;
+       }
 
        len = run_ebpf_filter(tun, skb, len);
-       if (len == 0 || pskb_trim(skb, len))
+       if (len == 0) {
+               drop_reason = SKB_DROP_REASON_TAP_FILTER;
                goto drop;
+       }
+
+       if (pskb_trim(skb, len)) {
+               drop_reason = SKB_DROP_REASON_NOMEM;
+               goto drop;
+       }
 
-       if (unlikely(skb_orphan_frags_rx(skb, GFP_ATOMIC)))
+       if (unlikely(skb_orphan_frags_rx(skb, GFP_ATOMIC))) {
+               drop_reason = SKB_DROP_REASON_SKB_UCOPY_FAULT;
                goto drop;
+       }
 
        skb_tx_timestamp(skb);
 
@@ -1101,8 +1117,10 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
 
        nf_reset_ct(skb);
 
-       if (ptr_ring_produce(&tfile->tx_ring, skb))
+       if (ptr_ring_produce(&tfile->tx_ring, skb)) {
+               drop_reason = SKB_DROP_REASON_FULL_RING;
                goto drop;
+       }
 
        /* NETIF_F_LLTX requires to do our own update of trans_start */
        queue = netdev_get_tx_queue(dev, txq);
@@ -1117,9 +1135,9 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
        return NETDEV_TX_OK;
 
 drop:
-       atomic_long_inc(&dev->tx_dropped);
+       dev_core_stats_tx_dropped_inc(dev);
        skb_tx_error(skb);
-       kfree_skb(skb);
+       kfree_skb_reason(skb, drop_reason);
        rcu_read_unlock();
        return NET_XMIT_DROP;
 }
@@ -1273,7 +1291,7 @@ resample:
                void *frame = tun_xdp_to_ptr(xdp);
 
                if (__ptr_ring_produce(&tfile->tx_ring, frame)) {
-                       atomic_long_inc(&dev->tx_dropped);
+                       dev_core_stats_tx_dropped_inc(dev);
                        break;
                }
                nxmit++;
@@ -1608,7 +1626,7 @@ static int tun_xdp_act(struct tun_struct *tun, struct bpf_prog *xdp_prog,
                trace_xdp_exception(tun->dev, xdp_prog, act);
                fallthrough;
        case XDP_DROP:
-               atomic_long_inc(&tun->dev->rx_dropped);
+               dev_core_stats_rx_dropped_inc(tun->dev);
                break;
        }
 
@@ -1717,6 +1735,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
        u32 rxhash = 0;
        int skb_xdp = 1;
        bool frags = tun_napi_frags_enabled(tfile);
+       enum skb_drop_reason drop_reason;
 
        if (!(tun->flags & IFF_NO_PI)) {
                if (len < sizeof(pi))
@@ -1778,7 +1797,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
                 */
                skb = tun_build_skb(tun, tfile, from, &gso, len, &skb_xdp);
                if (IS_ERR(skb)) {
-                       atomic_long_inc(&tun->dev->rx_dropped);
+                       dev_core_stats_rx_dropped_inc(tun->dev);
                        return PTR_ERR(skb);
                }
                if (!skb)
@@ -1807,7 +1826,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
 
                if (IS_ERR(skb)) {
                        if (PTR_ERR(skb) != -EAGAIN)
-                               atomic_long_inc(&tun->dev->rx_dropped);
+                               dev_core_stats_rx_dropped_inc(tun->dev);
                        if (frags)
                                mutex_unlock(&tfile->napi_mutex);
                        return PTR_ERR(skb);
@@ -1820,9 +1839,10 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
 
                if (err) {
                        err = -EFAULT;
+                       drop_reason = SKB_DROP_REASON_SKB_UCOPY_FAULT;
 drop:
-                       atomic_long_inc(&tun->dev->rx_dropped);
-                       kfree_skb(skb);
+                       dev_core_stats_rx_dropped_inc(tun->dev);
+                       kfree_skb_reason(skb, drop_reason);
                        if (frags) {
                                tfile->napi.skb = NULL;
                                mutex_unlock(&tfile->napi_mutex);
@@ -1856,7 +1876,7 @@ drop:
                                pi.proto = htons(ETH_P_IPV6);
                                break;
                        default:
-                               atomic_long_inc(&tun->dev->rx_dropped);
+                               dev_core_stats_rx_dropped_inc(tun->dev);
                                kfree_skb(skb);
                                return -EINVAL;
                        }
@@ -1869,6 +1889,7 @@ drop:
        case IFF_TAP:
                if (frags && !pskb_may_pull(skb, ETH_HLEN)) {
                        err = -ENOMEM;
+                       drop_reason = SKB_DROP_REASON_HDR_TRUNC;
                        goto drop;
                }
                skb->protocol = eth_type_trans(skb, tun->dev);
@@ -1922,6 +1943,7 @@ drop:
        if (unlikely(!(tun->dev->flags & IFF_UP))) {
                err = -EIO;
                rcu_read_unlock();
+               drop_reason = SKB_DROP_REASON_DEV_READY;
                goto drop;
        }
 
@@ -1934,7 +1956,7 @@ drop:
                                          skb_headlen(skb));
 
                if (unlikely(headlen > skb_headlen(skb))) {
-                       atomic_long_inc(&tun->dev->rx_dropped);
+                       dev_core_stats_rx_dropped_inc(tun->dev);
                        napi_free_frags(&tfile->napi);
                        rcu_read_unlock();
                        mutex_unlock(&tfile->napi_mutex);
@@ -1962,7 +1984,7 @@ drop:
        } else if (!IS_ENABLED(CONFIG_4KSTACKS)) {
                tun_rx_batched(tun, tfile, skb, more);
        } else {
-               netif_rx_ni(skb);
+               netif_rx(skb);
        }
        rcu_read_unlock();
 
@@ -2388,9 +2410,10 @@ static int tun_xdp_one(struct tun_struct *tun,
        struct virtio_net_hdr *gso = &hdr->gso;
        struct bpf_prog *xdp_prog;
        struct sk_buff *skb = NULL;
+       struct sk_buff_head *queue;
        u32 rxhash = 0, act;
        int buflen = hdr->buflen;
-       int err = 0;
+       int ret = 0;
        bool skb_xdp = false;
        struct page *page;
 
@@ -2405,13 +2428,13 @@ static int tun_xdp_one(struct tun_struct *tun,
                xdp_set_data_meta_invalid(xdp);
 
                act = bpf_prog_run_xdp(xdp_prog, xdp);
-               err = tun_xdp_act(tun, xdp_prog, xdp, act);
-               if (err < 0) {
+               ret = tun_xdp_act(tun, xdp_prog, xdp, act);
+               if (ret < 0) {
                        put_page(virt_to_head_page(xdp->data));
-                       return err;
+                       return ret;
                }
 
-               switch (err) {
+               switch (ret) {
                case XDP_REDIRECT:
                        *flush = true;
                        fallthrough;
@@ -2435,7 +2458,7 @@ static int tun_xdp_one(struct tun_struct *tun,
 build:
        skb = build_skb(xdp->data_hard_start, buflen);
        if (!skb) {
-               err = -ENOMEM;
+               ret = -ENOMEM;
                goto out;
        }
 
@@ -2445,7 +2468,7 @@ build:
        if (virtio_net_hdr_to_skb(skb, gso, tun_is_little_endian(tun))) {
                atomic_long_inc(&tun->rx_frame_errors);
                kfree_skb(skb);
-               err = -EINVAL;
+               ret = -EINVAL;
                goto out;
        }
 
@@ -2455,16 +2478,27 @@ build:
        skb_record_rx_queue(skb, tfile->queue_index);
 
        if (skb_xdp) {
-               err = do_xdp_generic(xdp_prog, skb);
-               if (err != XDP_PASS)
+               ret = do_xdp_generic(xdp_prog, skb);
+               if (ret != XDP_PASS) {
+                       ret = 0;
                        goto out;
+               }
        }
 
        if (!rcu_dereference(tun->steering_prog) && tun->numqueues > 1 &&
            !tfile->detached)
                rxhash = __skb_get_hash_symmetric(skb);
 
-       netif_receive_skb(skb);
+       if (tfile->napi_enabled) {
+               queue = &tfile->sk.sk_write_queue;
+               spin_lock(&queue->lock);
+               __skb_queue_tail(queue, skb);
+               spin_unlock(&queue->lock);
+               ret = 1;
+       } else {
+               netif_receive_skb(skb);
+               ret = 0;
+       }
 
        /* No need to disable preemption here since this function is
         * always called with bh disabled
@@ -2475,7 +2509,7 @@ build:
                tun_flow_update(tun, rxhash, tfile);
 
 out:
-       return err;
+       return ret;
 }
 
 static int tun_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len)
@@ -2489,10 +2523,11 @@ static int tun_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len)
        if (!tun)
                return -EBADFD;
 
-       if (ctl && (ctl->type == TUN_MSG_PTR)) {
+       if (m->msg_controllen == sizeof(struct tun_msg_ctl) &&
+           ctl && ctl->type == TUN_MSG_PTR) {
                struct tun_page tpage;
                int n = ctl->num;
-               int flush = 0;
+               int flush = 0, queued = 0;
 
                memset(&tpage, 0, sizeof(tpage));
 
@@ -2501,12 +2536,17 @@ static int tun_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len)
 
                for (i = 0; i < n; i++) {
                        xdp = &((struct xdp_buff *)ctl->ptr)[i];
-                       tun_xdp_one(tun, tfile, xdp, &flush, &tpage);
+                       ret = tun_xdp_one(tun, tfile, xdp, &flush, &tpage);
+                       if (ret > 0)
+                               queued += ret;
                }
 
                if (flush)
                        xdp_do_flush();
 
+               if (tfile->napi_enabled && queued > 0)
+                       napi_schedule(&tfile->napi);
+
                rcu_read_unlock();
                local_bh_enable();