From patchwork Thu Aug 2 00:35:46 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi-Hung Wei X-Patchwork-Id: 952489 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="iskMJWdR"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41grvr26VHz9s3x for ; Thu, 2 Aug 2018 10:41:28 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id C0E71DF2; Thu, 2 Aug 2018 00:41:02 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id CD6E3DC2 for ; Thu, 2 Aug 2018 00:41:01 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pl0-f66.google.com (mail-pl0-f66.google.com [209.85.160.66]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 36C737B3 for ; Thu, 2 Aug 2018 00:41:01 +0000 (UTC) Received: by mail-pl0-f66.google.com with SMTP id u11-v6so202558plq.5 for ; Wed, 01 Aug 2018 17:41:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=lWHuCJIXD0FH0wHnqL7ztyciST3M6rGFO/A4c8Ns1Ag=; b=iskMJWdRWoBUVXW+Pp8+vFsAY/Z3EOhs+f/dLPgCk7r77iXhT+r3MNv+Vb4UolyW80 SMuIDcC12iY+ZQjwXYEiVGlzkQ6WwC49/bWAxglqA5OBJKfs1mf6vsfKAGph+LgNFLAJ W25RQxAhH6V/FkkaO+IVHUZ2O/KsYY+wutA4HRhvcgCII9JYgT1sfQM+y9VobnRUO1ic XQogI0WgedgKDTj5MSNwNYOVcxcZJrY6jqeBfjvN+AC5DtZU3HnNFixeaxxQ4VNo8M+f tMcIFN5WyWO1+AkzCi/3pVjMfcN1sGrg9oohTPxdZfckaXGf1gk2Yi1DqE9J2+7J0ML9 BIEw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=lWHuCJIXD0FH0wHnqL7ztyciST3M6rGFO/A4c8Ns1Ag=; b=HdLoDMK3MsF2a29dRTTGT5ETLZV8QlRI3V30kq4HLMbCVKMzBn49fEcGO9zq7ZN6MT pWGpbF5GTlMccp4PiEgDV1eovVlo5hXIMQI6ubGkFNgF2iyIQZudkgeBviAJNlFAs/+l FP3JD7pqQ7GdqMugoOa2YMqdBmjvyae36umEzS+zXLQH4LY/bLpFhHy+zNxr82PEome6 FogiNcGaSq91Fh4gscNX9DLgAji0wOqUrRDs3yKeT+9+bHrUNBXTDqG3Vr2EFq3i0xPi oF0Kc91696UGO0bheKVxsCgoLa5JmIWQcPqrepx5hT5jIFlNGfSvKG8+ePrDaK7XxcRD 0S1w== X-Gm-Message-State: AOUpUlE0Qtvv1dtwphRyXo3U9EGbCgZ3oNirN3bianYiMn8rvF1gLGOp RwULEo7gOKJDfNrmtccSKAZQT/VU X-Google-Smtp-Source: AAOMgpdSwzwtjzrCKcZeEOREtVkOH4lFKLGygD+9+A982Ac1fODS8SL1BOu0zQO/1lqOB9Vm0GRwrg== X-Received: by 2002:a17:902:7446:: with SMTP id e6-v6mr440678plt.161.1533170460300; Wed, 01 Aug 2018 17:41:00 -0700 (PDT) Received: from Husky.eng.vmware.com ([66.170.99.1]) by smtp.gmail.com with ESMTPSA id s73-v6sm328627pfi.154.2018.08.01.17.40.58 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Aug 2018 17:40:59 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Wed, 1 Aug 2018 17:35:46 -0700 Message-Id: <1533170156-769-2-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533170156-769-1-git-send-email-yihung.wei@gmail.com> References: <1533170156-769-1-git-send-email-yihung.wei@gmail.com> X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v2 01/11] compat: Backport nf_ct_netns_{get, put}() X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org This patch backports nf_ct_netns_get/put() in order to support a feature in the follow up patch. nf_ct_netns_{get,put} were first introduced in upstream net-next commit ecb2421b5ddf ("netfilter: add and use nf_ct_netns_get/put") in kernel v4.10, and then updated in commmit 7e35ec0e8044 ("netfilter: conntrack: move nf_ct_netns_{get,put}() to core") in kernel v4.15. We need to invoke nf_ct_netns_get/put() when the underlying nf_conntrack_l3proto supports net_ns_{get,put}(). Therefore, there are 3 cases that we need to consider. 1) Before nf_ct_{get,put}() is introduced. We just mock nf_ct_nets_{get,put}() and do nothing. 2) After 1) and before v4.15 Backports based on commit 7e35ec0e8044 . 3) Staring from v4.15 Use the upstream version. Signed-off-by: Yi-Hung Wei --- acinclude.m4 | 4 + datapath/linux/Modules.mk | 4 +- .../compat/include/net/netfilter/nf_conntrack.h | 8 ++ .../linux/compat/include/uapi/linux/netfilter.h | 14 +++ datapath/linux/compat/nf_conntrack_proto.c | 112 +++++++++++++++++++++ 5 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 datapath/linux/compat/include/uapi/linux/netfilter.h create mode 100644 datapath/linux/compat/nf_conntrack_proto.c diff --git a/acinclude.m4 b/acinclude.m4 index ad6b5b5e067e..731bc07be8fa 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -588,6 +588,8 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [ [OVS_DEFINE([HAVE_NF_HOOKFN_ARG_PRIV])]) OVS_FIND_FIELD_IFELSE([$KSRC/include/linux/netfilter.h], [nf_hook_ops], [owner], [OVS_DEFINE([HAVE_NF_HOOKS_OPS_OWNER])]) + OVS_GREP_IFELSE([$KSRC/include/linux/netfilter.h], [NFPROTO_INET]) + OVS_FIND_FIELD_IFELSE([$KSRC/include/linux/netfilter_ipv6.h], [nf_ipv6_ops], [fragment.*sock], [OVS_DEFINE([HAVE_NF_IPV6_OPS_FRAGMENT])]) @@ -610,6 +612,8 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [ [nf_ct_is_untracked]) OVS_GREP_IFELSE([$KSRC/include/net/netfilter/nf_conntrack_zones.h], [nf_ct_zone_init]) + OVS_FIND_FIELD_IFELSE([$KSRC/include/net/netfilter/nf_conntrack_l3proto.h], + [net_ns_get]) OVS_GREP_IFELSE([$KSRC/include/net/netfilter/nf_conntrack_labels.h], [nf_connlabels_get]) OVS_FIND_PARAM_IFELSE([$KSRC/include/net/netfilter/nf_conntrack_labels.h], diff --git a/datapath/linux/Modules.mk b/datapath/linux/Modules.mk index 104c32fa16ea..04ea5b756b6c 100644 --- a/datapath/linux/Modules.mk +++ b/datapath/linux/Modules.mk @@ -18,6 +18,7 @@ openvswitch_sources += \ linux/compat/lisp.c \ linux/compat/netdevice.c \ linux/compat/nf_conntrack_core.c \ + linux/compat/nf_conntrack_proto.c \ linux/compat/nf_conntrack_reasm.c \ linux/compat/reciprocal_div.c \ linux/compat/skbuff-openvswitch.c \ @@ -107,5 +108,6 @@ openvswitch_headers += \ linux/compat/include/net/netfilter/nf_nat.h \ linux/compat/include/net/netfilter/ipv6/nf_defrag_ipv6.h \ linux/compat/include/net/sctp/checksum.h \ - linux/compat/include/net/erspan.h + linux/compat/include/net/erspan.h \ + linux/compat/include/uapi/linux/netfilter.h EXTRA_DIST += linux/compat/build-aux/export-check-whitelist diff --git a/datapath/linux/compat/include/net/netfilter/nf_conntrack.h b/datapath/linux/compat/include/net/netfilter/nf_conntrack.h index bb40b0f6da2a..50db914a39a1 100644 --- a/datapath/linux/compat/include/net/netfilter/nf_conntrack.h +++ b/datapath/linux/compat/include/net/netfilter/nf_conntrack.h @@ -22,4 +22,12 @@ nf_ct_set(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info info) skb->nfctinfo = info; } #endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0) +int rpl_nf_ct_netns_get(struct net *net, u8 nfproto); +void rpl_nf_ct_netns_put(struct net *net, u8 nfproto); +#define nf_ct_netns_get rpl_nf_ct_netns_get +#define nf_ct_netns_put rpl_nf_ct_netns_put +#endif + #endif /* _NF_CONNTRACK_WRAPPER_H */ diff --git a/datapath/linux/compat/include/uapi/linux/netfilter.h b/datapath/linux/compat/include/uapi/linux/netfilter.h new file mode 100644 index 000000000000..56895b17b334 --- /dev/null +++ b/datapath/linux/compat/include/uapi/linux/netfilter.h @@ -0,0 +1,14 @@ +#ifndef _NETFILTER_WRAPPER_H +#define _NETFILTER_WRAPPER_H + +#include_next + +/* + * NFPROTO_INET was introduced in net-next commit 1d49144c0aaa + * ("netfilter: nf_tables: add "inet" table for IPv4/IPv6") in v3.14. + * Define this symbol to support back to v3.10 kernel. */ +#ifndef HAVE_NFPROTO_INET +#define NFPROTO_INET 1 +#endif + +#endif /* _NETFILTER_WRAPPER_H */ diff --git a/datapath/linux/compat/nf_conntrack_proto.c b/datapath/linux/compat/nf_conntrack_proto.c new file mode 100644 index 000000000000..e877d763892d --- /dev/null +++ b/datapath/linux/compat/nf_conntrack_proto.c @@ -0,0 +1,112 @@ +#include + +#include +#include + +/* + * Upstream net-next commmit 7e35ec0e8044 + * ("netfilter: conntrack: move nf_ct_netns_{get,put}() to core") + * is introduced in v4.15, and it supports NFPROTO_INET in + * nf_ct_netns_{get,put}() that OVS conntrack uses this feature. + * + * However, we only need this feature if the underlying nf_conntrack_l3proto + * supports net_ns_get/put. Thus, we just mock the functions if + * HAVE_NET_NS_SET is false. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0) +#ifdef HAVE_NET_NS_SET +static int nf_ct_netns_do_get(struct net *net, u8 nfproto) +{ + const struct nf_conntrack_l3proto *l3proto; + int ret; + + might_sleep(); + + ret = nf_ct_l3proto_try_module_get(nfproto); + if (ret < 0) + return ret; + + /* we already have a reference, can't fail */ + rcu_read_lock(); + l3proto = __nf_ct_l3proto_find(nfproto); + rcu_read_unlock(); + + if (!l3proto->net_ns_get) + return 0; + + ret = l3proto->net_ns_get(net); + if (ret < 0) + nf_ct_l3proto_module_put(nfproto); + + return ret; +} + +int rpl_nf_ct_netns_get(struct net *net, u8 nfproto) +{ + int err; + + if (nfproto == NFPROTO_INET) { + err = nf_ct_netns_do_get(net, NFPROTO_IPV4); + if (err < 0) + goto err1; + err = nf_ct_netns_do_get(net, NFPROTO_IPV6); + if (err < 0) + goto err2; + } else { + err = nf_ct_netns_do_get(net, nfproto); + if (err < 0) + goto err1; + } + return 0; + +err2: + nf_ct_netns_put(net, NFPROTO_IPV4); +err1: + return err; +} +EXPORT_SYMBOL_GPL(rpl_nf_ct_netns_get); + +static void nf_ct_netns_do_put(struct net *net, u8 nfproto) +{ + const struct nf_conntrack_l3proto *l3proto; + + might_sleep(); + + /* same as nf_conntrack_netns_get(), reference assumed */ + rcu_read_lock(); + l3proto = __nf_ct_l3proto_find(nfproto); + rcu_read_unlock(); + + if (WARN_ON(!l3proto)) + return; + + if (l3proto->net_ns_put) + l3proto->net_ns_put(net); + + nf_ct_l3proto_module_put(nfproto); +} + +void rpl_nf_ct_netns_put(struct net *net, uint8_t nfproto) +{ + if (nfproto == NFPROTO_INET) { + nf_ct_netns_do_put(net, NFPROTO_IPV4); + nf_ct_netns_do_put(net, NFPROTO_IPV6); + } else + nf_ct_netns_do_put(net, nfproto); +} +EXPORT_SYMBOL_GPL(rpl_nf_ct_netns_put); + +#else /* !HAVE_NET_NS_SET */ +void rpl_nf_ct_netns_put(struct net *net, uint8_t nfproto) +{ +} +EXPORT_SYMBOL_GPL(rpl_nf_ct_netns_put); + +int rpl_nf_ct_netns_get(struct net *net, u8 nfproto) +{ + return 0; +} +EXPORT_SYMBOL_GPL(rpl_nf_ct_netns_get); + +#endif /* HAVE_NET_NS_SET */ +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0) */ From patchwork Thu Aug 2 00:35:47 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi-Hung Wei X-Patchwork-Id: 952490 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="IfRzoJ2X"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41grwP6dFfz9s3x for ; Thu, 2 Aug 2018 10:41:57 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 8500FE31; Thu, 2 Aug 2018 00:41:06 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id EFCC1E1E for ; Thu, 2 Aug 2018 00:41:04 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pl0-f66.google.com (mail-pl0-f66.google.com [209.85.160.66]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 63EE77B3 for ; Thu, 2 Aug 2018 00:41:03 +0000 (UTC) Received: by mail-pl0-f66.google.com with SMTP id m1-v6so201615plt.6 for ; Wed, 01 Aug 2018 17:41:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=HBCL7QLLULMt3R7Uvg3jOmyy5fBjUr+EGbGcE9O9cxA=; b=IfRzoJ2XO5BhpfviyoS3RS+Zur9o4Djlb2RDt6DhljrLOXw9txqdUe0oYLFpXcBO36 ZeWE//ny11qNyIqJygXYQMrS9ZC9xzh10m2tEiVNQHlxUOvlQm0ZJ9me7DVKlji5IwHk 3EIW+aKTC7WVxWFmr9zNS0DEMC/xvzbRehn5NSq5GEZG+kzmaJVCJcPsWWQ6UBJxh3Tb 5W9v3lFP/QSPjJ8Mi0GHZdo0sHtwWHpfYIzmilvznIDS0PtvsgLVvvinRxb9DRXcw8dq FPquFe0r2ZfCgd+0FSJjFOUctCkDweWx0PzRZrZWeEysNvMlkN5wn2FCd3oJjClyaHmE lWvA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=HBCL7QLLULMt3R7Uvg3jOmyy5fBjUr+EGbGcE9O9cxA=; b=aW8YXHg4C7JU1QPpqsJoRW4+LYymvJyIY1BN7v+XEMxFJfpRHXt3YcW8GAAAB0L4eg q7z1XWMDO/p4fTNgqm1ht2Ieeq8ohar+gdl8wlwaKJDxBeW0OqPP8ZOwHZWgHecrqyno FNGky6QXZ9PH/JaCOdV8CsGyVUO4HnMdUPLdhqfiGfw7bD0flQ82zmwzc2Tot/bnVxSx R6czZWBYOQgBJAJAhb/enMo3gX9+DOUuRK03JuVPYlw8C6uIW3LuR/UkDatBuRueAWnT zofuTdN68eX0rDSPftr+71IpiG1fajf880MC+iTtFaH++LZnr4V4ZqUoNpA5gxWvVoNn N6pw== X-Gm-Message-State: AOUpUlE3Gzu/lZsk3IPyWeeQ94gk3IavI0+USk6eVY2LkwfYgz1UXC6W nvHsAds9oGPkiwWlZ8IQuHqThZzP X-Google-Smtp-Source: AAOMgpfHj12vBw9je56JCOtdJVnDQsm/IEdLpd0R5d5ARa3WZb9doJZ1901VOAd1wsALfmPidHEFVA== X-Received: by 2002:a17:902:123:: with SMTP id 32-v6mr430400plb.181.1533170462246; Wed, 01 Aug 2018 17:41:02 -0700 (PDT) Received: from Husky.eng.vmware.com ([66.170.99.1]) by smtp.gmail.com with ESMTPSA id s73-v6sm328627pfi.154.2018.08.01.17.41.00 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Aug 2018 17:41:00 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Wed, 1 Aug 2018 17:35:47 -0700 Message-Id: <1533170156-769-3-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533170156-769-1-git-send-email-yihung.wei@gmail.com> References: <1533170156-769-1-git-send-email-yihung.wei@gmail.com> X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v2 02/11] datapath: compat: Backports nf_conncount X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org This patch backports the nf_conncount backend that counts the number of connections matching an arbitrary key. The following patch will use the feature to support connection tracking zone limit in ovs kernel datapath. This backport is based on an upstream net-next commit 5c789e131cbb ("netfilter: nf_conncount: Add list lock and gc worker, and RCU for init tree search") that applies a couple of techniques to optimize nf_conncount performance. The upstream nf_conncount has a couple of export functions while this patch only export the ones that ovs kernel module needs. Signed-off-by: Yi-Hung Wei --- acinclude.m4 | 2 + datapath/linux/Modules.mk | 2 + .../include/net/netfilter/nf_conntrack_count.h | 61 ++ datapath/linux/compat/nf_conncount.c | 637 +++++++++++++++++++++ 4 files changed, 702 insertions(+) create mode 100644 datapath/linux/compat/include/net/netfilter/nf_conntrack_count.h create mode 100644 datapath/linux/compat/nf_conncount.c diff --git a/acinclude.m4 b/acinclude.m4 index 731bc07be8fa..96fcad55a7cb 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -625,6 +625,8 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [ OVS_GREP_IFELSE([$KSRC/include/net/netfilter/nf_nat.h], [nf_nat_alloc_null_binding]) OVS_GREP_IFELSE([$KSRC/include/net/netfilter/nf_nat.h], [nf_nat_range2]) OVS_GREP_IFELSE([$KSRC/include/net/netfilter/nf_conntrack_seqadj.h], [nf_ct_seq_adjust]) + OVS_GREP_IFELSE([$KSRC/include/net/netfilter/nf_conntrack_count.h], [nf_conncount_gc_list], + [OVS_DEFINE([HAVE_UPSTREAM_NF_CONNCOUNT])]) OVS_GREP_IFELSE([$KSRC/include/linux/random.h], [prandom_u32]) OVS_GREP_IFELSE([$KSRC/include/linux/random.h], [prandom_u32_max]) diff --git a/datapath/linux/Modules.mk b/datapath/linux/Modules.mk index 04ea5b756b6c..f5c3b6580ad7 100644 --- a/datapath/linux/Modules.mk +++ b/datapath/linux/Modules.mk @@ -17,6 +17,7 @@ openvswitch_sources += \ linux/compat/ip6_tunnel.c \ linux/compat/lisp.c \ linux/compat/netdevice.c \ + linux/compat/nf_conncount.c \ linux/compat/nf_conntrack_core.c \ linux/compat/nf_conntrack_proto.c \ linux/compat/nf_conntrack_reasm.c \ @@ -100,6 +101,7 @@ openvswitch_headers += \ linux/compat/include/net/vxlan.h \ linux/compat/include/net/netfilter/nf_conntrack.h \ linux/compat/include/net/netfilter/nf_conntrack_core.h \ + linux/compat/include/net/netfilter/nf_conntrack_count.h \ linux/compat/include/net/netfilter/nf_conntrack_expect.h \ linux/compat/include/net/netfilter/nf_conntrack_helper.h \ linux/compat/include/net/netfilter/nf_conntrack_labels.h \ diff --git a/datapath/linux/compat/include/net/netfilter/nf_conntrack_count.h b/datapath/linux/compat/include/net/netfilter/nf_conntrack_count.h new file mode 100644 index 000000000000..fd536f3e1854 --- /dev/null +++ b/datapath/linux/compat/include/net/netfilter/nf_conntrack_count.h @@ -0,0 +1,61 @@ +#ifndef _NF_CONNTRACK_COUNT_WRAPPER_H +#define _NF_CONNTRACK_COUNT_WRAPPER_H + +#include + +#ifdef HAVE_UPSTREAM_NF_CONNCOUNT +#include_next + +static inline int rpl_nf_conncount_modinit(void) +{ + return 0; +} + +static inline void rpl_nf_conncount_modexit(void) +{ +} + +#else +#include +#include +#define CONFIG_NETFILTER_CONNCOUNT 1 +struct nf_conncount_data; + +enum nf_conncount_list_add { + NF_CONNCOUNT_ADDED, /* list add was ok */ + NF_CONNCOUNT_ERR, /* -ENOMEM, must drop skb */ + NF_CONNCOUNT_SKIP, /* list is already reclaimed by gc */ +}; + +struct nf_conncount_list { + spinlock_t list_lock; + struct list_head head; /* connections with the same filtering key */ + unsigned int count; /* length of list */ + bool dead; +}; + +struct nf_conncount_data +*rpl_nf_conncount_init(struct net *net, unsigned int family, + unsigned int keylen); + +void rpl_nf_conncount_destroy(struct net *net, unsigned int family, + struct nf_conncount_data *data); + +unsigned int rpl_nf_conncount_count(struct net *net, + struct nf_conncount_data *data, + const u32 *key, + const struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_zone *zone); + +#define nf_conncount_init rpl_nf_conncount_init +#define nf_conncount_destroy rpl_nf_conncount_destroy +#define nf_conncount_count rpl_nf_conncount_count + +int rpl_nf_conncount_modinit(void); +void rpl_nf_conncount_modexit(void); +#endif /* HAVE_UPSTREAM_NF_CONNCOUNT */ + +#define nf_conncount_mod_init rpl_nf_conncount_modinit +#define nf_conncount_modexit rpl_nf_conncount_modexit + +#endif /* _NF_CONNTRACK_COUNT_WRAPPER_H */ diff --git a/datapath/linux/compat/nf_conncount.c b/datapath/linux/compat/nf_conncount.c new file mode 100644 index 000000000000..0bee96274b00 --- /dev/null +++ b/datapath/linux/compat/nf_conncount.c @@ -0,0 +1,637 @@ +/* + * Backported from upstream commit 5c789e131cbb ("netfilter: + * nf_conncount: Add list lock and gc worker, and RCU for init tree search") + * + * count the number of connections matching an arbitrary key. + * + * (C) 2017 Red Hat GmbH + * Author: Florian Westphal + * + * split from xt_connlimit.c: + * (c) 2000 Gerd Knorr + * Nov 2002: Martin Bene : + * only ignore TIME_WAIT or gone connections + * (C) CC Computer Consultants GmbH, 2007 + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CONNCOUNT_SLOTS 256U + +#ifdef CONFIG_LOCKDEP +#define CONNCOUNT_LOCK_SLOTS 8U +#else +#define CONNCOUNT_LOCK_SLOTS 256U +#endif + +#define CONNCOUNT_GC_MAX_NODES 8 +#define MAX_KEYLEN 5 + +/* we will save the tuples of all connections we care about */ +struct nf_conncount_tuple { + struct list_head node; + struct nf_conntrack_tuple tuple; + struct nf_conntrack_zone zone; + int cpu; + u32 jiffies32; + struct rcu_head rcu_head; +}; + +struct nf_conncount_rb { + struct rb_node node; + struct nf_conncount_list list; + u32 key[MAX_KEYLEN]; + struct rcu_head rcu_head; +}; + +static spinlock_t nf_conncount_locks[CONNCOUNT_LOCK_SLOTS] __cacheline_aligned_in_smp; + +struct nf_conncount_data { + unsigned int keylen; + struct rb_root root[CONNCOUNT_SLOTS]; + struct net *net; + struct work_struct gc_work; + unsigned long pending_trees[BITS_TO_LONGS(CONNCOUNT_SLOTS)]; + unsigned int gc_tree; +}; + +static u_int32_t conncount_rnd __read_mostly; +static struct kmem_cache *conncount_rb_cachep __read_mostly; +static struct kmem_cache *conncount_conn_cachep __read_mostly; + +static inline bool already_closed(const struct nf_conn *conn) +{ + if (nf_ct_protonum(conn) == IPPROTO_TCP) + return conn->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT || + conn->proto.tcp.state == TCP_CONNTRACK_CLOSE; + else + return false; +} + +static int key_diff(const u32 *a, const u32 *b, unsigned int klen) +{ + return memcmp(a, b, klen * sizeof(u32)); +} + +static enum nf_conncount_list_add +nf_conncount_add(struct nf_conncount_list *list, + const struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_zone *zone) +{ + struct nf_conncount_tuple *conn; + + if (WARN_ON_ONCE(list->count > INT_MAX)) + return NF_CONNCOUNT_ERR; + + conn = kmem_cache_alloc(conncount_conn_cachep, GFP_ATOMIC); + if (conn == NULL) + return NF_CONNCOUNT_ERR; + + conn->tuple = *tuple; + conn->zone = *zone; + conn->cpu = raw_smp_processor_id(); + conn->jiffies32 = (u32)jiffies; + spin_lock(&list->list_lock); + if (list->dead == true) { + kmem_cache_free(conncount_conn_cachep, conn); + spin_unlock(&list->list_lock); + return NF_CONNCOUNT_SKIP; + } + list_add_tail(&conn->node, &list->head); + list->count++; + spin_unlock(&list->list_lock); + return NF_CONNCOUNT_ADDED; +} + +static void __conn_free(struct rcu_head *h) +{ + struct nf_conncount_tuple *conn; + + conn = container_of(h, struct nf_conncount_tuple, rcu_head); + kmem_cache_free(conncount_conn_cachep, conn); +} + +static bool conn_free(struct nf_conncount_list *list, + struct nf_conncount_tuple *conn) +{ + bool free_entry = false; + + spin_lock(&list->list_lock); + + if (list->count == 0) { + spin_unlock(&list->list_lock); + return free_entry; + } + + list->count--; + list_del_rcu(&conn->node); + if (list->count == 0) + free_entry = true; + + spin_unlock(&list->list_lock); + call_rcu(&conn->rcu_head, __conn_free); + return free_entry; +} + +static const struct nf_conntrack_tuple_hash * +find_or_evict(struct net *net, struct nf_conncount_list *list, + struct nf_conncount_tuple *conn, bool *free_entry) +{ + const struct nf_conntrack_tuple_hash *found; + unsigned long a, b; + int cpu = raw_smp_processor_id(); + __s32 age; + + found = nf_conntrack_find_get(net, &conn->zone, &conn->tuple); + if (found) + return found; + b = conn->jiffies32; + a = (u32)jiffies; + + /* conn might have been added just before by another cpu and + * might still be unconfirmed. In this case, nf_conntrack_find() + * returns no result. Thus only evict if this cpu added the + * stale entry or if the entry is older than two jiffies. + */ + age = a - b; + if (conn->cpu == cpu || age >= 2) { + *free_entry = conn_free(list, conn); + return ERR_PTR(-ENOENT); + } + + return ERR_PTR(-EAGAIN); +} + +static void nf_conncount_lookup(struct net *net, + struct nf_conncount_list *list, + const struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_zone *zone, + bool *addit) +{ + const struct nf_conntrack_tuple_hash *found; + struct nf_conncount_tuple *conn, *conn_n; + struct nf_conn *found_ct; + unsigned int collect = 0; + bool free_entry = false; + + /* best effort only */ + *addit = tuple ? true : false; + + /* check the saved connections */ + list_for_each_entry_safe(conn, conn_n, &list->head, node) { + if (collect > CONNCOUNT_GC_MAX_NODES) + break; + + found = find_or_evict(net, list, conn, &free_entry); + if (IS_ERR(found)) { + /* Not found, but might be about to be confirmed */ + if (PTR_ERR(found) == -EAGAIN) { + if (!tuple) + continue; + + if (nf_ct_tuple_equal(&conn->tuple, tuple) && + nf_ct_zone_id(&conn->zone, conn->zone.dir) == + nf_ct_zone_id(zone, zone->dir)) + *addit = false; + } else if (PTR_ERR(found) == -ENOENT) + collect++; + continue; + } + + found_ct = nf_ct_tuplehash_to_ctrack(found); + + if (tuple && nf_ct_tuple_equal(&conn->tuple, tuple) && + nf_ct_zone_equal(found_ct, zone, zone->dir)) { + /* + * We should not see tuples twice unless someone hooks + * this into a table without "-p tcp --syn". + * + * Attempt to avoid a re-add in this case. + */ + *addit = false; + } else if (already_closed(found_ct)) { + /* + * we do not care about connections which are + * closed already -> ditch it + */ + nf_ct_put(found_ct); + conn_free(list, conn); + collect++; + continue; + } + + nf_ct_put(found_ct); + } +} + +static void nf_conncount_list_init(struct nf_conncount_list *list) +{ + spin_lock_init(&list->list_lock); + INIT_LIST_HEAD(&list->head); + list->count = 1; + list->dead = false; +} + +/* Return true if the list is empty */ +static bool nf_conncount_gc_list(struct net *net, + struct nf_conncount_list *list) +{ + const struct nf_conntrack_tuple_hash *found; + struct nf_conncount_tuple *conn, *conn_n; + struct nf_conn *found_ct; + unsigned int collected = 0; + bool free_entry = false; + + list_for_each_entry_safe(conn, conn_n, &list->head, node) { + found = find_or_evict(net, list, conn, &free_entry); + if (IS_ERR(found)) { + if (PTR_ERR(found) == -ENOENT) { + if (free_entry) + return true; + collected++; + } + continue; + } + + found_ct = nf_ct_tuplehash_to_ctrack(found); + if (already_closed(found_ct)) { + /* + * we do not care about connections which are + * closed already -> ditch it + */ + nf_ct_put(found_ct); + if (conn_free(list, conn)) + return true; + collected++; + continue; + } + + nf_ct_put(found_ct); + if (collected > CONNCOUNT_GC_MAX_NODES) + return false; + } + return false; +} + +static void __tree_nodes_free(struct rcu_head *h) +{ + struct nf_conncount_rb *rbconn; + + rbconn = container_of(h, struct nf_conncount_rb, rcu_head); + kmem_cache_free(conncount_rb_cachep, rbconn); +} + +static void tree_nodes_free(struct rb_root *root, + struct nf_conncount_rb *gc_nodes[], + unsigned int gc_count) +{ + struct nf_conncount_rb *rbconn; + + while (gc_count) { + rbconn = gc_nodes[--gc_count]; + spin_lock(&rbconn->list.list_lock); + if (rbconn->list.count == 0 && rbconn->list.dead == false) { + rbconn->list.dead = true; + rb_erase(&rbconn->node, root); + call_rcu(&rbconn->rcu_head, __tree_nodes_free); + } + spin_unlock(&rbconn->list.list_lock); + } +} + +static void schedule_gc_worker(struct nf_conncount_data *data, int tree) +{ + set_bit(tree, data->pending_trees); + schedule_work(&data->gc_work); +} + +static unsigned int +insert_tree(struct net *net, + struct nf_conncount_data *data, + struct rb_root *root, + unsigned int hash, + const u32 *key, + u8 keylen, + const struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_zone *zone) +{ + enum nf_conncount_list_add ret; + struct nf_conncount_rb *gc_nodes[CONNCOUNT_GC_MAX_NODES]; + struct rb_node **rbnode, *parent; + struct nf_conncount_rb *rbconn; + struct nf_conncount_tuple *conn; + unsigned int count = 0, gc_count = 0; + bool node_found = false; + + spin_lock_bh(&nf_conncount_locks[hash % CONNCOUNT_LOCK_SLOTS]); + + parent = NULL; + rbnode = &(root->rb_node); + while (*rbnode) { + int diff; + rbconn = rb_entry(*rbnode, struct nf_conncount_rb, node); + + parent = *rbnode; + diff = key_diff(key, rbconn->key, keylen); + if (diff < 0) { + rbnode = &((*rbnode)->rb_left); + } else if (diff > 0) { + rbnode = &((*rbnode)->rb_right); + } else { + /* unlikely: other cpu added node already */ + node_found = true; + ret = nf_conncount_add(&rbconn->list, tuple, zone); + if (ret == NF_CONNCOUNT_ERR) { + count = 0; /* hotdrop */ + } else if (ret == NF_CONNCOUNT_ADDED) { + count = rbconn->list.count; + } else { + /* NF_CONNCOUNT_SKIP, rbconn is already + * reclaimed by gc, insert a new tree node + */ + node_found = false; + } + break; + } + + if (gc_count >= ARRAY_SIZE(gc_nodes)) + continue; + + if (nf_conncount_gc_list(net, &rbconn->list)) + gc_nodes[gc_count++] = rbconn; + } + + if (gc_count) { + tree_nodes_free(root, gc_nodes, gc_count); + /* tree_node_free before new allocation permits + * allocator to re-use newly free'd object. + * + * This is a rare event; in most cases we will find + * existing node to re-use. (or gc_count is 0). + */ + + if (gc_count >= ARRAY_SIZE(gc_nodes)) + schedule_gc_worker(data, hash); + } + + if (node_found) + goto out_unlock; + + /* expected case: match, insert new node */ + rbconn = kmem_cache_alloc(conncount_rb_cachep, GFP_ATOMIC); + if (rbconn == NULL) + goto out_unlock; + + conn = kmem_cache_alloc(conncount_conn_cachep, GFP_ATOMIC); + if (conn == NULL) { + kmem_cache_free(conncount_rb_cachep, rbconn); + goto out_unlock; + } + + conn->tuple = *tuple; + conn->zone = *zone; + memcpy(rbconn->key, key, sizeof(u32) * keylen); + + nf_conncount_list_init(&rbconn->list); + list_add(&conn->node, &rbconn->list.head); + count = 1; + + rb_link_node(&rbconn->node, parent, rbnode); + rb_insert_color(&rbconn->node, root); +out_unlock: + spin_unlock_bh(&nf_conncount_locks[hash % CONNCOUNT_LOCK_SLOTS]); + return count; +} + +static unsigned int +count_tree(struct net *net, + struct nf_conncount_data *data, + const u32 *key, + const struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_zone *zone) +{ + enum nf_conncount_list_add ret; + struct rb_root *root; + struct rb_node *parent; + struct nf_conncount_rb *rbconn; + unsigned int hash; + u8 keylen = data->keylen; + + hash = jhash2(key, data->keylen, conncount_rnd) % CONNCOUNT_SLOTS; + root = &data->root[hash]; + + parent = rcu_dereference_raw(root->rb_node); + while (parent) { + int diff; + bool addit; + + rbconn = rb_entry(parent, struct nf_conncount_rb, node); + + diff = key_diff(key, rbconn->key, keylen); + if (diff < 0) { + parent = rcu_dereference_raw(parent->rb_left); + } else if (diff > 0) { + parent = rcu_dereference_raw(parent->rb_right); + } else { + /* same source network -> be counted! */ + nf_conncount_lookup(net, &rbconn->list, tuple, zone, + &addit); + + if (!addit) + return rbconn->list.count; + + ret = nf_conncount_add(&rbconn->list, tuple, zone); + if (ret == NF_CONNCOUNT_ERR) { + return 0; /* hotdrop */ + } else if (ret == NF_CONNCOUNT_ADDED) { + return rbconn->list.count; + } else { + /* NF_CONNCOUNT_SKIP, rbconn is already + * reclaimed by gc, insert a new tree node + */ + break; + } + } + } + + if (!tuple) + return 0; + + return insert_tree(net, data, root, hash, key, keylen, tuple, zone); +} + +static void tree_gc_worker(struct work_struct *work) +{ + struct nf_conncount_data *data = container_of(work, struct nf_conncount_data, gc_work); + struct nf_conncount_rb *gc_nodes[CONNCOUNT_GC_MAX_NODES], *rbconn; + struct rb_root *root; + struct rb_node *node; + unsigned int tree, next_tree, gc_count = 0; + + tree = data->gc_tree % CONNCOUNT_LOCK_SLOTS; + root = &data->root[tree]; + + rcu_read_lock(); + for (node = rb_first(root); node != NULL; node = rb_next(node)) { + rbconn = rb_entry(node, struct nf_conncount_rb, node); + if (nf_conncount_gc_list(data->net, &rbconn->list)) + gc_nodes[gc_count++] = rbconn; + } + rcu_read_unlock(); + + spin_lock_bh(&nf_conncount_locks[tree]); + + if (gc_count) { + tree_nodes_free(root, gc_nodes, gc_count); + } + + clear_bit(tree, data->pending_trees); + + next_tree = (tree + 1) % CONNCOUNT_SLOTS; + next_tree = find_next_bit(data->pending_trees, next_tree, CONNCOUNT_SLOTS); + + if (next_tree < CONNCOUNT_SLOTS) { + data->gc_tree = next_tree; + schedule_work(work); + } + + spin_unlock_bh(&nf_conncount_locks[tree]); +} + +/* Count and return number of conntrack entries in 'net' with particular 'key'. + * If 'tuple' is not null, insert it into the accounting data structure. + * Call with RCU read lock. + */ +unsigned int rpl_nf_conncount_count(struct net *net, + struct nf_conncount_data *data, + const u32 *key, + const struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_zone *zone) +{ + return count_tree(net, data, key, tuple, zone); +} +EXPORT_SYMBOL_GPL(rpl_nf_conncount_count); + +struct nf_conncount_data *rpl_nf_conncount_init(struct net *net, unsigned int family, + unsigned int keylen) +{ + struct nf_conncount_data *data; + int ret, i; + + if (keylen % sizeof(u32) || + keylen / sizeof(u32) > MAX_KEYLEN || + keylen == 0) + return ERR_PTR(-EINVAL); + + net_get_random_once(&conncount_rnd, sizeof(conncount_rnd)); + + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return ERR_PTR(-ENOMEM); + + ret = nf_ct_netns_get(net, family); + if (ret < 0) { + kfree(data); + return ERR_PTR(ret); + } + + for (i = 0; i < ARRAY_SIZE(data->root); ++i) + data->root[i] = RB_ROOT; + + data->keylen = keylen / sizeof(u32); + data->net = net; + INIT_WORK(&data->gc_work, tree_gc_worker); + + return data; +} +EXPORT_SYMBOL_GPL(rpl_nf_conncount_init); + +static void nf_conncount_cache_free(struct nf_conncount_list *list) +{ + struct nf_conncount_tuple *conn, *conn_n; + + list_for_each_entry_safe(conn, conn_n, &list->head, node) + kmem_cache_free(conncount_conn_cachep, conn); +} + +static void destroy_tree(struct rb_root *r) +{ + struct nf_conncount_rb *rbconn; + struct rb_node *node; + + while ((node = rb_first(r)) != NULL) { + rbconn = rb_entry(node, struct nf_conncount_rb, node); + + rb_erase(node, r); + + nf_conncount_cache_free(&rbconn->list); + + kmem_cache_free(conncount_rb_cachep, rbconn); + } +} + +void rpl_nf_conncount_destroy(struct net *net, unsigned int family, + struct nf_conncount_data *data) +{ + unsigned int i; + + cancel_work_sync(&data->gc_work); + nf_ct_netns_put(net, family); + + for (i = 0; i < ARRAY_SIZE(data->root); ++i) + destroy_tree(&data->root[i]); + + kfree(data); +} +EXPORT_SYMBOL_GPL(rpl_nf_conncount_destroy); + +int rpl_nf_conncount_modinit(void) +{ + int i; + + BUILD_BUG_ON(CONNCOUNT_LOCK_SLOTS > CONNCOUNT_SLOTS); + BUILD_BUG_ON((CONNCOUNT_SLOTS % CONNCOUNT_LOCK_SLOTS) != 0); + + for (i = 0; i < CONNCOUNT_LOCK_SLOTS; ++i) + spin_lock_init(&nf_conncount_locks[i]); + + conncount_conn_cachep = kmem_cache_create("nf_conncount_tuple", + sizeof(struct nf_conncount_tuple), + 0, 0, NULL); + if (!conncount_conn_cachep) + return -ENOMEM; + + conncount_rb_cachep = kmem_cache_create("nf_conncount_rb", + sizeof(struct nf_conncount_rb), + 0, 0, NULL); + if (!conncount_rb_cachep) { + kmem_cache_destroy(conncount_conn_cachep); + return -ENOMEM; + } + + return 0; +} + +void rpl_nf_conncount_modexit(void) +{ + kmem_cache_destroy(conncount_conn_cachep); + kmem_cache_destroy(conncount_rb_cachep); +} From patchwork Thu Aug 2 00:35:48 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi-Hung Wei X-Patchwork-Id: 952491 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="n95wB40M"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41grxD1cDVz9s3q for ; Thu, 2 Aug 2018 10:42:40 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 6E697E3E; Thu, 2 Aug 2018 00:41:07 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id C5831E1E for ; Thu, 2 Aug 2018 00:41:05 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg1-f196.google.com (mail-pg1-f196.google.com [209.85.215.196]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 656D67AC for ; Thu, 2 Aug 2018 00:41:05 +0000 (UTC) Received: by mail-pg1-f196.google.com with SMTP id y5-v6so251032pgv.1 for ; Wed, 01 Aug 2018 17:41:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=QCcFYV5nV7mwUcPH81Fx3jMRKojWWg7VNZcxu3wulxE=; b=n95wB40MusqwU8t/kOS8qCcKdPmxRy4kzzT/TrrZqPbMWVSjou+q6AWICmL/I7OugC N8I4bied8ciCCbJjv02xL6YTf0HOU6mXUORFXHZbWjBNL3ZE+MQP2eseqdjzo7M/g2ka ztaUefy7UusbrmbVke/o7fZB942FW+jxmYIKtqvbuOzCLMB3t1nqezgDKNm68TPkgQbZ poyNYrR0f1Ds7slIkkja8sNhKu3Z91z/AE4XQAAiwHheEm0QT1pFppUm7NiJg+plqoof RipIOOqe68ku54bcGfvosnVcIhY6zp9zBU10czpZBl7s8NlzpQlNQn08kahhgcS9QNHZ FDbw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=QCcFYV5nV7mwUcPH81Fx3jMRKojWWg7VNZcxu3wulxE=; b=Vbabha4ZFbOi+QtRWdY8s7nWzJsKODmgo8EsU4l9OxjAuRQ/fGwQsm/l/trMmmtfwy qyg4/ZHGJ+MVmURrGe5ElBG5Yk8DPqwxAFLPO6qdFVtiUc77pvnG3T/dAbRkIcujWg99 d2QEmfw18aD9a69WFcB0+05D9W/pawlya8B4MVl/cjmbMIlh6yNj8kzdiqnScEk9iRhA 8/dsvQNbHc9fZChzP571kMlqnE7DS6BTOIq3CqSBEVgHhvYDygo57h3M7fRl7yfwl4oM Ese83eJk+v5pUT2R86mubsusudwYcWduK4sC7gghd6kPqycg+SAkwgkP0FUHxCpuQech EBmA== X-Gm-Message-State: AOUpUlEqwSM2bo5M8MfvzrMBVzBvr6AISsE85OSBNlukDLr0S5BilZq7 8s0hM4CJVIbU0glzBboVkl9sGs/o X-Google-Smtp-Source: AAOMgpdObvnPYx0fDIY3zKNYn3QPvVPMzXEuF2+MHAcNYkNb9h+lIHK5Rm/2/xYzeKsYk1c+3uiO0A== X-Received: by 2002:a63:65c2:: with SMTP id z185-v6mr536703pgb.276.1533170464408; Wed, 01 Aug 2018 17:41:04 -0700 (PDT) Received: from Husky.eng.vmware.com ([66.170.99.1]) by smtp.gmail.com with ESMTPSA id s73-v6sm328627pfi.154.2018.08.01.17.41.02 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Aug 2018 17:41:02 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Wed, 1 Aug 2018 17:35:48 -0700 Message-Id: <1533170156-769-4-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533170156-769-1-git-send-email-yihung.wei@gmail.com> References: <1533170156-769-1-git-send-email-yihung.wei@gmail.com> X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v2 03/11] datapath: compat: Introduce static key support X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org This is a feature that is needed for a follow up patch in ovs kernel datapath. Signed-off-by: Yi-Hung Wei --- acinclude.m4 | 3 + datapath/linux/Modules.mk | 1 + datapath/linux/compat/include/linux/static_key.h | 70 ++++++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 datapath/linux/compat/include/linux/static_key.h diff --git a/acinclude.m4 b/acinclude.m4 index 96fcad55a7cb..341edbbd70f1 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -467,6 +467,9 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [ OVS_GREP_IFELSE([$KSRC/include/linux/err.h], [IS_ERR_OR_NULL]) OVS_GREP_IFELSE([$KSRC/include/linux/err.h], [PTR_ERR_OR_ZERO]) + OVS_GREP_IFELSE([$KSRC/include/linux/jump_label.h], [DEFINE_STATIC_KEY_FALSE], + [OVS_DEFINE([HAVE_UPSTREAM_STATIC_KEY])]) + OVS_GREP_IFELSE([$KSRC/include/linux/etherdevice.h], [eth_hw_addr_random]) OVS_GREP_IFELSE([$KSRC/include/linux/etherdevice.h], [ether_addr_copy]) diff --git a/datapath/linux/Modules.mk b/datapath/linux/Modules.mk index f5c3b6580ad7..2fec6500e7c8 100644 --- a/datapath/linux/Modules.mk +++ b/datapath/linux/Modules.mk @@ -63,6 +63,7 @@ openvswitch_headers += \ linux/compat/include/linux/reciprocal_div.h \ linux/compat/include/linux/rtnetlink.h \ linux/compat/include/linux/skbuff.h \ + linux/compat/include/linux/static_key.h \ linux/compat/include/linux/stddef.h \ linux/compat/include/linux/types.h \ linux/compat/include/linux/u64_stats_sync.h \ diff --git a/datapath/linux/compat/include/linux/static_key.h b/datapath/linux/compat/include/linux/static_key.h new file mode 100644 index 000000000000..ea59e3e285a1 --- /dev/null +++ b/datapath/linux/compat/include/linux/static_key.h @@ -0,0 +1,70 @@ +#ifndef _STATIC_KEY_WRAPPER_H +#define _STATIC_KEY_WRAPPER_H + +#include_next +#ifndef HAVE_UPSTREAM_STATIC_KEY +/* + * This backport is based on upstream net-next commit 11276d5306b8 + * ("locking/static_keys: Add a new static_key interface"). + * + * For kernel that does not support the new static key interface, + * we do not backport the jump label support but the fall back version + * of static key that is simply a conditional branch. + */ + +struct static_key_true { + struct static_key key; +}; + +struct static_key_false { + struct static_key key; +}; + +#define rpl_STATIC_KEY_INIT_TRUE { .enabled = ATOMIC_INIT(1) } +#define rpl_STATIC_KEY_INIT_FALSE { .enabled = ATOMIC_INIT(0) } + +#define STATIC_KEY_TRUE_INIT \ + (struct static_key_true) { .key = rpl_STATIC_KEY_INIT_TRUE, } +#define STATIC_KEY_FALSE_INIT \ + (struct static_key_false){ .key = rpl_STATIC_KEY_INIT_FALSE, } + +#define DEFINE_STATIC_KEY_TRUE(name) \ + struct static_key_true name = STATIC_KEY_TRUE_INIT + +#define DEFINE_STATIC_KEY_FALSE(name) \ + struct static_key_false name = STATIC_KEY_FALSE_INIT + +static inline int rpl_static_key_count(struct static_key *key) +{ + return atomic_read(&key->enabled); +} + +static inline void rpl_static_key_enable(struct static_key *key) +{ + int count = rpl_static_key_count(key); + + WARN_ON_ONCE(count < 0 || count > 1); + + if (!count) + static_key_slow_inc(key); +} + +static inline void rpl_static_key_disable(struct static_key *key) +{ + int count = rpl_static_key_count(key); + + WARN_ON_ONCE(count < 0 || count > 1); + + if (count) + static_key_slow_dec(key); +} + +#define static_branch_likely(x) likely(static_key_enabled(&(x)->key)) +#define static_branch_unlikely(x) unlikely(static_key_enabled(&(x)->key)) + +#define static_branch_enable(x) rpl_static_key_enable(&(x)->key) +#define static_branch_disable(x) rpl_static_key_disable(&(x)->key) + +#endif /* HAVE_UPSTREAM_STATIC_KEY */ + +#endif /* _STATIC_KEY_WRAPPER_H */ From patchwork Thu Aug 2 00:35:49 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi-Hung Wei X-Patchwork-Id: 952492 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="cuN0YHQk"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41grxh4hJVz9s3q for ; Thu, 2 Aug 2018 10:43:04 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 29851E40; Thu, 2 Aug 2018 00:41:10 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 725A8E42 for ; Thu, 2 Aug 2018 00:41:07 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg1-f193.google.com (mail-pg1-f193.google.com [209.85.215.193]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 035BA7C3 for ; Thu, 2 Aug 2018 00:41:06 +0000 (UTC) Received: by mail-pg1-f193.google.com with SMTP id e6-v6so248082pgv.2 for ; Wed, 01 Aug 2018 17:41:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=wyehxtpQ9fypFbfzBbtWWRq2+STKJJlg0Q2ALF61F+0=; b=cuN0YHQkuct2PweeDaenKoh6gIG5FwoUAz7fOgJ90sXsu/r1yEgRVp2FPoad31kq9D psPUddNeH28YZM79afWQPPF5bGh/eXJojQJz973OX7Rs/xm4yzWFgVUb42CKSn+LNDyM yKj3ibdzwHLRUFRdbbh3Nh33mQv+W3ubikfktskR5+zm/FQh2CbvzmmGaOh5aHugonXm 89bdr72p2qy8lL7cEYMVcX983OYvCrIRPVTgOUmpmQo3mU2J120F7ek0CownXgVviNAY 2sgmxyUOjMoB8UWmzOsxzJwemyzmQAgMyiRL5dbdDdivKFPzHHscYEbqHzNU9qFaodOt EWFQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=wyehxtpQ9fypFbfzBbtWWRq2+STKJJlg0Q2ALF61F+0=; b=kXPjBrr17V9LbypeAlsDnCJwN/8GHqYtZmxWdESZqewhqlCWH0QnJchEglyceOYb+7 8vvt7kZkXOnq3e/ZBrnchWErIY8IfFKKHlEcS/AcbvWETAxpUC/jM+xAqTaMA6V7Yg9T qXCE3xwzGqAYhN6TKQbPDa0JSF55nRNU1/MrVXSgKgg1nBayNjuoPrH2vqC+7WsKHSOA f2NQd4BX7hwlO3/vzqBPyrxoPzbCwHXwdW+zC/AtykIK/IrDCF9N8PcTqgwKlusVYuyZ VVnw8bAOfPCpjm/zYo4pfEUnEeFD5dldCcehwrUz+ca1TDtq47SIlAWaJonWDBWylnGD XXcQ== X-Gm-Message-State: AOUpUlHOaLcHtxqu5SqOb3nsSmOXhFzkbUxCNs4K9/WM0CRXretPj9pP lzdehPwTRWXNc9UxFxoZnEs5D8u9 X-Google-Smtp-Source: AAOMgpczSNjchpebmzi/qKDgc5JgMLGG0kZp/NWZtZbkjJ9yNSlHHJsnOK1v+csmgfLlr2Pl0Oa0cQ== X-Received: by 2002:a63:e14a:: with SMTP id h10-v6mr549326pgk.358.1533170466202; Wed, 01 Aug 2018 17:41:06 -0700 (PDT) Received: from Husky.eng.vmware.com ([66.170.99.1]) by smtp.gmail.com with ESMTPSA id s73-v6sm328627pfi.154.2018.08.01.17.41.04 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Aug 2018 17:41:04 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Wed, 1 Aug 2018 17:35:49 -0700 Message-Id: <1533170156-769-5-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533170156-769-1-git-send-email-yihung.wei@gmail.com> References: <1533170156-769-1-git-send-email-yihung.wei@gmail.com> X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v2 04/11] datapath: Add conntrack limit netlink definition X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Upstream commit: commit 5972be6b2495c6bffbf444497517fd1c070eef78 Author: Yi-Hung Wei Date: Thu May 24 17:56:42 2018 -0700 openvswitch: Add conntrack limit netlink definition Define netlink messages and attributes to support user kernel communication that uses the conntrack limit feature. Signed-off-by: Yi-Hung Wei Acked-by: Pravin B Shelar Signed-off-by: David S. Miller Signed-off-by: Yi-Hung Wei --- datapath/linux/compat/include/linux/openvswitch.h | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h index 8e5f3b6fbfb1..aaeb0341ab51 100644 --- a/datapath/linux/compat/include/linux/openvswitch.h +++ b/datapath/linux/compat/include/linux/openvswitch.h @@ -1004,4 +1004,32 @@ enum ovs_meter_band_type { #define OVS_METER_BAND_TYPE_MAX (__OVS_METER_BAND_TYPE_MAX - 1) +/* Conntrack limit */ +#define OVS_CT_LIMIT_FAMILY "ovs_ct_limit" +#define OVS_CT_LIMIT_MCGROUP "ovs_ct_limit" +#define OVS_CT_LIMIT_VERSION 0x1 + +enum ovs_ct_limit_cmd { + OVS_CT_LIMIT_CMD_UNSPEC, + OVS_CT_LIMIT_CMD_SET, /* Add or modify ct limit. */ + OVS_CT_LIMIT_CMD_DEL, /* Delete ct limit. */ + OVS_CT_LIMIT_CMD_GET /* Get ct limit. */ +}; + +enum ovs_ct_limit_attr { + OVS_CT_LIMIT_ATTR_UNSPEC, + OVS_CT_LIMIT_ATTR_ZONE_LIMIT, /* Nested struct ovs_zone_limit. */ + __OVS_CT_LIMIT_ATTR_MAX +}; + +#define OVS_CT_LIMIT_ATTR_MAX (__OVS_CT_LIMIT_ATTR_MAX - 1) + +#define OVS_ZONE_LIMIT_DEFAULT_ZONE -1 + +struct ovs_zone_limit { + int zone_id; + __u32 limit; + __u32 count; +}; + #endif /* _LINUX_OPENVSWITCH_H */ From patchwork Thu Aug 2 00:35:50 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi-Hung Wei X-Patchwork-Id: 952493 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="nALSj6gV"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41gry80n17z9s3x for ; Thu, 2 Aug 2018 10:43:27 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id DE728E47; Thu, 2 Aug 2018 00:41:11 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id A8C21E4E for ; Thu, 2 Aug 2018 00:41:10 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf1-f194.google.com (mail-pf1-f194.google.com [209.85.210.194]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 3983D7C1 for ; Thu, 2 Aug 2018 00:41:09 +0000 (UTC) Received: by mail-pf1-f194.google.com with SMTP id i26-v6so244438pfo.12 for ; Wed, 01 Aug 2018 17:41:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=d8+qcejRiC3RArrw5JWXmfFdcTJ2wxZByfg4jRoAKsM=; b=nALSj6gV40AioEvervwGFHeWRqO7Oeu1if/Ft0cEiWCcehciRLORZPB0W3X7harTR2 TO1NBTH1inZ+U2fQxtINL2hmzaYglQSBRlNuSpzkVGCJC2BfdvEbE82y8O0iZTpitYkS /13lj1c6pKeDzPaov4JWcKoAzQ79aw3G0xQsRP+rxzf/PpLpNgbbliNms/YHVcIj6HW1 46m6Gt6Uy+7IohY57WtzcZ3HxZARIPizcPDCVEhp7JxPD1z/dgEUhzEGOdP+xYT8rtA/ vnrq4doH7HFS0D4azs4hXMyheYHUlxIPydGhE575mjDhlb6skfwAGiVR5sLwS+IkcjYz tYNA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=d8+qcejRiC3RArrw5JWXmfFdcTJ2wxZByfg4jRoAKsM=; b=XUpB+wsQJwrinx5Rxe1G0xzW9nWUQPui6F6sPb5d++mf90rQo4l+T+XBaRrpucypvX hFKzEyhC/iFDh2a23AT+tFT8qiR2iwWAt2BArkioL5259uHTDrJThTT9lgdvzYvJuEyl kZ/IyGobrFWUfvALM0a4Nf10Yo3tVDdSMLcvbzTI6nppDof3j8xdRJx+UDxw/oc94agb mz2yleBtDYKMEVPpueHV5eQqnRHJCmi8hQX85oAs+0FpAqO8rVtEI4+BhdV1IrFTKa+e UmIzrvJo+BV1Vq4oyR8bdLPqL5TRuVnhUrb9xKWrJRVbQRrBRi385Dhimvq4ADxjq7fu paTg== X-Gm-Message-State: AOUpUlFicJF4z8YuvAu288x8ipxRR0NcjN2lD6mjoGlVYs8nZPRPrhF9 l6gR8gudO1sQOPxAMeh5BvsZsgq+ X-Google-Smtp-Source: AAOMgpdx/rMcRywIpPyMgy41ZIZUGHEd0BLjJ76U8FxXjI3EbFWSlkDK+IOwOBlylxhi5yUosWuDHA== X-Received: by 2002:a63:2dc1:: with SMTP id t184-v6mr556337pgt.62.1533170468263; Wed, 01 Aug 2018 17:41:08 -0700 (PDT) Received: from Husky.eng.vmware.com ([66.170.99.1]) by smtp.gmail.com with ESMTPSA id s73-v6sm328627pfi.154.2018.08.01.17.41.06 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Aug 2018 17:41:07 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Wed, 1 Aug 2018 17:35:50 -0700 Message-Id: <1533170156-769-6-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533170156-769-1-git-send-email-yihung.wei@gmail.com> References: <1533170156-769-1-git-send-email-yihung.wei@gmail.com> X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v2 05/11] datapath: conntrack: Support conntrack zone limit X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Upstream commit: commit 11efd5cb04a184eea4f57b68ea63dddd463158d1 Author: Yi-Hung Wei Date: Thu May 24 17:56:43 2018 -0700 openvswitch: Support conntrack zone limit Currently, nf_conntrack_max is used to limit the maximum number of conntrack entries in the conntrack table for every network namespace. For the VMs and containers that reside in the same namespace, they share the same conntrack table, and the total # of conntrack entries for all the VMs and containers are limited by nf_conntrack_max. In this case, if one of the VM/container abuses the usage the conntrack entries, it blocks the others from committing valid conntrack entries into the conntrack table. Even if we can possibly put the VM in different network namespace, the current nf_conntrack_max configuration is kind of rigid that we cannot limit different VM/container to have different # conntrack entries. To address the aforementioned issue, this patch proposes to have a fine-grained mechanism that could further limit the # of conntrack entries per-zone. For example, we can designate different zone to different VM, and set conntrack limit to each zone. By providing this isolation, a mis-behaved VM only consumes the conntrack entries in its own zone, and it will not influence other well-behaved VMs. Moreover, the users can set various conntrack limit to different zone based on their preference. The proposed implementation utilizes Netfilter's nf_conncount backend to count the number of connections in a particular zone. If the number of connection is above a configured limitation, ovs will return ENOMEM to the userspace. If userspace does not configure the zone limit, the limit defaults to zero that is no limitation, which is backward compatible to the behavior without this patch. The following high leve APIs are provided to the userspace: - OVS_CT_LIMIT_CMD_SET: * set default connection limit for all zones * set the connection limit for a particular zone - OVS_CT_LIMIT_CMD_DEL: * remove the connection limit for a particular zone - OVS_CT_LIMIT_CMD_GET: * get the default connection limit for all zones * get the connection limit for a particular zone Signed-off-by: Yi-Hung Wei Acked-by: Pravin B Shelar Signed-off-by: David S. Miller Signed-off-by: Yi-Hung Wei --- NEWS | 1 + datapath/compat.h | 8 + datapath/conntrack.c | 551 ++++++++++++++++++++++++++++++++++++++++++++++++++- datapath/conntrack.h | 9 +- datapath/datapath.c | 7 +- datapath/datapath.h | 3 + 6 files changed, 574 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index 27ef12d599d9..8270ef46ea34 100644 --- a/NEWS +++ b/NEWS @@ -28,6 +28,7 @@ v2.10.0 - xx xxx xxxx - Linux datapath * Add support for compiling OVS with the latest Linux 4.14 kernel. * Added support for meters. + * Add support for conntrack zone limit. - ovn: * Implemented icmp4/icmp6/tcp_reset actions in order to drop the packet and reply with a RST for TCP or ICMPv4/ICMPv6 unreachable message for diff --git a/datapath/compat.h b/datapath/compat.h index 816f754c64e2..98b68640a372 100644 --- a/datapath/compat.h +++ b/datapath/compat.h @@ -26,6 +26,7 @@ #include #include #include +#include /* Even though vanilla 3.10 kernel has grp->id, RHEL 7 kernel is missing * this field. */ @@ -59,8 +60,14 @@ static inline int __init compat_init(void) if (err) goto error_frag6_exit; + err = rpl_nf_conncount_modinit(); + if (err) + goto error_nf_conncount_exit; + return 0; +error_nf_conncount_exit: + rpl_nf_conncount_modexit(); error_frag6_exit: nf_ct_frag6_cleanup(); error_ipfrag_exit: @@ -69,6 +76,7 @@ error_ipfrag_exit: } static inline void compat_exit(void) { + rpl_nf_conncount_modexit(); ip6_output_exit(); nf_ct_frag6_cleanup(); rpl_ipfrag_fini(); diff --git a/datapath/conntrack.c b/datapath/conntrack.c index 42c7929055f0..c6e731bf5978 100644 --- a/datapath/conntrack.c +++ b/datapath/conntrack.c @@ -21,8 +21,11 @@ #include #include #include +#include #include +#include #include +#include #include #include #include @@ -87,6 +90,31 @@ struct ovs_conntrack_info { #endif }; +#if IS_ENABLED(CONFIG_NETFILTER_CONNCOUNT) +#define OVS_CT_LIMIT_UNLIMITED 0 +#define OVS_CT_LIMIT_DEFAULT OVS_CT_LIMIT_UNLIMITED +#define CT_LIMIT_HASH_BUCKETS 512 +static DEFINE_STATIC_KEY_FALSE(ovs_ct_limit_enabled); + +struct ovs_ct_limit { + /* Elements in ovs_ct_limit_info->limits hash table */ + struct hlist_node hlist_node; + struct rcu_head rcu; + u16 zone; + u32 limit; +}; + +struct ovs_ct_limit_info { + u32 default_limit; + struct hlist_head *limits; + struct nf_conncount_data *data; +}; + +static const struct nla_policy ct_limit_policy[OVS_CT_LIMIT_ATTR_MAX + 1] = { + [OVS_CT_LIMIT_ATTR_ZONE_LIMIT] = { .type = NLA_NESTED, }, +}; +#endif + static bool labels_nonzero(const struct ovs_key_ct_labels *labels); static void __ovs_ct_free_action(struct ovs_conntrack_info *ct_info); @@ -1080,6 +1108,89 @@ static bool labels_nonzero(const struct ovs_key_ct_labels *labels) return false; } +#if IS_ENABLED(CONFIG_NETFILTER_CONNCOUNT) +static struct hlist_head *ct_limit_hash_bucket( + const struct ovs_ct_limit_info *info, u16 zone) +{ + return &info->limits[zone & (CT_LIMIT_HASH_BUCKETS - 1)]; +} + +/* Call with ovs_mutex */ +static void ct_limit_set(const struct ovs_ct_limit_info *info, + struct ovs_ct_limit *new_ct_limit) +{ + struct ovs_ct_limit *ct_limit; + struct hlist_head *head; + + head = ct_limit_hash_bucket(info, new_ct_limit->zone); + hlist_for_each_entry_rcu(ct_limit, head, hlist_node) { + if (ct_limit->zone == new_ct_limit->zone) { + hlist_replace_rcu(&ct_limit->hlist_node, + &new_ct_limit->hlist_node); + kfree_rcu(ct_limit, rcu); + return; + } + } + + hlist_add_head_rcu(&new_ct_limit->hlist_node, head); +} + +/* Call with ovs_mutex */ +static void ct_limit_del(const struct ovs_ct_limit_info *info, u16 zone) +{ + struct ovs_ct_limit *ct_limit; + struct hlist_head *head; + struct hlist_node *n; + + head = ct_limit_hash_bucket(info, zone); + hlist_for_each_entry_safe(ct_limit, n, head, hlist_node) { + if (ct_limit->zone == zone) { + hlist_del_rcu(&ct_limit->hlist_node); + kfree_rcu(ct_limit, rcu); + return; + } + } +} + +/* Call with RCU read lock */ +static u32 ct_limit_get(const struct ovs_ct_limit_info *info, u16 zone) +{ + struct ovs_ct_limit *ct_limit; + struct hlist_head *head; + + head = ct_limit_hash_bucket(info, zone); + hlist_for_each_entry_rcu(ct_limit, head, hlist_node) { + if (ct_limit->zone == zone) + return ct_limit->limit; + } + + return info->default_limit; +} + +static int ovs_ct_check_limit(struct net *net, + const struct ovs_conntrack_info *info, + const struct nf_conntrack_tuple *tuple) +{ + struct ovs_net *ovs_net = net_generic(net, ovs_net_id); + const struct ovs_ct_limit_info *ct_limit_info = ovs_net->ct_limit_info; + u32 per_zone_limit, connections; + u32 conncount_key; + + conncount_key = info->zone.id; + + per_zone_limit = ct_limit_get(ct_limit_info, info->zone.id); + if (per_zone_limit == OVS_CT_LIMIT_UNLIMITED) + return 0; + + connections = nf_conncount_count(net, ct_limit_info->data, + &conncount_key, tuple, &info->zone); + if (connections > per_zone_limit) + return -ENOMEM; + + return 0; +} +#endif + /* Lookup connection and confirm if unconfirmed. */ static int ovs_ct_commit(struct net *net, struct sw_flow_key *key, const struct ovs_conntrack_info *info, @@ -1098,6 +1209,21 @@ static int ovs_ct_commit(struct net *net, struct sw_flow_key *key, if (!ct) return 0; +#if IS_ENABLED(CONFIG_NETFILTER_CONNCOUNT) + if (static_branch_unlikely(&ovs_ct_limit_enabled)) { + if (!nf_ct_is_confirmed(ct)) { + err = ovs_ct_check_limit(net, info, + &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + if (err) { + net_warn_ratelimited("openvswitch: zone: %u " + "execeeds conntrack limit\n", + info->zone.id); + return err; + } + } + } +#endif + /* Set the conntrack event mask if given. NEW and DELETE events have * their own groups, but the NFNLGRP_CONNTRACK_UPDATE group listener * typically would receive many kinds of updates. Setting the event @@ -1712,7 +1838,420 @@ static void __ovs_ct_free_action(struct ovs_conntrack_info *ct_info) nf_ct_tmpl_free(ct_info->ct); } -void ovs_ct_init(struct net *net) +#if IS_ENABLED(CONFIG_NETFILTER_CONNCOUNT) +static int ovs_ct_limit_init(struct net *net, struct ovs_net *ovs_net) +{ + int i, err; + + ovs_net->ct_limit_info = kmalloc(sizeof(*ovs_net->ct_limit_info), + GFP_KERNEL); + if (!ovs_net->ct_limit_info) + return -ENOMEM; + + ovs_net->ct_limit_info->default_limit = OVS_CT_LIMIT_DEFAULT; + ovs_net->ct_limit_info->limits = + kmalloc_array(CT_LIMIT_HASH_BUCKETS, sizeof(struct hlist_head), + GFP_KERNEL); + if (!ovs_net->ct_limit_info->limits) { + kfree(ovs_net->ct_limit_info); + return -ENOMEM; + } + + for (i = 0; i < CT_LIMIT_HASH_BUCKETS; i++) + INIT_HLIST_HEAD(&ovs_net->ct_limit_info->limits[i]); + + ovs_net->ct_limit_info->data = + nf_conncount_init(net, NFPROTO_INET, sizeof(u32)); + + if (IS_ERR(ovs_net->ct_limit_info->data)) { + err = PTR_ERR(ovs_net->ct_limit_info->data); + kfree(ovs_net->ct_limit_info->limits); + kfree(ovs_net->ct_limit_info); + pr_err("openvswitch: failed to init nf_conncount %d\n", err); + return err; + } + return 0; +} + +static void ovs_ct_limit_exit(struct net *net, struct ovs_net *ovs_net) +{ + const struct ovs_ct_limit_info *info = ovs_net->ct_limit_info; + int i; + + nf_conncount_destroy(net, NFPROTO_INET, info->data); + for (i = 0; i < CT_LIMIT_HASH_BUCKETS; ++i) { + struct hlist_head *head = &info->limits[i]; + struct ovs_ct_limit *ct_limit; + + hlist_for_each_entry_rcu(ct_limit, head, hlist_node) + kfree_rcu(ct_limit, rcu); + } + kfree(ovs_net->ct_limit_info->limits); + kfree(ovs_net->ct_limit_info); +} + +static struct sk_buff * +ovs_ct_limit_cmd_reply_start(struct genl_info *info, u8 cmd, + struct ovs_header **ovs_reply_header) +{ + struct ovs_header *ovs_header = info->userhdr; + struct sk_buff *skb; + + skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!skb) + return ERR_PTR(-ENOMEM); + + *ovs_reply_header = genlmsg_put(skb, info->snd_portid, + info->snd_seq, + &dp_ct_limit_genl_family, 0, cmd); + + if (!*ovs_reply_header) { + nlmsg_free(skb); + return ERR_PTR(-EMSGSIZE); + } + (*ovs_reply_header)->dp_ifindex = ovs_header->dp_ifindex; + + return skb; +} + +static bool check_zone_id(int zone_id, u16 *pzone) +{ + if (zone_id >= 0 && zone_id <= 65535) { + *pzone = (u16)zone_id; + return true; + } + return false; +} + +static int ovs_ct_limit_set_zone_limit(struct nlattr *nla_zone_limit, + struct ovs_ct_limit_info *info) +{ + struct ovs_zone_limit *zone_limit; + int rem; + u16 zone; + + rem = NLA_ALIGN(nla_len(nla_zone_limit)); + zone_limit = (struct ovs_zone_limit *)nla_data(nla_zone_limit); + + while (rem >= sizeof(*zone_limit)) { + if (unlikely(zone_limit->zone_id == + OVS_ZONE_LIMIT_DEFAULT_ZONE)) { + ovs_lock(); + info->default_limit = zone_limit->limit; + ovs_unlock(); + } else if (unlikely(!check_zone_id( + zone_limit->zone_id, &zone))) { + OVS_NLERR(true, "zone id is out of range"); + } else { + struct ovs_ct_limit *ct_limit; + + ct_limit = kmalloc(sizeof(*ct_limit), GFP_KERNEL); + if (!ct_limit) + return -ENOMEM; + + ct_limit->zone = zone; + ct_limit->limit = zone_limit->limit; + + ovs_lock(); + ct_limit_set(info, ct_limit); + ovs_unlock(); + } + rem -= NLA_ALIGN(sizeof(*zone_limit)); + zone_limit = (struct ovs_zone_limit *)((u8 *)zone_limit + + NLA_ALIGN(sizeof(*zone_limit))); + } + + if (rem) + OVS_NLERR(true, "set zone limit has %d unknown bytes", rem); + + return 0; +} + +static int ovs_ct_limit_del_zone_limit(struct nlattr *nla_zone_limit, + struct ovs_ct_limit_info *info) +{ + struct ovs_zone_limit *zone_limit; + int rem; + u16 zone; + + rem = NLA_ALIGN(nla_len(nla_zone_limit)); + zone_limit = (struct ovs_zone_limit *)nla_data(nla_zone_limit); + + while (rem >= sizeof(*zone_limit)) { + if (unlikely(zone_limit->zone_id == + OVS_ZONE_LIMIT_DEFAULT_ZONE)) { + ovs_lock(); + info->default_limit = OVS_CT_LIMIT_DEFAULT; + ovs_unlock(); + } else if (unlikely(!check_zone_id( + zone_limit->zone_id, &zone))) { + OVS_NLERR(true, "zone id is out of range"); + } else { + ovs_lock(); + ct_limit_del(info, zone); + ovs_unlock(); + } + rem -= NLA_ALIGN(sizeof(*zone_limit)); + zone_limit = (struct ovs_zone_limit *)((u8 *)zone_limit + + NLA_ALIGN(sizeof(*zone_limit))); + } + + if (rem) + OVS_NLERR(true, "del zone limit has %d unknown bytes", rem); + + return 0; +} + +static int ovs_ct_limit_get_default_limit(struct ovs_ct_limit_info *info, + struct sk_buff *reply) +{ + struct ovs_zone_limit zone_limit; + int err; + + zone_limit.zone_id = OVS_ZONE_LIMIT_DEFAULT_ZONE; + zone_limit.limit = info->default_limit; + err = nla_put_nohdr(reply, sizeof(zone_limit), &zone_limit); + if (err) + return err; + + return 0; +} + +static int __ovs_ct_limit_get_zone_limit(struct net *net, + struct nf_conncount_data *data, + u16 zone_id, u32 limit, + struct sk_buff *reply) +{ + struct nf_conntrack_zone ct_zone; + struct ovs_zone_limit zone_limit; + u32 conncount_key = zone_id; + + zone_limit.zone_id = zone_id; + zone_limit.limit = limit; + nf_ct_zone_init(&ct_zone, zone_id, NF_CT_DEFAULT_ZONE_DIR, 0); + + zone_limit.count = nf_conncount_count(net, data, &conncount_key, NULL, + &ct_zone); + return nla_put_nohdr(reply, sizeof(zone_limit), &zone_limit); +} + +static int ovs_ct_limit_get_zone_limit(struct net *net, + struct nlattr *nla_zone_limit, + struct ovs_ct_limit_info *info, + struct sk_buff *reply) +{ + struct ovs_zone_limit *zone_limit; + int rem, err; + u32 limit; + u16 zone; + + rem = NLA_ALIGN(nla_len(nla_zone_limit)); + zone_limit = (struct ovs_zone_limit *)nla_data(nla_zone_limit); + + while (rem >= sizeof(*zone_limit)) { + if (unlikely(zone_limit->zone_id == + OVS_ZONE_LIMIT_DEFAULT_ZONE)) { + err = ovs_ct_limit_get_default_limit(info, reply); + if (err) + return err; + } else if (unlikely(!check_zone_id(zone_limit->zone_id, + &zone))) { + OVS_NLERR(true, "zone id is out of range"); + } else { + rcu_read_lock(); + limit = ct_limit_get(info, zone); + rcu_read_unlock(); + + err = __ovs_ct_limit_get_zone_limit( + net, info->data, zone, limit, reply); + if (err) + return err; + } + rem -= NLA_ALIGN(sizeof(*zone_limit)); + zone_limit = (struct ovs_zone_limit *)((u8 *)zone_limit + + NLA_ALIGN(sizeof(*zone_limit))); + } + + if (rem) + OVS_NLERR(true, "get zone limit has %d unknown bytes", rem); + + return 0; +} + +static int ovs_ct_limit_get_all_zone_limit(struct net *net, + struct ovs_ct_limit_info *info, + struct sk_buff *reply) +{ + struct ovs_ct_limit *ct_limit; + struct hlist_head *head; + int i, err = 0; + + err = ovs_ct_limit_get_default_limit(info, reply); + if (err) + return err; + + rcu_read_lock(); + for (i = 0; i < CT_LIMIT_HASH_BUCKETS; ++i) { + head = &info->limits[i]; + hlist_for_each_entry_rcu(ct_limit, head, hlist_node) { + err = __ovs_ct_limit_get_zone_limit(net, info->data, + ct_limit->zone, ct_limit->limit, reply); + if (err) + goto exit_err; + } + } + +exit_err: + rcu_read_unlock(); + return err; +} + +static int ovs_ct_limit_cmd_set(struct sk_buff *skb, struct genl_info *info) +{ + struct nlattr **a = info->attrs; + struct sk_buff *reply; + struct ovs_header *ovs_reply_header; + struct ovs_net *ovs_net = net_generic(sock_net(skb->sk), ovs_net_id); + struct ovs_ct_limit_info *ct_limit_info = ovs_net->ct_limit_info; + int err; + + reply = ovs_ct_limit_cmd_reply_start(info, OVS_CT_LIMIT_CMD_SET, + &ovs_reply_header); + if (IS_ERR(reply)) + return PTR_ERR(reply); + + if (!a[OVS_CT_LIMIT_ATTR_ZONE_LIMIT]) { + err = -EINVAL; + goto exit_err; + } + + err = ovs_ct_limit_set_zone_limit(a[OVS_CT_LIMIT_ATTR_ZONE_LIMIT], + ct_limit_info); + if (err) + goto exit_err; + + static_branch_enable(&ovs_ct_limit_enabled); + + genlmsg_end(reply, ovs_reply_header); + return genlmsg_reply(reply, info); + +exit_err: + nlmsg_free(reply); + return err; +} + +static int ovs_ct_limit_cmd_del(struct sk_buff *skb, struct genl_info *info) +{ + struct nlattr **a = info->attrs; + struct sk_buff *reply; + struct ovs_header *ovs_reply_header; + struct ovs_net *ovs_net = net_generic(sock_net(skb->sk), ovs_net_id); + struct ovs_ct_limit_info *ct_limit_info = ovs_net->ct_limit_info; + int err; + + reply = ovs_ct_limit_cmd_reply_start(info, OVS_CT_LIMIT_CMD_DEL, + &ovs_reply_header); + if (IS_ERR(reply)) + return PTR_ERR(reply); + + if (!a[OVS_CT_LIMIT_ATTR_ZONE_LIMIT]) { + err = -EINVAL; + goto exit_err; + } + + err = ovs_ct_limit_del_zone_limit(a[OVS_CT_LIMIT_ATTR_ZONE_LIMIT], + ct_limit_info); + if (err) + goto exit_err; + + genlmsg_end(reply, ovs_reply_header); + return genlmsg_reply(reply, info); + +exit_err: + nlmsg_free(reply); + return err; +} + +static int ovs_ct_limit_cmd_get(struct sk_buff *skb, struct genl_info *info) +{ + struct nlattr **a = info->attrs; + struct nlattr *nla_reply; + struct sk_buff *reply; + struct ovs_header *ovs_reply_header; + struct net *net = sock_net(skb->sk); + struct ovs_net *ovs_net = net_generic(net, ovs_net_id); + struct ovs_ct_limit_info *ct_limit_info = ovs_net->ct_limit_info; + int err; + + reply = ovs_ct_limit_cmd_reply_start(info, OVS_CT_LIMIT_CMD_GET, + &ovs_reply_header); + if (IS_ERR(reply)) + return PTR_ERR(reply); + + nla_reply = nla_nest_start(reply, OVS_CT_LIMIT_ATTR_ZONE_LIMIT); + + if (a[OVS_CT_LIMIT_ATTR_ZONE_LIMIT]) { + err = ovs_ct_limit_get_zone_limit( + net, a[OVS_CT_LIMIT_ATTR_ZONE_LIMIT], ct_limit_info, + reply); + if (err) + goto exit_err; + } else { + err = ovs_ct_limit_get_all_zone_limit(net, ct_limit_info, + reply); + if (err) + goto exit_err; + } + + nla_nest_end(reply, nla_reply); + genlmsg_end(reply, ovs_reply_header); + return genlmsg_reply(reply, info); + +exit_err: + nlmsg_free(reply); + return err; +} + +static struct genl_ops ct_limit_genl_ops[] = { + { .cmd = OVS_CT_LIMIT_CMD_SET, + .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN + * privilege. */ + .policy = ct_limit_policy, + .doit = ovs_ct_limit_cmd_set, + }, + { .cmd = OVS_CT_LIMIT_CMD_DEL, + .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN + * privilege. */ + .policy = ct_limit_policy, + .doit = ovs_ct_limit_cmd_del, + }, + { .cmd = OVS_CT_LIMIT_CMD_GET, + .flags = 0, /* OK for unprivileged users. */ + .policy = ct_limit_policy, + .doit = ovs_ct_limit_cmd_get, + }, +}; + +static const struct genl_multicast_group ovs_ct_limit_multicast_group = { + .name = OVS_CT_LIMIT_MCGROUP, +}; + +struct genl_family dp_ct_limit_genl_family __ro_after_init = { + .hdrsize = sizeof(struct ovs_header), + .name = OVS_CT_LIMIT_FAMILY, + .version = OVS_CT_LIMIT_VERSION, + .maxattr = OVS_CT_LIMIT_ATTR_MAX, + .netnsok = true, + .parallel_ops = true, + .ops = ct_limit_genl_ops, + .n_ops = ARRAY_SIZE(ct_limit_genl_ops), + .mcgrps = &ovs_ct_limit_multicast_group, + .n_mcgrps = 1, + .module = THIS_MODULE, +}; +#endif + +int ovs_ct_init(struct net *net) { unsigned int n_bits = sizeof(struct ovs_key_ct_labels) * BITS_PER_BYTE; struct ovs_net *ovs_net = net_generic(net, ovs_net_id); @@ -1723,12 +2262,22 @@ void ovs_ct_init(struct net *net) } else { ovs_net->xt_label = true; } + +#if IS_ENABLED(CONFIG_NETFILTER_CONNCOUNT) + return ovs_ct_limit_init(net, ovs_net); +#else + return 0; +#endif } void ovs_ct_exit(struct net *net) { struct ovs_net *ovs_net = net_generic(net, ovs_net_id); +#if IS_ENABLED(CONFIG_NETFILTER_CONNCOUNT) + ovs_ct_limit_exit(net, ovs_net); +#endif + if (ovs_net->xt_label) nf_connlabels_put(net); } diff --git a/datapath/conntrack.h b/datapath/conntrack.h index 0c3964f5bcaf..5b4b34c19c40 100644 --- a/datapath/conntrack.h +++ b/datapath/conntrack.h @@ -18,10 +18,11 @@ #include "flow.h" struct ovs_conntrack_info; +struct ovs_ct_limit_info; enum ovs_key_attr; #if IS_ENABLED(CONFIG_NF_CONNTRACK) -void ovs_ct_init(struct net *); +int ovs_ct_init(struct net *); void ovs_ct_exit(struct net *); bool ovs_ct_verify(struct net *, enum ovs_key_attr attr); int ovs_ct_copy_action(struct net *, const struct nlattr *, @@ -45,7 +46,7 @@ void ovs_ct_free_action(const struct nlattr *a); #else #include -static inline void ovs_ct_init(struct net *net) { } +static inline int ovs_ct_init(struct net *net) { return 0; } static inline void ovs_ct_exit(struct net *net) { } @@ -105,4 +106,8 @@ static inline void ovs_ct_free_action(const struct nlattr *a) { } #define CT_SUPPORTED_MASK 0 #endif + +#if IS_ENABLED(CONFIG_NETFILTER_CONNCOUNT) +extern struct genl_family dp_ct_limit_genl_family; +#endif #endif /* ovs_conntrack.h */ diff --git a/datapath/datapath.c b/datapath/datapath.c index f90d0f5857f0..a8d09fb415d4 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -2305,6 +2305,9 @@ static struct genl_family *dp_genl_families[] = { &dp_flow_genl_family, &dp_packet_genl_family, &dp_meter_genl_family, +#if IS_ENABLED(CONFIG_NETFILTER_CONNCOUNT) + &dp_ct_limit_genl_family, +#endif }; static void dp_unregister_genl(int n_families) @@ -2340,10 +2343,9 @@ static int __net_init ovs_init_net(struct net *net) INIT_LIST_HEAD(&ovs_net->dps); INIT_WORK(&ovs_net->dp_notify_work, ovs_dp_notify_wq); - ovs_ct_init(net); ovs_netns_frags_init(net); ovs_netns_frags6_init(net); - return 0; + return ovs_ct_init(net); } static void __net_exit list_vports_from_net(struct net *net, struct net *dnet, @@ -2510,3 +2512,4 @@ MODULE_ALIAS_GENL_FAMILY(OVS_VPORT_FAMILY); MODULE_ALIAS_GENL_FAMILY(OVS_FLOW_FAMILY); MODULE_ALIAS_GENL_FAMILY(OVS_PACKET_FAMILY); MODULE_ALIAS_GENL_FAMILY(OVS_METER_FAMILY); +MODULE_ALIAS_GENL_FAMILY(OVS_CT_LIMIT_FAMILY); diff --git a/datapath/datapath.h b/datapath/datapath.h index c38286df75c7..ee766621550c 100644 --- a/datapath/datapath.h +++ b/datapath/datapath.h @@ -145,6 +145,9 @@ struct dp_upcall_info { struct ovs_net { struct list_head dps; struct work_struct dp_notify_work; +#if IS_ENABLED(CONFIG_NETFILTER_CONNCOUNT) + struct ovs_ct_limit_info *ct_limit_info; +#endif /* Module reference for configuring conntrack. */ bool xt_label; From patchwork Thu Aug 2 00:35:51 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi-Hung Wei X-Patchwork-Id: 952494 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="dL1g5Ykc"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41gryZ6Rggz9s3q for ; Thu, 2 Aug 2018 10:43:50 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id A0887E50; Thu, 2 Aug 2018 00:41:12 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 57FAAE47 for ; Thu, 2 Aug 2018 00:41:11 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf1-f196.google.com (mail-pf1-f196.google.com [209.85.210.196]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id BBCC17C1 for ; Thu, 2 Aug 2018 00:41:10 +0000 (UTC) Received: by mail-pf1-f196.google.com with SMTP id d4-v6so276026pfn.0 for ; Wed, 01 Aug 2018 17:41:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=OGncU1tfnjux9svYpUL966P52RtTiAwR8PiMIIrJNE0=; b=dL1g5YkckMOUCzIROUZrKIeDbiaCKUFoHTSY9pEWhXNmp7idFJ5Zc5cMrrVfz/pbXh iu0ltqSDgxKG3q3LRDM5nT3IXTJBnF4iBuXJBYIZ5HLA555JxwcaPZ862AjqrHoZxp0J iK2iNI+golZ8+Q7pn0TeZksnpWry7BU4FwGNqmWH74/SZbllusYEuNYxgOEJKZGwQNKJ Z2WOfV0IUkorI5x6he6P88JRh/FIMcy3tuU/zAVVtYEP+9rNtqP/1GgF3vEYCcu5abc7 yHrf9gLE+HQvWzC4sureW4rslPeCoxC9m2C18j5XGLaeyMuGQsYJdCketd7g+R6TdqTC r+Og== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=OGncU1tfnjux9svYpUL966P52RtTiAwR8PiMIIrJNE0=; b=Y+xDW2O2W6PaDPsqppBeoHAplQuqfuGfLspOaSgJRmzzwt4V6550lvos85DQ7aKqYu mmu3vSvK+ic4pSUH/ko3WqH1mTkj38gjE5YOIZ7Z/RBxyEoHv9m4+HTVBKp8Sc8cE2c8 2PJj8eaq4REMy7tXjAEp3Po7RBQAwYPH37LqDYxACgJPH4hw/pVxF3wX4Arfi7cCWtaI 3gCyyK7e94mfzbBeZKtii4WoWirK8KeBabo+r00218ec0EKbim139o1LNeo7fuVGjyHW Rn+vf4kyXaGA20hFgB53T//9MoTxW17PPLeTl1uxF+JjDcDAt2eBe14xAaOQ7a9SV1WD Wabg== X-Gm-Message-State: AOUpUlG8yNj9zFBtzqxKsDeALx+HgkFF5Y/4/XcwLRHha2Fevk0gK+4F wrPIchVIwZ0v+7o1siChd+ZlMVyA X-Google-Smtp-Source: AAOMgpclNCG6wbcKBZOWtgpv9XHp5xlbg4m7jOvRH23Igy2iymMOS0zzMJX9SO7m3brTRgvOxhXAdQ== X-Received: by 2002:a62:c505:: with SMTP id j5-v6mr551239pfg.153.1533170469975; Wed, 01 Aug 2018 17:41:09 -0700 (PDT) Received: from Husky.eng.vmware.com ([66.170.99.1]) by smtp.gmail.com with ESMTPSA id s73-v6sm328627pfi.154.2018.08.01.17.41.08 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Aug 2018 17:41:08 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Wed, 1 Aug 2018 17:35:51 -0700 Message-Id: <1533170156-769-7-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533170156-769-1-git-send-email-yihung.wei@gmail.com> References: <1533170156-769-1-git-send-email-yihung.wei@gmail.com> X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v2 06/11] dpif: Support conntrack zone limit. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org This patch defines the dpif interface to support conntrack per zone limit. Basically, OVS users can use this interface to set, delete, and get the conntrack per zone limit for various dpif interfaces. The following patch will make use of the proposed interface to implement the feature. Signed-off-by: Yi-Hung Wei --- lib/ct-dpif.c | 30 ++++++++++++++++++++++++++++++ lib/ct-dpif.h | 12 ++++++++++++ lib/dpif-netdev.c | 3 +++ lib/dpif-netlink.c | 3 +++ lib/dpif-provider.h | 26 ++++++++++++++++++++++++++ 5 files changed, 74 insertions(+) diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c index 5fa3a97727e1..d1e8a6b8b4a9 100644 --- a/lib/ct-dpif.c +++ b/lib/ct-dpif.c @@ -164,6 +164,36 @@ ct_dpif_get_nconns(struct dpif *dpif, uint32_t *nconns) : EOPNOTSUPP); } +int +ct_dpif_set_limits(struct dpif *dpif, const uint32_t *default_limit, + const struct ovs_list *zone_limits) +{ + return (dpif->dpif_class->ct_set_limits + ? dpif->dpif_class->ct_set_limits(dpif, default_limit, + zone_limits) + : EOPNOTSUPP); +} + +int +ct_dpif_get_limits(struct dpif *dpif, uint32_t *default_limit, + const struct ovs_list *zone_limits_in, + struct ovs_list *zone_limits_out) +{ + return (dpif->dpif_class->ct_get_limits + ? dpif->dpif_class->ct_get_limits(dpif, default_limit, + zone_limits_in, + zone_limits_out) + : EOPNOTSUPP); +} + +int +ct_dpif_del_limits(struct dpif *dpif, const struct ovs_list *zone_limits) +{ + return (dpif->dpif_class->ct_del_limits + ? dpif->dpif_class->ct_del_limits(dpif, zone_limits) + : EOPNOTSUPP); +} + void ct_dpif_entry_uninit(struct ct_dpif_entry *entry) { diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h index 09e7698cf2bc..4e83bc555e03 100644 --- a/lib/ct-dpif.h +++ b/lib/ct-dpif.h @@ -191,6 +191,13 @@ struct ct_dpif_dump_state { struct dpif *dpif; }; +struct ct_dpif_zone_limit { + uint16_t zone; + uint32_t limit; + uint32_t count; + struct ovs_list node; /* In ct_zone_limits */ +}; + int ct_dpif_dump_start(struct dpif *, struct ct_dpif_dump_state **, const uint16_t *zone, int *); int ct_dpif_dump_next(struct ct_dpif_dump_state *, struct ct_dpif_entry *); @@ -200,6 +207,11 @@ int ct_dpif_flush(struct dpif *, const uint16_t *zone, int ct_dpif_set_maxconns(struct dpif *dpif, uint32_t maxconns); int ct_dpif_get_maxconns(struct dpif *dpif, uint32_t *maxconns); int ct_dpif_get_nconns(struct dpif *dpif, uint32_t *nconns); +int ct_dpif_set_limits(struct dpif *dpif, const uint32_t *default_limit, + const struct ovs_list *); +int ct_dpif_get_limits(struct dpif *dpif, uint32_t *default_limit, + const struct ovs_list *, struct ovs_list *); +int ct_dpif_del_limits(struct dpif *dpif, const struct ovs_list *); void ct_dpif_entry_uninit(struct ct_dpif_entry *); void ct_dpif_format_entry(const struct ct_dpif_entry *, struct ds *, bool verbose, bool print_stats); diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 26d07b39c9af..63368e365da4 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -6825,6 +6825,9 @@ const struct dpif_class dpif_netdev_class = { dpif_netdev_ct_set_maxconns, dpif_netdev_ct_get_maxconns, dpif_netdev_ct_get_nconns, + NULL, /* ct_set_limits */ + NULL, /* ct_get_limits */ + NULL, /* ct_del_limits */ dpif_netdev_meter_get_features, dpif_netdev_meter_set, dpif_netdev_meter_get, diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index f669b1108d61..ee98a3b7d8b6 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -3252,6 +3252,9 @@ const struct dpif_class dpif_netlink_class = { NULL, /* ct_set_maxconns */ NULL, /* ct_get_maxconns */ NULL, /* ct_get_nconns */ + NULL, /* ct_set_limits */ + NULL, /* ct_get_limits */ + NULL, /* ct_del_limits */ dpif_netlink_meter_get_features, dpif_netlink_meter_set, dpif_netlink_meter_get, diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h index 62b3598acfc5..53a4fbdf7ae8 100644 --- a/lib/dpif-provider.h +++ b/lib/dpif-provider.h @@ -444,6 +444,32 @@ struct dpif_class { /* Get number of connections tracked. */ int (*ct_get_nconns)(struct dpif *, uint32_t *nconns); + /* Connection tracking per zone limit */ + + /* Per zone conntrack limit sets the maximum allowed connections in zones + * to provide resource isolation. If a per zone limit for a particular + * zone is not available in the datapath, it defaults to the default + * per zone limit. Initially, the default per zone limit is + * unlimited (0). */ + + /* Set max connections allowed per zone according to 'zone_limits'. + * If 'default_limit' is not NULL, modifies the default limit to + * '*default_limit'. */ + int (*ct_set_limits)(struct dpif *, const uint32_t *default_limit, + const struct ovs_list *zone_limits); + + /* Look up the default per zone limit and stores that in 'default_limit'. + * Look up the per zone limits for all zones in the 'zone_limits_in' + * list, and stores reply that includes the zone, the per zone limit, + * and the number of connections in the zone into 'zone_limits_out' + * list. */ + int (*ct_get_limits)(struct dpif *, uint32_t *default_limit, + const struct ovs_list *zone_limits_in, + struct ovs_list *zone_limits_out); + + /* Delete per zone limit of all zones specified in 'zone_limits'. */ + int (*ct_del_limits)(struct dpif *, const struct ovs_list *zone_limits); + /* Meters */ /* Queries 'dpif' for supported meter features. From patchwork Thu Aug 2 00:35:52 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi-Hung Wei X-Patchwork-Id: 952495 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="FBRZwUzp"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41grz71nWtz9s3q for ; Thu, 2 Aug 2018 10:44:19 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 82ACDE5E; Thu, 2 Aug 2018 00:41:14 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id BB3D5E57 for ; Thu, 2 Aug 2018 00:41:12 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf1-f194.google.com (mail-pf1-f194.google.com [209.85.210.194]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 762AC7B3 for ; Thu, 2 Aug 2018 00:41:12 +0000 (UTC) Received: by mail-pf1-f194.google.com with SMTP id b11-v6so268858pfo.3 for ; Wed, 01 Aug 2018 17:41:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=5SjpOG5oj8Qm102LKxolDNMEi680Z2PRlcjd646zCEw=; b=FBRZwUzpq9iACyreSrTGp26RwCgqGodn8yZmi5D1WP90d6o4qkHeBNrvx0xok4yoEu xUkA7Cu6cMOeUS/GXW+bwb5fR+FSJjG7oYLd6EmV2ufOC8Nb/DdydRc+j+Ppr2U/CGOX heYK8kcY+GAGEUqgDW0gtfbEIesLnKMLQ2HFMimu2k69j3RWS2rRwtkTTqV7JeTEar2V a/uywQbG7wRI3qZBjXNRZAtrWqp50ED3KQL/hz0aOWutPFkfPx93gY6YzD6/TliriYKE YUVLwpnIJg3aP5aDB6gLXRHy/xgvdlTOcv+OWUgVAMD/7pSuAAhdURI42IOqiU0kjLfE pTjg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=5SjpOG5oj8Qm102LKxolDNMEi680Z2PRlcjd646zCEw=; b=klwKE24B25XzEdUbdVjNihlrPB/1SajqDNTtaUN0vWhcVAHWIDBUi4tKfjdkJEVvmC 5WQ83LRWFzlYK0rgoOZvkFyWCSMxP1KdlJ+AhVgVPPlFPq5FVyYVl4DiIzBM5bN6Ezwr 7WQwCOa8gFQQhcb9VujJ/YGcc6l2xSA67W3Lg/d4d00fvfDRaODxsRmt5oGq3MF/nqyT AyAXncB8c9TB4AgzWm/RgrZmpg/1GYLwiC+yHscgs2d7rSjtkIbHkVcUL3ZPf2laCcfq kJ0e4HYAT96ree3BqVug73/JkhgT3fa4iClfIxNStma+Ad5anx4fVAwWdRde4oOyXC5/ 7y6Q== X-Gm-Message-State: AOUpUlGCcoNvpNuqAItQgUN+Lva0XyKLEmt9OF428Ac+09RkC0lbuL4n 344GqA8F7JYpnMknk2VLiObp02zn X-Google-Smtp-Source: AAOMgpchQn6rti2cdv1irUVrzegtk09AzvNhCUxEks1QMi3NETg7Mm7g6tN/z/IZqM2FVOiQfpSfuA== X-Received: by 2002:a63:8c0b:: with SMTP id m11-v6mr535002pgd.372.1533170471636; Wed, 01 Aug 2018 17:41:11 -0700 (PDT) Received: from Husky.eng.vmware.com ([66.170.99.1]) by smtp.gmail.com with ESMTPSA id s73-v6sm328627pfi.154.2018.08.01.17.41.10 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Aug 2018 17:41:10 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Wed, 1 Aug 2018 17:35:52 -0700 Message-Id: <1533170156-769-8-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533170156-769-1-git-send-email-yihung.wei@gmail.com> References: <1533170156-769-1-git-send-email-yihung.wei@gmail.com> X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v2 07/11] ct-dpif: Helper functions for conntrack zone limit X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org This patch implments some helper function for conntrack zone limit. It will be useful for the following patches. Signed-off-by: Yi-Hung Wei --- lib/ct-dpif.c | 32 ++++++++++++++++++++++++++++++++ lib/ct-dpif.h | 4 ++++ 2 files changed, 36 insertions(+) diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c index d1e8a6b8b4a9..a772799fe347 100644 --- a/lib/ct-dpif.c +++ b/lib/ct-dpif.c @@ -597,3 +597,35 @@ error: free(copy); return false; } + +void +ct_dpif_push_zone_limit(struct ovs_list *zone_limits, uint16_t zone, + uint32_t limit, uint32_t count) +{ + struct ct_dpif_zone_limit *zone_limit = xmalloc(sizeof *zone_limit); + zone_limit->zone = zone; + zone_limit->limit = limit; + zone_limit->count = count; + ovs_list_push_back(zone_limits, &zone_limit->node); +} + +/* The caller takes ownership of 'struct ct_dpif_zone_limit *', and is + * responsible to free that struct. */ +struct ct_dpif_zone_limit * +ct_dpif_pop_zone_limit(struct ovs_list *zone_limits) +{ + struct ct_dpif_zone_limit *zone_limit; + LIST_FOR_EACH_POP (zone_limit, node, zone_limits) { + return zone_limit; + } + OVS_NOT_REACHED(); +} + +void +ct_dpif_free_zone_limits(struct ovs_list *zone_limits) +{ + while (!ovs_list_is_empty(zone_limits)) { + struct ct_dpif_zone_limit *p = ct_dpif_pop_zone_limit(zone_limits); + free(p); + } +} diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h index 4e83bc555e03..c80e18b72b56 100644 --- a/lib/ct-dpif.h +++ b/lib/ct-dpif.h @@ -219,5 +219,9 @@ void ct_dpif_format_tuple(struct ds *, const struct ct_dpif_tuple *); uint8_t ct_dpif_coalesce_tcp_state(uint8_t state); void ct_dpif_format_tcp_stat(struct ds *, int, int); bool ct_dpif_parse_tuple(struct ct_dpif_tuple *, const char *s, struct ds *); +void ct_dpif_push_zone_limit(struct ovs_list *, uint16_t zone, uint32_t limit, + uint32_t count); +struct ct_dpif_zone_limit * ct_dpif_pop_zone_limit(struct ovs_list *); +void ct_dpif_free_zone_limits(struct ovs_list *); #endif /* CT_DPIF_H */ From patchwork Thu Aug 2 00:35:53 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi-Hung Wei X-Patchwork-Id: 952496 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="MjUueAN2"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41grzV2rkvz9s3q for ; Thu, 2 Aug 2018 10:44:38 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 4180AE62; Thu, 2 Aug 2018 00:41:16 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 60A3EE59 for ; Thu, 2 Aug 2018 00:41:15 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg1-f196.google.com (mail-pg1-f196.google.com [209.85.215.196]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id B1BD97C1 for ; Thu, 2 Aug 2018 00:41:14 +0000 (UTC) Received: by mail-pg1-f196.google.com with SMTP id r1-v6so226374pgp.11 for ; Wed, 01 Aug 2018 17:41:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=OA6Ru4mMr8+HwpeRp7Nd3wYeH/aDFkCAJB/93TStOaE=; b=MjUueAN2ICAd1bVO2pVHE+fCVC7bMM+2Z2lC32bvEz725yRI1ZtBPRXjtDnaKvDuD3 ym6Mse87f5Rl6DkHwodsbWnbp0Jd8kKi/l7WL1q3GYz8Xv+noJnvlNc0F8AGb0eFIjZO btuyaUGunN7xxqWYXFWYlAQ56oEyMrSILuByptHTJ96Eg2QtZ8wJbDI/XNYWckH9mrib AFptSjW2ptKHcRmdDwLwYJ8l23eDuYPt00k2y2VDsjNCbzK8/ujYgAOahSlH3t4gDjYu JKdL0HeE7/bI9MXBakTCamIoLuYo3dNYR149OPG7MRHBEuF8oeY8pnm3MG4zjf3HNHYn cGkQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=OA6Ru4mMr8+HwpeRp7Nd3wYeH/aDFkCAJB/93TStOaE=; b=ETKGNOTJt1t0KkPLb5F2JjwaDLptWgjlck559NC1nFcqZJhMABk66ipXO06RIZU0Io 8KnvkUWSz2NdxyU9fBjRA1kbR9FwTyRr1FYnq5Nm4y64nGYcE4QX6lyMSObiycQsw9k4 jRzVJEErQiOJ5rwys1E8eGtIczOt78sL7sHwPT/KRhktrrfuUrPKt1GaYMkoBR0vmgh4 VkvB0CUwhhCgbgaAYK2RG3zGdGEByq9yKS0ggFYqSqKSMPmpxCP83utFWBhi0ufH4dyf 9/gJkn8lCEoQE7khdDvsYOnfUpVSsXVqA/Ov5nWfUWXYDdfvg5nBN7cQkJAjlBROCFtJ 9ztQ== X-Gm-Message-State: AOUpUlGjFklWO1FJ6kzZSAERxxQXFsvx8KHaiXgxcEzvqFjmUEDGVmZc By7tMStkx1miDFRI2vggZvvQHA+W X-Google-Smtp-Source: AAOMgpcgHLKO3l7+ZLaaDjo9YGnM1aY72r8z4yT9WtAzf1A7JJfS4ZPMA/8tB2pyZInf5gtabiFVCA== X-Received: by 2002:a62:c98e:: with SMTP id l14-v6mr610253pfk.10.1533170473853; Wed, 01 Aug 2018 17:41:13 -0700 (PDT) Received: from Husky.eng.vmware.com ([66.170.99.1]) by smtp.gmail.com with ESMTPSA id s73-v6sm328627pfi.154.2018.08.01.17.41.11 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Aug 2018 17:41:12 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Wed, 1 Aug 2018 17:35:53 -0700 Message-Id: <1533170156-769-9-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533170156-769-1-git-send-email-yihung.wei@gmail.com> References: <1533170156-769-1-git-send-email-yihung.wei@gmail.com> X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v2 08/11] dpif-netlink: Implement conntrack zone limiit X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org This patch provides the implementation of conntrack zone limit in dpif-netlink. It basically utilizes the netlink API to communicate with OVS kernel module to set, delete, and get conntrack zone limit. Signed-off-by: Yi-Hung Wei --- lib/dpif-netlink.c | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 199 insertions(+), 3 deletions(-) diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index ee98a3b7d8b6..365b38047fe1 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -213,6 +213,7 @@ static int ovs_vport_family; static int ovs_flow_family; static int ovs_packet_family; static int ovs_meter_family; +static int ovs_ct_limit_family; /* Generic Netlink multicast groups for OVS. * @@ -2919,6 +2920,195 @@ dpif_netlink_ct_flush(struct dpif *dpif OVS_UNUSED, const uint16_t *zone, } } +static int +dpif_netlink_set_limits(struct dpif *dpif OVS_UNUSED, + const uint32_t *default_limits, + const struct ovs_list *zone_limits) +{ + struct ofpbuf *request; + struct ovs_header *ovs_header; + size_t opt_offset; + int err; + struct ovs_zone_limit req_zone_limit; + + if (ovs_ct_limit_family < 0) { + return EOPNOTSUPP; + } + + request = ofpbuf_new(NL_DUMP_BUFSIZE); + nl_msg_put_genlmsghdr(request, 0, ovs_ct_limit_family, + NLM_F_REQUEST | NLM_F_ECHO, OVS_CT_LIMIT_CMD_SET, + OVS_CT_LIMIT_VERSION); + + ovs_header = ofpbuf_put_uninit(request, sizeof *ovs_header); + ovs_header->dp_ifindex = 0; + + opt_offset = nl_msg_start_nested(request, OVS_CT_LIMIT_ATTR_ZONE_LIMIT); + if (default_limits) { + req_zone_limit.zone_id = OVS_ZONE_LIMIT_DEFAULT_ZONE; + req_zone_limit.limit = *default_limits; + nl_msg_put(request, &req_zone_limit, sizeof req_zone_limit); + } + + if (!ovs_list_is_empty(zone_limits)) { + struct ct_dpif_zone_limit *zone_limit; + + LIST_FOR_EACH (zone_limit, node, zone_limits) { + req_zone_limit.zone_id = zone_limit->zone; + req_zone_limit.limit = zone_limit->limit; + nl_msg_put(request, &req_zone_limit, sizeof req_zone_limit); + } + } + nl_msg_end_nested(request, opt_offset); + + err = nl_transact(NETLINK_GENERIC, request, NULL); + ofpbuf_uninit(request); + return err; +} + +static int +dpif_netlink_zone_limits_from_ofpbuf(const struct ofpbuf *buf, + uint32_t *default_limit, + struct ovs_list *zone_limits) +{ + static const struct nl_policy ovs_ct_limit_policy[] = { + [OVS_CT_LIMIT_ATTR_ZONE_LIMIT] = { .type = NL_A_NESTED, + .optional = true }, + }; + + struct ofpbuf b = ofpbuf_const_initializer(buf->data, buf->size); + struct nlmsghdr *nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg); + struct genlmsghdr *genl = ofpbuf_try_pull(&b, sizeof *genl); + struct ovs_header *ovs_header = ofpbuf_try_pull(&b, sizeof *ovs_header); + + struct nlattr *attr[ARRAY_SIZE(ovs_ct_limit_policy)]; + + if (!nlmsg || !genl || !ovs_header + || nlmsg->nlmsg_type != ovs_ct_limit_family + || !nl_policy_parse(&b, 0, ovs_ct_limit_policy, attr, + ARRAY_SIZE(ovs_ct_limit_policy))) { + return EINVAL; + } + + + if (!attr[OVS_CT_LIMIT_ATTR_ZONE_LIMIT]) { + return EINVAL; + } + + int rem = NLA_ALIGN( + nl_attr_get_size(attr[OVS_CT_LIMIT_ATTR_ZONE_LIMIT])); + const struct ovs_zone_limit *zone_limit = + nl_attr_get(attr[OVS_CT_LIMIT_ATTR_ZONE_LIMIT]); + + while (rem >= sizeof *zone_limit) { + if (zone_limit->zone_id == OVS_ZONE_LIMIT_DEFAULT_ZONE) { + *default_limit = zone_limit->limit; + } else if (zone_limit->zone_id < OVS_ZONE_LIMIT_DEFAULT_ZONE || + zone_limit->zone_id > UINT16_MAX) { + } else { + ct_dpif_push_zone_limit(zone_limits, zone_limit->zone_id, + zone_limit->limit, zone_limit->count); + } + rem -= NLA_ALIGN(sizeof *zone_limit); + zone_limit = ALIGNED_CAST(struct ovs_zone_limit *, + (unsigned char *) zone_limit + NLA_ALIGN(sizeof *zone_limit)); + } + return 0; +} + +static int +dpif_netlink_get_limits(struct dpif *dpif OVS_UNUSED, uint32_t *default_limit, + const struct ovs_list *zone_limits_request, + struct ovs_list *zone_limits_reply) +{ + struct ofpbuf *request, *reply; + struct ovs_header *ovs_header; + struct ovs_zone_limit req_zone_limit; + struct ct_dpif_zone_limit *zone_limit; + size_t opt_offset; + int err; + + if (ovs_ct_limit_family < 0) { + return EOPNOTSUPP; + } + + request = ofpbuf_new(NL_DUMP_BUFSIZE); + nl_msg_put_genlmsghdr(request, 0, ovs_ct_limit_family, + NLM_F_REQUEST | NLM_F_ECHO, OVS_CT_LIMIT_CMD_GET, + OVS_CT_LIMIT_VERSION); + + ovs_header = ofpbuf_put_uninit(request, sizeof *ovs_header); + ovs_header->dp_ifindex = 0; + + if (!ovs_list_is_empty(zone_limits_request)) { + opt_offset = nl_msg_start_nested(request, + OVS_CT_LIMIT_ATTR_ZONE_LIMIT); + + req_zone_limit.zone_id = OVS_ZONE_LIMIT_DEFAULT_ZONE; + nl_msg_put(request, &req_zone_limit, sizeof req_zone_limit); + + LIST_FOR_EACH (zone_limit, node, zone_limits_request) { + req_zone_limit.zone_id = zone_limit->zone; + nl_msg_put(request, &req_zone_limit, sizeof req_zone_limit); + } + + nl_msg_end_nested(request, opt_offset); + } + + err = nl_transact(NETLINK_GENERIC, request, &reply); + if (err) { + goto out; + } + + err = dpif_netlink_zone_limits_from_ofpbuf(reply, default_limit, + zone_limits_reply); + +out: + ofpbuf_uninit(request); + ofpbuf_uninit(reply); + return err; +} + +static int +dpif_netlink_del_limits(struct dpif *dpif OVS_UNUSED, + const struct ovs_list *zone_limits) +{ + struct ovs_zone_limit req_zone_limit; + struct ofpbuf *request; + struct ovs_header *ovs_header; + size_t opt_offset; + int err; + + if (ovs_ct_limit_family < 0) { + return EOPNOTSUPP; + } + + request = ofpbuf_new(NL_DUMP_BUFSIZE); + nl_msg_put_genlmsghdr(request, 0, ovs_ct_limit_family, + NLM_F_REQUEST | NLM_F_ECHO, OVS_CT_LIMIT_CMD_DEL, + OVS_CT_LIMIT_VERSION); + + ovs_header = ofpbuf_put_uninit(request, sizeof *ovs_header); + ovs_header->dp_ifindex = 0; + + if (!ovs_list_is_empty(zone_limits)) { + struct ct_dpif_zone_limit *zone_limit; + + opt_offset = + nl_msg_start_nested(request, OVS_CT_LIMIT_ATTR_ZONE_LIMIT); + + LIST_FOR_EACH (zone_limit, node, zone_limits) { + req_zone_limit.zone_id = zone_limit->zone; + nl_msg_put(request, &req_zone_limit, sizeof req_zone_limit); + } + nl_msg_end_nested(request, opt_offset); + } + + err = nl_transact(NETLINK_GENERIC, request, NULL); + + ofpbuf_uninit(request); + return err; +} /* Meters */ @@ -3252,9 +3442,9 @@ const struct dpif_class dpif_netlink_class = { NULL, /* ct_set_maxconns */ NULL, /* ct_get_maxconns */ NULL, /* ct_get_nconns */ - NULL, /* ct_set_limits */ - NULL, /* ct_get_limits */ - NULL, /* ct_del_limits */ + dpif_netlink_set_limits, + dpif_netlink_get_limits, + dpif_netlink_del_limits, dpif_netlink_meter_get_features, dpif_netlink_meter_set, dpif_netlink_meter_get, @@ -3294,6 +3484,12 @@ dpif_netlink_init(void) VLOG_INFO("The kernel module does not support meters."); } } + if (nl_lookup_genl_family(OVS_CT_LIMIT_FAMILY, + &ovs_ct_limit_family) < 0) { + VLOG_INFO("Generic Netlink family '%s' does not exist. " + "Please update the Open vSwitch kernel module to enable " + "the conntrack limit feature.", OVS_CT_LIMIT_FAMILY); + } ovs_tunnels_out_of_tree = dpif_netlink_rtnl_probe_oot_tunnels(); From patchwork Thu Aug 2 00:35:54 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi-Hung Wei X-Patchwork-Id: 952497 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="LIUrW13Z"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41grzw3xwxz9s3q for ; Thu, 2 Aug 2018 10:45:00 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id EB907E67; Thu, 2 Aug 2018 00:41:17 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id E3015E4C for ; Thu, 2 Aug 2018 00:41:16 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf1-f170.google.com (mail-pf1-f170.google.com [209.85.210.170]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 63FCA7AC for ; Thu, 2 Aug 2018 00:41:16 +0000 (UTC) Received: by mail-pf1-f170.google.com with SMTP id k21-v6so248312pff.11 for ; Wed, 01 Aug 2018 17:41:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=mOX2GwrCPjW/Wd/fG7xb7nurEGEIK8umD50Li7uMSDo=; b=LIUrW13Z4YjBSLquLPSL2Q82a6y3/bu/sPmTndIsGYg9KNzEY8EfGJzQU47bDBPGjT UydTYyisiU2ZV8jOaYXcvkHFdj2OU5AFquhC8t8HxNMK2v6qXUuRj2L+z6AyOS4FTGjs dmRU832Zcj3wj5tQ1UhNyRD51IosBO13WtqjMkEKGNF2Co/AL4QFCdz57omHXIn3RgKV GMkyvjuHwvzupIsAk5M6bY+5X1qeQMGjv3QARwAr93YMLuLsYCUAd8iPCo6T+gEQFI/u igB2lednrnmvFWzyKPskSk0mPKtLO2kX8YQzh3DzFj/u4N2OpuZB6mn8NRHADi1koPj1 LANw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=mOX2GwrCPjW/Wd/fG7xb7nurEGEIK8umD50Li7uMSDo=; b=Eqa1H6eq2avOchRrjgP2WF1Pa6MPC9nZFx2mR81dSC27IgNVxhdRL05nf9VMpqM5Rc PQHFL66TFjBN6IS3BGrOQ5V4WkLVpvMhlXti28cBw74E9dokfi/XhKtjUXgtPY379f6z 5Kw0EYsn6FFwBhESKjr27wgujWiUpSFsp/uq0kVhK9SKmxDnQcSxQ9iKDv51nm1jDWh/ IorqRtF+wDsaJCpYsExHWpzz1Ah85j4x9gPpWoTqZu7wNY+Nqf5+OdQl8VOawqDNFamY sH9IsHngv/Wtv6dr0dfASqyvVKz1BG6bqrcJLfzh4K8+MVNcLaqlFOT3riBYIear8siO 9ztw== X-Gm-Message-State: AOUpUlH3IyEFqigzsV5gymiyisYn+GHM0cEQ3POUYLFuunUoBrr12Sld i1FVQGfW7aaSU6v45mXbDD4oX1qp X-Google-Smtp-Source: AAOMgpcHcTMen12dvxWnBcZL8vJM7OcaP1w0H1BDu/RbUUhleNQlu/5OtZh43HmdOLhgVOZ/kUU30Q== X-Received: by 2002:a63:8b44:: with SMTP id j65-v6mr546016pge.248.1533170475465; Wed, 01 Aug 2018 17:41:15 -0700 (PDT) Received: from Husky.eng.vmware.com ([66.170.99.1]) by smtp.gmail.com with ESMTPSA id s73-v6sm328627pfi.154.2018.08.01.17.41.13 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Aug 2018 17:41:14 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Wed, 1 Aug 2018 17:35:54 -0700 Message-Id: <1533170156-769-10-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533170156-769-1-git-send-email-yihung.wei@gmail.com> References: <1533170156-769-1-git-send-email-yihung.wei@gmail.com> X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v2 09/11] dpctl: Refactor opt_dpif_open(). X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Make opt_dpif_open() to support mulitple optional arguments. It will be useful for the following patches. Signed-off-by: Yi-Hung Wei --- lib/dpctl.c | 85 ++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/lib/dpctl.c b/lib/dpctl.c index 4f1e443f2662..35733774b331 100644 --- a/lib/dpctl.c +++ b/lib/dpctl.c @@ -191,14 +191,40 @@ parsed_dpif_open(const char *arg_, bool create, struct dpif **dpifp) * * The datapath name is not a mandatory parameter for this command. If * it is not specified -- so 'argc' < 'max_args' -- we retrieve it from - * the current setup, assuming only one exists. On success stores the - * opened dpif in '*dpifp'. */ + * the current setup, assuming only one exists. + * For commands with multiple optional arguments, we try to use the first + * argument as the dpif name. If it is failed, then we fallback to + * retrieve it form the current setup. + * On success stores the opened dpif in '*dpifp', and the next arugment + * to be parsed in '*indexp'. */ static int opt_dpif_open(int argc, const char *argv[], struct dpctl_params *dpctl_p, - uint8_t max_args, struct dpif **dpifp) + uint8_t max_args, struct dpif **dpifp, bool multi_opt, + int *indexp) { + char *dpname; int error = 0; - char *dpname = argc >= max_args ? xstrdup(argv[1]) : get_one_dp(dpctl_p); + + if (indexp) { + *indexp = 1; + } + + if (multi_opt && argc > 1) { + error = parsed_dpif_open(argv[1], false, dpifp); + if (!error) { + if (indexp) { + *indexp = 2; + } + return 0; + } else if (argc == max_args) { + dpctl_error(dpctl_p, error, "invalid datapath"); + return error; + } + dpname = get_one_dp(dpctl_p); + } else { + dpname = argc >= max_args ? xstrdup(argv[1]) : get_one_dp(dpctl_p); + } + if (!dpname) { error = EINVAL; dpctl_error(dpctl_p, error, "datapath not found"); @@ -863,7 +889,7 @@ dpctl_dump_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p) } } - error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif); + error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif, false, NULL); if (error) { goto out_free; } @@ -990,7 +1016,7 @@ dpctl_put_flow(int argc, const char *argv[], enum dpif_flow_put_flags flags, struct simap port_names; int n, error; - error = opt_dpif_open(argc, argv, dpctl_p, 4, &dpif); + error = opt_dpif_open(argc, argv, dpctl_p, 4, &dpif, false, NULL); if (error) { return error; } @@ -1092,7 +1118,7 @@ dpctl_get_flow(int argc, const char *argv[], struct dpctl_params *dpctl_p) struct ds ds; int n, error; - error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif); + error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif, false, NULL); if (error) { return error; } @@ -1141,7 +1167,7 @@ dpctl_del_flow(int argc, const char *argv[], struct dpctl_params *dpctl_p) struct simap port_names; int n, error; - error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif); + error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif, false, NULL); if (error) { return error; } @@ -1210,7 +1236,7 @@ dpctl_del_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p) { struct dpif *dpif; - int error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif); + int error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif, false, NULL); if (error) { return error; } @@ -1271,7 +1297,7 @@ dpctl_dump_conntrack(int argc, const char *argv[], argc--; } - error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif); + error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif, false, NULL); if (error) { return error; } @@ -1313,34 +1339,11 @@ dpctl_flush_conntrack(int argc, const char *argv[], struct ct_dpif_tuple tuple, *ptuple = NULL; struct ds ds = DS_EMPTY_INITIALIZER; uint16_t zone, *pzone = NULL; - char *name; int error, i = 1; - bool got_dpif = false; - /* Parse datapath name. It is not a mandatory parameter for this command. - * If it is not specified, we retrieve it from the current setup, - * assuming only one exists. */ - if (argc >= 2) { - error = parsed_dpif_open(argv[i], false, &dpif); - if (!error) { - got_dpif = true; - i++; - } else if (argc == 4) { - dpctl_error(dpctl_p, error, "invalid datapath"); - return error; - } - } - if (!got_dpif) { - name = get_one_dp(dpctl_p); - if (!name) { - return EINVAL; - } - error = parsed_dpif_open(name, false, &dpif); - free(name); - if (error) { - dpctl_error(dpctl_p, error, "opening datapath"); - return error; - } + error = opt_dpif_open(argc, argv, dpctl_p, 4, &dpif, true, &i); + if (error) { + return error; } /* Parse zone */ @@ -1412,7 +1415,7 @@ dpctl_ct_stats_show(int argc, const char *argv[], } } - error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif); + error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif, false, NULL); if (error) { return error; } @@ -1537,7 +1540,7 @@ dpctl_ct_bkts(int argc, const char *argv[], } } - error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif); + error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif, false, NULL); if (error) { return error; } @@ -1617,7 +1620,7 @@ dpctl_ct_set_maxconns(int argc, const char *argv[], struct dpctl_params *dpctl_p) { struct dpif *dpif; - int error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif); + int error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif, false, NULL); if (!error) { uint32_t maxconns; if (ovs_scan(argv[argc - 1], "%"SCNu32, &maxconns)) { @@ -1643,7 +1646,7 @@ dpctl_ct_get_maxconns(int argc, const char *argv[], struct dpctl_params *dpctl_p) { struct dpif *dpif; - int error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif); + int error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif, false, NULL); if (!error) { uint32_t maxconns; error = ct_dpif_get_maxconns(dpif, &maxconns); @@ -1664,7 +1667,7 @@ dpctl_ct_get_nconns(int argc, const char *argv[], struct dpctl_params *dpctl_p) { struct dpif *dpif; - int error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif); + int error = opt_dpif_open(argc, argv, dpctl_p, 2, &dpif, false, NULL); if (!error) { uint32_t nconns; error = ct_dpif_get_nconns(dpif, &nconns); From patchwork Thu Aug 2 00:35:55 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi-Hung Wei X-Patchwork-Id: 952498 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="dIWRjpjq"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41gs0R5h3Xz9s3q for ; Thu, 2 Aug 2018 10:45:27 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id CCA1AE6E; Thu, 2 Aug 2018 00:41:20 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id CAE30E66 for ; Thu, 2 Aug 2018 00:41:18 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf1-f196.google.com (mail-pf1-f196.google.com [209.85.210.196]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 0D0B87C4 for ; Thu, 2 Aug 2018 00:41:17 +0000 (UTC) Received: by mail-pf1-f196.google.com with SMTP id u24-v6so242433pfn.13 for ; Wed, 01 Aug 2018 17:41:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Es1nOmxl/1XgcqQAgBQtZqMFIY0kDWDInyuF4Kp0x/0=; b=dIWRjpjqlHYkP1k3SxCWKrixrA6MRuY7uOd9jwSPRaOV+94MqocoL8RHQk/znx6oZ1 aX4LF8TV9snSfswq3EvbVZyVMRkK0U7qATZNMsVCzfQTD0fyUtdX1GjnjPadDTMcB+0Q FJimg2J0658O+IocjNBfQoTOnHuElfVIo3OyZXSw1ZKdWUMxYqCzmWSP2+ToG5YXjWD2 VzvD3kl1kwBv81dziV8H+Ri7Eabx4VWj0R61OZ5Bby6HLrHTJbMQItExtHVuYKjLLop8 zt73GRG7ktrDnir1ambj0xeo++XoRzc2/BRJQPgX6LFt6Prg8jwUSNPCFoUbVKeMDg6v QPew== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Es1nOmxl/1XgcqQAgBQtZqMFIY0kDWDInyuF4Kp0x/0=; b=GN4xrF4nCHcT36fffSUbB4TFdaOPDXYvjGGiy/EVkIdau7tV2j4168e0XLWZDRkCS5 EA2pDrM77aWExiQ8C2Eq2IWNUTiEV0y22n9ZV5i5FPeMzycVOJeuQl2VwR6aWo5zZNdj fRt4lA/AHZTgkMpNAmq6xQWsLF+b5S+TjI37p2EH/23ifbhOUIgqBTcxp2uh6TydutGg djuSihhjlRFbAk2axl6hBOviA+x0GB6mzGJiJQGPi5vcHbgn3nR0CMfCAtH0jTWhj+9I B3mWClW2GSKy04aQIpOhi0DX65leCwI7qH+ad/lNDJ9b4yOZ5JoxMPs5oew/me+G1z45 8nzg== X-Gm-Message-State: AOUpUlFWBE76gRvz8OGr38iXC49OgnT4unS+rwhE0rH1+ex3PA/i4qmH rgMD75ExKbSxKbqKD2C5wPHpHxdR X-Google-Smtp-Source: AAOMgpeGTSE9gqkyGHKD6Gr5biTZgPhk8aYZI2EtVOzRo1MEr3pPZTqVdIV7eVVTNKBcj/T8qZ7nuw== X-Received: by 2002:a65:5545:: with SMTP id t5-v6mr523733pgr.157.1533170477082; Wed, 01 Aug 2018 17:41:17 -0700 (PDT) Received: from Husky.eng.vmware.com ([66.170.99.1]) by smtp.gmail.com with ESMTPSA id s73-v6sm328627pfi.154.2018.08.01.17.41.15 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Aug 2018 17:41:15 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Wed, 1 Aug 2018 17:35:55 -0700 Message-Id: <1533170156-769-11-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533170156-769-1-git-send-email-yihung.wei@gmail.com> References: <1533170156-769-1-git-send-email-yihung.wei@gmail.com> X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v2 10/11] dpctl: Implement dpctl commands for conntrack per zone limit X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org This patch implments the following three commands on dpctl so that users can use ovs-dpctl or ovs-appctl to set, delete, and get the per zone limit. For example, $ ovs-appctl dpctl/ct-set-limits default=10 zone=0,limit=5 zone=1,limit=3 $ ovs-appctl dpct/ct-del-limits zone=0 $ ovs-appctl dpct/ct-get-limits zone=1,2,3 Signed-off-by: Yi-Hung Wei --- NEWS | 2 + lib/ct-dpif.c | 67 +++++++++++++++++++++++ lib/ct-dpif.h | 4 ++ lib/dpctl.c | 169 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- lib/dpctl.man | 18 +++++++ 5 files changed, 259 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 8270ef46ea34..31c5a1e400dc 100644 --- a/NEWS +++ b/NEWS @@ -19,6 +19,8 @@ v2.10.0 - xx xxx xxxx default it always accepts names and in interactive use it displays them; use --names or --no-names to override. See ovs-ofctl(8) for details. - ovs-vsctl: New commands "add-bond-iface" and "del-bond-iface". + - ovs-dpctl: + * New commands "ct-set-limits", "ct-del-limits", and "ct-get-limits". - OpenFlow: * OFPT_ROLE_STATUS is now available in OpenFlow 1.3. * OpenFlow 1.5 extensible statistics (OXS) now implemented. diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c index a772799fe347..bb809d9920b5 100644 --- a/lib/ct-dpif.c +++ b/lib/ct-dpif.c @@ -629,3 +629,70 @@ ct_dpif_free_zone_limits(struct ovs_list *zone_limits) free(p); } } + +/* Parses a specification of a conntrack zone limit from 's' into '*pzone' + * and '*plimit'. Returns true on success. Otherwise, returns false and + * and puts the error message in 'ds'. */ +bool +ct_dpif_parse_zone_limit_tuple(const char *s, uint16_t *pzone, + uint32_t *plimit, struct ds *ds) +{ + char *pos, *key, *value, *copy, *err; + bool parsed_limit = false, parsed_zone = false; + + pos = copy = xstrdup(s); + while (ofputil_parse_key_value(&pos, &key, &value)) { + if (!*value) { + ds_put_format(ds, "field %s missing value", key); + goto error; + } + + if (!strcmp(key, "zone")) { + err = str_to_u16(value, key, pzone); + if (err) { + free(err); + goto error_with_msg; + } + parsed_zone = true; + } else if (!strcmp(key, "limit")) { + err = str_to_u32(value, plimit); + if (err) { + free(err); + goto error_with_msg; + } + parsed_limit = true; + } else { + ds_put_format(ds, "invalid zone limit field: %s", key); + goto error; + } + } + + if (parsed_zone == false || parsed_limit == false) { + ds_put_format(ds, "failed to parse zone limit"); + goto error; + } + + free(copy); + return true; + +error_with_msg: + ds_put_format(ds, "failed to parse field %s", key); +error: + free(copy); + return false; +} + +void +ct_dpif_format_zone_limits(uint32_t default_limit, + const struct ovs_list *zone_limits, struct ds *ds) +{ + struct ct_dpif_zone_limit *zone_limit; + + ds_put_format(ds, "default_limit=%"PRIu32, default_limit); + + LIST_FOR_EACH (zone_limit, node, zone_limits) { + ds_put_format(ds, " zone=%"PRIu16, zone_limit->zone); + ds_put_format(ds, ",limit=%"PRIu32, zone_limit->limit); + ds_put_format(ds, ",count=%"PRIu32, zone_limit->count); + } +} diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h index c80e18b72b56..c9cfb258b133 100644 --- a/lib/ct-dpif.h +++ b/lib/ct-dpif.h @@ -223,5 +223,9 @@ void ct_dpif_push_zone_limit(struct ovs_list *, uint16_t zone, uint32_t limit, uint32_t count); struct ct_dpif_zone_limit * ct_dpif_pop_zone_limit(struct ovs_list *); void ct_dpif_free_zone_limits(struct ovs_list *); +bool ct_dpif_parse_zone_limit_tuple(const char *s, uint16_t *pzone, + uint32_t *plimit, struct ds *); +void ct_dpif_format_zone_limits(uint32_t default_limit, + const struct ovs_list *, struct ds *); #endif /* CT_DPIF_H */ diff --git a/lib/dpctl.c b/lib/dpctl.c index 35733774b331..560f713cfd51 100644 --- a/lib/dpctl.c +++ b/lib/dpctl.c @@ -199,7 +199,7 @@ parsed_dpif_open(const char *arg_, bool create, struct dpif **dpifp) * to be parsed in '*indexp'. */ static int opt_dpif_open(int argc, const char *argv[], struct dpctl_params *dpctl_p, - uint8_t max_args, struct dpif **dpifp, bool multi_opt, + int max_args, struct dpif **dpifp, bool multi_opt, int *indexp) { char *dpname; @@ -1683,6 +1683,167 @@ dpctl_ct_get_nconns(int argc, const char *argv[], return error; } +static int +dpctl_ct_set_limits(int argc, const char *argv[], + struct dpctl_params *dpctl_p) +{ + struct dpif *dpif; + struct ds ds = DS_EMPTY_INITIALIZER; + int error, i = 1; + uint32_t default_limit, *p_default_limit = NULL; + struct ovs_list list = OVS_LIST_INITIALIZER(&list); + + error = opt_dpif_open(argc, argv, dpctl_p, INT_MAX, &dpif, true, &i); + if (error) { + return error; + } + + /* Parse default limit */ + if (!strncmp(argv[i], "default=", 8)) { + if (ovs_scan(argv[i], "default=%"SCNu32, &default_limit)) { + p_default_limit = &default_limit; + i++; + } else { + ds_put_cstr(&ds, "invalid default limit"); + error = EINVAL; + goto error; + } + } + + /* Parse ct zone limit tuples */ + while (i < argc) { + uint16_t zone; + uint32_t limit; + if (!ct_dpif_parse_zone_limit_tuple(argv[i++], &zone, &limit, &ds)) { + error = EINVAL; + goto error; + } + ct_dpif_push_zone_limit(&list, zone, limit, 0); + } + + error = ct_dpif_set_limits(dpif, p_default_limit, &list); + if (!error) { + ct_dpif_free_zone_limits(&list); + dpif_close(dpif); + return 0; + } else { + ds_put_cstr(&ds, "failed to set conntrack limit"); + } + +error: + dpctl_error(dpctl_p, error, "%s", ds_cstr(&ds)); + ds_destroy(&ds); + ct_dpif_free_zone_limits(&list); + dpif_close(dpif); + return error; +} + +static int +parse_ct_limit_zones(const char *argv, struct ovs_list *list, struct ds *ds) +{ + char *save_ptr = NULL, *argcopy, *next_zone; + uint16_t zone; + + if (strncmp(argv, "zone=", 5)) { + ds_put_format(ds, "invalid argument %s", argv); + return EINVAL; + } + + argcopy = xstrdup(argv + 5); + next_zone = strtok_r(argcopy, ",", &save_ptr); + + do { + if (ovs_scan(next_zone, "%"SCNu16, &zone)) { + ct_dpif_push_zone_limit(list, zone, 0, 0); + } else { + ds_put_cstr(ds, "invalid zone"); + return EINVAL; + } + } while ((next_zone = strtok_r(NULL, ",", &save_ptr)) != NULL); + + free(argcopy); + return 0; +} + +static int +dpctl_ct_del_limits(int argc, const char *argv[], + struct dpctl_params *dpctl_p) +{ + struct dpif *dpif; + struct ds ds = DS_EMPTY_INITIALIZER; + int error, i = 1; + struct ovs_list list = OVS_LIST_INITIALIZER(&list); + + error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif, true, &i); + if (error) { + return error; + } + + error = parse_ct_limit_zones(argv[i], &list, &ds); + if (error) { + goto error; + } + + error = ct_dpif_del_limits(dpif, &list); + if (!error) { + goto out; + } else { + ds_put_cstr(&ds, "failed to delete conntrack limit"); + } + +error: + dpctl_error(dpctl_p, error, "%s", ds_cstr(&ds)); + ds_destroy(&ds); +out: + ct_dpif_free_zone_limits(&list); + dpif_close(dpif); + return error; +} + +static int +dpctl_ct_get_limits(int argc, const char *argv[], + struct dpctl_params *dpctl_p) +{ + struct dpif *dpif; + struct ds ds = DS_EMPTY_INITIALIZER; + uint32_t default_limit; + int error, i = 1; + struct ovs_list list_query = OVS_LIST_INITIALIZER(&list_query); + struct ovs_list list_reply = OVS_LIST_INITIALIZER(&list_reply); + + error = opt_dpif_open(argc, argv, dpctl_p, 3, &dpif, true, &i); + if (error) { + return error; + } + + if (argc > i) { + error = parse_ct_limit_zones(argv[i], &list_query, &ds); + if (error) { + goto error; + } + } + + error = ct_dpif_get_limits(dpif, &default_limit, &list_query, + &list_reply); + if (!error) { + ct_dpif_format_zone_limits(default_limit, &list_reply, &ds); + dpctl_print(dpctl_p, "%s\n", ds_cstr(&ds)); + goto out; + } else { + ds_put_format(&ds, "failed to get conntrack limit %s", + ovs_strerror(error)); + } + +error: + dpctl_error(dpctl_p, error, "%s", ds_cstr(&ds)); +out: + ds_destroy(&ds); + ct_dpif_free_zone_limits(&list_query); + ct_dpif_free_zone_limits(&list_reply); + dpif_close(dpif); + return error; +} + /* Undocumented commands for unit testing. */ static int @@ -1982,6 +2143,12 @@ static const struct dpctl_command all_commands[] = { { "ct-set-maxconns", "[dp] maxconns", 1, 2, dpctl_ct_set_maxconns, DP_RW }, { "ct-get-maxconns", "[dp]", 0, 1, dpctl_ct_get_maxconns, DP_RO }, { "ct-get-nconns", "[dp]", 0, 1, dpctl_ct_get_nconns, DP_RO }, + { "ct-set-limits", "[dp] [default=L] [zone=N,limit=L]...", 1, INT_MAX, + dpctl_ct_set_limits, DP_RO }, + { "ct-del-limits", "[dp] zone=N1[,N2]...", 1, 2, dpctl_ct_del_limits, + DP_RO }, + { "ct-get-limits", "[dp] [zone=N1[,N2]...]", 0, 2, dpctl_ct_get_limits, + DP_RO }, { "help", "", 0, INT_MAX, dpctl_help, DP_RO }, { "list-commands", "", 0, INT_MAX, dpctl_list_commands, DP_RO }, diff --git a/lib/dpctl.man b/lib/dpctl.man index 5d987e62daaa..deb1bd32a34b 100644 --- a/lib/dpctl.man +++ b/lib/dpctl.man @@ -272,3 +272,21 @@ Only supported for userspace datapath. \*(DX\fBct\-get\-nconns\fR [\fIdp\fR] Prints the current number of connection tracker entries on \fIdp\fR. Only supported for userspace datapath. +. +.TP +\*(DX\fBct\-set\-limits\fR [\fIdp\fR] [\fBdefault=\fIdefault_limit\fR] [\fBzone=\fIzone\fR,\fBlimit=\fIlimit\fR]... +Sets the maximum allowed number of connections in connection tracking zones. +If a per zone limit for a particular zone is not available in the datapath, +it defaults to the default per zone limit. Initially, the default per zone +limit is unlimited(0). +. +.TP +\*(DX\fBct\-del\-limits\fR [\fIdp\fR] \fBzone=\fIzone[,zone]\fR... +Deletes the per zone limit on particular zones. The \fIzone\fR must be a +comma-separated list. +. +.TP +\*(DX\fBct\-get\-limits\fR [\fIdp\fR] [\fBzone=\fIzone[,zone]\fR...] +Retrieves the maximum allowed number of connections. The \fIzone\fR must +be a comma-separated list. Prints all zone limits if no \fIzone\fR is +provided. From patchwork Thu Aug 2 00:35:56 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi-Hung Wei X-Patchwork-Id: 952499 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="f4wS9FFB"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41gs0s4mdlz9s3q for ; Thu, 2 Aug 2018 10:45:49 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 7FB22E78; Thu, 2 Aug 2018 00:41:22 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id E55ADE71 for ; Thu, 2 Aug 2018 00:41:20 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pl0-f49.google.com (mail-pl0-f49.google.com [209.85.160.49]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id AE9897C1 for ; Thu, 2 Aug 2018 00:41:19 +0000 (UTC) Received: by mail-pl0-f49.google.com with SMTP id u11-v6so202864plq.5 for ; Wed, 01 Aug 2018 17:41:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=GG7Ofp/9TM1z6D9fY4Tk0yFAZsHNDh3uKv5prBpwzcU=; b=f4wS9FFBFZr/KytBiYPQ8NCYN1fQ+slb0joFc+qt7aU21g4kPJsv4FKLsYsYSKoLM3 hX3YwKDJn+7E5EkXh3RQchh6jLUIBlyBhk1GJZ6drIVedd5cBCylpnYls8unVdNugiyM AvHGXy9JovX218+t+2yKs9NP7BTkoLBTYZKtuKJrnGa/IXLDcNij4oy15L2Ixg09fN3p L2BqABi4UMGT/eVRVCB+g27rwVrVp7LkBdZrmmk++kkKzQD/iBybWEnEYunh4/rLD9dr ryHHCrdUVvQh/dL3U/KPOSrDSOLEg5Gj6fFUV6xu8V/HOaXfBCK9Jknq8kdh80oEOr9m BXPg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=GG7Ofp/9TM1z6D9fY4Tk0yFAZsHNDh3uKv5prBpwzcU=; b=LctvvmQlhT6WUn/McGB4WZnKY0N7ImkHypD7j7ZbJjb4ZOyIiE9VDxByhxTkqRwubS NTGNLrUhXpM0NVdzxZI7WH9HxiLw3MjkTN0gW7nKIfAm5fX0uV05VqLY6gQR2VmKdMAy 2IU0sdpdX7Jz3Y1j4MmWEQc2+6v5ObkovV74uhgNOPPMkX0Pe0EUlaQypvbSzsUFAiEy QG14DYi3E0NRxhE/f5YFXbipCqCrFR1/Y3HTRSOK8r3GRLzI/kZPbzdF5tWn4bIVWKK+ i3S520UiSl5/4bwnYRDuGkvkS1qxj16uWvRwFgK9o54rxOldyYx+iapUXbLP1UKkOv51 N9sg== X-Gm-Message-State: AOUpUlELFZx9kdG8td+YUWxah91WDyGXYePl3HzusWBSAMweNL9u0pX2 WfRDhMnEY7YmMIr25s54DqtBd5Qn X-Google-Smtp-Source: AAOMgpdCAQ+ukl0gt30IfT7+MqkLtYuDwK7ImRedz0IZY6UhuuR6U81CwKb62dZlCLwGjAHL2//uKw== X-Received: by 2002:a17:902:8a4:: with SMTP id 33-v6mr473534pll.82.1533170478841; Wed, 01 Aug 2018 17:41:18 -0700 (PDT) Received: from Husky.eng.vmware.com ([66.170.99.1]) by smtp.gmail.com with ESMTPSA id s73-v6sm328627pfi.154.2018.08.01.17.41.17 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Aug 2018 17:41:17 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Wed, 1 Aug 2018 17:35:56 -0700 Message-Id: <1533170156-769-12-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533170156-769-1-git-send-email-yihung.wei@gmail.com> References: <1533170156-769-1-git-send-email-yihung.wei@gmail.com> X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v2 11/11] system-traffic: Add conntrack per zoen limit test case X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Signed-off-by: Yi-Hung Wei --- tests/system-traffic.at | 75 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/tests/system-traffic.at b/tests/system-traffic.at index cbd954257ae8..1e6bf1e75565 100644 --- a/tests/system-traffic.at +++ b/tests/system-traffic.at @@ -2918,6 +2918,81 @@ tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=,dport=),reply=(src= OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP +AT_SETUP([conntrack - limit by zone]) +CHECK_CONNTRACK() +CHECK_CT_DPIF_FLUSH_BY_CT_TUPLE() +OVS_TRAFFIC_VSWITCHD_START() + +ADD_NAMESPACES(at_ns0, at_ns1) + +ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24") +ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24") + +AT_DATA([flows.txt], [dnl +priority=1,action=drop +priority=10,arp,action=normal +priority=100,in_port=1,udp,action=ct(commit),2 +priority=100,in_port=2,udp,action=ct(zone=3,commit),1 +]) + +AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt]) + +AT_CHECK([ovs-appctl dpctl/ct-set-limits default=10 zone=0,limit=5 zone=1,limit=15 zone=2,limit=3 zone=3,limit=3]) +AT_CHECK([ovs-appctl dpctl/ct-del-limits zone=1,2,4]) +AT_CHECK([ovs-appctl dpctl/ct-get-limits zone=0,1,2,3], [],[dnl +default_limit=10 zone=0,limit=5,count=0 zone=1,limit=10,count=0 zone=2,limit=10,count=0 zone=3,limit=3,count=0 +]) + +dnl Test UDP from port 1 +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"]) +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000300080000 actions=resubmit(,0)"]) +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000400080000 actions=resubmit(,0)"]) +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000500080000 actions=resubmit(,0)"]) +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000600080000 actions=resubmit(,0)"]) +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000700080000 actions=resubmit(,0)"]) +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000800080000 actions=resubmit(,0)"]) +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000900080000 actions=resubmit(,0)"]) +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000a00080000 actions=resubmit(,0)"]) + +AT_CHECK([ovs-appctl dpctl/ct-get-limits zone=0,1,2,3,4,5], [0], [dnl +default_limit=10 zone=0,limit=5,count=5 zone=1,limit=10,count=0 zone=2,limit=10,count=0 zone=3,limit=3,count=0 zone=4,limit=10,count=0 zone=5,limit=10,count=0 +]) + +dnl Test ct-get-limits for all zoens +AT_CHECK([ovs-appctl dpctl/ct-get-limits], [0], [dnl +default_limit=10 zone=0,limit=5,count=5 zone=3,limit=3,count=0 +]) + +AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "orig=.src=10\.1\.1\.1," | sort ], [0], [dnl +udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1) +udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=3),reply=(src=10.1.1.2,dst=10.1.1.1,sport=3,dport=1) +udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=4),reply=(src=10.1.1.2,dst=10.1.1.1,sport=4,dport=1) +udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=5),reply=(src=10.1.1.2,dst=10.1.1.1,sport=5,dport=1) +udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=6),reply=(src=10.1.1.2,dst=10.1.1.1,sport=6,dport=1) +]) + +dnl Test UDP from port 2 +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101030a0101040001000200080000 actions=resubmit(,0)"]) +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101030a0101040001000300080000 actions=resubmit(,0)"]) +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101030a0101040001000400080000 actions=resubmit(,0)"]) +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101030a0101040001000500080000 actions=resubmit(,0)"]) +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101030a0101040001000600080000 actions=resubmit(,0)"]) + +AT_CHECK([ovs-appctl dpctl/ct-get-limits zone=0,3], [0], [dnl +default_limit=10 zone=0,limit=5,count=5 zone=3,limit=3,count=3 +]) + +AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "orig=.src=10\.1\.1\.3," | sort ], [0], [dnl +udp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=1,dport=2),reply=(src=10.1.1.4,dst=10.1.1.3,sport=2,dport=1),zone=3 +udp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=1,dport=3),reply=(src=10.1.1.4,dst=10.1.1.3,sport=3,dport=1),zone=3 +udp,orig=(src=10.1.1.3,dst=10.1.1.4,sport=1,dport=4),reply=(src=10.1.1.4,dst=10.1.1.3,sport=4,dport=1),zone=3 +]) + +OVS_TRAFFIC_VSWITCHD_STOP(["dnl +/could not create datapath/d +/(Cannot allocate memory) on packet/d"]) +AT_CLEANUP + AT_SETUP([FTP - no conntrack]) AT_SKIP_IF([test $HAVE_FTP = no]) OVS_TRAFFIC_VSWITCHD_START()