From patchwork Mon Apr 27 15:42:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: William Tu X-Patchwork-Id: 1277754 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.137; helo=fraxinus.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=VsRqLnto; dkim-atps=neutral Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 499pvR74PYz9sRf for ; Tue, 28 Apr 2020 01:42:59 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 7F27285FBA; Mon, 27 Apr 2020 15:42:58 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 03i98s6nimXF; Mon, 27 Apr 2020 15:42:58 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id 037EA8458C; Mon, 27 Apr 2020 15:42:58 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id DF22DC18DC; Mon, 27 Apr 2020 15:42:57 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id F1E29C0172 for ; Mon, 27 Apr 2020 15:42:55 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id E15D68458C for ; Mon, 27 Apr 2020 15:42:55 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id wi_ZnNgW3uTd for ; Mon, 27 Apr 2020 15:42:55 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mail-pf1-f194.google.com (mail-pf1-f194.google.com [209.85.210.194]) by fraxinus.osuosl.org (Postfix) with ESMTPS id 7169F844AB for ; Mon, 27 Apr 2020 15:42:55 +0000 (UTC) Received: by mail-pf1-f194.google.com with SMTP id z1so7496184pfn.3 for ; Mon, 27 Apr 2020 08:42:55 -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=HDFZ03ENDTaqdW5zsjAqloDzeJTwK2FeZl6DPy5Yvys=; b=VsRqLntoBz79k7jqAC7YQV9f/1u3tqSz1jq5KYM7NZCbZNe+hSQDHxDEaz9M4vrbld Mc/bk0JDAilZimxY+p4Vz6JAoFcUJJIw2sYB4UGwmoDQrOFF1VhM1N3Kcfi4SWlX33iO 7/4NOeQ8S4Hp/b8g6DCBMCud+feUQlyWkET1IyfWqIrWJtdUUIEyoEora4T5atyl4X5L uVfxPPs8Q8fVleFL3zEpZiivF0kArcMOmg/nrZEHBuHXKYpNqRW2IzzdvIqPNBE8mexe 8eTnXUbgLxttU7nwYnoj4LUJP/vej9GVt4gcQhridIaf9t1h8tfu4WevsZ3hYicto1nr MBnA== 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=HDFZ03ENDTaqdW5zsjAqloDzeJTwK2FeZl6DPy5Yvys=; b=dJIBq8OBclOvfvKtoL82jXQZxb401ApTiKylGJMALNMut3Ve89LkBS+ejqX+st/5WY Y/+AiNUSUbCYz9XJqS0H/zAfhBkepj7IPhEyyXVxxo/hBAoLS/s24yqRQadW51HA1Q/3 p4ZKk7ktboXMWZxdKQW100ahqmOE4c0TlvhaF2YQO5hoAFgpu5JPKSDjsAv17sB3mIfW DdlmyRVxe6aQtU7R1m2rmMLPaV6MnWPhk2Nn1nA9FnHpXpf61qcimb6mdv8nbh2brSlB /zjc4qcrdhaNvdZgB6auFXX+LK84rA27wRhFN+G+orRUns+5kUxBd/AbFklbptT4lZXv gm3A== X-Gm-Message-State: AGi0PuYjR+IQXDqwwSQCQxH6c21uF1n1VILTnaYsRpe7rpwkReKEdU5J /Bz9Xkcg/4s9QGn9TxHtLhdN7LKn X-Google-Smtp-Source: APiQypIJgCeQ5eNRNVNlENsmRwcsQuG5tKw5MZ0GMKt3Paabvc58HSi6oNTuCSMfRQuYSZym9Qx3bw== X-Received: by 2002:a63:1759:: with SMTP id 25mr24108293pgx.417.1588002174769; Mon, 27 Apr 2020 08:42:54 -0700 (PDT) Received: from sc9-mailhost3.vmware.com (c-76-21-95-192.hsd1.ca.comcast.net. [76.21.95.192]) by smtp.gmail.com with ESMTPSA id f2sm11397998pju.32.2020.04.27.08.42.54 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 27 Apr 2020 08:42:54 -0700 (PDT) From: William Tu To: dev@openvswitch.org Date: Mon, 27 Apr 2020 08:42:29 -0700 Message-Id: <1588002150-9823-1-git-send-email-u9012063@gmail.com> X-Mailer: git-send-email 2.7.4 Subject: [ovs-dev] [PATCHv4 1/2] conntrack: Fix icmp conntrack state. 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" ICMP conntrack state should be ICMPS_REPLY after seeing both side of ICMP traffic. Signed-off-by: William Tu Acked-by: Yi-Hung Wei --- lib/conntrack-icmp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/conntrack-icmp.c b/lib/conntrack-icmp.c index 63246f0124d0..6cbf9656dd93 100644 --- a/lib/conntrack-icmp.c +++ b/lib/conntrack-icmp.c @@ -50,9 +50,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; } From patchwork Mon Apr 27 15:42:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: William Tu X-Patchwork-Id: 1277755 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=Qs9CsNRx; 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 499pvY53s8z9sRf for ; Tue, 28 Apr 2020 01:43:05 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 1B53187E60; Mon, 27 Apr 2020 15:43:04 +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 QGgk3wPEs743; Mon, 27 Apr 2020 15:43:00 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id A801D87E68; Mon, 27 Apr 2020 15:43:00 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 90524C18DC; Mon, 27 Apr 2020 15:43:00 +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 BB354C0172 for ; Mon, 27 Apr 2020 15:42:59 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id B7B7C86747 for ; Mon, 27 Apr 2020 15:42:59 +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 arkYCINgcXFi for ; Mon, 27 Apr 2020 15:42:57 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mail-pj1-f52.google.com (mail-pj1-f52.google.com [209.85.216.52]) by whitealder.osuosl.org (Postfix) with ESMTPS id 81E2884A75 for ; Mon, 27 Apr 2020 15:42:57 +0000 (UTC) Received: by mail-pj1-f52.google.com with SMTP id a32so7667686pje.5 for ; Mon, 27 Apr 2020 08:42:57 -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=W5KA63aBNersVPVrY2uRLtg71ERp2z1G3U2SS3yilsE=; b=Qs9CsNRxytid03TIqv5pHltKkDSwX6Un1f+9evDOJlKAMvrj2FZne5w0TpNucKPTNf WzObf3YVrqEUbpG/7cX7JjY1dqoAPXwIxQ+CQol/j128UVeu4n2ebD3VdZQxkTWGT39S UlrCzexWRk8Ul5kQUIjHbeGOMTWjeUExmPh+WeaQsNOOXyEGN75pvFdiYE2DvhyEzDF3 8f93dNReUDkFGeAF1xokJcMYboBVi5xl3ALtRw5yLGEt/pH0HbEl2Ud0/8fcVVDkxINM O9k33t+GwlyBImfY8sk895zE5VWX5DperIr0uDdSm07AkwgfWJkWfxtKSGZzX2+92+0R A36A== 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=W5KA63aBNersVPVrY2uRLtg71ERp2z1G3U2SS3yilsE=; b=DfcCnLC3YStXkPpA/q4GCll2o4fk/IUD6B90sWTPV3Bm0ms1PNNhRz9iPl/XpHF7Jx h1bjz4HRAggiqP8QiwntTxkDof1IetJ/PdLDrYTMxabLcI1rbia4WToG7LuY67VVRyth 8qshv/FAg2dfIEzioF3JGMHG+r3OofR7veDqrkGVeVhuG2KAHJvPLYrMYuLX5A1YX8BE fnnALofspglcdN2r+FJaFjllWHVzyn7fpl6vGFgsDWJOUYVX2KMwYTT6RArGa2HLfH8e OQEFSBK2+R7McmpkQPMAYpwqN9940LNBngBWGJbLb7+FXP8j/VvwEeGz1xzarRJw0DO/ reiw== X-Gm-Message-State: AGi0PuYCmKzKIuGiVzTbruIHMQdQcWm/sjPAp38wgHxxz9d1V2r/lCY8 uU9ki8SvaiyX/r4VunYf7RnQOnnp X-Google-Smtp-Source: APiQypLmnzgOI4LVBe4eEcZVNrHES5CJzuFJjddaQ3xe7vQAo6ZoKBkhE1shsoDPZVHbvVLa6pQPoA== X-Received: by 2002:a17:902:8ec1:: with SMTP id x1mr23716293plo.180.1588002176074; Mon, 27 Apr 2020 08:42:56 -0700 (PDT) Received: from sc9-mailhost3.vmware.com (c-76-21-95-192.hsd1.ca.comcast.net. [76.21.95.192]) by smtp.gmail.com with ESMTPSA id f2sm11397998pju.32.2020.04.27.08.42.55 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 27 Apr 2020 08:42:55 -0700 (PDT) From: William Tu To: dev@openvswitch.org Date: Mon, 27 Apr 2020 08:42:30 -0700 Message-Id: <1588002150-9823-2-git-send-email-u9012063@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1588002150-9823-1-git-send-email-u9012063@gmail.com> References: <1588002150-9823-1-git-send-email-u9012063@gmail.com> Subject: [ovs-dev] [PATCHv4 2/2] 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 --- v4: address feedback from Yi-Hung - move default policy value to lib/conntrack-tp.c - separate icmp bug patch - refactor and fix include issues - fix the clang lock analysis annotation - keep clean interval to 5 seconds - improve tests in system-traffic.at - travis: https://travis-ci.org/github/williamtu/ovs-travis/builds/680158645 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 --- Documentation/faq/releases.rst | 2 +- NEWS | 2 + lib/automake.mk | 2 + lib/conntrack-icmp.c | 6 +- lib/conntrack-other.c | 4 +- lib/conntrack-private.h | 70 +++------ lib/conntrack-tcp.c | 5 +- lib/conntrack-tp.c | 301 +++++++++++++++++++++++++++++++++++++++ lib/conntrack-tp.h | 30 ++++ lib/conntrack.c | 37 ++--- lib/conntrack.h | 8 +- lib/ct-dpif.h | 2 + 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 +- 17 files changed, 493 insertions(+), 95 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 6cbf9656dd93..bf49f9a9fa93 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 { @@ -79,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..3434753016f0 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 { @@ -131,28 +133,20 @@ enum ct_update_res { * are listed here. The name will be prefix by CT_TM_ and the value is in * milliseconds */ #define CT_TIMEOUTS \ - CT_TIMEOUT(TCP_FIRST_PACKET, 30 * 1000) \ - CT_TIMEOUT(TCP_OPENING, 30 * 1000) \ - CT_TIMEOUT(TCP_ESTABLISHED, 24 * 60 * 60 * 1000) \ - CT_TIMEOUT(TCP_CLOSING, 15 * 60 * 1000) \ - CT_TIMEOUT(TCP_FIN_WAIT, 45 * 1000) \ - CT_TIMEOUT(TCP_CLOSED, 30 * 1000) \ - CT_TIMEOUT(OTHER_FIRST, 60 * 1000) \ - CT_TIMEOUT(OTHER_MULTIPLE, 60 * 1000) \ - CT_TIMEOUT(OTHER_BIDIR, 30 * 1000) \ - CT_TIMEOUT(ICMP_FIRST, 60 * 1000) \ - CT_TIMEOUT(ICMP_REPLY, 30 * 1000) - -/* The smallest of the above values: it is used as an upper bound for the - * interval between two rounds of cleanup of expired entries */ -#define CT_TM_MIN (30 * 1000) - -#define CT_TIMEOUT(NAME, VAL) BUILD_ASSERT_DECL(VAL >= CT_TM_MIN); - CT_TIMEOUTS -#undef CT_TIMEOUT + CT_TIMEOUT(TCP_FIRST_PACKET) \ + CT_TIMEOUT(TCP_OPENING) \ + CT_TIMEOUT(TCP_ESTABLISHED) \ + CT_TIMEOUT(TCP_CLOSING) \ + CT_TIMEOUT(TCP_FIN_WAIT) \ + CT_TIMEOUT(TCP_CLOSED) \ + CT_TIMEOUT(OTHER_FIRST) \ + CT_TIMEOUT(OTHER_MULTIPLE) \ + CT_TIMEOUT(OTHER_BIDIR) \ + CT_TIMEOUT(ICMP_FIRST) \ + CT_TIMEOUT(ICMP_REPLY) enum ct_timeout { -#define CT_TIMEOUT(NAME, VALUE) CT_TM_##NAME, +#define CT_TIMEOUT(NAME) CT_TM_##NAME, CT_TIMEOUTS #undef CT_TIMEOUT N_CT_TM @@ -163,6 +157,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 +192,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 +201,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..295865fe14fd --- /dev/null +++ b/lib/conntrack-tp.c @@ -0,0 +1,301 @@ +/* + * 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 "openvswitch/vlog.h" + +VLOG_DEFINE_THIS_MODULE(conntrack_tp); +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + +static const char *ct_timeout_str[] = { +#define CT_TIMEOUT(NAME) #NAME, + CT_TIMEOUTS +#undef CT_TIMEOUT +}; + +/* Default timeout policy in seconds. */ +static unsigned int ct_dpif_netdev_tp_def[] = { + [CT_DPIF_TP_ATTR_TCP_SYN_SENT] = 30, + [CT_DPIF_TP_ATTR_TCP_SYN_RECV] = 30, + [CT_DPIF_TP_ATTR_TCP_ESTABLISHED] = 24 * 60 * 60, + [CT_DPIF_TP_ATTR_TCP_FIN_WAIT] = 15 * 60, + [CT_DPIF_TP_ATTR_TCP_TIME_WAIT] = 45, + [CT_DPIF_TP_ATTR_TCP_CLOSE] = 30, + [CT_DPIF_TP_ATTR_UDP_FIRST] = 60, + [CT_DPIF_TP_ATTR_UDP_SINGLE] = 60, + [CT_DPIF_TP_ATTR_UDP_MULTIPLE] = 30, + [CT_DPIF_TP_ATTR_ICMP_FIRST] = 60, + [CT_DPIF_TP_ATTR_ICMP_REPLY] = 30, +}; + +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, + const struct timeout_policy *tp_src) +{ + struct ct_dpif_timeout_policy *dst; + const struct ct_dpif_timeout_policy *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_netdev_tp_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); +} + +static 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); +} + +static void +timeout_policy_delete__(struct conntrack *ct, uint32_t tp_id) + OVS_REQUIRES(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, "Failed to delete a non-existent timeout " + "policy: id=%d", tp_id); + } +} + +int +timeout_policy_delete(struct conntrack *ct, uint32_t tp_id) +{ + ovs_mutex_lock(&ct->ct_lock); + timeout_policy_delete__(ct, 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); +} + +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) { + timeout_policy_delete__(ct, tp_id); + } + timeout_policy_create(ct, new_tp); + ovs_mutex_unlock(&ct->ct_lock); + return err; +} + +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_REQUIRES(conn->lock) +{ + 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(conn->lock) +{ + struct timeout_policy *tp; + uint32_t val; + + ovs_mutex_lock(&ct->ct_lock); + tp = timeout_policy_lookup(ct, conn->tp_id); + if (tp) { + val = tp->policy.attrs[tm_to_ct_dpif_tp(tm)]; + } else { + val = ct_dpif_netdev_tp_def[tm_to_ct_dpif_tp(tm)]; + } + ovs_mutex_unlock(&ct->ct_lock); + + VLOG_DBG_RL(&rl, "Update timeout %s zone=%u with policy id=%d " + "val=%u sec.", + ct_timeout_str[tm], conn->key.zone, 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_netdev_tp_def[tm_to_ct_dpif_tp(tm)]; + } + + VLOG_DBG_RL(&rl, "Init timeout %s zone=%u with policy id=%d val=%u sec.", + ct_timeout_str[tm], conn->key.zone, 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..4d411d19fd53 --- /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 + +#define CT_DPIF_NETDEV_TP_MIN 30 +enum ct_timeout; +void timeout_policy_init(struct conntrack *ct); +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 95d48c5eecae..f42ba4b601c7 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" @@ -89,7 +90,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); @@ -176,12 +178,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. @@ -313,6 +309,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(); @@ -503,6 +500,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); @@ -957,7 +960,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; @@ -988,7 +991,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); @@ -1276,7 +1279,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) { @@ -1360,7 +1364,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); } @@ -1396,7 +1400,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); @@ -1418,7 +1422,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); } } @@ -1524,7 +1529,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_NETDEV_TP_MIN); return next_wakeup; } @@ -2354,9 +2359,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.h b/lib/ct-dpif.h index 3e227d9e3b6e..e4c7a640b113 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) \ diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index ef14e83b5f06..5b3b97ae6beb 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" @@ -7342,6 +7343,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; @@ -7377,8 +7379,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; @@ -7464,7 +7469,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; } @@ -7698,6 +7703,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); @@ -7807,13 +7868,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 3ed03d92b566..2a0fbadff4a1 100644 --- a/tests/system-traffic.at +++ b/tests/system-traffic.at @@ -3311,8 +3311,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=$i 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 @@ -3327,7 +3334,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 6 AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl ]) @@ -3345,11 +3352,27 @@ 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 6 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 del-zone-tp $DP_TYPE zone=5]) + +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)"]) + +sleep 1 + +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); } }