get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/817699/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 817699,
    "url": "http://patchwork.ozlabs.org/api/patches/817699/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/netdev/patch/20170922204915.7889-3-peterpenkov96@gmail.com/",
    "project": {
        "id": 7,
        "url": "http://patchwork.ozlabs.org/api/projects/7/?format=api",
        "name": "Linux network development",
        "link_name": "netdev",
        "list_id": "netdev.vger.kernel.org",
        "list_email": "netdev@vger.kernel.org",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20170922204915.7889-3-peterpenkov96@gmail.com>",
    "list_archive_url": null,
    "date": "2017-09-22T20:49:15",
    "name": "[v3,net-next,2/2] tun: enable napi_gro_frags() for TUN/TAP driver",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "52a593ed3b3528b927d1ba78c4cab98c564caff7",
    "submitter": {
        "id": 72387,
        "url": "http://patchwork.ozlabs.org/api/people/72387/?format=api",
        "name": "Petar Penkov",
        "email": "peterpenkov96@gmail.com"
    },
    "delegate": {
        "id": 34,
        "url": "http://patchwork.ozlabs.org/api/users/34/?format=api",
        "username": "davem",
        "first_name": "David",
        "last_name": "Miller",
        "email": "davem@davemloft.net"
    },
    "mbox": "http://patchwork.ozlabs.org/project/netdev/patch/20170922204915.7889-3-peterpenkov96@gmail.com/mbox/",
    "series": [
        {
            "id": 4708,
            "url": "http://patchwork.ozlabs.org/api/series/4708/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/netdev/list/?series=4708",
            "date": "2017-09-22T20:49:13",
            "name": "Improve code coverage of syzkaller",
            "version": 3,
            "mbox": "http://patchwork.ozlabs.org/series/4708/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/817699/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/817699/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<netdev-owner@vger.kernel.org>",
        "X-Original-To": "patchwork-incoming@ozlabs.org",
        "Delivered-To": "patchwork-incoming@ozlabs.org",
        "Authentication-Results": [
            "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=vger.kernel.org\n\t(client-ip=209.132.180.67; helo=vger.kernel.org;\n\tenvelope-from=netdev-owner@vger.kernel.org;\n\treceiver=<UNKNOWN>)",
            "ozlabs.org; dkim=pass (2048-bit key;\n\tunprotected) header.d=gmail.com header.i=@gmail.com\n\theader.b=\"Cc5qAZuA\"; dkim-atps=neutral"
        ],
        "Received": [
            "from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id 3xzQZw160Kz9s7c\n\tfor <patchwork-incoming@ozlabs.org>;\n\tSat, 23 Sep 2017 06:49:44 +1000 (AEST)",
            "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1752165AbdIVUtm (ORCPT <rfc822;patchwork-incoming@ozlabs.org>);\n\tFri, 22 Sep 2017 16:49:42 -0400",
            "from mail-pf0-f194.google.com ([209.85.192.194]:33876 \"EHLO\n\tmail-pf0-f194.google.com\" rhost-flags-OK-OK-OK-OK) by vger.kernel.org\n\twith ESMTP id S1752094AbdIVUtf (ORCPT\n\t<rfc822;netdev@vger.kernel.org>); Fri, 22 Sep 2017 16:49:35 -0400",
            "by mail-pf0-f194.google.com with SMTP id g65so912882pfe.1\n\tfor <netdev@vger.kernel.org>; Fri, 22 Sep 2017 13:49:34 -0700 (PDT)",
            "from petey-VirtualBox ([128.12.253.5])\n\tby smtp.gmail.com with ESMTPSA id\n\td190sm838533pgc.11.2017.09.22.13.49.33\n\t(version=TLS1 cipher=ECDHE-RSA-AES128-SHA bits=128/128);\n\tFri, 22 Sep 2017 13:49:33 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=gmail.com; s=20161025;\n\th=from:to:cc:subject:date:message-id:in-reply-to:references;\n\tbh=/h6N++3TxfGAfCTRHsgcTfKoQu+V73w75CbkaAeoz/o=;\n\tb=Cc5qAZuAX59dXfPHFRKxnUebUunvKWCa+ZqGPIlbZ2PqJm9k5pM6oyna5Ji+/OXOHb\n\t4hsMw1BrqC4qPEqvZmf38821H3DIvjnzI4o1KnVIEbizSpckd3tgQ0zvBIeFlszmZyy+\n\tHFBSNpgfOPORTAnqcGaGdm5qKQN6uvkvfHctv4HC+WrNxNmTJmQa5fS3VbGhyxNDQOSd\n\to05h9QvP9cqM0YyDCtzLZ5xCOq3ua+ZS6GJDxJB/RXaL+/DfhelhvSISm6hywLL8Fqy8\n\tXiQKP75T+efKwSPbI6YSM8n2Td0tF6gkHPffez6Q05J12TvZM93MaBHdDJB8QSpqjxrO\n\tiflQ==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references;\n\tbh=/h6N++3TxfGAfCTRHsgcTfKoQu+V73w75CbkaAeoz/o=;\n\tb=S9yRFadN2X/mBqsHYBOHqd1PjkEWSH47abzRGUfdmNQFY8L4CT1Q6TWUtiipyzPILQ\n\tdksOvX9H1Del1TKOGBgLBUF1K0blGQ+dhCc54QSmr6/z83pkG2L9iK4zd2D5pSxqrYAD\n\ts8B0T8zJpEaHVqSspvZNkS4tnjJrX3J4YoUFQ2Pdt2Hb9pJEGI1tMGaId9XgiKgYCAFq\n\t2ao5b0FQA4g1Sw/gB5UE/LdS/KMvrsjC6cUjVxjiDZirgcrXmjZWNRPoPSsISvFJeJY4\n\tcMQUeclSunzlfxU3l5uk+saHc5G4VS8glyQfItVT/oLOraBDgO/lrikxEQz+jWTcqhO1\n\tAJRQ==",
        "X-Gm-Message-State": "AHPjjUgCKSYth+SnCN6G9Iu90z1X1CcP7v/ZeEgLo9GEvPKKSTYvy3Rn\n\tNtdDTAnVhX4HEV4OQ81gQFo=",
        "X-Google-Smtp-Source": "AOwi7QDx4Bjeqor2X0wYy/NxS8sYB/eEYM1VYc8EbrE0kBHavNx9g5ZQ1UWt6SWgjgNbG/IL6/AdAQ==",
        "X-Received": "by 10.84.238.198 with SMTP id l6mr332659pln.152.1506113374451;\n\tFri, 22 Sep 2017 13:49:34 -0700 (PDT)",
        "From": "Petar Penkov <peterpenkov96@gmail.com>",
        "To": "netdev@vger.kernel.org",
        "Cc": "edumazet@google.com, maheshb@google.com, willemb@google.com,\n\tdavem@davemloft.net, ppenkov@stanford.edu,\n\tPetar Penkov <peterpenkov96@gmail.com>",
        "Subject": "[PATCH, v3,\n\tnet-next 2/2] tun: enable napi_gro_frags() for TUN/TAP driver",
        "Date": "Fri, 22 Sep 2017 13:49:15 -0700",
        "Message-Id": "<20170922204915.7889-3-peterpenkov96@gmail.com>",
        "X-Mailer": "git-send-email 2.11.0",
        "In-Reply-To": "<20170922204915.7889-1-peterpenkov96@gmail.com>",
        "References": "<20170922204915.7889-1-peterpenkov96@gmail.com>",
        "Sender": "netdev-owner@vger.kernel.org",
        "Precedence": "bulk",
        "List-ID": "<netdev.vger.kernel.org>",
        "X-Mailing-List": "netdev@vger.kernel.org"
    },
    "content": "Add a TUN/TAP receive mode that exercises the napi_gro_frags()\ninterface. This mode is available only in TAP mode, as the interface\nexpects packets with Ethernet headers.\n\nFurthermore, packets follow the layout of the iovec_iter that was\nreceived. The first iovec is the linear data, and every one after the\nfirst is a fragment. If there are more fragments than the max number,\ndrop the packet. Additionally, invoke eth_get_headlen() to exercise flow\ndissector code and to verify that the header resides in the linear data.\n\nThe napi_gro_frags() mode requires setting the IFF_NAPI_FRAGS option.\nThis is imposed because this mode is intended for testing via tools like\nsyzkaller and packetdrill, and the increased flexibility it provides can\nintroduce security vulnerabilities. This flag is accepted only if the\ndevice is in TAP mode and has the IFF_NAPI flag set as well. This is\ndone because both of these are explicit requirements for correct\noperation in this mode.\n\nSigned-off-by: Petar Penkov <peterpenkov96@gmail.com>\nCc: Eric Dumazet <edumazet@google.com>\nCc: Mahesh Bandewar <maheshb@google.com>\nCc: Willem de Bruijn <willemb@google.com>\nCc: davem@davemloft.net\nCc: ppenkov@stanford.edu\n---\n drivers/net/tun.c           | 134 ++++++++++++++++++++++++++++++++++++++++++--\n include/uapi/linux/if_tun.h |   1 +\n 2 files changed, 129 insertions(+), 6 deletions(-)",
    "diff": "diff --git a/drivers/net/tun.c b/drivers/net/tun.c\nindex f16407242b18..9880b3bc8fa5 100644\n--- a/drivers/net/tun.c\n+++ b/drivers/net/tun.c\n@@ -75,6 +75,7 @@\n #include <linux/skb_array.h>\n #include <linux/bpf.h>\n #include <linux/bpf_trace.h>\n+#include <linux/mutex.h>\n \n #include <linux/uaccess.h>\n \n@@ -121,7 +122,8 @@ do {\t\t\t\t\t\t\t\t\\\n #define TUN_VNET_BE     0x40000000\n \n #define TUN_FEATURES (IFF_NO_PI | IFF_ONE_QUEUE | IFF_VNET_HDR | \\\n-\t\t      IFF_MULTI_QUEUE | IFF_NAPI)\n+\t\t      IFF_MULTI_QUEUE | IFF_NAPI | IFF_NAPI_FRAGS)\n+\n #define GOODCOPY_LEN 128\n \n #define FLT_EXACT_COUNT 8\n@@ -173,6 +175,7 @@ struct tun_file {\n \t\tunsigned int ifindex;\n \t};\n \tstruct napi_struct napi;\n+\tstruct mutex napi_mutex;\t/* Protects access to the above napi */\n \tstruct list_head next;\n \tstruct tun_struct *detached;\n \tstruct skb_array tx_array;\n@@ -277,6 +280,7 @@ static void tun_napi_init(struct tun_struct *tun, struct tun_file *tfile,\n \t\tnetif_napi_add(tun->dev, &tfile->napi, tun_napi_poll,\n \t\t\t       NAPI_POLL_WEIGHT);\n \t\tnapi_enable(&tfile->napi);\n+\t\tmutex_init(&tfile->napi_mutex);\n \t}\n }\n \n@@ -292,6 +296,11 @@ static void tun_napi_del(struct tun_struct *tun, struct tun_file *tfile)\n \t\tnetif_napi_del(&tfile->napi);\n }\n \n+static bool tun_napi_frags_enabled(const struct tun_struct *tun)\n+{\n+\treturn READ_ONCE(tun->flags) & IFF_NAPI_FRAGS;\n+}\n+\n #ifdef CONFIG_TUN_VNET_CROSS_LE\n static inline bool tun_legacy_is_little_endian(struct tun_struct *tun)\n {\n@@ -1036,7 +1045,8 @@ static void tun_poll_controller(struct net_device *dev)\n \t * supports polling, which enables bridge devices in virt setups to\n \t * still use netconsole\n \t * If NAPI is enabled, however, we need to schedule polling for all\n-\t * queues.\n+\t * queues unless we are using napi_gro_frags(), which we call in\n+\t * process context and not in NAPI context.\n \t */\n \tstruct tun_struct *tun = netdev_priv(dev);\n \n@@ -1044,6 +1054,9 @@ static void tun_poll_controller(struct net_device *dev)\n \t\tstruct tun_file *tfile;\n \t\tint i;\n \n+\t\tif (tun_napi_frags_enabled(tun))\n+\t\t\treturn;\n+\n \t\trcu_read_lock();\n \t\tfor (i = 0; i < tun->numqueues; i++) {\n \t\t\ttfile = rcu_dereference(tun->tfiles[i]);\n@@ -1266,6 +1279,64 @@ static unsigned int tun_chr_poll(struct file *file, poll_table *wait)\n \treturn mask;\n }\n \n+static struct sk_buff *tun_napi_alloc_frags(struct tun_file *tfile,\n+\t\t\t\t\t    size_t len,\n+\t\t\t\t\t    const struct iov_iter *it)\n+{\n+\tstruct sk_buff *skb;\n+\tsize_t linear;\n+\tint err;\n+\tint i;\n+\n+\tif (it->nr_segs > MAX_SKB_FRAGS + 1)\n+\t\treturn ERR_PTR(-ENOMEM);\n+\n+\tlocal_bh_disable();\n+\tskb = napi_get_frags(&tfile->napi);\n+\tlocal_bh_enable();\n+\tif (!skb)\n+\t\treturn ERR_PTR(-ENOMEM);\n+\n+\tlinear = iov_iter_single_seg_count(it);\n+\terr = __skb_grow(skb, linear);\n+\tif (err)\n+\t\tgoto free;\n+\n+\tskb->len = len;\n+\tskb->data_len = len - linear;\n+\tskb->truesize += skb->data_len;\n+\n+\tfor (i = 1; i < it->nr_segs; i++) {\n+\t\tsize_t fragsz = it->iov[i].iov_len;\n+\t\tunsigned long offset;\n+\t\tstruct page *page;\n+\t\tvoid *data;\n+\n+\t\tif (fragsz == 0 || fragsz > PAGE_SIZE) {\n+\t\t\terr = -EINVAL;\n+\t\t\tgoto free;\n+\t\t}\n+\n+\t\tlocal_bh_disable();\n+\t\tdata = napi_alloc_frag(fragsz);\n+\t\tlocal_bh_enable();\n+\t\tif (!data) {\n+\t\t\terr = -ENOMEM;\n+\t\t\tgoto free;\n+\t\t}\n+\n+\t\tpage = virt_to_head_page(data);\n+\t\toffset = data - page_address(page);\n+\t\tskb_fill_page_desc(skb, i - 1, page, offset, fragsz);\n+\t}\n+\n+\treturn skb;\n+free:\n+\t/* frees skb and all frags allocated with napi_alloc_frag() */\n+\tnapi_free_frags(&tfile->napi);\n+\treturn ERR_PTR(err);\n+}\n+\n /* prepad is the amount to reserve at front.  len is length after that.\n  * linear is a hint as to how much to copy (usually headers). */\n static struct sk_buff *tun_alloc_skb(struct tun_file *tfile,\n@@ -1478,6 +1549,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,\n \tint err;\n \tu32 rxhash;\n \tint skb_xdp = 1;\n+\tbool frags = tun_napi_frags_enabled(tun);\n \n \tif (!(tun->dev->flags & IFF_UP))\n \t\treturn -EIO;\n@@ -1535,7 +1607,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,\n \t\t\tzerocopy = true;\n \t}\n \n-\tif (tun_can_build_skb(tun, tfile, len, noblock, zerocopy)) {\n+\tif (!frags && tun_can_build_skb(tun, tfile, len, noblock, zerocopy)) {\n \t\t/* For the packet that is not easy to be processed\n \t\t * (e.g gso or jumbo packet), we will do it at after\n \t\t * skb was created with generic XDP routine.\n@@ -1556,10 +1628,24 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,\n \t\t\t\tlinear = tun16_to_cpu(tun, gso.hdr_len);\n \t\t}\n \n-\t\tskb = tun_alloc_skb(tfile, align, copylen, linear, noblock);\n+\t\tif (frags) {\n+\t\t\tmutex_lock(&tfile->napi_mutex);\n+\t\t\tskb = tun_napi_alloc_frags(tfile, copylen, from);\n+\t\t\t/* tun_napi_alloc_frags() enforces a layout for the skb.\n+\t\t\t * If zerocopy is enabled, then this layout will be\n+\t\t\t * overwritten by zerocopy_sg_from_iter().\n+\t\t\t */\n+\t\t\tzerocopy = false;\n+\t\t} else {\n+\t\t\tskb = tun_alloc_skb(tfile, align, copylen, linear,\n+\t\t\t\t\t    noblock);\n+\t\t}\n+\n \t\tif (IS_ERR(skb)) {\n \t\t\tif (PTR_ERR(skb) != -EAGAIN)\n \t\t\t\tthis_cpu_inc(tun->pcpu_stats->rx_dropped);\n+\t\t\tif (frags)\n+\t\t\t\tmutex_unlock(&tfile->napi_mutex);\n \t\t\treturn PTR_ERR(skb);\n \t\t}\n \n@@ -1571,6 +1657,11 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,\n \t\tif (err) {\n \t\t\tthis_cpu_inc(tun->pcpu_stats->rx_dropped);\n \t\t\tkfree_skb(skb);\n+\t\t\tif (frags) {\n+\t\t\t\ttfile->napi.skb = NULL;\n+\t\t\t\tmutex_unlock(&tfile->napi_mutex);\n+\t\t\t}\n+\n \t\t\treturn -EFAULT;\n \t\t}\n \t}\n@@ -1578,6 +1669,11 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,\n \tif (virtio_net_hdr_to_skb(skb, &gso, tun_is_little_endian(tun))) {\n \t\tthis_cpu_inc(tun->pcpu_stats->rx_frame_errors);\n \t\tkfree_skb(skb);\n+\t\tif (frags) {\n+\t\t\ttfile->napi.skb = NULL;\n+\t\t\tmutex_unlock(&tfile->napi_mutex);\n+\t\t}\n+\n \t\treturn -EINVAL;\n \t}\n \n@@ -1603,7 +1699,8 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,\n \t\tskb->dev = tun->dev;\n \t\tbreak;\n \tcase IFF_TAP:\n-\t\tskb->protocol = eth_type_trans(skb, tun->dev);\n+\t\tif (!frags)\n+\t\t\tskb->protocol = eth_type_trans(skb, tun->dev);\n \t\tbreak;\n \t}\n \n@@ -1638,7 +1735,23 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,\n \n \trxhash = __skb_get_hash_symmetric(skb);\n \n-\tif (tun->flags & IFF_NAPI) {\n+\tif (frags) {\n+\t\t/* Exercise flow dissector code path. */\n+\t\tu32 headlen = eth_get_headlen(skb->data, skb_headlen(skb));\n+\n+\t\tif (headlen > skb_headlen(skb) || headlen < ETH_HLEN) {\n+\t\t\tthis_cpu_inc(tun->pcpu_stats->rx_dropped);\n+\t\t\tnapi_free_frags(&tfile->napi);\n+\t\t\tmutex_unlock(&tfile->napi_mutex);\n+\t\t\tWARN_ON(1);\n+\t\t\treturn -ENOMEM;\n+\t\t}\n+\n+\t\tlocal_bh_disable();\n+\t\tnapi_gro_frags(&tfile->napi);\n+\t\tlocal_bh_enable();\n+\t\tmutex_unlock(&tfile->napi_mutex);\n+\t} else if (tun->flags & IFF_NAPI) {\n \t\tstruct sk_buff_head *queue = &tfile->sk.sk_write_queue;\n \t\tint queue_len;\n \n@@ -2061,6 +2174,15 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)\n \tif (tfile->detached)\n \t\treturn -EINVAL;\n \n+\tif ((ifr->ifr_flags & IFF_NAPI_FRAGS)) {\n+\t\tif (!capable(CAP_NET_ADMIN))\n+\t\t\treturn -EPERM;\n+\n+\t\tif (!(ifr->ifr_flags & IFF_NAPI) ||\n+\t\t    (ifr->ifr_flags & TUN_TYPE_MASK) != IFF_TAP)\n+\t\t\treturn -EINVAL;\n+\t}\n+\n \tdev = __dev_get_by_name(net, ifr->ifr_name);\n \tif (dev) {\n \t\tif (ifr->ifr_flags & IFF_TUN_EXCL)\ndiff --git a/include/uapi/linux/if_tun.h b/include/uapi/linux/if_tun.h\nindex 30b6184884eb..365ade5685c9 100644\n--- a/include/uapi/linux/if_tun.h\n+++ b/include/uapi/linux/if_tun.h\n@@ -61,6 +61,7 @@\n #define IFF_TUN\t\t0x0001\n #define IFF_TAP\t\t0x0002\n #define IFF_NAPI\t0x0010\n+#define IFF_NAPI_FRAGS\t0x0020\n #define IFF_NO_PI\t0x1000\n /* This flag has no real effect */\n #define IFF_ONE_QUEUE\t0x2000\n",
    "prefixes": [
        "v3",
        "net-next",
        "2/2"
    ]
}