Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.0/patches/2196533/?format=api
{ "id": 2196533, "url": "http://patchwork.ozlabs.org/api/1.0/patches/2196533/?format=api", "project": { "id": 26, "url": "http://patchwork.ozlabs.org/api/1.0/projects/26/?format=api", "name": "Netfilter Development", "link_name": "netfilter-devel", "list_id": "netfilter-devel.vger.kernel.org", "list_email": "netfilter-devel@vger.kernel.org", "web_url": null, "scm_url": null, "webscm_url": null }, "msgid": "<20260214151230.18970-2-ja@ssi.bg>", "date": "2026-02-14T15:12:25", "name": "[nf-next,1/6] ipvs: make ip_vs_svc_table and ip_vs_svc_fwm_table per netns", "commit_ref": null, "pull_url": null, "state": "accepted", "archived": true, "hash": "7c8f4b2ec6f8b3fdb9d1a70d46442cd47b74deaf", "submitter": { "id": 2825, "url": "http://patchwork.ozlabs.org/api/1.0/people/2825/?format=api", "name": "Julian Anastasov", "email": "ja@ssi.bg" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/netfilter-devel/patch/20260214151230.18970-2-ja@ssi.bg/mbox/", "series": [ { "id": 492179, "url": "http://patchwork.ozlabs.org/api/1.0/series/492179/?format=api", "date": "2026-02-14T15:12:24", "name": "IPVS changes, part 2 of 4 - optimizations", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/492179/mbox/" } ], "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2196533/checks/", "tags": {}, "headers": { "Return-Path": "\n <netfilter-devel+bounces-10781-incoming=patchwork.ozlabs.org@vger.kernel.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "netfilter-devel@vger.kernel.org" ], "Delivered-To": "patchwork-incoming@legolas.ozlabs.org", "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (4096-bit key;\n unprotected) header.d=ssi.bg header.i=@ssi.bg header.a=rsa-sha256\n header.s=ssi header.b=dOpPdQ3w;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=172.105.105.114; helo=tor.lore.kernel.org;\n envelope-from=netfilter-devel+bounces-10781-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)", "smtp.subspace.kernel.org;\n\tdkim=pass (4096-bit key) header.d=ssi.bg header.i=@ssi.bg header.b=\"dOpPdQ3w\"", "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=193.238.174.39", "smtp.subspace.kernel.org;\n dmarc=pass (p=reject dis=none) header.from=ssi.bg", "smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=ssi.bg" ], "Received": [ "from tor.lore.kernel.org (tor.lore.kernel.org [172.105.105.114])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fCt390W2sz1xr1\n\tfor <incoming@patchwork.ozlabs.org>; Sun, 15 Feb 2026 02:18:29 +1100 (AEDT)", "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby tor.lore.kernel.org (Postfix) with ESMTP id 39184300B984\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 14 Feb 2026 15:18:27 +0000 (UTC)", "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id A269026F46F;\n\tSat, 14 Feb 2026 15:18:26 +0000 (UTC)", "from mx.ssi.bg (mx.ssi.bg [193.238.174.39])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id D2EA325F96B;\n\tSat, 14 Feb 2026 15:18:23 +0000 (UTC)", "from mx.ssi.bg (localhost [127.0.0.1])\n\tby mx.ssi.bg (Potsfix) with ESMTP id 9088021D5D;\n\tSat, 14 Feb 2026 17:17:52 +0200 (EET)", "from box.ssi.bg (box.ssi.bg [193.238.174.46])\n\tby mx.ssi.bg (Potsfix) with ESMTPS;\n\tSat, 14 Feb 2026 17:17:48 +0200 (EET)", "from ja.ssi.bg (unknown [213.16.62.126])\n\tby box.ssi.bg (Potsfix) with ESMTPSA id 447FF609BE;\n\tSat, 14 Feb 2026 17:17:48 +0200 (EET)", "from ja.home.ssi.bg (localhost.localdomain [127.0.0.1])\n\tby ja.ssi.bg (8.18.1/8.18.1) with ESMTP id 61EFCv0Q019346;\n\tSat, 14 Feb 2026 17:12:57 +0200", "(from root@localhost)\n\tby ja.home.ssi.bg (8.18.1/8.18.1/Submit) id 61EFCvKA019343;\n\tSat, 14 Feb 2026 17:12:57 +0200" ], "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1771082305; cv=none;\n b=u1H2ncQDOCVYtLGCotFbcw1/zVYngnGQ4s3hQDSxEDof1geliFKcFynHjqL/lJlrOGu6SvyezFpSqKZHtpUcweDK4WlIDIinUK3YoODRycwpw0LKRFKFwpRGc/D+HsPR+ArujHgWm4KaC/+y/Z14ik6dMnArtbAnfZ1Lc6srj9o=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1771082305; c=relaxed/simple;\n\tbh=5vBkdqSDHGwzSixEvHMo9KuoiEV2F95NualGVpCrC/s=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=rXP/uXDyCeD0OI5bFxDRmUFlpbFlNuzCC4Ef6z/TxHJvvzGcKTpFLcSBioO1LEnGbQoKlrkx5CysAypht8z+cXLDeA723AFpE/3LIaRtpZlWxfDwS8YFx/G9HHG+u8M7XrJ4koneOGdo8rcdlQMoLV0XqoO/0xPTAEae9UV1vog=", "ARC-Authentication-Results": "i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=reject dis=none) header.from=ssi.bg;\n spf=pass smtp.mailfrom=ssi.bg;\n dkim=pass (4096-bit key) header.d=ssi.bg header.i=@ssi.bg header.b=dOpPdQ3w;\n arc=none smtp.client-ip=193.238.174.39", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=ssi.bg; h=cc:cc\n\t:content-transfer-encoding:date:from:from:in-reply-to:message-id\n\t:mime-version:references:reply-to:subject:subject:to:to; s=ssi;\n\t bh=VdhOLAJFQNdx9Ea7xDQza+p8tekzgQEdNxcX8cZmorw=; b=dOpPdQ3wsGU5\n\t7NhtBG/jwaqhyTg0K9FHX9U7XFZM+p5lk5c9V6D6pbsYO6kjNNmliy+DuYPfhyPi\n\tkld+RsKGWWahn+6BizlDavqcjfbJYEvHLYg85ydEIqtY7tzCTTwHHOeil+5sRAev\n\tQICXzU1m3A3V+FXZvHGXPdrFs6KinZva0VOFt1RJ9YQytO2owxQ0PJV4cAGxINQ9\n\tCKxpoIMYgAA+zT6hkT2vvEz7Y0DJlxMKVUfa2KokCRgGiMcZ5xL3NdhiusLmw+fb\n\tKbPddfO50BetunY7yWBiHcDTJ8EA1yem6bwKwzOEhfNGqfqAo5JMZFT1O3NFVYMJ\n\tuw0ULIwB2MS3lyNqqv4/EMWT5weiw5brZw2YH17iF8lq63CqH4/jYniWD2SEPQBc\n\t0Qu7uiVxAtIlabbsxZOfEPX8ur02ASQwt/hd3msV58iiNasVgvGNLkfzVrPNChDy\n\tzkMol7cF5ZtJ+ZgzEElDA8XuTNTUt6rlT1qxhbbtgg4L6/ATLPAws15auRtGO2lo\n\tu/R+25ipIcn5g7DTK7/ZB7LXNyctALGulsohChoLp3pLXcfOTx3f6iY/wJGymZtn\n\tJnutP9rFtBsWWyZBLiXI02XkqfVxG5/gnNMRrlJGGo1/F2HAt8YFf0SAYC9IVUc8\n\tILs7udO2cM5djB2JOpWWcIYEfTSKF/Y=", "From": "Julian Anastasov <ja@ssi.bg>", "To": "Simon Horman <horms@verge.net.au>", "Cc": "Pablo Neira Ayuso <pablo@netfilter.org>, lvs-devel@vger.kernel.org,\n netfilter-devel@vger.kernel.org, Dust Li <dust.li@linux.alibaba.com>,\n Jiejian Wu <jiejian@linux.alibaba.com>", "Subject": "[PATCH nf-next 1/6] ipvs: make ip_vs_svc_table and\n ip_vs_svc_fwm_table per netns", "Date": "Sat, 14 Feb 2026 17:12:25 +0200", "Message-ID": "<20260214151230.18970-2-ja@ssi.bg>", "X-Mailer": "git-send-email 2.53.0", "In-Reply-To": "<20260214151230.18970-1-ja@ssi.bg>", "References": "<20260214151230.18970-1-ja@ssi.bg>", "Precedence": "bulk", "X-Mailing-List": "netfilter-devel@vger.kernel.org", "List-Id": "<netfilter-devel.vger.kernel.org>", "List-Subscribe": "<mailto:netfilter-devel+subscribe@vger.kernel.org>", "List-Unsubscribe": "<mailto:netfilter-devel+unsubscribe@vger.kernel.org>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit" }, "content": "From: Jiejian Wu <jiejian@linux.alibaba.com>\n\nCurrent ipvs uses one global mutex \"__ip_vs_mutex\" to keep the global\n\"ip_vs_svc_table\" and \"ip_vs_svc_fwm_table\" safe. But when there are\ntens of thousands of services from different netns in the table, it\ntakes a long time to look up the table, for example, using \"ipvsadm\n-ln\" from different netns simultaneously.\n\nWe make \"ip_vs_svc_table\" and \"ip_vs_svc_fwm_table\" per netns, and we\nadd \"service_mutex\" per netns to keep these two tables safe instead of\nthe global \"__ip_vs_mutex\" in current version. To this end, looking up\nservices from different netns simultaneously will not get stuck,\nshortening the time consumption in large-scale deployment. It can be\nreproduced using the simple scripts below.\n\ninit.sh: #!/bin/bash\nfor((i=1;i<=4;i++));do\n ip netns add ns$i\n ip netns exec ns$i ip link set dev lo up\n ip netns exec ns$i sh add-services.sh\ndone\n\nadd-services.sh: #!/bin/bash\nfor((i=0;i<30000;i++)); do\n ipvsadm -A -t 10.10.10.10:$((80+$i)) -s rr\ndone\n\nruntest.sh: #!/bin/bash\nfor((i=1;i<4;i++));do\n ip netns exec ns$i ipvsadm -ln > /dev/null &\ndone\nip netns exec ns4 ipvsadm -ln > /dev/null\n\nRun \"sh init.sh\" to initiate the network environment. Then run \"time\n./runtest.sh\" to evaluate the time consumption. Our testbed is a 4-core\nIntel Xeon ECS. The result of the original version is around 8 seconds,\nwhile the result of the modified version is only 0.8 seconds.\n\nSigned-off-by: Jiejian Wu <jiejian@linux.alibaba.com>\nCo-developed-by: Dust Li <dust.li@linux.alibaba.com>\nSigned-off-by: Dust Li <dust.li@linux.alibaba.com>\nSigned-off-by: Julian Anastasov <ja@ssi.bg>\n---\n include/net/ip_vs.h | 13 +++\n net/netfilter/ipvs/ip_vs_ctl.c | 167 ++++++++++++++-------------------\n net/netfilter/ipvs/ip_vs_est.c | 18 ++--\n 3 files changed, 94 insertions(+), 104 deletions(-)", "diff": "diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h\nindex 29a36709e7f3..074a204ec6db 100644\n--- a/include/net/ip_vs.h\n+++ b/include/net/ip_vs.h\n@@ -33,6 +33,12 @@\n \n #define IP_VS_HDR_INVERSE\t1\n #define IP_VS_HDR_ICMP\t\t2\n+/*\n+ *\tHash table: for virtual service lookups\n+ */\n+#define IP_VS_SVC_TAB_BITS 8\n+#define IP_VS_SVC_TAB_SIZE BIT(IP_VS_SVC_TAB_BITS)\n+#define IP_VS_SVC_TAB_MASK (IP_VS_SVC_TAB_SIZE - 1)\n \n /* Generic access of ipvs struct */\n static inline struct netns_ipvs *net_ipvs(struct net* net)\n@@ -1041,6 +1047,13 @@ struct netns_ipvs {\n \t */\n \tunsigned int\t\tmixed_address_family_dests;\n \tunsigned int\t\thooks_afmask;\t/* &1=AF_INET, &2=AF_INET6 */\n+\n+\t/* the service mutex that protect svc_table and svc_fwm_table */\n+\tstruct mutex service_mutex;\n+\t/* the service table hashed by <protocol, addr, port> */\n+\tstruct hlist_head svc_table[IP_VS_SVC_TAB_SIZE];\n+\t/* the service table hashed by fwmark */\n+\tstruct hlist_head svc_fwm_table[IP_VS_SVC_TAB_SIZE];\n };\n \n #define DEFAULT_SYNC_THRESHOLD\t3\ndiff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c\nindex 068702894377..d871273ce917 100644\n--- a/net/netfilter/ipvs/ip_vs_ctl.c\n+++ b/net/netfilter/ipvs/ip_vs_ctl.c\n@@ -48,7 +48,7 @@\n \n MODULE_ALIAS_GENL_FAMILY(IPVS_GENL_NAME);\n \n-DEFINE_MUTEX(__ip_vs_mutex); /* Serialize configuration with sockopt/netlink */\n+static struct lock_class_key __ipvs_service_key;\n \n /* sysctl variables */\n \n@@ -293,17 +293,6 @@ ip_vs_use_count_dec(void)\n }\n \n \n-/*\n- *\tHash table: for virtual service lookups\n- */\n-#define IP_VS_SVC_TAB_BITS 8\n-#define IP_VS_SVC_TAB_SIZE (1 << IP_VS_SVC_TAB_BITS)\n-#define IP_VS_SVC_TAB_MASK (IP_VS_SVC_TAB_SIZE - 1)\n-\n-/* the service table hashed by <protocol, addr, port> */\n-static struct hlist_head ip_vs_svc_table[IP_VS_SVC_TAB_SIZE];\n-/* the service table hashed by fwmark */\n-static struct hlist_head ip_vs_svc_fwm_table[IP_VS_SVC_TAB_SIZE];\n \n \n /*\n@@ -338,8 +327,8 @@ static inline unsigned int ip_vs_svc_fwm_hashkey(struct netns_ipvs *ipvs, __u32\n }\n \n /*\n- *\tHashes a service in the ip_vs_svc_table by <netns,proto,addr,port>\n- *\tor in the ip_vs_svc_fwm_table by fwmark.\n+ *\tHashes a service in the svc_table by <netns,proto,addr,port>\n+ *\tor in the svc_fwm_table by fwmark.\n *\tShould be called with locked tables.\n */\n static int ip_vs_svc_hash(struct ip_vs_service *svc)\n@@ -354,17 +343,17 @@ static int ip_vs_svc_hash(struct ip_vs_service *svc)\n \n \tif (svc->fwmark == 0) {\n \t\t/*\n-\t\t * Hash it by <netns,protocol,addr,port> in ip_vs_svc_table\n+\t\t * Hash it by <netns,protocol,addr,port> in svc_table\n \t\t */\n \t\thash = ip_vs_svc_hashkey(svc->ipvs, svc->af, svc->protocol,\n \t\t\t\t\t &svc->addr, svc->port);\n-\t\thlist_add_head_rcu(&svc->s_list, &ip_vs_svc_table[hash]);\n+\t\thlist_add_head_rcu(&svc->s_list, &svc->ipvs->svc_table[hash]);\n \t} else {\n \t\t/*\n \t\t * Hash it by fwmark in svc_fwm_table\n \t\t */\n \t\thash = ip_vs_svc_fwm_hashkey(svc->ipvs, svc->fwmark);\n-\t\thlist_add_head_rcu(&svc->f_list, &ip_vs_svc_fwm_table[hash]);\n+\t\thlist_add_head_rcu(&svc->f_list, &svc->ipvs->svc_fwm_table[hash]);\n \t}\n \n \tsvc->flags |= IP_VS_SVC_F_HASHED;\n@@ -413,12 +402,9 @@ __ip_vs_service_find(struct netns_ipvs *ipvs, int af, __u16 protocol,\n \t/* Check for \"full\" addressed entries */\n \thash = ip_vs_svc_hashkey(ipvs, af, protocol, vaddr, vport);\n \n-\thlist_for_each_entry_rcu(svc, &ip_vs_svc_table[hash], s_list) {\n-\t\tif ((svc->af == af)\n-\t\t && ip_vs_addr_equal(af, &svc->addr, vaddr)\n-\t\t && (svc->port == vport)\n-\t\t && (svc->protocol == protocol)\n-\t\t && (svc->ipvs == ipvs)) {\n+\thlist_for_each_entry_rcu(svc, &ipvs->svc_table[hash], s_list) {\n+\t\tif (svc->af == af && ip_vs_addr_equal(af, &svc->addr, vaddr) &&\n+\t\t svc->port == vport && svc->protocol == protocol) {\n \t\t\t/* HIT */\n \t\t\treturn svc;\n \t\t}\n@@ -440,9 +426,8 @@ __ip_vs_svc_fwm_find(struct netns_ipvs *ipvs, int af, __u32 fwmark)\n \t/* Check for fwmark addressed entries */\n \thash = ip_vs_svc_fwm_hashkey(ipvs, fwmark);\n \n-\thlist_for_each_entry_rcu(svc, &ip_vs_svc_fwm_table[hash], f_list) {\n-\t\tif (svc->fwmark == fwmark && svc->af == af\n-\t\t && (svc->ipvs == ipvs)) {\n+\thlist_for_each_entry_rcu(svc, &ipvs->svc_fwm_table[hash], f_list) {\n+\t\tif (svc->fwmark == fwmark && svc->af == af) {\n \t\t\t/* HIT */\n \t\t\treturn svc;\n \t\t}\n@@ -1701,10 +1686,9 @@ static int ip_vs_flush(struct netns_ipvs *ipvs, bool cleanup)\n \t * Flush the service table hashed by <netns,protocol,addr,port>\n \t */\n \tfor(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {\n-\t\thlist_for_each_entry_safe(svc, n, &ip_vs_svc_table[idx],\n+\t\thlist_for_each_entry_safe(svc, n, &ipvs->svc_table[idx],\n \t\t\t\t\t s_list) {\n-\t\t\tif (svc->ipvs == ipvs)\n-\t\t\t\tip_vs_unlink_service(svc, cleanup);\n+\t\t\tip_vs_unlink_service(svc, cleanup);\n \t\t}\n \t}\n \n@@ -1712,10 +1696,9 @@ static int ip_vs_flush(struct netns_ipvs *ipvs, bool cleanup)\n \t * Flush the service table hashed by fwmark\n \t */\n \tfor(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {\n-\t\thlist_for_each_entry_safe(svc, n, &ip_vs_svc_fwm_table[idx],\n+\t\thlist_for_each_entry_safe(svc, n, &ipvs->svc_fwm_table[idx],\n \t\t\t\t\t f_list) {\n-\t\t\tif (svc->ipvs == ipvs)\n-\t\t\t\tip_vs_unlink_service(svc, cleanup);\n+\t\t\tip_vs_unlink_service(svc, cleanup);\n \t\t}\n \t}\n \n@@ -1732,12 +1715,12 @@ void ip_vs_service_nets_cleanup(struct list_head *net_list)\n \tstruct net *net;\n \n \t/* Check for \"full\" addressed entries */\n-\tmutex_lock(&__ip_vs_mutex);\n \tlist_for_each_entry(net, net_list, exit_list) {\n \t\tipvs = net_ipvs(net);\n+\t\tmutex_lock(&ipvs->service_mutex);\n \t\tip_vs_flush(ipvs, true);\n+\t\tmutex_unlock(&ipvs->service_mutex);\n \t}\n-\tmutex_unlock(&__ip_vs_mutex);\n }\n \n /* Put all references for device (dst_cache) */\n@@ -1775,25 +1758,20 @@ static int ip_vs_dst_event(struct notifier_block *this, unsigned long event,\n \tif (event != NETDEV_DOWN || !ipvs)\n \t\treturn NOTIFY_DONE;\n \tIP_VS_DBG(3, \"%s() dev=%s\\n\", __func__, dev->name);\n-\tmutex_lock(&__ip_vs_mutex);\n+\tmutex_lock(&ipvs->service_mutex);\n \tfor (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {\n-\t\thlist_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {\n-\t\t\tif (svc->ipvs == ipvs) {\n-\t\t\t\tlist_for_each_entry(dest, &svc->destinations,\n-\t\t\t\t\t\t n_list) {\n-\t\t\t\t\tip_vs_forget_dev(dest, dev);\n-\t\t\t\t}\n+\t\thlist_for_each_entry(svc, &ipvs->svc_table[idx], s_list) {\n+\t\t\tlist_for_each_entry(dest, &svc->destinations,\n+\t\t\t\t\t n_list) {\n+\t\t\t\tip_vs_forget_dev(dest, dev);\n \t\t\t}\n \t\t}\n \n-\t\thlist_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {\n-\t\t\tif (svc->ipvs == ipvs) {\n-\t\t\t\tlist_for_each_entry(dest, &svc->destinations,\n-\t\t\t\t\t\t n_list) {\n-\t\t\t\t\tip_vs_forget_dev(dest, dev);\n-\t\t\t\t}\n+\t\thlist_for_each_entry(svc, &ipvs->svc_fwm_table[idx], f_list) {\n+\t\t\tlist_for_each_entry(dest, &svc->destinations,\n+\t\t\t\t\t n_list) {\n+\t\t\t\tip_vs_forget_dev(dest, dev);\n \t\t\t}\n-\n \t\t}\n \t}\n \n@@ -1802,7 +1780,7 @@ static int ip_vs_dst_event(struct notifier_block *this, unsigned long event,\n \t\tip_vs_forget_dev(dest, dev);\n \t}\n \tspin_unlock_bh(&ipvs->dest_trash_lock);\n-\tmutex_unlock(&__ip_vs_mutex);\n+\tmutex_unlock(&ipvs->service_mutex);\n \treturn NOTIFY_DONE;\n }\n \n@@ -1826,16 +1804,14 @@ static int ip_vs_zero_all(struct netns_ipvs *ipvs)\n \tstruct ip_vs_service *svc;\n \n \tfor(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {\n-\t\thlist_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {\n-\t\t\tif (svc->ipvs == ipvs)\n-\t\t\t\tip_vs_zero_service(svc);\n+\t\thlist_for_each_entry(svc, &ipvs->svc_table[idx], s_list) {\n+\t\t\tip_vs_zero_service(svc);\n \t\t}\n \t}\n \n \tfor(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {\n-\t\thlist_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {\n-\t\t\tif (svc->ipvs == ipvs)\n-\t\t\t\tip_vs_zero_service(svc);\n+\t\thlist_for_each_entry(svc, &ipvs->svc_fwm_table[idx], f_list) {\n+\t\t\tip_vs_zero_service(svc);\n \t\t}\n \t}\n \n@@ -2306,9 +2282,9 @@ static struct ip_vs_service *ip_vs_info_array(struct seq_file *seq, loff_t pos)\n \n \t/* look in hash by protocol */\n \tfor (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {\n-\t\thlist_for_each_entry_rcu(svc, &ip_vs_svc_table[idx], s_list) {\n-\t\t\tif ((svc->ipvs == ipvs) && pos-- == 0) {\n-\t\t\t\titer->table = ip_vs_svc_table;\n+\t\thlist_for_each_entry_rcu(svc, &ipvs->svc_table[idx], s_list) {\n+\t\t\tif (pos-- == 0) {\n+\t\t\t\titer->table = ipvs->svc_table;\n \t\t\t\titer->bucket = idx;\n \t\t\t\treturn svc;\n \t\t\t}\n@@ -2317,10 +2293,10 @@ static struct ip_vs_service *ip_vs_info_array(struct seq_file *seq, loff_t pos)\n \n \t/* keep looking in fwmark */\n \tfor (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {\n-\t\thlist_for_each_entry_rcu(svc, &ip_vs_svc_fwm_table[idx],\n+\t\thlist_for_each_entry_rcu(svc, &ipvs->svc_fwm_table[idx],\n \t\t\t\t\t f_list) {\n-\t\t\tif ((svc->ipvs == ipvs) && pos-- == 0) {\n-\t\t\t\titer->table = ip_vs_svc_fwm_table;\n+\t\t\tif (pos-- == 0) {\n+\t\t\t\titer->table = ipvs->svc_fwm_table;\n \t\t\t\titer->bucket = idx;\n \t\t\t\treturn svc;\n \t\t\t}\n@@ -2343,6 +2319,8 @@ static void *ip_vs_info_seq_next(struct seq_file *seq, void *v, loff_t *pos)\n \tstruct hlist_node *e;\n \tstruct ip_vs_iter *iter;\n \tstruct ip_vs_service *svc;\n+\tstruct net *net = seq_file_net(seq);\n+\tstruct netns_ipvs *ipvs = net_ipvs(net);\n \n \t++*pos;\n \tif (v == SEQ_START_TOKEN)\n@@ -2351,7 +2329,7 @@ static void *ip_vs_info_seq_next(struct seq_file *seq, void *v, loff_t *pos)\n \tsvc = v;\n \titer = seq->private;\n \n-\tif (iter->table == ip_vs_svc_table) {\n+\tif (iter->table == ipvs->svc_table) {\n \t\t/* next service in table hashed by protocol */\n \t\te = rcu_dereference(hlist_next_rcu(&svc->s_list));\n \t\tif (e)\n@@ -2359,13 +2337,13 @@ static void *ip_vs_info_seq_next(struct seq_file *seq, void *v, loff_t *pos)\n \n \t\twhile (++iter->bucket < IP_VS_SVC_TAB_SIZE) {\n \t\t\thlist_for_each_entry_rcu(svc,\n-\t\t\t\t\t\t &ip_vs_svc_table[iter->bucket],\n+\t\t\t\t\t\t &ipvs->svc_table[iter->bucket],\n \t\t\t\t\t\t s_list) {\n \t\t\t\treturn svc;\n \t\t\t}\n \t\t}\n \n-\t\titer->table = ip_vs_svc_fwm_table;\n+\t\titer->table = ipvs->svc_fwm_table;\n \t\titer->bucket = -1;\n \t\tgoto scan_fwmark;\n \t}\n@@ -2378,7 +2356,7 @@ static void *ip_vs_info_seq_next(struct seq_file *seq, void *v, loff_t *pos)\n scan_fwmark:\n \twhile (++iter->bucket < IP_VS_SVC_TAB_SIZE) {\n \t\thlist_for_each_entry_rcu(svc,\n-\t\t\t\t\t &ip_vs_svc_fwm_table[iter->bucket],\n+\t\t\t\t\t &ipvs->svc_fwm_table[iter->bucket],\n \t\t\t\t\t f_list)\n \t\t\treturn svc;\n \t}\n@@ -2414,7 +2392,7 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)\n \n \t\tif (svc->ipvs != ipvs)\n \t\t\treturn 0;\n-\t\tif (iter->table == ip_vs_svc_table) {\n+\t\tif (iter->table == ipvs->svc_table) {\n #ifdef CONFIG_IP_VS_IPV6\n \t\t\tif (svc->af == AF_INET6)\n \t\t\t\tseq_printf(seq, \"%s [%pI6]:%04X %s \",\n@@ -2736,7 +2714,7 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, sockptr_t ptr, unsigned int len)\n \t\treturn ret;\n \t}\n \n-\tmutex_lock(&__ip_vs_mutex);\n+\tmutex_lock(&ipvs->service_mutex);\n \tif (cmd == IP_VS_SO_SET_FLUSH) {\n \t\t/* Flush the virtual service */\n \t\tret = ip_vs_flush(ipvs, false);\n@@ -2833,7 +2811,7 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, sockptr_t ptr, unsigned int len)\n \t}\n \n out_unlock:\n-\tmutex_unlock(&__ip_vs_mutex);\n+\tmutex_unlock(&ipvs->service_mutex);\n \treturn ret;\n }\n \n@@ -2871,9 +2849,9 @@ __ip_vs_get_service_entries(struct netns_ipvs *ipvs,\n \tint ret = 0;\n \n \tfor (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {\n-\t\thlist_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {\n+\t\thlist_for_each_entry(svc, &ipvs->svc_table[idx], s_list) {\n \t\t\t/* Only expose IPv4 entries to old interface */\n-\t\t\tif (svc->af != AF_INET || (svc->ipvs != ipvs))\n+\t\t\tif (svc->af != AF_INET)\n \t\t\t\tcontinue;\n \n \t\t\tif (count >= get->num_services)\n@@ -2890,9 +2868,9 @@ __ip_vs_get_service_entries(struct netns_ipvs *ipvs,\n \t}\n \n \tfor (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {\n-\t\thlist_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {\n+\t\thlist_for_each_entry(svc, &ipvs->svc_fwm_table[idx], f_list) {\n \t\t\t/* Only expose IPv4 entries to old interface */\n-\t\t\tif (svc->af != AF_INET || (svc->ipvs != ipvs))\n+\t\t\tif (svc->af != AF_INET)\n \t\t\t\tcontinue;\n \n \t\t\tif (count >= get->num_services)\n@@ -3061,7 +3039,7 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)\n \t\treturn ret;\n \t}\n \n-\tmutex_lock(&__ip_vs_mutex);\n+\tmutex_lock(&ipvs->service_mutex);\n \tswitch (cmd) {\n \tcase IP_VS_SO_GET_VERSION:\n \t{\n@@ -3160,7 +3138,7 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)\n \t}\n \n out:\n-\tmutex_unlock(&__ip_vs_mutex);\n+\tmutex_unlock(&ipvs->service_mutex);\n \treturn ret;\n }\n \n@@ -3395,10 +3373,10 @@ static int ip_vs_genl_dump_services(struct sk_buff *skb,\n \tstruct net *net = sock_net(skb->sk);\n \tstruct netns_ipvs *ipvs = net_ipvs(net);\n \n-\tmutex_lock(&__ip_vs_mutex);\n+\tmutex_lock(&ipvs->service_mutex);\n \tfor (i = 0; i < IP_VS_SVC_TAB_SIZE; i++) {\n-\t\thlist_for_each_entry(svc, &ip_vs_svc_table[i], s_list) {\n-\t\t\tif (++idx <= start || (svc->ipvs != ipvs))\n+\t\thlist_for_each_entry(svc, &ipvs->svc_table[i], s_list) {\n+\t\t\tif (++idx <= start)\n \t\t\t\tcontinue;\n \t\t\tif (ip_vs_genl_dump_service(skb, svc, cb) < 0) {\n \t\t\t\tidx--;\n@@ -3408,8 +3386,8 @@ static int ip_vs_genl_dump_services(struct sk_buff *skb,\n \t}\n \n \tfor (i = 0; i < IP_VS_SVC_TAB_SIZE; i++) {\n-\t\thlist_for_each_entry(svc, &ip_vs_svc_fwm_table[i], f_list) {\n-\t\t\tif (++idx <= start || (svc->ipvs != ipvs))\n+\t\thlist_for_each_entry(svc, &ipvs->svc_fwm_table[i], f_list) {\n+\t\t\tif (++idx <= start)\n \t\t\t\tcontinue;\n \t\t\tif (ip_vs_genl_dump_service(skb, svc, cb) < 0) {\n \t\t\t\tidx--;\n@@ -3419,7 +3397,7 @@ static int ip_vs_genl_dump_services(struct sk_buff *skb,\n \t}\n \n nla_put_failure:\n-\tmutex_unlock(&__ip_vs_mutex);\n+\tmutex_unlock(&ipvs->service_mutex);\n \tcb->args[0] = idx;\n \n \treturn skb->len;\n@@ -3608,7 +3586,7 @@ static int ip_vs_genl_dump_dests(struct sk_buff *skb,\n \tstruct net *net = sock_net(skb->sk);\n \tstruct netns_ipvs *ipvs = net_ipvs(net);\n \n-\tmutex_lock(&__ip_vs_mutex);\n+\tmutex_lock(&ipvs->service_mutex);\n \n \t/* Try to find the service for which to dump destinations */\n \tif (nlmsg_parse_deprecated(cb->nlh, GENL_HDRLEN, attrs, IPVS_CMD_ATTR_MAX, ip_vs_cmd_policy, cb->extack))\n@@ -3633,7 +3611,7 @@ static int ip_vs_genl_dump_dests(struct sk_buff *skb,\n \tcb->args[0] = idx;\n \n out_err:\n-\tmutex_unlock(&__ip_vs_mutex);\n+\tmutex_unlock(&ipvs->service_mutex);\n \n \treturn skb->len;\n }\n@@ -3916,7 +3894,7 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)\n \n \tcmd = info->genlhdr->cmd;\n \n-\tmutex_lock(&__ip_vs_mutex);\n+\tmutex_lock(&ipvs->service_mutex);\n \n \tif (cmd == IPVS_CMD_FLUSH) {\n \t\tret = ip_vs_flush(ipvs, false);\n@@ -4028,7 +4006,7 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)\n \t}\n \n out:\n-\tmutex_unlock(&__ip_vs_mutex);\n+\tmutex_unlock(&ipvs->service_mutex);\n \n \treturn ret;\n }\n@@ -4058,7 +4036,7 @@ static int ip_vs_genl_get_cmd(struct sk_buff *skb, struct genl_info *info)\n \tif (!msg)\n \t\treturn -ENOMEM;\n \n-\tmutex_lock(&__ip_vs_mutex);\n+\tmutex_lock(&ipvs->service_mutex);\n \n \treply = genlmsg_put_reply(msg, info, &ip_vs_genl_family, 0, reply_cmd);\n \tif (reply == NULL)\n@@ -4126,7 +4104,7 @@ static int ip_vs_genl_get_cmd(struct sk_buff *skb, struct genl_info *info)\n out_err:\n \tnlmsg_free(msg);\n out:\n-\tmutex_unlock(&__ip_vs_mutex);\n+\tmutex_unlock(&ipvs->service_mutex);\n \n \treturn ret;\n }\n@@ -4243,6 +4221,7 @@ static struct genl_family ip_vs_genl_family __ro_after_init = {\n \t.small_ops\t= ip_vs_genl_ops,\n \t.n_small_ops\t= ARRAY_SIZE(ip_vs_genl_ops),\n \t.resv_start_op\t= IPVS_CMD_FLUSH + 1,\n+\t.parallel_ops\t= 1,\n };\n \n static int __init ip_vs_genl_register(void)\n@@ -4425,6 +4404,13 @@ int __net_init ip_vs_control_net_init(struct netns_ipvs *ipvs)\n \tint ret = -ENOMEM;\n \tint idx;\n \n+\t/* Initialize service_mutex, svc_table, svc_fwm_table per netns */\n+\t__mutex_init(&ipvs->service_mutex, \"ipvs->service_mutex\", &__ipvs_service_key);\n+\tfor (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {\n+\t\tINIT_HLIST_HEAD(&ipvs->svc_table[idx]);\n+\t\tINIT_HLIST_HEAD(&ipvs->svc_fwm_table[idx]);\n+\t}\n+\n \t/* Initialize rs_table */\n \tfor (idx = 0; idx < IP_VS_RTAB_SIZE; idx++)\n \t\tINIT_HLIST_HEAD(&ipvs->rs_table[idx]);\n@@ -4529,17 +4515,8 @@ void ip_vs_unregister_nl_ioctl(void)\n \n int __init ip_vs_control_init(void)\n {\n-\tint idx;\n \tint ret;\n \n-\t/* Initialize svc_table, ip_vs_svc_fwm_table */\n-\tfor (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {\n-\t\tINIT_HLIST_HEAD(&ip_vs_svc_table[idx]);\n-\t\tINIT_HLIST_HEAD(&ip_vs_svc_fwm_table[idx]);\n-\t}\n-\n-\tsmp_wmb();\t/* Do we really need it now ? */\n-\n \tret = register_netdevice_notifier(&ip_vs_dst_notifier);\n \tif (ret < 0)\n \t\treturn ret;\ndiff --git a/net/netfilter/ipvs/ip_vs_est.c b/net/netfilter/ipvs/ip_vs_est.c\nindex 77f4f637ff67..dc207172ca9f 100644\n--- a/net/netfilter/ipvs/ip_vs_est.c\n+++ b/net/netfilter/ipvs/ip_vs_est.c\n@@ -602,7 +602,7 @@ static void ip_vs_est_drain_temp_list(struct netns_ipvs *ipvs)\n \twhile (1) {\n \t\tint max = 16;\n \n-\t\tmutex_lock(&__ip_vs_mutex);\n+\t\tmutex_lock(&ipvs->service_mutex);\n \n \t\twhile (max-- > 0) {\n \t\t\test = hlist_entry_safe(ipvs->est_temp_list.first,\n@@ -622,12 +622,12 @@ static void ip_vs_est_drain_temp_list(struct netns_ipvs *ipvs)\n \t\t\t}\n \t\t\tgoto unlock;\n \t\t}\n-\t\tmutex_unlock(&__ip_vs_mutex);\n+\t\tmutex_unlock(&ipvs->service_mutex);\n \t\tcond_resched();\n \t}\n \n unlock:\n-\tmutex_unlock(&__ip_vs_mutex);\n+\tmutex_unlock(&ipvs->service_mutex);\n }\n \n /* Calculate limits for all kthreads */\n@@ -647,9 +647,9 @@ static int ip_vs_est_calc_limits(struct netns_ipvs *ipvs, int *chain_max)\n \tu64 val;\n \n \tINIT_HLIST_HEAD(&chain);\n-\tmutex_lock(&__ip_vs_mutex);\n+\tmutex_lock(&ipvs->service_mutex);\n \tkd = ipvs->est_kt_arr[0];\n-\tmutex_unlock(&__ip_vs_mutex);\n+\tmutex_unlock(&ipvs->service_mutex);\n \ts = kd ? kd->calc_stats : NULL;\n \tif (!s)\n \t\tgoto out;\n@@ -748,7 +748,7 @@ static void ip_vs_est_calc_phase(struct netns_ipvs *ipvs)\n \tif (!ip_vs_est_calc_limits(ipvs, &chain_max))\n \t\treturn;\n \n-\tmutex_lock(&__ip_vs_mutex);\n+\tmutex_lock(&ipvs->service_mutex);\n \n \t/* Stop all other tasks, so that we can immediately move the\n \t * estimators to est_temp_list without RCU grace period\n@@ -815,9 +815,9 @@ static void ip_vs_est_calc_phase(struct netns_ipvs *ipvs)\n \t\t/* Give chance estimators to be added (to est_temp_list)\n \t\t * and deleted (releasing kthread contexts)\n \t\t */\n-\t\tmutex_unlock(&__ip_vs_mutex);\n+\t\tmutex_unlock(&ipvs->service_mutex);\n \t\tcond_resched();\n-\t\tmutex_lock(&__ip_vs_mutex);\n+\t\tmutex_lock(&ipvs->service_mutex);\n \n \t\t/* Current kt released ? */\n \t\tif (id >= ipvs->est_kt_count)\n@@ -893,7 +893,7 @@ static void ip_vs_est_calc_phase(struct netns_ipvs *ipvs)\n \tmutex_unlock(&ipvs->est_mutex);\n \n unlock:\n-\tmutex_unlock(&__ip_vs_mutex);\n+\tmutex_unlock(&ipvs->service_mutex);\n }\n \n void ip_vs_zero_estimator(struct ip_vs_stats *stats)\n", "prefixes": [ "nf-next", "1/6" ] }