From patchwork Wed Aug 1 22:46:10 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: 952457 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="EQJ07p7u"; 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 41gpSV6p1cz9s4c for ; Thu, 2 Aug 2018 08:51:06 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 133A4D88; Wed, 1 Aug 2018 22:50:35 +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 72174D6D for ; Wed, 1 Aug 2018 22:50:33 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pl0-f67.google.com (mail-pl0-f67.google.com [209.85.160.67]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id D2C556C5 for ; Wed, 1 Aug 2018 22:50:32 +0000 (UTC) Received: by mail-pl0-f67.google.com with SMTP id x6-v6so92824plv.10 for ; Wed, 01 Aug 2018 15:50:32 -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=EQJ07p7uNGKgbD1hILhBya/6arhf7Q9zJio8KZ0OGIqIvo/BuH/C/3rwfemnimpCUe VJZBpQvM8lz+DNSnNUGmwCy7+cEPDzYuQcGQX3ymkXsj41iA3nUpj1aIK1JqDvZ9seBu CWQ6jWTOvZeJk60Nyk4DjC6n3mab2sWbvPgqRfx5qOyXJ/0UKnrXMEERnlsMy3NyKFFR RCrufLHgFcQyLqy2w3RkmMCGyLV6yF77Ji4J8/5NOTUAZ8/bSrno2DiqMCMckFvx0Tn0 +gfN6GJdvW1LUt9zaz0EoDDXFdFFl+V3o0gCy3xGQ8b95cvQevFk361ztoMw4f+34h1M Bv8g== 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=LyWsv42FxJHHSlfGpdhbGqEm+N4aB/K20tZ3gs58UHCiqrd7v5L1tMddK9O9NWqBRj CznJgG9Zg4kYxtKYFrGqt/9CEnjz+LiI/Ejot+kf9vvhZh7yjUcSXw7+On8l+RZIJVvE fn882GXyqAi3GyRuv1DQqys8B542xRzNFg2+fZol+QpuvJDRtU0+Q690Bk3M37lfMmfk dpzClgGtxdzjJF0s/cuAgiH4kESGRyhr8/nxi2UII0U3waHnwOh0rv/iacMslxriRFxg LZOcFZRYOv1EXGpwhc9tQX5aI3wAZEB0Dm0cjWyVROVdkRwNtMGnDoZqx0fZ0e0i/3Pt CaQQ== X-Gm-Message-State: AOUpUlE4Jrl1zizwQWtuqTjqy+jEHZueW69CxpTO2QpBVduyMHf8XJk3 bdLDG7NBh9UoZJAZHjyrtoRwS/5t X-Google-Smtp-Source: AAOMgpdkMeo5Plh3O7/BWSFOosAdOwrwv3gpfbRNeZ/2c6Hug4mjbYLIrcEKAn8UY715yhQ0WvpZ7w== X-Received: by 2002:a17:902:7d8f:: with SMTP id a15-v6mr213473plm.332.1533163831931; Wed, 01 Aug 2018 15:50:31 -0700 (PDT) Received: from Husky.eng.vmware.com ([66.170.99.1]) by smtp.gmail.com with ESMTPSA id l85-v6sm196899pfk.34.2018.08.01.15.50.30 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Aug 2018 15:50:30 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Wed, 1 Aug 2018 15:46:10 -0700 Message-Id: <1533163580-27989-2-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533163580-27989-1-git-send-email-yihung.wei@gmail.com> References: <1533163580-27989-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 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 Wed Aug 1 22:46:11 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: 952458 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="F3VtzpOv"; 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 41gpT5107Jz9s3Z for ; Thu, 2 Aug 2018 08:51:37 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id C2A7ADA2; Wed, 1 Aug 2018 22:50:37 +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 806CFD9B for ; Wed, 1 Aug 2018 22:50:36 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pl0-f65.google.com (mail-pl0-f65.google.com [209.85.160.65]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id D90E76C5 for ; Wed, 1 Aug 2018 22:50:34 +0000 (UTC) Received: by mail-pl0-f65.google.com with SMTP id x6-v6so92861plv.10 for ; Wed, 01 Aug 2018 15:50:34 -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=F3VtzpOvKfUEnbKZunV24oN0U/kvFgxLggzN4nc9Ps/9wo6mm2IE169EPgXrt+GX4N zbHxExghDxupUrBFdY2gJEQBcV7hLA0dEc4SYjElpUw27unViqPYYu0SckLkY4b9/ISo 2/UJTKhaUVRQb6Qmpd6+vOdVDdKaFUok9hB2mkiloQhDzN5wtJY50vKZ71A6sXIIencq nOGqjjZw+e+4Zl5iwkE99tGxA5h6ngCAFdm0HSgZNzDIr+3xfsSs5vtLsIXvKhI/rcjW SLwnnFlVyfNUMOc1vap823seaPGZHrI12J1tUMqKZM4HDuji9zpraui6cwzP7wUooDlf qvuw== 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=p26hdJZWw2/eHJ5yOikkXt7Bx+UGef12jtEFs5oW8lGOq83BPT25CpMeSSNvXbBbfv 6HANHNs1gzbUPVYLuZTKPULNR2losELSLKT6muLtH6FJlCoN9sEeuCQgl0Vd8NqnJ9lv bYRz0vB/Vlg3sZT/Tq/uF6NOsLsJS408LgA4weiJ2D3tHibYks0/EXv9uwSTWfKpi5j9 a3Q3VQeHhUdzgluzQkoDjg/sb5iMqBkNRqfYEQCz0YpyFOltCSyEIZUDhbojvP133aBG BcwWgayVV81xvOOV7/lTVmGVWsq8IramCryd7vu39TdFYzxlzTS5/PmmkpHX75LTTVT3 AEFg== X-Gm-Message-State: AOUpUlFB+UiQIbUGJCF4skyxyqVpwa6VkV1WvDx37zTRXEMfZfQYKqTd RaSpZAA9z9eUY2ellh7igMh79vfX X-Google-Smtp-Source: AAOMgpcjomqa4I59GSFJwljbarpABL1Llru6bhAAv2zfDVhVSPfNj6h0P0iqI9F05pIgEzZ+yjZMMQ== X-Received: by 2002:a17:902:32a4:: with SMTP id z33-v6mr223388plb.226.1533163833831; Wed, 01 Aug 2018 15:50:33 -0700 (PDT) Received: from Husky.eng.vmware.com ([66.170.99.1]) by smtp.gmail.com with ESMTPSA id l85-v6sm196899pfk.34.2018.08.01.15.50.31 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Aug 2018 15:50:32 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Wed, 1 Aug 2018 15:46:11 -0700 Message-Id: <1533163580-27989-3-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533163580-27989-1-git-send-email-yihung.wei@gmail.com> References: <1533163580-27989-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 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 Wed Aug 1 22:46:12 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: 952459 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="QJrNDSbZ"; 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 41gpTh53cQz9s3Z for ; Thu, 2 Aug 2018 08:52:08 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 81D8EDA0; Wed, 1 Aug 2018 22:50:38 +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 0C50BD62 for ; Wed, 1 Aug 2018 22:50:37 +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 9E6A06C5 for ; Wed, 1 Aug 2018 22:50:36 +0000 (UTC) Received: by mail-pl0-f66.google.com with SMTP id w3-v6so108781plq.2 for ; Wed, 01 Aug 2018 15:50:36 -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=QJrNDSbZ6DO2CIUljQmVddeE1ILWnxPr8xZbF/fd/XgTebQLwHA8TyFOTraiCQYduy HcAxnyvkFy0LAzgmcoXCeGmClerqntXM3OUODElJEs5Bi7EGGy1yBI8YEYwKUWTCEMuS FDOHUHZ57A3L9n4QugQdSvHkhQ8MWHxPoGEJRB/lvtb5B8AnTxsgfXaA9O1cTuSlBleo 8kAgopINPh3WtHVdhDUsQelKUOsbW+iRxwlHg82MNwG8/pEh56HIEcM6qRJ1Cti8BTbL tzAB5zA1NQOXoD6Fi0o44wjkFAjud3kG5uyilCSnNV64h9rZmDahR4VDyGcVvswzMwTz KxNA== 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=JEx4CbM7TgFQAOBgF59NHQKn50/m8AGU0KmHz4cJkZ62dJ7ah16fnBS5Kw6FWEvbRq NDT7vT4FxP3WRMhcyuwsCvfBkFH+pV+u1EtbkftoUYB3iR9cDfxGHnz/Zy+LlQXdX2oO eA5kE37ZOECeXPccrsJHskDoc1wqw+xA3jlID6xF4i6kA7AY/8BFGtqwjWMTbZrfwavt UoUePEt7Ib2o+QDGYDbgENTooDQkBQPeCVBeN81r+GjpBcopxL8A6hdvsooTw0PZDMBL 2FFf+2fsZtHhMWewFce9Xz4yLoPkTK77egP4G1AX7byJC0eaN/FI9V2ZMb0pTKCNpwqx 26Pw== X-Gm-Message-State: AOUpUlEQaf+MOb1lb/qnlXrH2pCA9ms7NpA+KSIgzEfOrDe12JgFqzlj zmWPC1YcWET1X/K1EhmP8YgAvkMT X-Google-Smtp-Source: AAOMgpd1P0wJTcBoFp1XMAu5K2wUUX0iBFaNTDR9jpmJyOEe5cONu2ztKiLtdxuGyWwbRc4JB+oomw== X-Received: by 2002:a17:902:143:: with SMTP id 61-v6mr196499plb.171.1533163835789; Wed, 01 Aug 2018 15:50:35 -0700 (PDT) Received: from Husky.eng.vmware.com ([66.170.99.1]) by smtp.gmail.com with ESMTPSA id l85-v6sm196899pfk.34.2018.08.01.15.50.33 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Aug 2018 15:50:34 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Wed, 1 Aug 2018 15:46:12 -0700 Message-Id: <1533163580-27989-4-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533163580-27989-1-git-send-email-yihung.wei@gmail.com> References: <1533163580-27989-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 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 Wed Aug 1 22:46:13 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: 952460 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="Urp/jg1F"; 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 41gpVP1gtvz9s3Z for ; Thu, 2 Aug 2018 08:52:45 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 684EFDB6; Wed, 1 Aug 2018 22:50:40 +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 CCD3CD9D for ; Wed, 1 Aug 2018 22:50:38 +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 6B69A6C5 for ; Wed, 1 Aug 2018 22:50:38 +0000 (UTC) Received: by mail-pl0-f66.google.com with SMTP id e11-v6so106220plb.3 for ; Wed, 01 Aug 2018 15:50:38 -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=Urp/jg1F77TyqxIn3pTTyiy5YY+aWJchRAbYPy4yJqpmk3NQnnhLYM9XKKzuo2gn6t IWvhl+pSq+Xk1DgGZPqPovx0o8RXrkzAaOmNud+L24VCRVbxkXQ8RpkKUmiR52By8pao 4ZaHHH2ci00imJJm7BHfPLZwOX7MFiXcdCZXLhpkmJf3a1D0ScM1q3nhdl+OA/hj6Gac 65oXXnKBRxDFyhrg/xjP6Re/6GjwCOaxKbz2mi5POOPj/R3jpvbD6H4NhQWwpcmxd7hQ 510OMMrpm8RhklOupC0XWf5vYcXQnnHMzwL1oRB60tPN6ohnmsC1P1EPgj/bce3y/70f f9Kg== 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=d2VeamYe4HsiWmiPfhWGbTkw5zPWj6VrtF3XSUwZJUf8dPvtOkSNtUK/qn8us/1md+ cUVyJW2l+lXbxZ7hkdSRjsV/bN1drzHdxL+b5pVm9HvDquGIvv25u8rBHh+W7rzdusSI ptP3Jv48cVaPAQVZWy7RBF2RQhKR1d4cTchI5HETCWEETf3MEkigkeqoQMRlpluheusf BdTkIhkfpMi5oeJauQnTwFJjim/hcnIY2HQNhIOwTunam06qIZ8Cc2QYe+zIN4v4UU4e Uh8mnqjDew3+9rSb9IIzr53qPxflvJ/Hy3GOxllfOL3ZeluwMdcSGYkgsK7aZ9LGcsii VFzA== X-Gm-Message-State: AOUpUlGmc4SzIfxn9qgbvJPr/AKnZA+NQHk5lnD93+jfI1sIbMssJOgf uPqbRNuBLJR4gycgI0FbLcFwbNcs X-Google-Smtp-Source: AAOMgpds9wGtXMmLXkyNG8jSSQGRpVcA/MKwh6mXSWl0K9XHrvPmvxPq32xAx4bHFiprYwpYML2qDA== X-Received: by 2002:a17:902:5617:: with SMTP id h23-v6mr208613pli.324.1533163837580; Wed, 01 Aug 2018 15:50:37 -0700 (PDT) Received: from Husky.eng.vmware.com ([66.170.99.1]) by smtp.gmail.com with ESMTPSA id l85-v6sm196899pfk.34.2018.08.01.15.50.35 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Aug 2018 15:50:36 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Wed, 1 Aug 2018 15:46:13 -0700 Message-Id: <1533163580-27989-5-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533163580-27989-1-git-send-email-yihung.wei@gmail.com> References: <1533163580-27989-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 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 Wed Aug 1 22:46:14 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: 952461 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="CuOy4NZT"; 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 41gpVn5Wh8z9s3Z for ; Thu, 2 Aug 2018 08:53:05 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 1824DDB3; Wed, 1 Aug 2018 22:50:43 +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 D88CDDA5 for ; Wed, 1 Aug 2018 22:50:41 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg1-f194.google.com (mail-pg1-f194.google.com [209.85.215.194]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 64FC5713 for ; Wed, 1 Aug 2018 22:50:40 +0000 (UTC) Received: by mail-pg1-f194.google.com with SMTP id e6-v6so129530pgv.2 for ; Wed, 01 Aug 2018 15:50:40 -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=CuOy4NZTyoyzpQpVU8HBQo6GNkEbW4GLkaZTPvEIqT85IP0dlYqmnymmJCX4zsMpJj QH1BC0kVIllZkc5dvZsR+6UbymTnbsWzurt8sw6QhTdUS3ivaSlZ/qrGs1u3jZVeKtGU uYNAz+MIkugCvrFOFENj4IXTHEOgxR8CPkwlJ8jzngco9c9TM0ybww6T8LbyNV5HqNbG F0FciSzB+kIr8xDwbXEyhQsmQYVnhRU+/1+jp5H3zqPIF9HUmYALmtOVjf++ahH+Aiaq jEU3+ulUF6rMbKAwVd6go5TdE2I3/0a+RDkxheDvfif+zdalK8wnLdzgl3XKQ2eQH423 CAVA== 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=mf24zUq4jdfkbTZnftEYEwPEVqLUQme5cSljqlJ1+ZU5jRgv7VhhK4GIJOoNb5+l64 AOJM5De4UcT8v+Ek/GpWD3vzzvr5ypw6cdeSZGvm414OmsPBQjlIKuXnm4OXbf9uJYZr 0itluPmdBdq62XsPZSVrDAcd9q0ZpH+fLhmc9ejFDjdQXbPLEp5Oxxg8aNVOguh+H9oS 1z6YpXtVZd9WtIIFe5zI45PfRcZRRstDDtNmihBlTvCSRcJ9VE3TDqK7uAfClV3g1C+k 06oAZnxO1onme3N4vPvPyVm1BzsVpPB3v0pwaMpJhlf3Tw44VL26WP2xtxIjTT3gM+iN Y5DA== X-Gm-Message-State: AOUpUlFY0dVByQHUY1TUC1Kgki4LkVZZbhUJZ/ECBbZecYuDoV+5nBBY qONiauBLLwUCsCrk0N6cg9iHNv1T X-Google-Smtp-Source: AAOMgpfrfjO8CIyTDWVsoqz9ahLADZtN4In1VURglgM9MOBHjZ9F0jjIxtd/ZLoTOs8YSFyoAbdU9g== X-Received: by 2002:a63:fe02:: with SMTP id p2-v6mr271554pgh.148.1533163839420; Wed, 01 Aug 2018 15:50:39 -0700 (PDT) Received: from Husky.eng.vmware.com ([66.170.99.1]) by smtp.gmail.com with ESMTPSA id l85-v6sm196899pfk.34.2018.08.01.15.50.37 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Aug 2018 15:50:37 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Wed, 1 Aug 2018 15:46:14 -0700 Message-Id: <1533163580-27989-6-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533163580-27989-1-git-send-email-yihung.wei@gmail.com> References: <1533163580-27989-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 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 Wed Aug 1 22:46:15 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: 952462 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="nOB2XFTF"; 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 41gpWL13WHz9s3Z for ; Thu, 2 Aug 2018 08:53:34 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 215A4DBC; Wed, 1 Aug 2018 22:50:44 +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 BE209DB5 for ; Wed, 1 Aug 2018 22:50:42 +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 486A07A4 for ; Wed, 1 Aug 2018 22:50:42 +0000 (UTC) Received: by mail-pf1-f196.google.com with SMTP id k21-v6so118724pff.11 for ; Wed, 01 Aug 2018 15:50:42 -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=nOB2XFTFAbAuxSAHdRD+a3HZ0wWkn8ZDs1z2zWXSEQVIL1Bhg/BLG/VHaljRCWAObX GvOGGnmKf11HjCaLdexc9B6LeLdbLVi/iDPy+IcJE6kbKLoTev7GLb86DQrhF1q46Sxe GfOkuRHkQUUmE1Y624z6uaUDOCBdPn6FSg+2fd3ETMUK4q/QfH20Ed62LGxf7SbRUQSo mqubGNelln8py2jNNWfyy01V06chFp5bGf5XShQl4h6QsrIRnZYfE1J6WzU10zo+Ilbt o8wtMR1kUHE0FZBD+z34rOIkNCWU9+ujKDaAqcQSd464YgocgVLmoMPnx424GPHlvgFO KUjA== 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=edYRur4isCXKsJd5wp5WlbZugZ6LRmi91/gIY2aeQly1qciO6RPaP8RlDcyEfHl2Is +QjoMjIsl07In9L8DriSzMavnG2TvL2Ycz5l4FuLGMXF1S5k8tEHkFpDt/GaxcjI7hTJ nTz+vyy6XbRMpjvImdabM0RLdcO+iMwcHw/qZuV2CIhd9DbpF7RBllpRfq2IImfJD18+ sDq8cELwKtbsjKk3NRd2jnBeEMbR6/YI6HlU2amSQ6bKw3zs4/SNyjjoUxl1PfVkJ5Qj mzsP6gtDJd862pIjxG5FYK5yEpL04Sw7eo6emny0ojWAkQPxqTqCQhSRzUv+/WJq7ukg 2mig== X-Gm-Message-State: AOUpUlG+U9dhVIw0UyydwioUa7p6DvScGsC4ZGYLkfQ/zxVnIwJQCVja WNL4yspG97SZYVpZyY+PGNdu7GgE X-Google-Smtp-Source: AAOMgpe6coAjHtvKYo5+ijRB4oKVuIUFzvHFINqwNs4i3yVS1ulz2N4wY55GU9ChYfmclCx5TG65hA== X-Received: by 2002:a63:5b51:: with SMTP id l17-v6mr238278pgm.165.1533163841370; Wed, 01 Aug 2018 15:50:41 -0700 (PDT) Received: from Husky.eng.vmware.com ([66.170.99.1]) by smtp.gmail.com with ESMTPSA id l85-v6sm196899pfk.34.2018.08.01.15.50.39 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Aug 2018 15:50:39 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Wed, 1 Aug 2018 15:46:15 -0700 Message-Id: <1533163580-27989-7-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533163580-27989-1-git-send-email-yihung.wei@gmail.com> References: <1533163580-27989-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 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 Wed Aug 1 22:46:16 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: 952463 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="cVgyu0XA"; 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 41gpWl3v1dz9s4c for ; Thu, 2 Aug 2018 08:53:55 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id E7930DC8; Wed, 1 Aug 2018 22:50:45 +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 5DF66D7D for ; Wed, 1 Aug 2018 22:50:44 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pl0-f68.google.com (mail-pl0-f68.google.com [209.85.160.68]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 0D0596C5 for ; Wed, 1 Aug 2018 22:50:43 +0000 (UTC) Received: by mail-pl0-f68.google.com with SMTP id d5-v6so105011pll.4 for ; Wed, 01 Aug 2018 15:50:43 -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=cVgyu0XAaLHw4pMTruVPD6G79V4qZOSNsM1gZNbqcU/HmQ3i0eSuAPLfvwq2x0GL7v DB2qowutPYG4tBaGpeYEndzy/Be4ZxPtKH2zHk2OsdMp0rV3+vau4jJwL/xGDC/nL7dl XsVPMhAedvykvLN7PcR6n9KFRsDrfjQ5NyL3hDXbhqlk1gQTBB0tQRmOVeLAbI0uP238 Uj6mIXG8dQcdUNmomOVXldFDGV52nwAmCRq6JMW63ksBT6lyDstcr4zzPxf8gl7joqQx pS9YLzHYRmKIjCZZVH4N9/clLjTKnY7pW8ufgDbUxr3alb+nMj9lvVP2JjS2t0BDZ3hb wbWQ== 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=EphjwVAf5Eopb8jTwtS+7j1I/U8GU+Q49ZGDzAP06J0wK5d+lZ1+jxhXjJMCUPZG+M 5N1+r8AYXhmli48zjqMcMjmdOIRmhiPxgjBo8Z8Y7y6H9Glb6r3f8zxuMwgkTqEXQL6H 5xtSBn3Yr61Fx+hae2sDiuO79IrDf/ElPGl9/6aFgP4SPsIYiOZErZoeiGBZ6tEHtBuH IFl9nbOs9s+8lB7x5NPydDjP9flHTPsYjwzzscoCcND9ynnuiYXe37tDjRHGxvqJ4poF TWaI2GZGGVcl3iv/MIi2QBfAuL1As3ZWyY8WK3kkVE6yv0QqlFIT8yZbdEXwBkJyayyX GX/w== X-Gm-Message-State: AOUpUlEkTbfR+31yeb7SS8EeuPsUidd1CntJnQJwOBIMejZKoWsA0MJr J/vi6cn2WqhTtN/CCicZi7AH/m+T X-Google-Smtp-Source: AAOMgpd0+4QOerDf6Wj2ndPqPXbbZR+yS70dSJ01Ta7WFxlUMKKWVBnLrfMfdq1M6PM5hbSJUyIvFQ== X-Received: by 2002:a17:902:8a90:: with SMTP id p16-v6mr226041plo.106.1533163843163; Wed, 01 Aug 2018 15:50:43 -0700 (PDT) Received: from Husky.eng.vmware.com ([66.170.99.1]) by smtp.gmail.com with ESMTPSA id l85-v6sm196899pfk.34.2018.08.01.15.50.41 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Aug 2018 15:50:41 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Wed, 1 Aug 2018 15:46:16 -0700 Message-Id: <1533163580-27989-8-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533163580-27989-1-git-send-email-yihung.wei@gmail.com> References: <1533163580-27989-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 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 Wed Aug 1 22:46:17 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: 952464 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="rVwQ1f0K"; 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 41gpX90Gbdz9s3Z for ; Thu, 2 Aug 2018 08:54:17 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 97B1EDD5; Wed, 1 Aug 2018 22:50:47 +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 821A3DC9 for ; Wed, 1 Aug 2018 22:50:46 +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 EE33A713 for ; Wed, 1 Aug 2018 22:50:45 +0000 (UTC) Received: by mail-pf1-f194.google.com with SMTP id j26-v6so119994pfi.10 for ; Wed, 01 Aug 2018 15:50:45 -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=e2wY37N1OZr8pDPtsQn16+ceN0q60jaM10DuA1gG3rE=; b=rVwQ1f0KeRKNdUJVDlKGk9QZ0K+dKcUvp+OhePEQit3MMBaanxu6b/kYTtf7VP/keP 0V5ndf5XTmd93yWH05QFq1sMOZL4JT2lHO1vYmJ2P5E82l2Cc77Oc6e9LK5Cnv/kGF1L WJNWdfu+m4ulKm7AM1vy37HFYDMk2KZ3XzeqnYrdoxuLPg83jefNvJsm7lTKIcz1ymXa bij/Zk3YCl17OmEBhMw7F7dY4ur603ZtWC949oN3HjYQvA+a02OOElNgmKe6WKIRTKSt 3ft9aafoqTHR8pxd+GJKe7MJk5mT8mF6rdRMQ/5O7GB1dxYLKMfynV2XexzsnZQpmM/T hGkQ== 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=e2wY37N1OZr8pDPtsQn16+ceN0q60jaM10DuA1gG3rE=; b=oLOQSITzgOeuSXu70omT+0Rd5w4/B/G8NvuIXaYDLTdCQdXji2ry86E0MgYdS2y8kr qKg748BEt/fngrQWVVmJrVyDu3mbTZMjNfElpSdu9vgcYSa8hNQXzmI/a1CsKX8TGgHL r29VV1XPsg7YcMtIa1hLL98e9zeHMV4hIweDktx2PPHyyqSQ61r6DSkX13mL7JdJaL6/ C7yaVdqPGW5EEL4/L+PsXGpAdbJrCB9kktWyqRrjvHr32HfYPad/zt83we2lBs6CPvNq TzAW3XgJsyR13aBRjvW0QVDvz0iPSRMe3Hm2iMptqTelKjCHOP0mOcUMk/K/5DSlKyxz AWDA== X-Gm-Message-State: AOUpUlEuCbljI76Ytv/gItLlnj6yTaTrIyF91DRktt6XqeI2HxMz3X+O x4xG4bTnbdUeBkntXg67H/4PWDT/ X-Google-Smtp-Source: AAOMgpdu7VnFmOguvie2JO9Mr6jvtoxqq/vrRDBCdAikJ1mgaR2LjvvcezneKbukp3vSATR4xnO0bQ== X-Received: by 2002:a63:2106:: with SMTP id h6-v6mr243835pgh.161.1533163844996; Wed, 01 Aug 2018 15:50:44 -0700 (PDT) Received: from Husky.eng.vmware.com ([66.170.99.1]) by smtp.gmail.com with ESMTPSA id l85-v6sm196899pfk.34.2018.08.01.15.50.43 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Aug 2018 15:50:43 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Wed, 1 Aug 2018 15:46:17 -0700 Message-Id: <1533163580-27989-9-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533163580-27989-1-git-send-email-yihung.wei@gmail.com> References: <1533163580-27989-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 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 | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 198 insertions(+), 3 deletions(-) diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index ee98a3b7d8b6..4af827b83aa9 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, @@ -3293,6 +3483,11 @@ dpif_netlink_init(void) if (nl_lookup_genl_family(OVS_METER_FAMILY, &ovs_meter_family)) { 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 Wed Aug 1 22:46:18 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: 952465 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="hhKpGOMe"; 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 41gpXb6cdnz9s3Z for ; Thu, 2 Aug 2018 08:54:39 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 60A19DDE; Wed, 1 Aug 2018 22:50:49 +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 73B91DD0 for ; Wed, 1 Aug 2018 22:50:48 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pl0-f42.google.com (mail-pl0-f42.google.com [209.85.160.42]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id E3329F1 for ; Wed, 1 Aug 2018 22:50:47 +0000 (UTC) Received: by mail-pl0-f42.google.com with SMTP id f6-v6so110464plo.1 for ; Wed, 01 Aug 2018 15:50:47 -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=hhKpGOMeunylbbN0vK+H+WhqE0Xdyj2UmdohGgP6Edi5cHz6DvugsuNK/3c+Q3Jy4x Vf58IW2IvOyCIJbqFXElkOvhwerJW6nF5LU5CPGKtSxoDOg1NIzSP5gVatKxawvO4Dba V8dLNi1NLgYhofof6xPQs5aHaTKy6RqyOOl7VOgLkb01W69kJlsalLirHcka0j9Qa4IE kOWGqr43NX1njOI2nR2hB+bAMFugrsix4z5J/7FXDTh33xRNFBsHegC+2KUDRgH5goUO 99L6qJe9q6VjiJNtA0syEGYNskCwJk4CdfJy+wQxSfaVu0lXkkJz9N0Zy2PX4q6VkuvI E4vg== 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=RZQhPXnHkm33QDpbhBsJL+M+QDNnj3JbgPwRQuR+MOzScv/rZIYY9lxNcQOjI7zpqD Tbu9+fBEfrc2WRXI+53bA37ZfWvLiV764M/axjvtdnayHpFHOhPKcmVZ/CxhS7/MAN4L RTN+bh3Nqucwzmu1VnWndrvxuh1OZPodaKmWJqjQg0Mk33bjixizcbK9ZoTzzpan3V3I JDEs0B27bNc9pMdgJIr/1NMb1MHdf4mcXauoKbYrvWuzxBixywuzb4GQ8KcdfVMqNkui n9hYl75B/hgr+FfJAvj1S/6EGx2d5ClghCia4IWasM7CQFCDrlHOgrR7NaGkUsy7Rs6r sOhg== X-Gm-Message-State: AOUpUlGU1I5LQAZNyLVqg0Sl+fjm2C61FZzDNC4e4JHrM8Vousw1kdi4 QkvwaYoav1xsVjt9VEqyfbfPoKqZ X-Google-Smtp-Source: AAOMgpciIzQe8h+ua0G4k7ioOBXp2RNROn5jz1YhYERTiC7EolcuEa51QFXblXAOzPerfPGunskgSA== X-Received: by 2002:a17:902:7446:: with SMTP id e6-v6mr201506plt.161.1533163847024; Wed, 01 Aug 2018 15:50:47 -0700 (PDT) Received: from Husky.eng.vmware.com ([66.170.99.1]) by smtp.gmail.com with ESMTPSA id l85-v6sm196899pfk.34.2018.08.01.15.50.45 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Aug 2018 15:50:45 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Wed, 1 Aug 2018 15:46:18 -0700 Message-Id: <1533163580-27989-10-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533163580-27989-1-git-send-email-yihung.wei@gmail.com> References: <1533163580-27989-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 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 Wed Aug 1 22:46:19 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: 952466 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="p5cRt3PD"; 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 41gpY86yPYz9s3Z for ; Thu, 2 Aug 2018 08:55:08 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 461FAE0E; Wed, 1 Aug 2018 22:50:51 +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 E8A85DB7 for ; Wed, 1 Aug 2018 22:50:50 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf1-f193.google.com (mail-pf1-f193.google.com [209.85.210.193]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id C06136C5 for ; Wed, 1 Aug 2018 22:50:49 +0000 (UTC) Received: by mail-pf1-f193.google.com with SMTP id a26-v6so136522pfo.4 for ; Wed, 01 Aug 2018 15:50:49 -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=p5cRt3PDs2mlxXwqEQVUYxaxotkPkcd/22SVEVxZvekIVjhBTQt8jR2dMDa3N2+Ui5 IszphbSn87HaDjgur2lrCVM31JvRo48vIVA8QK2R4lRo/v/qRqKDK0zMU0EwpAa7LDj/ LLssSXTzeZ/YBqRNSjwsygUd1veRadfe4WX0JhzVmoq7h5kCBsoaYR+k1aq5C5oQa2Jc hS9g+nr2r9SsPtcBTnLJ7YA1qsVkfHOdOOuwGRJ4I/cRC0q3w3kG9GMJOKUPSd6vqQUg GrLi/YPmXZYVY+UMDzKFClBkNouXUbkP1/cgpwtt5DleZuU+uNRO5gXmxa6urwLxEeEw JTlg== 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=AArqveIAS3TQXYqtcOPr0eScaRm76lMHITCC9xxoP4f5iSCtFxAzjccFntv5fRclVN h6vHUDNzXdjvqYlAO8l/Lw05sy/ndncyXZfRbhEHOY+vrR2NHZ7FrOGmCiQmkb44/dn4 ermbHUD1RoZw1WynuARqo/ET2Gbr/nIzIbFZrO0DDtFoemUI84ZUwcKPUMxCtEDhFEu7 DQFbL42hzw4HNHPBAF/Lk/S1As6XezwjOK/1Ye0Vs8q364bvxIiKRb/hOuO5UPM6qACV NshkU2DqL7FwAT/zo7BKnx4mk7cHx0AlGIq3OWoqIIXk3uMfaGKipGZKs1w4ubiwrFBv MOJA== X-Gm-Message-State: AOUpUlH3R/0Ja7eX2nNQdlhQf32ed00ExW55wIIZsPiRTPaetZ/DUHkB CGwU8UGq0iLP2z+PktHPKo6a0VVw X-Google-Smtp-Source: AAOMgpfL2O1MomHmI9bGTPwRERnINlbfSsDVoVqXlOFwcEKepg5XKy1TSkXm+XkJ7e+bWXqlJvOD+Q== X-Received: by 2002:a62:6eca:: with SMTP id j193-v6mr277811pfc.256.1533163848818; Wed, 01 Aug 2018 15:50:48 -0700 (PDT) Received: from Husky.eng.vmware.com ([66.170.99.1]) by smtp.gmail.com with ESMTPSA id l85-v6sm196899pfk.34.2018.08.01.15.50.47 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Aug 2018 15:50:47 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Wed, 1 Aug 2018 15:46:19 -0700 Message-Id: <1533163580-27989-11-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533163580-27989-1-git-send-email-yihung.wei@gmail.com> References: <1533163580-27989-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 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 Wed Aug 1 22:46:20 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: 952467 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="Z5r4QiOL"; 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 41gpYY2DStz9s3Z for ; Thu, 2 Aug 2018 08:55:29 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 0041FE18; Wed, 1 Aug 2018 22:50:54 +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 22C21D9D for ; Wed, 1 Aug 2018 22:50:52 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf1-f177.google.com (mail-pf1-f177.google.com [209.85.210.177]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 92052798 for ; Wed, 1 Aug 2018 22:50:51 +0000 (UTC) Received: by mail-pf1-f177.google.com with SMTP id x17-v6so134904pfh.5 for ; Wed, 01 Aug 2018 15:50:51 -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=Z5r4QiOLFQ0x3EJMVlQj6Yri6knlR1MRRCF5ePwBV5pecii1YcStclSJhrCBoQoS0U OVs1RJcKXw3yOg92MmVqzKo0l1TazciMhhB50xu3j1Lj8E0R+Phayfyj2uNvEcxlSQqg Lphg0wJSSenEROx1dRgiPh2w9e9wfvoZVBY1BYuD31VVpHzcE5r35thv5otLxi8P1HJF YP8Lfb/P64SlrumpuoTzpq6dnsU+E+8lFgIFJosGTP8J9DCCAe2X0GCjLsronWDn9wbI +delxnCkr/yAf7UQLV+VilR5XOkbzrQ/8HdKyeTrWKHzL3XYD5exB3QLg52ICZ3CbiiT oZxw== 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=JI20Jb9zXE8w+9Ey9bHOclP9VVfhWozJ1i+S49XxkMSc633LBTKfLvb9qEatJEbZWp 938ZJ1bXBPOd+JovhVC4F5nWScSjv4QnmUYG2ccu8frdouDmxTTw47ZpUUh4/XWtmsGV +2p1uvKpbeIiHJXpuD4NXmonWsz4HhRZ94n5rLvDqtRJj53vx8X7blahA1O4BqnfJpBN l6rMof2reBW7rHkO/C8qtuOgcpkgGNpW/d4UXl/+f5np5IBomlY5+Ax1jDIC8tTR9g/d W+O7EsoJnBpneIfklZRCa5wdVSkNJcDKyaBo/FEzHi8ujX+aAhhhB9CCrmEKveHkSfx+ Vdlg== X-Gm-Message-State: AOUpUlGMuLUNyueiLAFEVmOy1eIfrLYs1b/VufPP4AF71/g0T9ljMJvp h6QAUq+C9M2AvOeX7nI2AypDec0m X-Google-Smtp-Source: AAOMgpcAfz5FiDAJysO8KbS72tJ4dFONPlbEVVsdp5as256NKp+9q8HABxRJ9x4R9MEdlrJM+I3hvw== X-Received: by 2002:a63:f657:: with SMTP id u23-v6mr265484pgj.258.1533163850708; Wed, 01 Aug 2018 15:50:50 -0700 (PDT) Received: from Husky.eng.vmware.com ([66.170.99.1]) by smtp.gmail.com with ESMTPSA id l85-v6sm196899pfk.34.2018.08.01.15.50.48 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Aug 2018 15:50:49 -0700 (PDT) From: Yi-Hung Wei To: dev@openvswitch.org Date: Wed, 1 Aug 2018 15:46:20 -0700 Message-Id: <1533163580-27989-12-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1533163580-27989-1-git-send-email-yihung.wei@gmail.com> References: <1533163580-27989-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 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()