Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/852536/?format=api
{ "id": 852536, "url": "http://patchwork.ozlabs.org/api/patches/852536/?format=api", "web_url": "http://patchwork.ozlabs.org/project/netdev/patch/20171222192732.13188-8-pablo@netfilter.org/", "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": "<20171222192732.13188-8-pablo@netfilter.org>", "list_archive_url": null, "date": "2017-12-22T19:27:32", "name": "[RFC,nf-next,v3,7/7] netfilter: nf_flow_table: add hardware offload support", "commit_ref": null, "pull_url": null, "state": "rfc", "archived": true, "hash": "3a01c8db4a79f3ccce189b455c31a241e7c24cf5", "submitter": { "id": 1315, "url": "http://patchwork.ozlabs.org/api/people/1315/?format=api", "name": "Pablo Neira Ayuso", "email": "pablo@netfilter.org" }, "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/20171222192732.13188-8-pablo@netfilter.org/mbox/", "series": [ { "id": 20090, "url": "http://patchwork.ozlabs.org/api/series/20090/?format=api", "web_url": "http://patchwork.ozlabs.org/project/netdev/list/?series=20090", "date": "2017-12-22T19:27:25", "name": "Flow offload infrastructure", "version": 3, "mbox": "http://patchwork.ozlabs.org/series/20090/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/852536/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/852536/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 3z3JTW4B1fz9s7f\n\tfor <patchwork-incoming@ozlabs.org>;\n\tSat, 23 Dec 2017 06:28:47 +1100 (AEDT)", "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1756720AbdLVT2p (ORCPT <rfc822;patchwork-incoming@ozlabs.org>);\n\tFri, 22 Dec 2017 14:28:45 -0500", "from mail.us.es ([193.147.175.20]:42374 \"EHLO mail.us.es\"\n\trhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP\n\tid S1756065AbdLVT2L (ORCPT <rfc822;netdev@vger.kernel.org>);\n\tFri, 22 Dec 2017 14:28:11 -0500", "from antivirus1-rhel7.int (unknown [192.168.2.11])\n\tby mail.us.es (Postfix) with ESMTP id 847BEEBAE4\n\tfor <netdev@vger.kernel.org>; Fri, 22 Dec 2017 20:28:10 +0100 (CET)", "from antivirus1-rhel7.int (localhost [127.0.0.1])\n\tby antivirus1-rhel7.int (Postfix) with ESMTP id 736B3F731B\n\tfor <netdev@vger.kernel.org>; Fri, 22 Dec 2017 20:28:10 +0100 (CET)", "by antivirus1-rhel7.int (Postfix, from userid 99)\n\tid 60BD2F7323; Fri, 22 Dec 2017 20:28:10 +0100 (CET)", "from antivirus1-rhel7.int (localhost [127.0.0.1])\n\tby antivirus1-rhel7.int (Postfix) with ESMTP id E3C20F730E;\n\tFri, 22 Dec 2017 20:28:07 +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, 22 Dec 2017 20:28:07 +0100 (CET)", "from salvia.here (129.166.216.87.static.jazztel.es\n\t[87.216.166.129]) (Authenticated sender: pneira@us.es)\n\tby entrada.int (Postfix) with ESMTPA id 0FBEF4265A31;\n\tFri, 22 Dec 2017 20:28:06 +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, f.fainelli@gmail.com,\n\tsimon.horman@netronome.com, ronye@mellanox.com, jiri@mellanox.com,\n\tnbd@nbd.name, john@phrozen.org, kubakici@wp.pl, fw@strlen.de", "Subject": "[PATCH RFC nf-next,\n\tv3 7/7] netfilter: nf_flow_table: add hardware offload support", "Date": "Fri, 22 Dec 2017 20:27:32 +0100", "Message-Id": "<20171222192732.13188-8-pablo@netfilter.org>", "X-Mailer": "git-send-email 2.11.0", "In-Reply-To": "<20171222192732.13188-1-pablo@netfilter.org>", "References": "<20171222192732.13188-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 infrastructure to offload flows to hardware, in case\nthe nic/switch comes with built-in flow tables capabilities.\n\nIf the hardware comes with no hardware flow tables or they have\nlimitations in terms of features, this falls back to the software\ngeneric flow table implementation.\n\nThe software flow table garbage collector skips entries that resides in\nthe hardware, so the hardware will be responsible for releasing this\nflow table entry too via flow_offload_dead(). In the next garbage\ncollector run, this removes the entries both in the software and\nhardware flow table from user context.\n\nSigned-off-by: Pablo Neira Ayuso <pablo@netfilter.org>\n---\n include/linux/netdevice.h | 9 +++\n include/net/netfilter/nf_flow_table.h | 6 ++\n net/netfilter/Kconfig | 9 +++\n net/netfilter/Makefile | 1 +\n net/netfilter/nf_flow_table.c | 13 ++++\n net/netfilter/nf_flow_table_hw.c | 127 ++++++++++++++++++++++++++++++++++\n net/netfilter/nf_tables_api.c | 2 +\n net/netfilter/nft_flow_offload.c | 4 ++\n 8 files changed, 171 insertions(+)\n create mode 100644 net/netfilter/nf_flow_table_hw.c", "diff": "diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h\nindex f535779d9dc1..5f2919775632 100644\n--- a/include/linux/netdevice.h\n+++ b/include/linux/netdevice.h\n@@ -826,6 +826,13 @@ struct xfrmdev_ops {\n };\n #endif\n \n+struct flow_offload;\n+\n+enum flow_offload_type {\n+\tFLOW_OFFLOAD_ADD\t= 0,\n+\tFLOW_OFFLOAD_DEL,\n+};\n+\n /*\n * This structure defines the management hooks for network devices.\n * The following hooks can be defined; unless noted otherwise, they are\n@@ -1281,6 +1288,8 @@ struct net_device_ops {\n \tint\t\t\t(*ndo_bridge_dellink)(struct net_device *dev,\n \t\t\t\t\t\t struct nlmsghdr *nlh,\n \t\t\t\t\t\t u16 flags);\n+\tint\t\t\t(*ndo_flow_offload)(enum flow_offload_type type,\n+\t\t\t\t\t\t struct flow_offload *flow);\n \tint\t\t\t(*ndo_change_carrier)(struct net_device *dev,\n \t\t\t\t\t\t bool new_carrier);\n \tint\t\t\t(*ndo_get_phys_port_id)(struct net_device *dev,\ndiff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h\nindex b22b22082733..02ac8c7e4f7f 100644\n--- a/include/net/netfilter/nf_flow_table.h\n+++ b/include/net/netfilter/nf_flow_table.h\n@@ -23,6 +23,7 @@ struct nf_flowtable {\n \tstruct rhashtable\t\trhashtable;\n \tconst struct nf_flowtable_type\t*type;\n \tstruct delayed_work\t\tgc_work;\n+\tpossible_net_t\t\t\tft_net;\n };\n \n enum flow_offload_tuple_dir {\n@@ -65,6 +66,7 @@ struct flow_offload_tuple_rhash {\n #define FLOW_OFFLOAD_SNAT\t0x1\n #define FLOW_OFFLOAD_DNAT\t0x2\n #define FLOW_OFFLOAD_DYING\t0x4\n+#define FLOW_OFFLOAD_HW\t\t0x8\n \n struct flow_offload {\n \tstruct flow_offload_tuple_rhash\t\ttuplehash[FLOW_OFFLOAD_DIR_MAX];\n@@ -116,6 +118,10 @@ unsigned int nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,\n unsigned int nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,\n \t\t\t\t const struct nf_hook_state *state);\n \n+void flow_offload_hw_add(struct net *net, struct flow_offload *flow,\n+\t\t\t struct nf_conn *ct);\n+void flow_offload_hw_del(struct net *net, struct flow_offload *flow);\n+\n #define MODULE_ALIAS_NF_FLOWTABLE(family)\t\\\n \tMODULE_ALIAS(\"nf-flowtable-\" __stringify(family))\n \ndiff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig\nindex 1ada46345f3c..cc25876cf223 100644\n--- a/net/netfilter/Kconfig\n+++ b/net/netfilter/Kconfig\n@@ -671,6 +671,15 @@ config NF_FLOW_TABLE\n \n \t To compile it as a module, choose M here.\n \n+config NF_FLOW_TABLE_HW\n+\ttristate \"Netfilter flow table hardware offload module\"\n+\tdepends on NF_FLOW_TABLE\n+\thelp\n+\t This option adds hardware offload support for the flow table core\n+\t infrastructure.\n+\n+\t To compile it as a module, choose M here.\n+\n config NETFILTER_XTABLES\n \ttristate \"Netfilter Xtables support (required for ip_tables)\"\n \tdefault m if NETFILTER_ADVANCED=n\ndiff --git a/net/netfilter/Makefile b/net/netfilter/Makefile\nindex 2c1b8de922f2..1a97a47ad4e8 100644\n--- a/net/netfilter/Makefile\n+++ b/net/netfilter/Makefile\n@@ -109,6 +109,7 @@ obj-$(CONFIG_NFT_FWD_NETDEV)\t+= nft_fwd_netdev.o\n \n # flow table infrastructure\n obj-$(CONFIG_NF_FLOW_TABLE)\t+= nf_flow_table.o\n+obj-$(CONFIG_NF_FLOW_TABLE_HW)\t+= nf_flow_table_hw.o\n \n # generic X tables \n obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o\ndiff --git a/net/netfilter/nf_flow_table.c b/net/netfilter/nf_flow_table.c\nindex e1024b17b910..a505351980fd 100644\n--- a/net/netfilter/nf_flow_table.c\n+++ b/net/netfilter/nf_flow_table.c\n@@ -237,15 +237,22 @@ static inline bool nf_flow_is_dying(const struct flow_offload *flow)\n \treturn flow->flags & FLOW_OFFLOAD_DYING;\n }\n \n+static inline bool nf_flow_in_hw(const struct flow_offload *flow)\n+{\n+\treturn flow->flags & FLOW_OFFLOAD_HW;\n+}\n+\n void nf_flow_offload_work_gc(struct work_struct *work)\n {\n \tstruct flow_offload_tuple_rhash *tuplehash;\n \tstruct nf_flowtable *flow_table;\n \tstruct rhashtable_iter hti;\n \tstruct flow_offload *flow;\n+\tstruct net *net;\n \tint err;\n \n \tflow_table = container_of(work, struct nf_flowtable, gc_work.work);\n+\tnet = read_pnet(&flow_table->ft_net);\n \n \trhashtable_walk_init(&flow_table->rhashtable, &hti, GFP_KERNEL);\n \terr = rhashtable_walk_start(&hti);\n@@ -265,10 +272,16 @@ 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_in_hw(flow) &&\n+\t\t !nf_flow_is_dying(flow))\n+\t\t\tcontinue;\n+\n \t\tif (nf_flow_has_expired(flow) ||\n \t\t nf_flow_is_dying(flow)) {\n \t\t\tflow_offload_del(flow_table, flow);\n \t\t\tnf_flow_release_ct(flow);\n+\t\t\tif (nf_flow_in_hw(flow))\n+\t\t\t\tflow_offload_hw_del(net, flow);\n \t\t}\n \t}\n \ndiff --git a/net/netfilter/nf_flow_table_hw.c b/net/netfilter/nf_flow_table_hw.c\nnew file mode 100644\nindex 000000000000..2907564c8aec\n--- /dev/null\n+++ b/net/netfilter/nf_flow_table_hw.c\n@@ -0,0 +1,127 @@\n+#include <linux/kernel.h>\n+#include <linux/init.h>\n+#include <linux/module.h>\n+#include <linux/netfilter.h>\n+#include <linux/rhashtable.h>\n+#include <linux/netdevice.h>\n+#include <net/netfilter/nf_flow_table.h>\n+#include <net/netfilter/nf_conntrack.h>\n+#include <net/netfilter/nf_conntrack_core.h>\n+#include <net/netfilter/nf_conntrack_tuple.h>\n+\n+static DEFINE_SPINLOCK(flow_offload_hw_pending_list_lock);\n+static LIST_HEAD(flow_offload_hw_pending_list);\n+\n+static DEFINE_MUTEX(nf_flow_offload_hw_mutex);\n+static struct work_struct nft_flow_offload_hw_work;\n+\n+struct flow_offload_hw {\n+\tstruct list_head\tlist;\n+\tstruct flow_offload\t*flow;\n+\tstruct nf_conn\t\t*ct;\n+\tpossible_net_t\t\tflow_hw_net;\n+};\n+\n+static int do_flow_offload_hw(struct net *net, struct flow_offload *flow)\n+{\n+\tstruct net_device *indev;\n+\tint ret, ifindex;\n+\n+\tifindex = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.iifidx;\n+\tindev = dev_get_by_index(net, ifindex);\n+\tif (WARN_ON(!indev))\n+\t\treturn 0;\n+\n+\tmutex_lock(&nf_flow_offload_hw_mutex);\n+\tret = indev->netdev_ops->ndo_flow_offload(FLOW_OFFLOAD_ADD, flow);\n+\tmutex_unlock(&nf_flow_offload_hw_mutex);\n+\n+\tif (ret >= 0)\n+\t\tflow->flags |= FLOW_OFFLOAD_HW;\n+\n+\tdev_put(indev);\n+\n+\treturn ret;\n+}\n+\n+static void flow_offload_hw_work(struct work_struct *work)\n+{\n+\tstruct flow_offload_hw *offload, *next;\n+\tLIST_HEAD(hw_offload_pending);\n+\tstruct net *net;\n+\n+\tspin_lock_bh(&flow_offload_hw_pending_list_lock);\n+\tif (!list_empty(&flow_offload_hw_pending_list))\n+\t\tlist_move_tail(&flow_offload_hw_pending_list, &hw_offload_pending);\n+\tspin_unlock_bh(&flow_offload_hw_pending_list_lock);\n+\n+\tlist_for_each_entry_safe(offload, next, &hw_offload_pending, list) {\n+\t\tif (nf_ct_is_dying(offload->ct))\n+\t\t\tgoto next;\n+\n+\t\tnet = read_pnet(&offload->flow_hw_net);\n+\t\tdo_flow_offload_hw(net, offload->flow);\n+next:\n+\t\tnf_conntrack_put(&offload->ct->ct_general);\n+\t\tlist_del(&offload->list);\n+\t\tkfree(offload);\n+\t}\n+}\n+\n+void flow_offload_hw_add(struct net *net, struct flow_offload *flow,\n+\t\t\t struct nf_conn *ct)\n+{\n+\tstruct flow_offload_hw *offload;\n+\n+\toffload = kmalloc(sizeof(struct flow_offload_hw), GFP_ATOMIC);\n+\tif (!offload)\n+\t\treturn;\n+\n+\tnf_conntrack_get(&ct->ct_general);\n+\toffload->ct = ct;\n+\toffload->flow = flow;\n+\twrite_pnet(&offload->flow_hw_net, net);\n+\n+\tspin_lock_bh(&flow_offload_hw_pending_list_lock);\n+\tlist_add_tail(&offload->list, &flow_offload_hw_pending_list);\n+\tspin_unlock_bh(&flow_offload_hw_pending_list_lock);\n+\n+\tschedule_work(&nft_flow_offload_hw_work);\n+}\n+EXPORT_SYMBOL_GPL(flow_offload_hw_add);\n+\n+void flow_offload_hw_del(struct net *net, struct flow_offload *flow)\n+{\n+\tstruct net_device *indev;\n+\tint ret, ifindex;\n+\n+\tifindex = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.iifidx;\n+\tindev = dev_get_by_index(net, ifindex);\n+\tif (WARN_ON(!indev))\n+\t\treturn;\n+\n+\tmutex_lock(&nf_flow_offload_hw_mutex);\n+\tret = indev->netdev_ops->ndo_flow_offload(FLOW_OFFLOAD_DEL, flow);\n+\tmutex_unlock(&nf_flow_offload_hw_mutex);\n+\n+\tdev_put(indev);\n+}\n+EXPORT_SYMBOL_GPL(flow_offload_hw_del);\n+\n+static int __init nf_flow_table_module_init(void)\n+{\n+\tINIT_WORK(&nft_flow_offload_hw_work, flow_offload_hw_work);\n+\n+\treturn 0;\n+}\n+\n+static void __exit nf_flow_table_module_exit(void)\n+{\n+\tcancel_work_sync(&nft_flow_offload_hw_work);\n+}\n+\n+module_init(nf_flow_table_module_init);\n+module_exit(nf_flow_table_module_exit);\n+\n+MODULE_LICENSE(\"GPL\");\n+MODULE_AUTHOR(\"Pablo Neira Ayuso <pablo@netfilter.org>\");\ndiff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c\nindex efd9405a8a5e..6583d2a0e35b 100644\n--- a/net/netfilter/nf_tables_api.c\n+++ b/net/netfilter/nf_tables_api.c\n@@ -5095,6 +5095,8 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,\n \t}\n \n \tflowtable->data.type = type;\n+\twrite_pnet(&flowtable->data.ft_net, net);\n+\n \terr = rhashtable_init(&flowtable->data.rhashtable, type->params);\n \tif (err < 0)\n \t\tgoto err3;\ndiff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c\nindex 4f16c37acaa3..5c8ea236e8a3 100644\n--- a/net/netfilter/nft_flow_offload.c\n+++ b/net/netfilter/nft_flow_offload.c\n@@ -70,6 +70,7 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,\n {\n \tstruct nft_flow_offload *priv = nft_expr_priv(expr);\n \tstruct nf_flowtable *flowtable = &priv->flowtable->data;\n+\tconst struct net_device *indev = nft_in(pkt);\n \tenum ip_conntrack_info ctinfo;\n \tstruct nf_flow_route route;\n \tstruct flow_offload *flow;\n@@ -114,6 +115,9 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,\n \tif (ret < 0)\n \t\tgoto err_flow_add;\n \n+\tif (indev->netdev_ops->ndo_flow_offload)\n+\t\tflow_offload_hw_add(nft_net(pkt), flow, ct);\n+\n \treturn;\n \n err_flow_add:\n", "prefixes": [ "RFC", "nf-next", "v3", "7/7" ] }