get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 833935,
    "url": "http://patchwork.ozlabs.org/api/1.2/patches/833935/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/netdev/patch/20171103152636.9967-4-pablo@netfilter.org/",
    "project": {
        "id": 7,
        "url": "http://patchwork.ozlabs.org/api/1.2/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": "<20171103152636.9967-4-pablo@netfilter.org>",
    "list_archive_url": null,
    "date": "2017-11-03T15:26:34",
    "name": "[RFC,WIP,3/5] netfilter: nf_flow_offload: integration with conntrack",
    "commit_ref": null,
    "pull_url": null,
    "state": "rfc",
    "archived": true,
    "hash": "7b0df0ad95ad9ebba003a1ea1bffa0dc3c477f5c",
    "submitter": {
        "id": 1315,
        "url": "http://patchwork.ozlabs.org/api/1.2/people/1315/?format=api",
        "name": "Pablo Neira Ayuso",
        "email": "pablo@netfilter.org"
    },
    "delegate": {
        "id": 34,
        "url": "http://patchwork.ozlabs.org/api/1.2/users/34/?format=api",
        "username": "davem",
        "first_name": "David",
        "last_name": "Miller",
        "email": "davem@davemloft.net"
    },
    "mbox": "http://patchwork.ozlabs.org/project/netdev/patch/20171103152636.9967-4-pablo@netfilter.org/mbox/",
    "series": [
        {
            "id": 11752,
            "url": "http://patchwork.ozlabs.org/api/1.2/series/11752/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/netdev/list/?series=11752",
            "date": "2017-11-03T15:26:31",
            "name": "Flow offload infrastructure",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/11752/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/833935/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/833935/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>)",
        "Received": [
            "from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id 3yT5RQ4ZXDz9s7M\n\tfor <patchwork-incoming@ozlabs.org>;\n\tSat,  4 Nov 2017 02:27:14 +1100 (AEDT)",
            "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1755721AbdKCP1L (ORCPT <rfc822;patchwork-incoming@ozlabs.org>);\n\tFri, 3 Nov 2017 11:27:11 -0400",
            "from mail.us.es ([193.147.175.20]:43330 \"EHLO mail.us.es\"\n\trhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP\n\tid S1755865AbdKCP0s (ORCPT <rfc822;netdev@vger.kernel.org>);\n\tFri, 3 Nov 2017 11:26:48 -0400",
            "from antivirus1-rhel7.int (unknown [192.168.2.11])\n\tby mail.us.es (Postfix) with ESMTP id 10876C0B3F\n\tfor <netdev@vger.kernel.org>; Fri,  3 Nov 2017 16:26:47 +0100 (CET)",
            "from antivirus1-rhel7.int (localhost [127.0.0.1])\n\tby antivirus1-rhel7.int (Postfix) with ESMTP id F1E4BB7FE9\n\tfor <netdev@vger.kernel.org>; Fri,  3 Nov 2017 16:26:46 +0100 (CET)",
            "by antivirus1-rhel7.int (Postfix, from userid 99)\n\tid E7AA2B7FE3; Fri,  3 Nov 2017 16:26:46 +0100 (CET)",
            "from antivirus1-rhel7.int (localhost [127.0.0.1])\n\tby antivirus1-rhel7.int (Postfix) with ESMTP id 8AD81B7FE5;\n\tFri,  3 Nov 2017 16:26:44 +0100 (CET)",
            "from 192.168.1.97 (192.168.1.97) by antivirus1-rhel7.int\n\t(F-Secure/fsigk_smtp/550/antivirus1-rhel7.int); \n\tFri, 03 Nov 2017 16:26:44 +0100 (CET)",
            "from salvia.here (unknown [31.4.245.115])\n\t(Authenticated sender: pneira@us.es)\n\tby entrada.int (Postfix) with ESMTPA id 4D810403DFA1;\n\tFri,  3 Nov 2017 16:26:44 +0100 (CET)"
        ],
        "X-Spam-Checker-Version": "SpamAssassin 3.4.1 (2015-04-28) on\n\tantivirus1-rhel7.int",
        "X-Spam-Level": "",
        "X-Spam-Status": "No, score=-108.2 required=7.5 tests=ALL_TRUSTED,BAYES_50,\n\tSMTPAUTH_US2,USER_IN_WHITELIST autolearn=disabled version=3.4.1",
        "X-Virus-Status": "clean(F-Secure/fsigk_smtp/550/antivirus1-rhel7.int)",
        "X-SMTPAUTHUS": "auth mail.us.es",
        "From": "Pablo Neira Ayuso <pablo@netfilter.org>",
        "To": "netfilter-devel@vger.kernel.org",
        "Cc": "netdev@vger.kernel.org",
        "Subject": "[PATCH RFC,\n\tWIP 3/5] netfilter: nf_flow_offload: integration with conntrack",
        "Date": "Fri,  3 Nov 2017 16:26:34 +0100",
        "Message-Id": "<20171103152636.9967-4-pablo@netfilter.org>",
        "X-Mailer": "git-send-email 2.11.0",
        "In-Reply-To": "<20171103152636.9967-1-pablo@netfilter.org>",
        "References": "<20171103152636.9967-1-pablo@netfilter.org>",
        "X-Virus-Scanned": "ClamAV using ClamSMTP",
        "Sender": "netdev-owner@vger.kernel.org",
        "Precedence": "bulk",
        "List-ID": "<netdev.vger.kernel.org>",
        "X-Mailing-List": "netdev@vger.kernel.org"
    },
    "content": "This patch adds the IPS_OFFLOAD status bit, this new bit tells us that\nthe conntrack entry is owned by the flow offload infrastructure. The\ntimer of such conntrack entries is stopped - the conntrack garbage\ncollector skips them - and they display no internal state in the case of\nTCP flows.\n\n # cat /proc/net/nf_conntrack\n ipv4     2 tcp      6 src=10.141.10.2 dst=147.75.205.195 sport=36392 dport=443 src=147.75.205.195 dst=192.168.2.195 sport=443 dport=36392 [OFFLOAD] mark=0 zone=0 use=2\n\nNote the [OFFLOAD] tag in the listing.\n\nConntrack entries that have been offloaded to the flow table\ninfrastructure cannot be deleted/flushed via ctnetlink. The flow table\ninfrastructure is also responsible for releasing this conntrack entry.\n\nSigned-off-by: Pablo Neira Ayuso <pablo@netfilter.org>\n---\nInstead of nf_flow_release_ct(), I'd rather keep a pointer reference to\nthe conntrack object from the flow_offload entry, so we can skip the\nconntrack look up.\n\n include/net/netfilter/nf_conntrack.h               |  3 +-\n include/uapi/linux/netfilter/nf_conntrack_common.h |  4 +++\n net/netfilter/nf_conntrack_core.c                  |  7 ++++-\n net/netfilter/nf_conntrack_netlink.c               | 15 ++++++++-\n net/netfilter/nf_conntrack_proto_tcp.c             |  3 ++\n net/netfilter/nf_conntrack_standalone.c            | 12 +++++---\n net/netfilter/nf_flow_offload.c                    | 36 ++++++++++++++++++++--\n 7 files changed, 71 insertions(+), 9 deletions(-)",
    "diff": "diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h\nindex 8f3bd30511de..9af4bb0c2f46 100644\n--- a/include/net/netfilter/nf_conntrack.h\n+++ b/include/net/netfilter/nf_conntrack.h\n@@ -272,7 +272,8 @@ static inline unsigned long nf_ct_expires(const struct nf_conn *ct)\n \n static inline bool nf_ct_is_expired(const struct nf_conn *ct)\n {\n-\treturn (__s32)(ct->timeout - nfct_time_stamp) <= 0;\n+\treturn (__s32)(ct->timeout - nfct_time_stamp) <= 0 &&\n+\t       !test_bit(IPS_OFFLOAD_BIT, &ct->status);\n }\n \n /* use after obtaining a reference count */\ndiff --git a/include/uapi/linux/netfilter/nf_conntrack_common.h b/include/uapi/linux/netfilter/nf_conntrack_common.h\nindex dc947e59d03a..6b463b88182d 100644\n--- a/include/uapi/linux/netfilter/nf_conntrack_common.h\n+++ b/include/uapi/linux/netfilter/nf_conntrack_common.h\n@@ -100,6 +100,10 @@ enum ip_conntrack_status {\n \tIPS_HELPER_BIT = 13,\n \tIPS_HELPER = (1 << IPS_HELPER_BIT),\n \n+\t/* Conntrack has been offloaded to flow table. */\n+\tIPS_OFFLOAD_BIT = 14,\n+\tIPS_OFFLOAD = (1 << IPS_OFFLOAD_BIT),\n+\n \t/* Be careful here, modifying these bits can make things messy,\n \t * so don't let users modify them directly.\n \t */\ndiff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c\nindex 01130392b7c0..48f36c4fb756 100644\n--- a/net/netfilter/nf_conntrack_core.c\n+++ b/net/netfilter/nf_conntrack_core.c\n@@ -901,6 +901,9 @@ static unsigned int early_drop_list(struct net *net,\n \thlist_nulls_for_each_entry_rcu(h, n, head, hnnode) {\n \t\ttmp = nf_ct_tuplehash_to_ctrack(h);\n \n+\t\tif (test_bit(IPS_OFFLOAD_BIT, &tmp->status))\n+\t\t\tcontinue;\n+\n \t\tif (nf_ct_is_expired(tmp)) {\n \t\t\tnf_ct_gc_expired(tmp);\n \t\t\tcontinue;\n@@ -1011,12 +1014,14 @@ static void gc_worker(struct work_struct *work)\n \t\t\ttmp = nf_ct_tuplehash_to_ctrack(h);\n \n \t\t\tscanned++;\n+\t\t\tif (test_bit(IPS_OFFLOAD_BIT, &tmp->status))\n+\t\t\t\tcontinue;\n+\n \t\t\tif (nf_ct_is_expired(tmp)) {\n \t\t\t\tnf_ct_gc_expired(tmp);\n \t\t\t\texpired_count++;\n \t\t\t\tcontinue;\n \t\t\t}\n-\n \t\t\tif (nf_conntrack_max95 == 0 || gc_worker_skip_ct(tmp))\n \t\t\t\tcontinue;\n \ndiff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c\nindex de4053d84364..79a74aec7c1e 100644\n--- a/net/netfilter/nf_conntrack_netlink.c\n+++ b/net/netfilter/nf_conntrack_netlink.c\n@@ -1105,6 +1105,14 @@ static const struct nla_policy ct_nla_policy[CTA_MAX+1] = {\n \t\t\t\t    .len = NF_CT_LABELS_MAX_SIZE },\n };\n \n+static int ctnetlink_flush_iterate(struct nf_conn *ct, void *data)\n+{\n+\tif (test_bit(IPS_OFFLOAD_BIT, &ct->status))\n+\t\treturn 0;\n+\n+\treturn ctnetlink_filter_match(ct, data);\n+}\n+\n static int ctnetlink_flush_conntrack(struct net *net,\n \t\t\t\t     const struct nlattr * const cda[],\n \t\t\t\t     u32 portid, int report)\n@@ -1117,7 +1125,7 @@ static int ctnetlink_flush_conntrack(struct net *net,\n \t\t\treturn PTR_ERR(filter);\n \t}\n \n-\tnf_ct_iterate_cleanup_net(net, ctnetlink_filter_match, filter,\n+\tnf_ct_iterate_cleanup_net(net, ctnetlink_flush_iterate, filter,\n \t\t\t\t  portid, report);\n \tkfree(filter);\n \n@@ -1163,6 +1171,11 @@ static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl,\n \n \tct = nf_ct_tuplehash_to_ctrack(h);\n \n+\tif (test_bit(IPS_OFFLOAD_BIT, &ct->status)) {\n+\t\tnf_ct_put(ct);\n+\t\treturn -EBUSY;\n+\t}\n+\n \tif (cda[CTA_ID]) {\n \t\tu_int32_t id = ntohl(nla_get_be32(cda[CTA_ID]));\n \t\tif (id != (u32)(unsigned long)ct) {\ndiff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c\nindex cba1c6ffe51a..156f529d1668 100644\n--- a/net/netfilter/nf_conntrack_proto_tcp.c\n+++ b/net/netfilter/nf_conntrack_proto_tcp.c\n@@ -305,6 +305,9 @@ static bool tcp_invert_tuple(struct nf_conntrack_tuple *tuple,\n /* Print out the private part of the conntrack. */\n static void tcp_print_conntrack(struct seq_file *s, struct nf_conn *ct)\n {\n+\tif (test_bit(IPS_OFFLOAD_BIT, &ct->status))\n+\t\treturn;\n+\n \tseq_printf(s, \"%s \", tcp_conntrack_names[ct->proto.tcp.state]);\n }\n #endif\ndiff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c\nindex 5a101caa3e12..46d32baad095 100644\n--- a/net/netfilter/nf_conntrack_standalone.c\n+++ b/net/netfilter/nf_conntrack_standalone.c\n@@ -309,10 +309,12 @@ static int ct_seq_show(struct seq_file *s, void *v)\n \tWARN_ON(!l4proto);\n \n \tret = -ENOSPC;\n-\tseq_printf(s, \"%-8s %u %-8s %u %ld \",\n+\tseq_printf(s, \"%-8s %u %-8s %u \",\n \t\t   l3proto_name(l3proto->l3proto), nf_ct_l3num(ct),\n-\t\t   l4proto_name(l4proto->l4proto), nf_ct_protonum(ct),\n-\t\t   nf_ct_expires(ct)  / HZ);\n+\t\t   l4proto_name(l4proto->l4proto), nf_ct_protonum(ct));\n+\n+\tif (!test_bit(IPS_OFFLOAD_BIT, &ct->status))\n+\t\tseq_printf(s, \"%ld \", nf_ct_expires(ct)  / HZ);\n \n \tif (l4proto->print_conntrack)\n \t\tl4proto->print_conntrack(s, ct);\n@@ -339,7 +341,9 @@ static int ct_seq_show(struct seq_file *s, void *v)\n \tif (seq_print_acct(s, ct, IP_CT_DIR_REPLY))\n \t\tgoto release;\n \n-\tif (test_bit(IPS_ASSURED_BIT, &ct->status))\n+\tif (test_bit(IPS_OFFLOAD_BIT, &ct->status))\n+\t\tseq_puts(s, \"[OFFLOAD] \");\n+\telse if (test_bit(IPS_ASSURED_BIT, &ct->status))\n \t\tseq_puts(s, \"[ASSURED] \");\n \n \tif (seq_has_overflowed(s))\ndiff --git a/net/netfilter/nf_flow_offload.c b/net/netfilter/nf_flow_offload.c\nindex c967b29d11a6..f4a3fbe11b69 100644\n--- a/net/netfilter/nf_flow_offload.c\n+++ b/net/netfilter/nf_flow_offload.c\n@@ -13,6 +13,9 @@\n #include <linux/udp.h>\n #include <linux/icmpv6.h>\n \n+#include <net/netfilter/nf_conntrack_core.h>\n+#include <net/netfilter/nf_conntrack_tuple.h>\n+\n static struct rhashtable flow_table;\n \n static u32 flow_offload_hash(const void *data, u32 len, u32 seed)\n@@ -91,6 +94,34 @@ static inline bool nf_flow_has_expired(const struct flow_offload *flow)\n \treturn (__s32)(flow->timeout - (u32)jiffies) <= 0;\n }\n \n+static void nf_flow_release_ct(const struct flow_offload_tuple_rhash *th)\n+{\n+\tstruct nf_conntrack_tuple tuple = {};\n+\tstruct nf_conntrack_tuple_hash *h;\n+\tstruct nf_conntrack_zone zone;\n+\tstruct nf_conn *ct;\n+\n+\tnf_ct_zone_init(&zone, NF_CT_DEFAULT_ZONE_ID,\n+\t\t\tNF_CT_DEFAULT_ZONE_DIR, 0);\n+\n+\ttuple.src.u3.ip\t\t= th->tuple.src_v4.s_addr;\n+\ttuple.dst.u3.ip\t\t= th->tuple.dst_v4.s_addr;\n+\ttuple.src.u.all\t\t= th->tuple.src_port;\n+\ttuple.dst.u.all\t\t= th->tuple.dst_port;\n+\ttuple.src.l3num\t\t= th->tuple.l3proto;\n+\ttuple.dst.protonum\t= th->tuple.l4proto;\n+\ttuple.dst.dir\t\t= IP_CT_DIR_ORIGINAL;\n+\n+\th = nf_conntrack_find_get(&init_net, &zone, &tuple);\n+\tif (!h) {\n+\t\tpr_err(\"cannot find conntrack for flow hash %p\\n\", th);\n+\t\treturn;\n+\t}\n+\tct = nf_ct_tuplehash_to_ctrack(h);\n+\tnf_ct_delete(ct, 0, 0);\n+\tnf_ct_put(ct);\n+}\n+\n static void nf_flow_offload_work_gc(struct work_struct *work)\n {\n \tstruct flow_offload_tuple_rhash *tuplehash;\n@@ -116,9 +147,10 @@ static void nf_flow_offload_work_gc(struct work_struct *work)\n \n \t\tflow = container_of(tuplehash, struct flow_offload, tuplehash[0]);\n \n-\t\tif (nf_flow_has_expired(flow))\n+\t\tif (nf_flow_has_expired(flow)) {\n \t\t\tflow_offload_del(flow);\n-\n+\t\t\tnf_flow_release_ct(tuplehash);\n+\t\t}\n \t\tcounter++;\n \t}\n \n",
    "prefixes": [
        "RFC",
        "WIP",
        "3/5"
    ]
}