From patchwork Sun Apr 19 16:05:11 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: William Tu X-Patchwork-Id: 1272958 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.133; helo=hemlock.osuosl.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.a=rsa-sha256 header.s=20161025 header.b=o7HS/57y; dkim-atps=neutral Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 494vnn2nyGz9s71 for ; Mon, 20 Apr 2020 02:06:04 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 04B3487552; Sun, 19 Apr 2020 16:06:02 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id y0zaA5Boxp82; Sun, 19 Apr 2020 16:05:57 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id 3E6A1873E3; Sun, 19 Apr 2020 16:05:57 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 210B5C1D7E; Sun, 19 Apr 2020 16:05:57 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 49ECFC0177 for ; Sun, 19 Apr 2020 16:05:55 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 3294484BC1 for ; Sun, 19 Apr 2020 16:05:55 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id UMcYXPCxfQ7A for ; Sun, 19 Apr 2020 16:05:53 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mail-pj1-f48.google.com (mail-pj1-f48.google.com [209.85.216.48]) by whitealder.osuosl.org (Postfix) with ESMTPS id F09F584CCE for ; Sun, 19 Apr 2020 16:05:52 +0000 (UTC) Received: by mail-pj1-f48.google.com with SMTP id t40so3336979pjb.3 for ; Sun, 19 Apr 2020 09:05:52 -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; bh=pT6zZBpr9ckmJBskJMteTYwbD/rXocdYSS596n+zT70=; b=o7HS/57ychcKmTrLnPM4lqG2/utfSMmCzqF6YgFNd8QrxBG+W3KwzS0KKAtbql5TVL jc9pF+oENAGXsqUTyT2N+6ltynifi3ZQBloKu3WAt47ySSQgcJSDUyJiF3FIYv1hqv7t BiO1T+0AkkPEoE6DMVpgKCiBbq92oaJXezINssU6wtu5C6yteN6HevSX91VUvX/iH/gH VTeFDN5Kxyq6eJf2hUTH/vU2Kl4pn7sNtDizORFllzKDBfB00sPuC7tb1Jy/FeHG5omT MLcGNYUjAZofymNN/KykBmqKZp1dEIUck4iwiOu/ltf2fciluKRUPhgxot4HJkol/gBB A4lg== 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; bh=pT6zZBpr9ckmJBskJMteTYwbD/rXocdYSS596n+zT70=; b=YQfBhNQ14SxvnSeyXi79wgMAu6yQeSTwk3QwluvqspKpGPsXC8QSdUL2EOAfvLxAKh XJHpSxGPzE0MrhUa/uS+jZVmAnofG2xGt4yWVe73zkzDoHLIGGa4XPGPlDgUOTAJYsMV iXPg3r7teJzIXmV15qcmVXCOkNe8ShxAUke4IypbNbTSvC9x7962zfXp9HSvh4PyPvuQ d2oshvBVvisBBQHfb8qyfEejaGVco3+L+kxTDaz4uVnK4EQ6hUFZMnVBL9VLLHlQ7R30 FYBVDWr8P0IE7YzMCRF8+0bsg6/yh1YWorOetmFOlW83b37K0U1/BqoOIYjV9f70g8Uz IFVQ== X-Gm-Message-State: AGi0PuYrt4ImoRc5JB8HsvfUPAuRW0lOEXn2A0tq/YH3BpkEhhLpG1C6 CyzzJY8lTdLIV9RFHrq25koDQ4Px X-Google-Smtp-Source: APiQypJsNVNJ+ClT3CGyX25/VxFUAYHTbbFl75uaLvf9uRwsiZ6x3maszg6mFNhHyjoeBsVJdZNCgg== X-Received: by 2002:a17:90a:1954:: with SMTP id 20mr17120755pjh.106.1587312351558; Sun, 19 Apr 2020 09:05:51 -0700 (PDT) Received: from sc9-mailhost2.vmware.com (c-76-21-95-192.hsd1.ca.comcast.net. [76.21.95.192]) by smtp.gmail.com with ESMTPSA id x123sm1759629pfb.1.2020.04.19.09.05.50 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sun, 19 Apr 2020 09:05:50 -0700 (PDT) From: William Tu To: dev@openvswitch.org Date: Sun, 19 Apr 2020 09:05:11 -0700 Message-Id: <1587312311-59294-1-git-send-email-u9012063@gmail.com> X-Mailer: git-send-email 2.7.4 Subject: [ovs-dev] [PATCHv3] userspace: Add conntrack timeout policy support. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Commit 1f1613183733 ("ct-dpif, dpif-netlink: Add conntrack timeout policy support") adds conntrack timeout policy for kernel datapath. This patch enables support for the userspace datapath. I tested using the 'make check-system-userspace' which checks the timeout policies for ICMP and UDP cases. Signed-off-by: William Tu --- v3: - address feedback from Yi-Hung - use ID 0 as default policy - move conn_{init,update}_expiration to lib/conntrack-tp.c - s/tpid/tp_id/ - add default timeout value to CT_DPIF_TP_*_ATTRs - reduce the CT_CLEAN_INTERVAL from 5 to 3s, to make the tests run faster. - add more tests to system-traffic.at - code refactoring and renaming - travis: https://travis-ci.org/github/williamtu/ovs-travis/builds/676683451 --- Documentation/faq/releases.rst | 2 +- NEWS | 2 + lib/automake.mk | 2 + lib/conntrack-icmp.c | 13 +- lib/conntrack-other.c | 4 +- lib/conntrack-private.h | 38 +---- lib/conntrack-tcp.c | 5 +- lib/conntrack-tp.c | 319 +++++++++++++++++++++++++++++++++++++++ lib/conntrack-tp.h | 30 ++++ lib/conntrack.c | 41 ++--- lib/conntrack.h | 8 +- lib/ct-dpif.c | 6 +- lib/ct-dpif.h | 57 ++++--- lib/dpif-netdev.c | 75 ++++++++- ofproto/ofproto-dpif.c | 3 +- tests/system-traffic.at | 29 +++- tests/system-userspace-macros.at | 6 +- tests/test-conntrack.c | 6 +- 18 files changed, 544 insertions(+), 102 deletions(-) create mode 100644 lib/conntrack-tp.c create mode 100644 lib/conntrack-tp.h diff --git a/Documentation/faq/releases.rst b/Documentation/faq/releases.rst index b3507bd1c7fa..4884515446d7 100644 --- a/Documentation/faq/releases.rst +++ b/Documentation/faq/releases.rst @@ -118,7 +118,7 @@ Q: Are all features available with all datapaths? ========================== ============== ============== ========= ======= Connection tracking 4.3 2.5 2.6 YES Conntrack Fragment Reass. 4.3 2.6 2.12 YES - Conntrack Timeout Policies 5.2 2.12 NO NO + Conntrack Timeout Policies 5.2 2.12 2.14 NO Conntrack Zone Limit 4.18 2.10 2.13 YES Conntrack NAT 4.6 2.6 2.8 YES Tunnel - LISP NO 2.11 NO NO diff --git a/NEWS b/NEWS index 70bd17584594..1e6af8f57bdd 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,8 @@ Post-v2.13.0 * Deprecated DPDK ring ports (dpdkr) are no longer supported. - Linux datapath: * Support for kernel versions up to 5.5.x. + - Userspace datapath: + * Add support for conntrack zone-based timeout policy. v2.13.0 - 14 Feb 2020 diff --git a/lib/automake.mk b/lib/automake.mk index 95925b57c351..86940ccd2f9e 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -53,6 +53,8 @@ lib_libopenvswitch_la_SOURCES = \ lib/conntrack-icmp.c \ lib/conntrack-private.h \ lib/conntrack-tcp.c \ + lib/conntrack-tp.c \ + lib/conntrack-tp.h \ lib/conntrack-other.c \ lib/conntrack.c \ lib/conntrack.h \ diff --git a/lib/conntrack-icmp.c b/lib/conntrack-icmp.c index 63246f0124d0..5c6ef37d2eb4 100644 --- a/lib/conntrack-icmp.c +++ b/lib/conntrack-icmp.c @@ -22,6 +22,7 @@ #include #include "conntrack-private.h" +#include "conntrack-tp.h" #include "dp-packet.h" enum OVS_PACKED_ENUM icmp_state { @@ -50,9 +51,12 @@ icmp_conn_update(struct conntrack *ct, struct conn *conn_, struct dp_packet *pkt OVS_UNUSED, bool reply, long long now) { struct conn_icmp *conn = conn_icmp_cast(conn_); - conn->state = reply ? ICMPS_REPLY : ICMPS_FIRST; - conn_update_expiration(ct, &conn->up, icmp_timeouts[conn->state], now); + if (reply && conn->state == ICMPS_FIRST) { + conn->state = ICMPS_REPLY; + } + + conn_update_expiration(ct, &conn->up, icmp_timeouts[conn->state], now); return CT_UPDATE_VALID; } @@ -76,12 +80,13 @@ icmp6_valid_new(struct dp_packet *pkt) static struct conn * icmp_new_conn(struct conntrack *ct, struct dp_packet *pkt OVS_UNUSED, - long long now) + long long now, uint32_t tp_id) { struct conn_icmp *conn = xzalloc(sizeof *conn); conn->state = ICMPS_FIRST; - conn_init_expiration(ct, &conn->up, icmp_timeouts[conn->state], now); + conn->up.tp_id = tp_id; + conn_init_expiration(ct, &conn->up, icmp_timeouts[conn->state], now); return &conn->up; } diff --git a/lib/conntrack-other.c b/lib/conntrack-other.c index de22ef87cc19..d3b46018586c 100644 --- a/lib/conntrack-other.c +++ b/lib/conntrack-other.c @@ -17,6 +17,7 @@ #include #include "conntrack-private.h" +#include "conntrack-tp.h" #include "dp-packet.h" enum OVS_PACKED_ENUM other_state { @@ -69,12 +70,13 @@ other_valid_new(struct dp_packet *pkt OVS_UNUSED) static struct conn * other_new_conn(struct conntrack *ct, struct dp_packet *pkt OVS_UNUSED, - long long now) + long long now, uint32_t tp_id) { struct conn_other *conn; conn = xzalloc(sizeof *conn); conn->state = OTHERS_FIRST; + conn->up.tp_id = tp_id; conn_init_expiration(ct, &conn->up, other_timeouts[conn->state], now); diff --git a/lib/conntrack-private.h b/lib/conntrack-private.h index 9a8ca3910157..ccccc1d523ea 100644 --- a/lib/conntrack-private.h +++ b/lib/conntrack-private.h @@ -118,6 +118,8 @@ struct conn { /* Immutable data. */ bool alg_related; /* True if alg data connection. */ enum ct_conn_type conn_type; + + uint32_t tp_id; /* Timeout policy ID. */ }; enum ct_update_res { @@ -163,6 +165,7 @@ struct conntrack { struct cmap conns OVS_GUARDED; struct ovs_list exp_lists[N_CT_TM] OVS_GUARDED; struct hmap zone_limits OVS_GUARDED; + struct hmap timeout_policies OVS_GUARDED; uint32_t hash_basis; /* Salt for hashing a connection key. */ pthread_t clean_thread; /* Periodically cleans up connection tracker. */ struct latch clean_thread_exit; /* To destroy the 'clean_thread'. */ @@ -197,7 +200,7 @@ extern struct ct_l4_proto ct_proto_icmp6; struct ct_l4_proto { struct conn *(*new_conn)(struct conntrack *ct, struct dp_packet *pkt, - long long now); + long long now, uint32_t tp_id); bool (*valid_new)(struct dp_packet *pkt); enum ct_update_res (*conn_update)(struct conntrack *ct, struct conn *conn, struct dp_packet *pkt, bool reply, @@ -206,39 +209,6 @@ struct ct_l4_proto { struct ct_dpif_protoinfo *); }; -extern long long ct_timeout_val[]; - - -/* ct_lock must be held. */ -static inline void -conn_init_expiration(struct conntrack *ct, struct conn *conn, - enum ct_timeout tm, long long now) -{ - conn->expiration = now + ct_timeout_val[tm]; - ovs_list_push_back(&ct->exp_lists[tm], &conn->exp_node); -} - -/* The conn entry lock must be held on entry and exit. */ -static inline void -conn_update_expiration(struct conntrack *ct, struct conn *conn, - enum ct_timeout tm, long long now) - OVS_NO_THREAD_SAFETY_ANALYSIS -{ - ovs_mutex_unlock(&conn->lock); - - ovs_mutex_lock(&ct->ct_lock); - ovs_mutex_lock(&conn->lock); - if (!conn->cleaned) { - conn->expiration = now + ct_timeout_val[tm]; - ovs_list_remove(&conn->exp_node); - ovs_list_push_back(&ct->exp_lists[tm], &conn->exp_node); - } - ovs_mutex_unlock(&conn->lock); - ovs_mutex_unlock(&ct->ct_lock); - - ovs_mutex_lock(&conn->lock); -} - static inline uint32_t tcp_payload_length(struct dp_packet *pkt) { diff --git a/lib/conntrack-tcp.c b/lib/conntrack-tcp.c index 47261c7551d1..18a2aa7c7d02 100644 --- a/lib/conntrack-tcp.c +++ b/lib/conntrack-tcp.c @@ -39,6 +39,7 @@ #include #include "conntrack-private.h" +#include "conntrack-tp.h" #include "coverage.h" #include "ct-dpif.h" #include "dp-packet.h" @@ -435,7 +436,8 @@ tcp_valid_new(struct dp_packet *pkt) } static struct conn * -tcp_new_conn(struct conntrack *ct, struct dp_packet *pkt, long long now) +tcp_new_conn(struct conntrack *ct, struct dp_packet *pkt, long long now, + uint32_t tp_id) { struct conn_tcp* newconn = NULL; struct tcp_header *tcp = dp_packet_l4(pkt); @@ -471,6 +473,7 @@ tcp_new_conn(struct conntrack *ct, struct dp_packet *pkt, long long now) src->state = CT_DPIF_TCPS_SYN_SENT; dst->state = CT_DPIF_TCPS_CLOSED; + newconn->up.tp_id = tp_id; conn_init_expiration(ct, &newconn->up, CT_TM_TCP_FIRST_PACKET, now); return &newconn->up; diff --git a/lib/conntrack-tp.c b/lib/conntrack-tp.c new file mode 100644 index 000000000000..5e59f56eb949 --- /dev/null +++ b/lib/conntrack-tp.c @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2020 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "conntrack-private.h" +#include "conntrack-tp.h" +#include "ct-dpif.h" +#include "dp-packet.h" + +#include "openvswitch/vlog.h" +VLOG_DEFINE_THIS_MODULE(conntrack_tp); +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + +#define DEFAULT_TP_ID 0 + +static const char *ct_timeout_str[] = { +#define CT_TIMEOUT(NAME, VALUE) #NAME, + CT_TIMEOUTS +#undef CT_TIMEOUT +}; + +static const char *dpif_ct_timeout_str[] = { +#define xstr(s) #s +#define CT_DPIF_TP_TCP_ATTR(NAME, VAL) xstr(TCP_##NAME), + CT_DPIF_TP_TCP_ATTRS +#undef CT_DPIF_TP_TCP_ATTR +#define CT_DPIF_TP_UDP_ATTR(NAME, VAL) xstr(UDP_##NAME), + CT_DPIF_TP_UDP_ATTRS +#undef CT_DPIF_TP_UDP_ATTR +#define CT_DPIF_TP_ICMP_ATTR(NAME, VAL) xstr(ICMP_##NAME), + CT_DPIF_TP_ICMP_ATTRS +#undef CT_DPIF_TP_ICMP_ATTR +#undef xstr +}; + +static unsigned int ct_dpif_timeout_value_def[] = { +#define CT_DPIF_TP_TCP_ATTR(NAME, VAL) [CT_DPIF_TP_ATTR_TCP_##NAME] = VAL, + CT_DPIF_TP_TCP_ATTRS +#undef CT_DPIF_TP_TCP_ATTR +#define CT_DPIF_TP_UDP_ATTR(NAME, VAL) [CT_DPIF_TP_ATTR_UDP_##NAME] = VAL, + CT_DPIF_TP_UDP_ATTRS +#undef CT_DPIF_TP_UDP_ATTR +#define CT_DPIF_TP_ICMP_ATTR(NAME, VAL) [CT_DPIF_TP_ATTR_ICMP_##NAME] = VAL, + CT_DPIF_TP_ICMP_ATTRS +#undef CT_DPIF_TP_ICMP_ATTR +}; + +static void OVS_UNUSED +timeout_policy_dump(struct timeout_policy *tp) +{ + bool present; + int i; + + VLOG_DBG("Timeout Policy ID %u:", tp->policy.id); + for (i = 0; i < ARRAY_SIZE(tp->policy.attrs); i++) { + if (tp->policy.present & (1 << i)) { + present = !!(tp->policy.present & (1 << i)); + VLOG_DBG(" Policy: %s present: %u value: %u", + dpif_ct_timeout_str[i], present, tp->policy.attrs[i]); + } + } +} + +static struct timeout_policy * +timeout_policy_lookup(struct conntrack *ct, int32_t tp_id) + OVS_REQUIRES(ct->ct_lock) +{ + struct timeout_policy *tp; + uint32_t hash; + + hash = hash_int(tp_id, ct->hash_basis); + HMAP_FOR_EACH_IN_BUCKET (tp, node, hash, &ct->timeout_policies) { + if (tp->policy.id == tp_id) { + return tp; + } + } + return NULL; +} + +struct timeout_policy * +timeout_policy_get(struct conntrack *ct, int32_t tp_id) +{ + struct timeout_policy *tp; + + ovs_mutex_lock(&ct->ct_lock); + tp = timeout_policy_lookup(ct, tp_id); + if (!tp) { + ovs_mutex_unlock(&ct->ct_lock); + return NULL; + } + + ovs_mutex_unlock(&ct->ct_lock); + return tp; +} + +static void +update_existing_tp(struct timeout_policy *tp_dst, + struct timeout_policy *tp_src) +{ + struct ct_dpif_timeout_policy *dst, *src; + int i; + + dst = &tp_dst->policy; + src = &tp_src->policy; + + /* Set the value and present bit to dst if present + * bit in src is set. + */ + for (i = 0; i < ARRAY_SIZE(dst->attrs); i++) { + if (src->present & (1 << i)) { + dst->attrs[i] = src->attrs[i]; + dst->present |= (1 << i); + } + } +} + +static void +init_default_tp(struct timeout_policy *tp, uint32_t tp_id) +{ + tp->policy.id = tp_id; + /* Initialize the timeout value to default, but not + * setting the present bit. + */ + tp->policy.present = 0; + memcpy(tp->policy.attrs, ct_dpif_timeout_value_def, + sizeof tp->policy.attrs); +} + +static void +timeout_policy_create(struct conntrack *ct, + struct timeout_policy *new_tp) + OVS_REQUIRES(ct->ct_lock) +{ + uint32_t tp_id = new_tp->policy.id; + struct timeout_policy *tp; + uint32_t hash; + + tp = xzalloc(sizeof *tp); + init_default_tp(tp, tp_id); + update_existing_tp(tp, new_tp); + hash = hash_int(tp_id, ct->hash_basis); + hmap_insert(&ct->timeout_policies, &tp->node, hash); +} + +int +timeout_policy_update(struct conntrack *ct, + struct timeout_policy *new_tp) +{ + int err = 0; + uint32_t tp_id = new_tp->policy.id; + + ovs_mutex_lock(&ct->ct_lock); + struct timeout_policy *tp = timeout_policy_lookup(ct, tp_id); + if (tp) { + update_existing_tp(tp, new_tp); + } else { + timeout_policy_create(ct, new_tp); + } + ovs_mutex_unlock(&ct->ct_lock); + return err; +} + +void +timeout_policy_clean(struct conntrack *ct, struct timeout_policy *tp) + OVS_REQUIRES(ct->ct_lock) +{ + hmap_remove(&ct->timeout_policies, &tp->node); + free(tp); +} + +int +timeout_policy_delete(struct conntrack *ct, uint32_t tp_id) +{ + ovs_mutex_lock(&ct->ct_lock); + struct timeout_policy *tp = timeout_policy_lookup(ct, tp_id); + if (tp) { + timeout_policy_clean(ct, tp); + } else { + VLOG_WARN_RL(&rl, "Attempted delete of non-existent timeout " + "policy: zone %d", tp_id); + } + ovs_mutex_unlock(&ct->ct_lock); + return 0; +} + +void +timeout_policy_init(struct conntrack *ct) + OVS_REQUIRES(ct->ct_lock) +{ + struct timeout_policy tp; + + hmap_init(&ct->timeout_policies); + + /* Create default timeout policy. */ + memset(&tp, 0, sizeof tp); + tp.policy.id = DEFAULT_TP_ID; + timeout_policy_create(ct, &tp); +} + +static enum ct_dpif_tp_attr +tm_to_ct_dpif_tp(enum ct_timeout tm) +{ + switch (tm) { + case CT_TM_TCP_FIRST_PACKET: + return CT_DPIF_TP_ATTR_TCP_SYN_SENT; + case CT_TM_TCP_OPENING: + return CT_DPIF_TP_ATTR_TCP_SYN_RECV; + case CT_TM_TCP_ESTABLISHED: + return CT_DPIF_TP_ATTR_TCP_ESTABLISHED; + case CT_TM_TCP_CLOSING: + return CT_DPIF_TP_ATTR_TCP_FIN_WAIT; + case CT_TM_TCP_FIN_WAIT: + return CT_DPIF_TP_ATTR_TCP_TIME_WAIT; + case CT_TM_TCP_CLOSED: + return CT_DPIF_TP_ATTR_TCP_CLOSE; + case CT_TM_OTHER_FIRST: + return CT_DPIF_TP_ATTR_UDP_FIRST; + case CT_TM_OTHER_BIDIR: + return CT_DPIF_TP_ATTR_UDP_SINGLE; + case CT_TM_OTHER_MULTIPLE: + return CT_DPIF_TP_ATTR_UDP_MULTIPLE; + case CT_TM_ICMP_FIRST: + return CT_DPIF_TP_ATTR_ICMP_FIRST; + case CT_TM_ICMP_REPLY: + return CT_DPIF_TP_ATTR_ICMP_REPLY; + case N_CT_TM: + default: + OVS_NOT_REACHED(); + break; + } + OVS_NOT_REACHED(); + return CT_DPIF_TP_ATTR_MAX; +} + +static void +conn_update_expiration__(struct conntrack *ct, struct conn *conn, + enum ct_timeout tm, long long now, + uint32_t tp_value) + OVS_NO_THREAD_SAFETY_ANALYSIS +{ + ovs_mutex_unlock(&conn->lock); + + ovs_mutex_lock(&ct->ct_lock); + ovs_mutex_lock(&conn->lock); + if (!conn->cleaned) { + conn->expiration = now + tp_value * 1000; + ovs_list_remove(&conn->exp_node); + ovs_list_push_back(&ct->exp_lists[tm], &conn->exp_node); + } + ovs_mutex_unlock(&conn->lock); + ovs_mutex_unlock(&ct->ct_lock); + + ovs_mutex_lock(&conn->lock); +} + +/* The conn entry lock must be held on entry and exit. */ +void +conn_update_expiration(struct conntrack *ct, struct conn *conn, + enum ct_timeout tm, long long now) + OVS_REQUIRES(ct->ct_lock) +{ + struct timeout_policy *tp; + uint32_t val; + + tp = timeout_policy_lookup(ct, conn->tp_id); + if (tp) { + val = tp->policy.attrs[tm_to_ct_dpif_tp(tm)]; + } else { + val = ct_dpif_timeout_value_def[tm_to_ct_dpif_tp(tm)]; + } + VLOG_DBG_RL(&rl, "Update timeout %s with policy id=%d val=%u sec.", + ct_timeout_str[tm], conn->tp_id, val); + + conn_update_expiration__(ct, conn, tm, now, val); +} + +static void +conn_init_expiration__(struct conntrack *ct, struct conn *conn, + enum ct_timeout tm, long long now, + uint32_t tp_value) +{ + conn->expiration = now + tp_value * 1000; + ovs_list_push_back(&ct->exp_lists[tm], &conn->exp_node); +} + +/* ct_lock must be held. */ +void +conn_init_expiration(struct conntrack *ct, struct conn *conn, + enum ct_timeout tm, long long now) + OVS_REQUIRES(ct->ct_lock) +{ + struct timeout_policy *tp; + uint32_t val; + + tp = timeout_policy_lookup(ct, conn->tp_id); + if (tp) { + val = tp->policy.attrs[tm_to_ct_dpif_tp(tm)]; + } else { + val = ct_dpif_timeout_value_def[tm_to_ct_dpif_tp(tm)]; + } + VLOG_DBG_RL(&rl, "Init timeout %s with policy id=%d val=%u sec.", + ct_timeout_str[tm], conn->tp_id, val); + + conn_init_expiration__(ct, conn, tm, now, val); +} diff --git a/lib/conntrack-tp.h b/lib/conntrack-tp.h new file mode 100644 index 000000000000..c912aa65443c --- /dev/null +++ b/lib/conntrack-tp.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CONNTRACK_TP_H +#define CONNTRACK_TP_H 1 + +enum ct_timeout; +void timeout_policy_init(struct conntrack *ct); +void timeout_policy_clean(struct conntrack *ct, struct timeout_policy *tp); +int timeout_policy_update(struct conntrack *ct, struct timeout_policy *tp); +int timeout_policy_delete(struct conntrack *ct, uint32_t tp_id); +struct timeout_policy *timeout_policy_get(struct conntrack *ct, int32_t tp_id); +void conn_init_expiration(struct conntrack *ct, struct conn *conn, + enum ct_timeout tm, long long now); +void conn_update_expiration(struct conntrack *ct, struct conn *conn, + enum ct_timeout tm, long long now); +#endif diff --git a/lib/conntrack.c b/lib/conntrack.c index 0cbc8f6d2b25..42ed1963569f 100644 --- a/lib/conntrack.c +++ b/lib/conntrack.c @@ -25,6 +25,7 @@ #include "bitmap.h" #include "conntrack.h" #include "conntrack-private.h" +#include "conntrack-tp.h" #include "coverage.h" #include "csum.h" #include "ct-dpif.h" @@ -88,7 +89,8 @@ static uint32_t conn_key_hash(const struct conn_key *, uint32_t basis); static void conn_key_reverse(struct conn_key *); static bool valid_new(struct dp_packet *pkt, struct conn_key *); static struct conn *new_conn(struct conntrack *ct, struct dp_packet *pkt, - struct conn_key *, long long now); + struct conn_key *, long long now, + uint32_t tp_id); static void delete_conn_cmn(struct conn *); static void delete_conn(struct conn *); static void delete_conn_one(struct conn *conn); @@ -175,12 +177,6 @@ static alg_helper alg_helpers[] = { [CT_ALG_CTL_TFTP] = handle_tftp_ctl, }; -long long ct_timeout_val[] = { -#define CT_TIMEOUT(NAME, VAL) [CT_TM_##NAME] = VAL, - CT_TIMEOUTS -#undef CT_TIMEOUT -}; - /* The maximum TCP or UDP port number. */ #define CT_MAX_L4_PORT 65535 /* String buffer used for parsing FTP string messages. @@ -312,6 +308,7 @@ conntrack_init(void) } hmap_init(&ct->zone_limits); ct->zone_limit_seq = 0; + timeout_policy_init(ct); ovs_mutex_unlock(&ct->ct_lock); ct->hash_basis = random_uint32(); @@ -502,6 +499,12 @@ conntrack_destroy(struct conntrack *ct) } hmap_destroy(&ct->zone_limits); + struct timeout_policy *tp; + HMAP_FOR_EACH_POP (tp, node, &ct->timeout_policies) { + free(tp); + } + hmap_destroy(&ct->timeout_policies); + ovs_mutex_unlock(&ct->ct_lock); ovs_mutex_destroy(&ct->ct_lock); @@ -956,7 +959,7 @@ conn_not_found(struct conntrack *ct, struct dp_packet *pkt, struct conn_lookup_ctx *ctx, bool commit, long long now, const struct nat_action_info_t *nat_action_info, const char *helper, const struct alg_exp_node *alg_exp, - enum ct_alg_ctl_type ct_alg_ctl) + enum ct_alg_ctl_type ct_alg_ctl, uint32_t tp_id) OVS_REQUIRES(ct->ct_lock) { struct conn *nc = NULL; @@ -987,7 +990,7 @@ conn_not_found(struct conntrack *ct, struct dp_packet *pkt, return nc; } - nc = new_conn(ct, pkt, &ctx->key, now); + nc = new_conn(ct, pkt, &ctx->key, now, tp_id); memcpy(&nc->key, &ctx->key, sizeof nc->key); memcpy(&nc->rev_key, &nc->key, sizeof nc->rev_key); conn_key_reverse(&nc->rev_key); @@ -1275,7 +1278,8 @@ process_one(struct conntrack *ct, struct dp_packet *pkt, bool force, bool commit, long long now, const uint32_t *setmark, const struct ovs_key_ct_labels *setlabel, const struct nat_action_info_t *nat_action_info, - ovs_be16 tp_src, ovs_be16 tp_dst, const char *helper) + ovs_be16 tp_src, ovs_be16 tp_dst, const char *helper, + uint32_t tp_id) { /* Reset ct_state whenever entering a new zone. */ if (pkt->md.ct_state && pkt->md.ct_zone != zone) { @@ -1359,7 +1363,7 @@ process_one(struct conntrack *ct, struct dp_packet *pkt, ovs_mutex_lock(&ct->ct_lock); if (!conn_lookup(ct, &ctx->key, now, NULL, NULL)) { conn = conn_not_found(ct, pkt, ctx, commit, now, nat_action_info, - helper, alg_exp, ct_alg_ctl); + helper, alg_exp, ct_alg_ctl, tp_id); } ovs_mutex_unlock(&ct->ct_lock); } @@ -1395,7 +1399,7 @@ conntrack_execute(struct conntrack *ct, struct dp_packet_batch *pkt_batch, const struct ovs_key_ct_labels *setlabel, ovs_be16 tp_src, ovs_be16 tp_dst, const char *helper, const struct nat_action_info_t *nat_action_info, - long long now) + long long now, uint32_t tp_id) { ipf_preprocess_conntrack(ct->ipf, pkt_batch, now, dl_type, zone, ct->hash_basis); @@ -1417,7 +1421,8 @@ conntrack_execute(struct conntrack *ct, struct dp_packet_batch *pkt_batch, write_ct_md(packet, zone, NULL, NULL, NULL); } else { process_one(ct, packet, &ctx, zone, force, commit, now, setmark, - setlabel, nat_action_info, tp_src, tp_dst, helper); + setlabel, nat_action_info, tp_src, tp_dst, helper, + tp_id); } } @@ -1523,7 +1528,7 @@ conntrack_clean(struct conntrack *ct, long long now) atomic_read_relaxed(&ct->n_conn_limit, &n_conn_limit); size_t clean_max = n_conn_limit > 10 ? n_conn_limit / 10 : 1; long long min_exp = ct_sweep(ct, now, clean_max); - long long next_wakeup = MIN(min_exp, now + CT_TM_MIN); + long long next_wakeup = MIN(min_exp, now + CT_DPIF_TP_MIN); return next_wakeup; } @@ -1540,14 +1545,14 @@ conntrack_clean(struct conntrack *ct, long long now) * - We want to reduce the number of wakeups and batch connection cleanup * when the load is not very high. CT_CLEAN_INTERVAL ensures that if we * are coping with the current cleanup tasks, then we wait at least - * 5 seconds to do further cleanup. + * 3 seconds to do further cleanup. * * - We don't want to keep the map locked too long, as we might prevent * traffic from flowing. CT_CLEAN_MIN_INTERVAL ensures that if cleanup is * behind, there is at least some 200ms blocks of time when the map will be * left alone, so the datapath can operate unhindered. */ -#define CT_CLEAN_INTERVAL 5000 /* 5 seconds */ +#define CT_CLEAN_INTERVAL 3000 /* 3 second */ #define CT_CLEAN_MIN_INTERVAL 200 /* 0.2 seconds */ static void * @@ -2347,9 +2352,9 @@ valid_new(struct dp_packet *pkt, struct conn_key *key) static struct conn * new_conn(struct conntrack *ct, struct dp_packet *pkt, struct conn_key *key, - long long now) + long long now, uint32_t tp_id) { - return l4_protos[key->nw_proto]->new_conn(ct, pkt, now); + return l4_protos[key->nw_proto]->new_conn(ct, pkt, now, tp_id); } static void diff --git a/lib/conntrack.h b/lib/conntrack.h index b0d0fc8d9597..9553b188a410 100644 --- a/lib/conntrack.h +++ b/lib/conntrack.h @@ -20,6 +20,7 @@ #include #include "cmap.h" +#include "ct-dpif.h" #include "latch.h" #include "odp-netlink.h" #include "openvswitch/hmap.h" @@ -93,7 +94,7 @@ int conntrack_execute(struct conntrack *ct, struct dp_packet_batch *pkt_batch, const struct ovs_key_ct_labels *setlabel, ovs_be16 tp_src, ovs_be16 tp_dst, const char *helper, const struct nat_action_info_t *nat_action_info, - long long now); + long long now, uint32_t tp_id); void conntrack_clear(struct dp_packet *packet); struct conntrack_dump { @@ -111,6 +112,11 @@ struct conntrack_zone_limit { uint32_t zone_limit_seq; /* Used to disambiguate zone limit counts. */ }; +struct timeout_policy { + struct hmap_node node; + struct ct_dpif_timeout_policy policy; +}; + enum { INVALID_ZONE = -2, DEFAULT_ZONE = -1, /* Default zone for zone limit management. */ diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c index 8c2480e7ac39..48062a1b8d3d 100644 --- a/lib/ct-dpif.c +++ b/lib/ct-dpif.c @@ -778,15 +778,15 @@ ct_dpif_format_zone_limits(uint32_t default_limit, } static const char *const ct_dpif_tp_attr_string[] = { -#define CT_DPIF_TP_TCP_ATTR(ATTR) \ +#define CT_DPIF_TP_TCP_ATTR(ATTR, VAL) \ [CT_DPIF_TP_ATTR_TCP_##ATTR] = "TCP_"#ATTR, CT_DPIF_TP_TCP_ATTRS #undef CT_DPIF_TP_TCP_ATTR -#define CT_DPIF_TP_UDP_ATTR(ATTR) \ +#define CT_DPIF_TP_UDP_ATTR(ATTR, VAL) \ [CT_DPIF_TP_ATTR_UDP_##ATTR] = "UDP_"#ATTR, CT_DPIF_TP_UDP_ATTRS #undef CT_DPIF_TP_UDP_ATTR -#define CT_DPIF_TP_ICMP_ATTR(ATTR) \ +#define CT_DPIF_TP_ICMP_ATTR(ATTR, VAL) \ [CT_DPIF_TP_ATTR_ICMP_##ATTR] = "ICMP_"#ATTR, CT_DPIF_TP_ICMP_ATTRS #undef CT_DPIF_TP_ICMP_ATTR diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h index 3e227d9e3b6e..707adf70402c 100644 --- a/lib/ct-dpif.h +++ b/lib/ct-dpif.h @@ -59,6 +59,8 @@ struct ct_dpif_timestamp { uint64_t stop; }; +#define DEFAULT_TP_ID 0 + #define CT_DPIF_TCP_STATES \ CT_DPIF_TCP_STATE(CLOSED) \ CT_DPIF_TCP_STATE(LISTEN) \ @@ -225,36 +227,53 @@ struct ct_dpif_zone_limit { struct ovs_list node; }; +/* TP attr with default timeout in seconds. */ #define CT_DPIF_TP_TCP_ATTRS \ - CT_DPIF_TP_TCP_ATTR(SYN_SENT) \ - CT_DPIF_TP_TCP_ATTR(SYN_RECV) \ - CT_DPIF_TP_TCP_ATTR(ESTABLISHED) \ - CT_DPIF_TP_TCP_ATTR(FIN_WAIT) \ - CT_DPIF_TP_TCP_ATTR(CLOSE_WAIT) \ - CT_DPIF_TP_TCP_ATTR(LAST_ACK) \ - CT_DPIF_TP_TCP_ATTR(TIME_WAIT) \ - CT_DPIF_TP_TCP_ATTR(CLOSE) \ - CT_DPIF_TP_TCP_ATTR(SYN_SENT2) \ - CT_DPIF_TP_TCP_ATTR(RETRANSMIT) \ - CT_DPIF_TP_TCP_ATTR(UNACK) + CT_DPIF_TP_TCP_ATTR(SYN_SENT, 30) \ + CT_DPIF_TP_TCP_ATTR(SYN_RECV, 30) \ + CT_DPIF_TP_TCP_ATTR(ESTABLISHED, 24 * 60 * 60) \ + CT_DPIF_TP_TCP_ATTR(FIN_WAIT, 15 * 60) \ + CT_DPIF_TP_TCP_ATTR(CLOSE_WAIT, 45) \ + CT_DPIF_TP_TCP_ATTR(LAST_ACK, 30) \ + CT_DPIF_TP_TCP_ATTR(TIME_WAIT, 45) \ + CT_DPIF_TP_TCP_ATTR(CLOSE, 30) \ + CT_DPIF_TP_TCP_ATTR(SYN_SENT2, 30) \ + CT_DPIF_TP_TCP_ATTR(RETRANSMIT, 30) \ + CT_DPIF_TP_TCP_ATTR(UNACK, 30) #define CT_DPIF_TP_UDP_ATTRS \ - CT_DPIF_TP_UDP_ATTR(FIRST) \ - CT_DPIF_TP_UDP_ATTR(SINGLE) \ - CT_DPIF_TP_UDP_ATTR(MULTIPLE) + CT_DPIF_TP_UDP_ATTR(FIRST, 60) \ + CT_DPIF_TP_UDP_ATTR(SINGLE, 60) \ + CT_DPIF_TP_UDP_ATTR(MULTIPLE, 30) #define CT_DPIF_TP_ICMP_ATTRS \ - CT_DPIF_TP_ICMP_ATTR(FIRST) \ - CT_DPIF_TP_ICMP_ATTR(REPLY) + CT_DPIF_TP_ICMP_ATTR(FIRST, 60) \ + CT_DPIF_TP_ICMP_ATTR(REPLY, 30) + +/* The minimum value of the default timeout. */ +#define CT_DPIF_TP_MIN 30 +#define CT_DPIF_TP_TCP_ATTR(ATTR, VAL) \ + BUILD_ASSERT_DECL(VAL >= CT_DPIF_TP_MIN); + CT_DPIF_TP_TCP_ATTRS +#define CT_DPIF_TP_UDP_ATTR(ATTR, VAL) \ + BUILD_ASSERT_DECL(VAL >= CT_DPIF_TP_MIN); + CT_DPIF_TP_UDP_ATTRS +#undef CT_DPIF_TP_UDP_ATTR +#define CT_DPIF_TP_ICMP_ATTR(ATTR, VAL) \ + BUILD_ASSERT_DECL(VAL >= CT_DPIF_TP_MIN); + CT_DPIF_TP_ICMP_ATTRS +#undef CT_DPIF_TP_ICMP_ATTR + +#undef CT_DPIF_TP_TCP_ATTR enum OVS_PACKED_ENUM ct_dpif_tp_attr { -#define CT_DPIF_TP_TCP_ATTR(ATTR) CT_DPIF_TP_ATTR_TCP_##ATTR, +#define CT_DPIF_TP_TCP_ATTR(ATTR, VAL) CT_DPIF_TP_ATTR_TCP_##ATTR, CT_DPIF_TP_TCP_ATTRS #undef CT_DPIF_TP_TCP_ATTR -#define CT_DPIF_TP_UDP_ATTR(ATTR) CT_DPIF_TP_ATTR_UDP_##ATTR, +#define CT_DPIF_TP_UDP_ATTR(ATTR, VAL) CT_DPIF_TP_ATTR_UDP_##ATTR, CT_DPIF_TP_UDP_ATTRS #undef CT_DPIF_TP_UDP_ATTR -#define CT_DPIF_TP_ICMP_ATTR(ATTR) CT_DPIF_TP_ATTR_ICMP_##ATTR, +#define CT_DPIF_TP_ICMP_ATTR(ATTR, VAL) CT_DPIF_TP_ATTR_ICMP_##ATTR, CT_DPIF_TP_ICMP_ATTRS #undef CT_DPIF_TP_ICMP_ATTR CT_DPIF_TP_ATTR_MAX diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index e456cc9befbe..916efc5370c9 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -36,6 +36,7 @@ #include "bitmap.h" #include "cmap.h" #include "conntrack.h" +#include "conntrack-tp.h" #include "coverage.h" #include "ct-dpif.h" #include "csum.h" @@ -7337,6 +7338,7 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_, bool commit = false; unsigned int left; uint16_t zone = 0; + uint32_t tp_id = 0; const char *helper = NULL; const uint32_t *setmark = NULL; const struct ovs_key_ct_labels *setlabel = NULL; @@ -7372,8 +7374,11 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_, * netlink events. */ break; case OVS_CT_ATTR_TIMEOUT: - /* Userspace datapath does not support customized timeout - * policy yet. */ + if (!str_to_uint(nl_attr_get_string(b), 10, &tp_id)) { + VLOG_WARN("Invalid Timeout Policy ID: %s.", + nl_attr_get_string(b)); + tp_id = DEFAULT_TP_ID; + } break; case OVS_CT_ATTR_NAT: { const struct nlattr *b_nest; @@ -7459,7 +7464,7 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_, conntrack_execute(dp->conntrack, packets_, aux->flow->dl_type, force, commit, zone, setmark, setlabel, aux->flow->tp_src, aux->flow->tp_dst, helper, nat_action_info_ref, - pmd->ctx.now / 1000); + pmd->ctx.now / 1000, tp_id); break; } @@ -7693,6 +7698,62 @@ dpif_netdev_ct_del_limits(struct dpif *dpif OVS_UNUSED, } static int +dpif_netdev_ct_set_timeout_policy(struct dpif *dpif, + const struct ct_dpif_timeout_policy *dpif_tp) +{ + struct timeout_policy tp; + struct dp_netdev *dp; + + dp = get_dp_netdev(dpif); + memcpy(&tp.policy, dpif_tp, sizeof tp.policy); + return timeout_policy_update(dp->conntrack, &tp); +} + +static int +dpif_netdev_ct_get_timeout_policy(struct dpif *dpif, uint32_t tp_id, + struct ct_dpif_timeout_policy *dpif_tp) +{ + struct timeout_policy *tp; + struct dp_netdev *dp; + int err = 0; + + dp = get_dp_netdev(dpif); + tp = timeout_policy_get(dp->conntrack, tp_id); + if (!tp) { + return EINVAL; + } + memcpy(dpif_tp, &tp->policy, sizeof tp->policy); + return err; +} + +static int +dpif_netdev_ct_del_timeout_policy(struct dpif *dpif, + uint32_t tp_id) +{ + struct dp_netdev *dp; + int err = 0; + + dp = get_dp_netdev(dpif); + err = timeout_policy_delete(dp->conntrack, tp_id); + return err; +} + +static int +dpif_netdev_ct_get_timeout_policy_name(struct dpif *dpif OVS_UNUSED, + uint32_t tp_id, + uint16_t dl_type OVS_UNUSED, + uint8_t nw_proto OVS_UNUSED, + char **tp_name, bool *is_generic) +{ + struct ds ds = DS_EMPTY_INITIALIZER; + + ds_put_format(&ds, "%"PRIu32, tp_id); + *tp_name = ds_steal_cstr(&ds); + *is_generic = true; + return 0; +} + +static int dpif_netdev_ipf_set_enabled(struct dpif *dpif, bool v6, bool enable) { struct dp_netdev *dp = get_dp_netdev(dpif); @@ -7802,13 +7863,13 @@ const struct dpif_class dpif_netdev_class = { dpif_netdev_ct_set_limits, dpif_netdev_ct_get_limits, dpif_netdev_ct_del_limits, - NULL, /* ct_set_timeout_policy */ - NULL, /* ct_get_timeout_policy */ - NULL, /* ct_del_timeout_policy */ + dpif_netdev_ct_set_timeout_policy, + dpif_netdev_ct_get_timeout_policy, + dpif_netdev_ct_del_timeout_policy, NULL, /* ct_timeout_policy_dump_start */ NULL, /* ct_timeout_policy_dump_next */ NULL, /* ct_timeout_policy_dump_done */ - NULL, /* ct_get_timeout_policy_name */ + dpif_netdev_ct_get_timeout_policy_name, dpif_netdev_ipf_set_enabled, dpif_netdev_ipf_set_min_frag, dpif_netdev_ipf_set_max_nfrags, diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index d21874b466f8..7e10375f2af8 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -5426,7 +5426,8 @@ clear_existing_ct_timeout_policies(struct dpif_backer *backer) static void ct_zone_config_init(struct dpif_backer *backer) { - backer->tp_ids = id_pool_create(0, MAX_TIMEOUT_POLICY_ID); + backer->tp_ids = id_pool_create(DEFAULT_TP_ID + 1, + MAX_TIMEOUT_POLICY_ID - 1); cmap_init(&backer->ct_zones); hmap_init(&backer->ct_tps); ovs_list_init(&backer->ct_tp_kill_list); diff --git a/tests/system-traffic.at b/tests/system-traffic.at index 4a39c929c207..f69a6cde7816 100644 --- a/tests/system-traffic.at +++ b/tests/system-traffic.at @@ -3291,7 +3291,7 @@ NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -w 2 10.1.1.2 | FORMAT_PING], [0], ]) AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"]) -sleep 4 +sleep 3 AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sort], [0], [dnl icmp,orig=(src=10.1.1.1,dst=10.1.1.2,id=,type=8,code=0),reply=(src=10.1.1.2,dst=10.1.1.1,id=,type=0,code=0),zone=5 @@ -3301,8 +3301,15 @@ udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=,dport=),reply=(src= AT_CHECK([ovs-appctl dpctl/flush-conntrack]) dnl Shorten the udp_single and icmp_first timeout in zone 5 +dnl Userspace datapath uses udp_first and icmp_reply, and +dnl kernel datapath uses udp_single and icmp_first VSCTL_ADD_DATAPATH_TABLE() -AT_CHECK([ovs-vsctl add-zone-tp $DP_TYPE zone=5 udp_single=3 icmp_first=3]) + +dnl Creating more timeout policies +for i in `seq 1 255`; do +ovs-vsctl --may-exist add-zone-tp $DP_TYPE zone=5 udp_first=$i udp_single=$i icmp_first=$i icmp_reply=$i; +done +AT_CHECK([ovs-vsctl --may-exist add-zone-tp $DP_TYPE zone=5 udp_first=1 udp_single=1 icmp_first=1 icmp_reply=1]) dnl Send ICMP and UDP traffic NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl @@ -3317,7 +3324,7 @@ udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=,dport=),reply=(src= dnl Wait until the timeout expire. dnl We intend to wait a bit longer, because conntrack does not recycle the entry right after it is expired. -sleep 4 +sleep 5 AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl ]) @@ -3335,11 +3342,25 @@ udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=,dport=),reply=(src= dnl Wait until the timeout expire. dnl We intend to wait a bit longer, because conntrack does not recycle the entry right after it is expired. -sleep 4 +sleep 5 AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl ]) +dnl Set the timeout policy to default again. +AT_CHECK([ovs-vsctl --may-exist add-zone-tp $DP_TYPE zone=5 icmp_first=30]) + +dnl Send ICMP and UDP traffic +NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) +AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"]) + +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sort], [0], [dnl +icmp,orig=(src=10.1.1.1,dst=10.1.1.2,id=,type=8,code=0),reply=(src=10.1.1.2,dst=10.1.1.1,id=,type=0,code=0),zone=5 +udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=,dport=),reply=(src=10.1.1.2,dst=10.1.1.1,sport=,dport=),zone=5 +]) + OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP diff --git a/tests/system-userspace-macros.at b/tests/system-userspace-macros.at index ba7f4102f494..72c84b9c7c82 100644 --- a/tests/system-userspace-macros.at +++ b/tests/system-userspace-macros.at @@ -99,12 +99,8 @@ m4_define([CHECK_CONNTRACK_NAT]) # CHECK_CONNTRACK_TIMEOUT() # # Perform requirements checks for running conntrack customized timeout tests. -* The userspace datapath does not support this feature yet. # -m4_define([CHECK_CONNTRACK_TIMEOUT], -[ - AT_SKIP_IF([:]) -]) +m4_define([CHECK_CONNTRACK_TIMEOUT]) # CHECK_CT_DPIF_SET_GET_MAXCONNS() # diff --git a/tests/test-conntrack.c b/tests/test-conntrack.c index f77ee75e38df..e7c73220aef5 100644 --- a/tests/test-conntrack.c +++ b/tests/test-conntrack.c @@ -90,7 +90,7 @@ ct_thread_main(void *aux_) ovs_barrier_block(&barrier); for (i = 0; i < n_pkts; i += batch_size) { conntrack_execute(ct, pkt_batch, dl_type, false, true, 0, NULL, NULL, - 0, 0, NULL, NULL, now); + 0, 0, NULL, NULL, now, 0); } ovs_barrier_block(&barrier); destroy_packets(pkt_batch); @@ -174,7 +174,7 @@ pcap_batch_execute_conntrack(struct conntrack *ct_, if (flow.dl_type != dl_type) { conntrack_execute(ct_, &new_batch, dl_type, false, true, 0, - NULL, NULL, 0, 0, NULL, NULL, now); + NULL, NULL, 0, 0, NULL, NULL, now, 0); dp_packet_batch_init(&new_batch); } dp_packet_batch_add(&new_batch, packet); @@ -182,7 +182,7 @@ pcap_batch_execute_conntrack(struct conntrack *ct_, if (!dp_packet_batch_is_empty(&new_batch)) { conntrack_execute(ct_, &new_batch, dl_type, false, true, 0, NULL, NULL, - 0, 0, NULL, NULL, now); + 0, 0, NULL, NULL, now, 0); } }