diff --git a/tests/ovn.at b/tests/ovn.at
index 4dabc98ab..aa16362c4 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -1958,6 +1958,17 @@ reg1[1] = lookup_fdb(outport, ip4.src);
reg1[1] = lookup_fdb(ip4.src, eth.src);
Cannot use numeric field ip4.src where string field is required.
+# push/pop
+push(xxreg0);push(xxreg1[10..20]);push(eth.src);pop(xxreg0[0..47]);pop(xxreg0[48..57]);pop(xxreg1);
+ formats as push(xxreg0); push(xxreg1[10..20]); push(eth.src); pop(xxreg0[0..47]); pop(xxreg0[48..57]); pop(xxreg1);
+ encodes as push:NXM_NX_XXREG0[],push:NXM_NX_XXREG1[10..20],push:NXM_OF_ETH_SRC[],pop:NXM_NX_XXREG0[0..47],pop:NXM_NX_XXREG0[48..57],pop:NXM_NX_XXREG1[]
+
+pop(eth.type);
+ Field eth.type is not modifiable.
+
+push(abc);
+ Syntax error at `abc' expecting field name.
+
# Miscellaneous negative tests.
;
Syntax error at `;'.
diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c
index bfac33782..b7460322e 100644
--- a/utilities/ovn-trace.c
+++ b/utilities/ovn-trace.c
@@ -1523,6 +1523,59 @@ execute_exchange(const struct ovnact_move *move, struct flow *uflow,
mf_subfield_swap(&a, &b, uflow, NULL);
}
+static void
+execute_push(const struct ovnact_push_pop *p, struct ofpbuf *stack,
+ struct flow *uflow OVS_UNUSED, struct ovs_list *super)
+{
+ struct mf_subfield sf = expr_resolve_field(&p->field);
+ union mf_subvalue sv;
+ mf_read_subfield(&sf, uflow, &sv);
+
+ struct ds s = DS_EMPTY_INITIALIZER;
+ ds_put_cstr(&s, "push(");
+ expr_field_format(&p->field, &s);
+ ds_put_cstr(&s, ") -> ");
+ mf_format_subvalue(&sv, &s);
+
+ ovntrace_node_append(super, OVNTRACE_NODE_MODIFY, "%s", ds_cstr(&s));
+ ds_destroy(&s);
+
+ uint8_t bytes = DIV_ROUND_UP(sf.n_bits, 8);
+ nx_stack_push(stack, &sv.u8[sizeof sv - bytes], bytes);
+}
+
+static void
+execute_pop(const struct ovnact_push_pop *p, struct ofpbuf *stack,
+ struct flow *uflow OVS_UNUSED, struct ovs_list *super)
+{
+ struct mf_subfield sf = expr_resolve_field(&p->field);
+ struct ds s = DS_EMPTY_INITIALIZER;
+ ds_put_cstr(&s, "pop(");
+ expr_field_format(&p->field, &s);
+ ds_put_cstr(&s, ") <- ");
+
+ uint8_t src_bytes;
+ const void *src = nx_stack_pop(stack, &src_bytes);
+ if (src) {
+ union mf_subvalue sv;
+ uint8_t dst_bytes = DIV_ROUND_UP(sf.n_bits, 8);
+
+ if (src_bytes < dst_bytes) {
+ memset(&sv.u8[sizeof sv - dst_bytes], 0,
+ dst_bytes - src_bytes);
+ }
+ memcpy(&sv.u8[sizeof sv - src_bytes], src, src_bytes);
+ mf_write_subfield_flow(&sf, &sv, uflow);
+ mf_format_subvalue(&sv, &s);
+ } else {
+ ds_put_cstr(&s, "/* empty stack */");
+ }
+
+ ovntrace_node_append(super, OVNTRACE_NODE_MODIFY, "%s", ds_cstr(&s));
+
+ ds_destroy(&s);
+}
+
static void
trace__(const struct ovntrace_datapath *dp, struct flow *uflow,
uint8_t table_id, enum ovnact_pipeline pipeline,
@@ -2577,6 +2630,8 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
return;
}
+ struct ofpbuf stack;
+ ofpbuf_init(&stack, 0);
struct ds s = DS_EMPTY_INITIALIZER;
const struct ovnact *a;
OVNACT_FOR_EACH (a, ovnacts, ovnacts_len) {
@@ -2607,6 +2662,14 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
execute_exchange(ovnact_get_EXCHANGE(a), uflow, super);
break;
+ case OVNACT_PUSH:
+ execute_push(ovnact_get_PUSH(a), &stack, uflow, super);
+ break;
+
+ case OVNACT_POP:
+ execute_pop(ovnact_get_POP(a), &stack, uflow, super);
+ break;
+
case OVNACT_DEC_TTL:
if (is_ip_any(uflow)) {
if (uflow->nw_ttl) {
@@ -2848,6 +2911,7 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
break;
}
}
+ ofpbuf_uninit(&stack);
ds_destroy(&s);
}
From patchwork Mon May 23 19:39:28 2022
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Dumitru Ceara
X-Patchwork-Id: 1634749
Return-Path:
X-Original-To: incoming@patchwork.ozlabs.org
Delivered-To: patchwork-incoming@bilbo.ozlabs.org
Authentication-Results: bilbo.ozlabs.org;
dkim=fail reason="signature verification failed" (1024-bit key;
unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256
header.s=mimecast20190719 header.b=LH83xGjP;
dkim-atps=neutral
Authentication-Results: ozlabs.org;
spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org
(client-ip=2605:bc80:3010::137; helo=smtp4.osuosl.org;
envelope-from=ovs-dev-bounces@openvswitch.org; receiver=)
Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest
SHA256)
(No client certificate requested)
by bilbo.ozlabs.org (Postfix) with ESMTPS id 4L6SMy10pjz9sG4
for ; Tue, 24 May 2022 05:39:57 +1000 (AEST)
Received: from localhost (localhost [127.0.0.1])
by smtp4.osuosl.org (Postfix) with ESMTP id 80EB04199F;
Mon, 23 May 2022 19:39:55 +0000 (UTC)
X-Virus-Scanned: amavisd-new at osuosl.org
Received: from smtp4.osuosl.org ([127.0.0.1])
by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)
with ESMTP id 2t1i9KXDTNIc; Mon, 23 May 2022 19:39:54 +0000 (UTC)
Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56])
by smtp4.osuosl.org (Postfix) with ESMTPS id 3ACE5417CB;
Mon, 23 May 2022 19:39:53 +0000 (UTC)
Received: from lf-lists.osuosl.org (localhost [127.0.0.1])
by lists.linuxfoundation.org (Postfix) with ESMTP id 1BFBCC0032;
Mon, 23 May 2022 19:39:53 +0000 (UTC)
X-Original-To: ovs-dev@openvswitch.org
Delivered-To: ovs-dev@lists.linuxfoundation.org
Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136])
by lists.linuxfoundation.org (Postfix) with ESMTP id 2107CC002D
for ; Mon, 23 May 2022 19:39:52 +0000 (UTC)
Received: from localhost (localhost [127.0.0.1])
by smtp3.osuosl.org (Postfix) with ESMTP id A075661120
for ; Mon, 23 May 2022 19:39:36 +0000 (UTC)
X-Virus-Scanned: amavisd-new at osuosl.org
Authentication-Results: smtp3.osuosl.org (amavisd-new);
dkim=pass (1024-bit key) header.d=redhat.com
Received: from smtp3.osuosl.org ([127.0.0.1])
by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)
with ESMTP id 5OvtfQPu2-E8 for ;
Mon, 23 May 2022 19:39:35 +0000 (UTC)
X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0
Received: from us-smtp-delivery-124.mimecast.com
(us-smtp-delivery-124.mimecast.com [170.10.129.124])
by smtp3.osuosl.org (Postfix) with ESMTPS id B09D86113C
for ; Mon, 23 May 2022 19:39:35 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;
s=mimecast20190719; t=1653334774;
h=from:from:reply-to:subject:subject:date:date:message-id:message-id:
to:to:cc:cc:mime-version:mime-version:content-type:content-type:
content-transfer-encoding:content-transfer-encoding:
in-reply-to:in-reply-to:references:references;
bh=3D93rIs6jV9Cx430RY0VjLdciCOHelKJGE5ruQBjeTQ=;
b=LH83xGjPiqcQnCPk+TwF0VXuuszC6ClpCES7aCP/q9CzYsm/P5k5LQbMnu+qUArPn3Bhbt
S8vVqwJ3fETiMT8AcjVe0Hrdv4sLhon3cti9aStys0KFvWj3j0gJ2yKYaaf8CrvUimkOEL
ifwq8dDDluulvkIh3u3MWbQ7vJu+zXI=
Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com
[66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS
(version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id
us-mta-253-yGzpQDNxOhWVOrnhxaatOw-1; Mon, 23 May 2022 15:39:31 -0400
X-MC-Unique: yGzpQDNxOhWVOrnhxaatOw-1
Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com
[10.11.54.10])
(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))
(No client certificate requested)
by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 34A08802A5B;
Mon, 23 May 2022 19:39:31 +0000 (UTC)
Received: from dceara.remote.csb (unknown [10.39.194.145])
by smtp.corp.redhat.com (Postfix) with ESMTP id 55678401E63;
Mon, 23 May 2022 19:39:30 +0000 (UTC)
From: Dumitru Ceara
To: ovs-dev@openvswitch.org
Date: Mon, 23 May 2022 21:39:28 +0200
Message-Id: <20220523193926.9544.1223.stgit@dceara.remote.csb>
In-Reply-To: <20220523193838.9544.70716.stgit@dceara.remote.csb>
References: <20220523193838.9544.70716.stgit@dceara.remote.csb>
User-Agent: StGit/0.17.1-dirty
MIME-Version: 1.0
X-Scanned-By: MIMEDefang 2.85 on 10.11.54.10
Authentication-Results: relay.mimecast.com;
auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=dceara@redhat.com
X-Mimecast-Spam-Score: 0
X-Mimecast-Originator: redhat.com
Subject: [ovs-dev] [PATCH ovn branch-21.12 4/6] ovn-northd: Improve the doc
and tests for ecmp-symmetric-reply.
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: ,
Errors-To: ovs-dev-bounces@openvswitch.org
Sender: "dev"
From: Han Zhou
1. The ovn-northd.8.xml didn't cover the flow in the lr_in_arp_resolve
stage.
2. The original test didn't really test the ecmp-symmetric-reply because
the option takes effect only for gateway routers. This patch set the
chassis to make the router a gateway router. Also, add the check
for the ecmp-symmetric-reply related flow in the lr_in_arp_resolve
stage..
Signed-off-by: Han Zhou
Acked-by: Numan Siddique
(cherry picked from commit bf55f7a655abb7aa0c3e5d537e79595ae13e89f2)
Signed-off-by: Dumitru Ceara
---
northd/ovn-northd.8.xml | 17 ++++++++++++++---
tests/ovn-northd.at | 4 ++++
2 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
index ad79a32d2..45aa91815 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -3457,9 +3457,12 @@ output;
ct_label
value is used to choose the destination. The least
significant 48 bits of the ct_label
tell the destination MAC
address to which the packet should be sent. The next 16 bits tell the
- logical router port on which the packet should be sent. These values in
- the ct_label
are set when the initial ingress traffic is
- received over the ECMP route.
+ logical router port on which the packet should be sent. These values are
+ saved to the ct_label
when the initial ingress traffic is
+ received over the ECMP route and committed to conntrack. The
+ priority-10300 flows in this stage set the outport
,
+ while the eth.dst
is set by flows at the ARP/ND Resolution
+ stage.
Static MAC bindings. MAC bindings can be known statically based on
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index e4de3e122..1a69c0ed8 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -5618,6 +5618,7 @@ ovn_start
check ovn-sbctl chassis-add ch1 geneve 127.0.0.1
check ovn-nbctl lr-add lr0
+check ovn-nbctl set logical_router lr0 options:chassis=ch1
check ovn-nbctl ls-add public
check ovn-nbctl lrp-add lr0 lr0-public 00:00:20:20:12:13 192.168.0.1/24
check ovn-nbctl lsp-add public public-lr0
@@ -5646,6 +5647,9 @@ AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed 's/192\.168\.0\..0/192.
table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 192.168.0.??; reg1 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; next;)
table=??(lr_in_ip_routing_ecmp), priority=150 , match=(reg8[[0..15]] == 0), action=(next;)
])
+AT_CHECK([grep -e "lr_in_arp_resolve.*ecmp" lr0flows | sed 's/table=../table=??/'], [0], [dnl
+ table=??(lr_in_arp_resolve ), priority=200 , match=(ct.rpl && ct_label.ecmp_reply_port == 1), action=(eth.dst = ct_label.ecmp_reply_eth; next;)
+])
# add ecmp route with wrong nexthop
check ovn-nbctl --wait=sb --ecmp-symmetric-reply lr-route-add lr0 1.0.0.1 192.168.1.20
From patchwork Mon May 23 19:39:38 2022
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Dumitru Ceara
X-Patchwork-Id: 1634750
Return-Path:
X-Original-To: incoming@patchwork.ozlabs.org
Delivered-To: patchwork-incoming@bilbo.ozlabs.org
Authentication-Results: bilbo.ozlabs.org;
dkim=fail reason="signature verification failed" (1024-bit key;
unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256
header.s=mimecast20190719 header.b=hN2jKUXQ;
dkim-atps=neutral
Authentication-Results: ozlabs.org;
spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org
(client-ip=2605:bc80:3010::138; helo=smtp1.osuosl.org;
envelope-from=ovs-dev-bounces@openvswitch.org; receiver=)
Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest
SHA256)
(No client certificate requested)
by bilbo.ozlabs.org (Postfix) with ESMTPS id 4L6SND1vMrz9sFx
for ; Tue, 24 May 2022 05:40:12 +1000 (AEST)
Received: from localhost (localhost [127.0.0.1])
by smtp1.osuosl.org (Postfix) with ESMTP id 6374C83EC7;
Mon, 23 May 2022 19:40:10 +0000 (UTC)
X-Virus-Scanned: amavisd-new at osuosl.org
Received: from smtp1.osuosl.org ([127.0.0.1])
by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)
with ESMTP id gwqOucpQ4dFL; Mon, 23 May 2022 19:40:09 +0000 (UTC)
Received: from lists.linuxfoundation.org (lf-lists.osuosl.org
[IPv6:2605:bc80:3010:104::8cd3:938])
by smtp1.osuosl.org (Postfix) with ESMTPS id 7111783E2F;
Mon, 23 May 2022 19:40:08 +0000 (UTC)
Received: from lf-lists.osuosl.org (localhost [127.0.0.1])
by lists.linuxfoundation.org (Postfix) with ESMTP id 32A9CC0032;
Mon, 23 May 2022 19:40:08 +0000 (UTC)
X-Original-To: ovs-dev@openvswitch.org
Delivered-To: ovs-dev@lists.linuxfoundation.org
Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136])
by lists.linuxfoundation.org (Postfix) with ESMTP id 14997C002D
for ; Mon, 23 May 2022 19:40:07 +0000 (UTC)
Received: from localhost (localhost [127.0.0.1])
by smtp3.osuosl.org (Postfix) with ESMTP id CE4186113E
for ; Mon, 23 May 2022 19:39:44 +0000 (UTC)
X-Virus-Scanned: amavisd-new at osuosl.org
Authentication-Results: smtp3.osuosl.org (amavisd-new);
dkim=pass (1024-bit key) header.d=redhat.com
Received: from smtp3.osuosl.org ([127.0.0.1])
by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)
with ESMTP id ogyoMgGIQAac for ;
Mon, 23 May 2022 19:39:44 +0000 (UTC)
X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0
Received: from us-smtp-delivery-124.mimecast.com
(us-smtp-delivery-124.mimecast.com [170.10.133.124])
by smtp3.osuosl.org (Postfix) with ESMTPS id 0542761139
for ; Mon, 23 May 2022 19:39:43 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;
s=mimecast20190719; t=1653334782;
h=from:from:reply-to:subject:subject:date:date:message-id:message-id:
to:to:cc:cc:mime-version:mime-version:content-type:content-type:
content-transfer-encoding:content-transfer-encoding:
in-reply-to:in-reply-to:references:references;
bh=1TGo+Z9TZVNdrIjxjUXbtFEnrVCeXf9xoBUX/oeyL4c=;
b=hN2jKUXQksihpnzdpXotyn534ik8xQGhrJRZ1CACSKsOa+M9Cs82lZAkbRa/5iANe5nBQP
zebWKpeZzG2d2rx+RpoV5uW08pXDmITsqMdYfw3XwFkQaTX4W9XqHOT6jqyy/Xjx+m9aHC
fFyIAaPFdi1b+FBeA05Unu6253Mcs88=
Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com
[66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS
(version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id
us-mta-380-rGNZ4w5DMLG_eCIUjlQcXQ-1; Mon, 23 May 2022 15:39:41 -0400
X-MC-Unique: rGNZ4w5DMLG_eCIUjlQcXQ-1
Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com
[10.11.54.6])
(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))
(No client certificate requested)
by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 4E4738015BA;
Mon, 23 May 2022 19:39:41 +0000 (UTC)
Received: from dceara.remote.csb (unknown [10.39.194.145])
by smtp.corp.redhat.com (Postfix) with ESMTP id 7C2272166B25;
Mon, 23 May 2022 19:39:40 +0000 (UTC)
From: Dumitru Ceara
To: ovs-dev@openvswitch.org
Date: Mon, 23 May 2022 21:39:38 +0200
Message-Id: <20220523193936.9544.49625.stgit@dceara.remote.csb>
In-Reply-To: <20220523193838.9544.70716.stgit@dceara.remote.csb>
References: <20220523193838.9544.70716.stgit@dceara.remote.csb>
User-Agent: StGit/0.17.1-dirty
MIME-Version: 1.0
X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6
Authentication-Results: relay.mimecast.com;
auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=dceara@redhat.com
X-Mimecast-Spam-Score: 0
X-Mimecast-Originator: redhat.com
Subject: [ovs-dev] [PATCH ovn branch-21.12 5/6] ovn-controller: Handle
SB_Global:options:northd_internal_version in I-P engine.
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: ,
Errors-To: ovs-dev-bounces@openvswitch.org
Sender: "dev"
From: Han Zhou
Add an engine node en_northd_internal_version as an input to
en_lflow_output. When this node is updated, it triggers a recompute for
en_lflow_output. This node adds SB_Global as its only input, and it is
updated only when SB_Global's options:northd_internal_version is updated.
In a later patch the northd_internal_version will be used in
en_lflow_output and impact flow generation.
Signed-off-by: Han Zhou
Acked-by: Numan Siddique
(cherry picked from commit c2eeb2c98ea860dbbc7eee5e9bae8a65769b0da3)
Signed-off-by: Dumitru Ceara
---
controller/ovn-controller.c | 66 +++++++++++++++++++++++++++++++++++++++++++
tests/ovn-controller.at | 48 +++++++++++++++++++++++++++++++
2 files changed, 114 insertions(+)
diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
index b7272d3ec..1457bb04d 100644
--- a/controller/ovn-controller.c
+++ b/controller/ovn-controller.c
@@ -953,6 +953,7 @@ ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl)
}
#define SB_NODES \
+ SB_NODE(sb_global, "sb_global") \
SB_NODE(chassis, "chassis") \
SB_NODE(encap, "encap") \
SB_NODE(address_set, "address_set") \
@@ -2161,6 +2162,65 @@ non_vif_data_ovs_iface_handler(struct engine_node *node, void *data OVS_UNUSED)
return local_nonvif_data_handle_ovs_iface_changes(iface_table);
}
+struct ed_type_northd_internal_version {
+ char *ver;
+};
+
+
+static void *
+en_northd_internal_version_init(struct engine_node *node OVS_UNUSED,
+ struct engine_arg *arg OVS_UNUSED)
+{
+ struct ed_type_northd_internal_version *n_ver = xzalloc(sizeof *n_ver);
+ n_ver->ver = xstrdup("");
+ return n_ver;
+}
+
+static void
+en_northd_internal_version_cleanup(void *data)
+{
+ struct ed_type_northd_internal_version *n_ver = data;
+ free(n_ver->ver);
+}
+
+static void
+en_northd_internal_version_run(struct engine_node *node, void *data)
+{
+ struct ed_type_northd_internal_version *n_ver = data;
+ struct sbrec_sb_global_table *sb_global_table =
+ (struct sbrec_sb_global_table *)EN_OVSDB_GET(
+ engine_get_input("SB_sb_global", node));
+ const struct sbrec_sb_global *sb_global =
+ sbrec_sb_global_table_first(sb_global_table);
+ free(n_ver->ver);
+ n_ver->ver =
+ xstrdup(sb_global ? smap_get_def(&sb_global->options,
+ "northd_internal_version", "") : "");
+ engine_set_node_state(node, EN_UPDATED);
+}
+
+static bool
+en_northd_internal_version_sb_sb_global_handler(struct engine_node *node,
+ void *data)
+{
+ struct ed_type_northd_internal_version *n_ver = data;
+ struct sbrec_sb_global_table *sb_global_table =
+ (struct sbrec_sb_global_table *)EN_OVSDB_GET(
+ engine_get_input("SB_sb_global", node));
+ const struct sbrec_sb_global *sb_global =
+ sbrec_sb_global_table_first(sb_global_table);
+
+ const char *new_ver =
+ sb_global ? smap_get_def(&sb_global->options,
+ "northd_internal_version", "") : "";
+ if (strcmp(new_ver, n_ver->ver)) {
+ free(n_ver->ver);
+ n_ver->ver = xstrdup(new_ver);
+ engine_set_node_state(node, EN_UPDATED);
+ }
+ return true;
+}
+
struct lflow_output_persistent_data {
struct lflow_cache *lflow_cache;
};
@@ -3252,6 +3312,7 @@ main(int argc, char *argv[])
ENGINE_NODE(flow_output, "flow_output");
ENGINE_NODE(addr_sets, "addr_sets");
ENGINE_NODE_WITH_CLEAR_TRACK_DATA(port_groups, "port_groups");
+ ENGINE_NODE(northd_internal_version, "northd_internal_version");
#define SB_NODE(NAME, NAME_STR) ENGINE_NODE_SB(NAME, NAME_STR);
SB_NODES
@@ -3300,6 +3361,11 @@ main(int argc, char *argv[])
engine_add_input(&en_pflow_output, &en_ovs_open_vswitch, NULL);
engine_add_input(&en_pflow_output, &en_ovs_bridge, NULL);
+ engine_add_input(&en_northd_internal_version, &en_sb_sb_global,
+ en_northd_internal_version_sb_sb_global_handler);
+
+ engine_add_input(&en_lflow_output, &en_northd_internal_version, NULL);
+
engine_add_input(&en_lflow_output, &en_addr_sets,
lflow_output_addr_sets_handler);
engine_add_input(&en_lflow_output, &en_port_groups,
diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at
index 2f39e5f3e..2c6e6e492 100644
--- a/tests/ovn-controller.at
+++ b/tests/ovn-controller.at
@@ -853,3 +853,51 @@ OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int | grep table=38 | grep -q "re
OVN_CLEANUP([hv1])
AT_CLEANUP
])
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([ovn-controller - I-P handle northd_internal_version change])
+
+ovn_start --backup-northd=none
+
+net_add n1
+sim_add hv1
+as hv1
+check ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.1
+check ovs-vsctl -- add-port br-int hv1-vif1 -- \
+ set interface hv1-vif1 external-ids:iface-id=ls1-lp1
+
+check ovn-nbctl ls-add ls1
+
+check ovn-nbctl lsp-add ls1 ls1-lp1 \
+-- lsp-set-addresses ls1-lp1 "f0:00:00:00:00:01"
+
+wait_for_ports_up
+ovn-appctl -t ovn-controller vlog/set file:dbg
+
+read_counter() {
+ ovn-appctl -t ovn-controller coverage/read-counter $1
+}
+
+# nb_cfg update in sb_global shouldn't trigger lflow_run.
+lflow_run_old=$(read_counter lflow_run)
+ovn-nbctl --wait=hv sync
+lflow_run_new=$(read_counter lflow_run)
+AT_CHECK([echo $(($lflow_run_new - $lflow_run_old))], [0], [0
+])
+
+# northd_internal_version update in sb_global:options should trigger lflow_run.
+as northd
+OVS_APP_EXIT_AND_WAIT(ovn-northd)
+as hv1
+lflow_run_old=$(read_counter lflow_run)
+check ovn-sbctl set SB_Global . options:northd_internal_version=foo
+sleep 0.1
+lflow_run_new=$(read_counter lflow_run)
+AT_CHECK([echo $(($lflow_run_new - $lflow_run_old))], [0], [1
+])
+
+as northd start_daemon ovn-northd
+OVN_CLEANUP([hv1])
+AT_CLEANUP
+])
From patchwork Mon May 23 19:39:48 2022
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Dumitru Ceara
X-Patchwork-Id: 1634751
Return-Path:
X-Original-To: incoming@patchwork.ozlabs.org
Delivered-To: patchwork-incoming@bilbo.ozlabs.org
Authentication-Results: bilbo.ozlabs.org;
dkim=fail reason="signature verification failed" (1024-bit key;
unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256
header.s=mimecast20190719 header.b=jV0UECLF;
dkim-atps=neutral
Authentication-Results: ozlabs.org;
spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org
(client-ip=140.211.166.133; helo=smtp2.osuosl.org;
envelope-from=ovs-dev-bounces@openvswitch.org; receiver=)
Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest
SHA256)
(No client certificate requested)
by bilbo.ozlabs.org (Postfix) with ESMTPS id 4L6SNy66DNz9sFx
for ; Tue, 24 May 2022 05:40:50 +1000 (AEST)
Received: from localhost (localhost [127.0.0.1])
by smtp2.osuosl.org (Postfix) with ESMTP id 8C43140B91;
Mon, 23 May 2022 19:40:48 +0000 (UTC)
X-Virus-Scanned: amavisd-new at osuosl.org
Received: from smtp2.osuosl.org ([127.0.0.1])
by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)
with ESMTP id Ppi8v4WaqKez; Mon, 23 May 2022 19:40:45 +0000 (UTC)
Received: from lists.linuxfoundation.org (lf-lists.osuosl.org
[IPv6:2605:bc80:3010:104::8cd3:938])
by smtp2.osuosl.org (Postfix) with ESMTPS id 9831140BA1;
Mon, 23 May 2022 19:40:44 +0000 (UTC)
Received: from lf-lists.osuosl.org (localhost [127.0.0.1])
by lists.linuxfoundation.org (Postfix) with ESMTP id 60D41C0081;
Mon, 23 May 2022 19:40:44 +0000 (UTC)
X-Original-To: ovs-dev@openvswitch.org
Delivered-To: ovs-dev@lists.linuxfoundation.org
Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137])
by lists.linuxfoundation.org (Postfix) with ESMTP id 31A81C002D
for ; Mon, 23 May 2022 19:40:43 +0000 (UTC)
Received: from localhost (localhost [127.0.0.1])
by smtp4.osuosl.org (Postfix) with ESMTP id F37D0419B2
for ; Mon, 23 May 2022 19:40:07 +0000 (UTC)
X-Virus-Scanned: amavisd-new at osuosl.org
Authentication-Results: smtp4.osuosl.org (amavisd-new);
dkim=pass (1024-bit key) header.d=redhat.com
Received: from smtp4.osuosl.org ([127.0.0.1])
by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)
with ESMTP id XeSZVSYv59bs for ;
Mon, 23 May 2022 19:40:05 +0000 (UTC)
X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0
Received: from us-smtp-delivery-124.mimecast.com
(us-smtp-delivery-124.mimecast.com [170.10.129.124])
by smtp4.osuosl.org (Postfix) with ESMTPS id B5BF3419BE
for ; Mon, 23 May 2022 19:39:55 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;
s=mimecast20190719; t=1653334794;
h=from:from:reply-to:subject:subject:date:date:message-id:message-id:
to:to:cc:cc:mime-version:mime-version:content-type:content-type:
content-transfer-encoding:content-transfer-encoding:
in-reply-to:in-reply-to:references:references;
bh=bqwVedx2TI5Hmm2fG6gDbCWOPhNs2eZZkUsLFILwvQw=;
b=jV0UECLF55KYcmd95GPnfmfpFgO6gTetOcT7JmA5iJbwDwfIKDdN9gnb6BF3zaGR7djKxc
8HZ6mG07BEY2axw8ntV1lJn1d9fcCnvQ2TvfjfhJelwkzeRNo1HcPjSMdiStp59JMsgNxQ
bcSUhai0iV2ZV3/ihe0/uGgzcF7s2UM=
Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com
[66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS
(version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id
us-mta-13-SM_ImGd4MrqMoNtlD5ztwQ-1; Mon, 23 May 2022 15:39:52 -0400
X-MC-Unique: SM_ImGd4MrqMoNtlD5ztwQ-1
Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com
[10.11.54.4])
(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))
(No client certificate requested)
by mimecast-mx02.redhat.com (Postfix) with ESMTPS id CC3B4185A79C;
Mon, 23 May 2022 19:39:51 +0000 (UTC)
Received: from dceara.remote.csb (unknown [10.39.194.145])
by smtp.corp.redhat.com (Postfix) with ESMTP id 76FC72026D6A;
Mon, 23 May 2022 19:39:50 +0000 (UTC)
From: Dumitru Ceara
To: ovs-dev@openvswitch.org
Date: Mon, 23 May 2022 21:39:48 +0200
Message-Id: <20220523193946.9544.32598.stgit@dceara.remote.csb>
In-Reply-To: <20220523193838.9544.70716.stgit@dceara.remote.csb>
References: <20220523193838.9544.70716.stgit@dceara.remote.csb>
User-Agent: StGit/0.17.1-dirty
MIME-Version: 1.0
X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4
Authentication-Results: relay.mimecast.com;
auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=dceara@redhat.com
X-Mimecast-Spam-Score: 0
X-Mimecast-Originator: redhat.com
Subject: [ovs-dev] [PATCH ovn branch-21.12 6/6] Use ct_mark for masked
access to make flows HW-offloading friendly.
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: ,
Errors-To: ovs-dev-bounces@openvswitch.org
Sender: "dev"
From: Han Zhou
Some NICs support HW offloading for datapath flows, but masked access to
the 128-bit ct_label field may prevent a flow being offloaded due to HW
limitations. OVN's use of ct_label currently includes:
- ct_label.blocked (1 bit)
- ct_label.natted (1 bit)
- ct_label.ecmp_reply_port (16 bits)
- ct_label.ecmp_reply_eth (48 bits)
- ct_label.label (32 bits)
This patch moves the bits blocked, natted and ecmp_reply_port to use
ct_mark (18 bits in total among the 32-bit ct_mark), and keep the rest
of the fields in ct_label:
- ct_mark.blocked (1 bit)
- ct_mark.natted (1 bit)
- ct_mark.ecmp_reply_port (16 bits)
- ct_label.ecmp_reply_eth (48 bits)
- ct_label.label (32 bits)
This would allow HW offloading to work for most of the cases.
For ct_label.ecmp_reply_eth, the flow matching it still uses masked
access, but it doesn't matter because the flow is for new connections
and requires ct_commit in its actions, so it wouldn't be offloaded
anyway for those NICs. There is a flow for established connections that
would access the masked field in the actions, while in this patch it
avoids masked access by using a register xxreg1 to temporarily read the
whole ct_label, and then use masked access to xxreg1 to read the actual
value.
The only exception is for ct_label.label, there is a flow that matches
the masked field for ACL logging of reply direction. This patch cannot
avoid the masked access to ct_label in this case. This flow is enabled
only for the feature "log-related". So offloading may still not work for
some NICs when an ACL is configured with a label and with "log-related"
enabled.
There are no other flows relying on masked ct_label match, but it's
worth noting that the LB hairpin related flows using ct_label.natted
which were hardcoded directly in ovn-controller are still kept to avoid
traffic breaking during upgrading. It relies on the
northd-internal-version to internally determine if it is currently
upgrading from a version that requires the ct_label flows being
kept, and automatically removes the flows when northd-internal-version
is up-to-date.
Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1957786
Signed-off-by: Han Zhou
Acked-by: Numan Siddique
(cherry picked from commit a075230e4a0fcc166251271db1c8ae01b993c9cf)
Signed-off-by: Dumitru Ceara
---
NEWS | 2
controller/lflow.c | 33 ++-
controller/lflow.h | 1
controller/ovn-controller.c | 13 +
include/ovn/logical-fields.h | 3
lib/logical-fields.c | 17 +-
lib/ovn-util.c | 25 ++
lib/ovn-util.h | 4
northd/northd.c | 97 +++++----
northd/ovn-northd.8.xml | 48 ++--
tests/ovn-northd.at | 476 +++++++++++++++++++++---------------------
tests/ovn.at | 173 ++++++++-------
tests/system-ovn.at | 178 ++++++++--------
13 files changed, 591 insertions(+), 479 deletions(-)
diff --git a/NEWS b/NEWS
index 3b3104c2f..de3330ab6 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,8 @@ OVN v21.12.2 - xx xxx xxxx
--------------------------
- When configured to log packets matching ACLs, log the direction (logical
pipeline) too.
+ - Replaced the usage of masked ct_label by ct_mark in most cases to work
+ better with hardware-offloading.
OVN v21.12.1 - 11 Mar 2022
--------------------------
diff --git a/controller/lflow.c b/controller/lflow.c
index b96fca5d5..b35632f24 100644
--- a/controller/lflow.c
+++ b/controller/lflow.c
@@ -1322,6 +1322,7 @@ add_lb_vip_hairpin_flows(struct ovn_controller_lb *lb,
struct ovn_lb_vip *lb_vip,
struct ovn_lb_backend *lb_backend,
uint8_t lb_proto,
+ bool check_ct_label_for_lb_hairpin,
struct ovn_desired_flow_table *flow_table)
{
uint64_t stub[1024 / 8];
@@ -1413,14 +1414,28 @@ add_lb_vip_hairpin_flows(struct ovn_controller_lb *lb,
* - the destination protocol and port must be of a valid backend that
* has the same IP as ip.dst.
*/
- ovs_u128 lb_ct_label = {
- .u64.lo = OVN_CT_NATTED,
- };
- match_set_ct_label_masked(&hairpin_match, lb_ct_label, lb_ct_label);
+ uint32_t lb_ct_mark = OVN_CT_NATTED;
+ match_set_ct_mark_masked(&hairpin_match, lb_ct_mark, lb_ct_mark);
ofctrl_add_flow(flow_table, OFTABLE_CHK_LB_HAIRPIN, 100,
lb->slb->header_.uuid.parts[0], &hairpin_match,
&ofpacts, &lb->slb->header_.uuid);
+
+ /* The below flow is identical to the above except that it checks
+ * ct_label.natted instead of ct_mark.natted, for backward compatibility
+ * during the upgrade from a previous version that uses ct_label. */
+ if (check_ct_label_for_lb_hairpin) {
+ match_set_ct_mark_masked(&hairpin_match, 0, 0);
+ ovs_u128 lb_ct_label = {
+ .u64.lo = OVN_CT_NATTED,
+ };
+ match_set_ct_label_masked(&hairpin_match, lb_ct_label, lb_ct_label);
+
+ ofctrl_add_flow(flow_table, OFTABLE_CHK_LB_HAIRPIN, 100,
+ lb->slb->header_.uuid.parts[0], &hairpin_match,
+ &ofpacts, &lb->slb->header_.uuid);
+ }
+
ofpbuf_uninit(&ofpacts);
}
@@ -1693,6 +1708,7 @@ add_lb_ct_snat_hairpin_flows(struct ovn_controller_lb *lb,
static void
consider_lb_hairpin_flows(const struct sbrec_load_balancer *sbrec_lb,
const struct hmap *local_datapaths,
+ bool check_ct_label_for_lb_hairpin,
struct ovn_desired_flow_table *flow_table,
struct simap *ids)
{
@@ -1732,6 +1748,7 @@ consider_lb_hairpin_flows(const struct sbrec_load_balancer *sbrec_lb,
struct ovn_lb_backend *lb_backend = &lb_vip->backends[j];
add_lb_vip_hairpin_flows(lb, lb_vip, lb_backend, lb_proto,
+ check_ct_label_for_lb_hairpin,
flow_table);
}
}
@@ -1746,6 +1763,7 @@ consider_lb_hairpin_flows(const struct sbrec_load_balancer *sbrec_lb,
static void
add_lb_hairpin_flows(const struct sbrec_load_balancer_table *lb_table,
const struct hmap *local_datapaths,
+ bool check_ct_label_for_lb_hairpin,
struct ovn_desired_flow_table *flow_table,
struct simap *ids,
struct id_pool *pool)
@@ -1768,7 +1786,9 @@ add_lb_hairpin_flows(const struct sbrec_load_balancer_table *lb_table,
ovs_assert(id_pool_alloc_id(pool, &id));
simap_put(ids, lb->name, id);
}
- consider_lb_hairpin_flows(lb, local_datapaths, flow_table, ids);
+ consider_lb_hairpin_flows(lb, local_datapaths,
+ check_ct_label_for_lb_hairpin,
+ flow_table, ids);
}
}
@@ -1874,6 +1894,7 @@ lflow_run(struct lflow_ctx_in *l_ctx_in, struct lflow_ctx_out *l_ctx_out)
l_ctx_in->mac_binding_table, l_ctx_in->local_datapaths,
l_ctx_out->flow_table);
add_lb_hairpin_flows(l_ctx_in->lb_table, l_ctx_in->local_datapaths,
+ l_ctx_in->check_ct_label_for_lb_hairpin,
l_ctx_out->flow_table,
l_ctx_out->hairpin_lb_ids,
l_ctx_out->hairpin_id_pool);
@@ -2008,6 +2029,7 @@ lflow_add_flows_for_datapath(const struct sbrec_datapath_binding *dp,
* associated. */
for (size_t i = 0; i < n_dp_lbs; i++) {
consider_lb_hairpin_flows(dp_lbs[i], l_ctx_in->local_datapaths,
+ l_ctx_in->check_ct_label_for_lb_hairpin,
l_ctx_out->flow_table,
l_ctx_out->hairpin_lb_ids);
}
@@ -2121,6 +2143,7 @@ lflow_handle_changed_lbs(struct lflow_ctx_in *l_ctx_in,
VLOG_DBG("Add load balancer hairpin flows for "UUID_FMT,
UUID_ARGS(&lb->header_.uuid));
consider_lb_hairpin_flows(lb, l_ctx_in->local_datapaths,
+ l_ctx_in->check_ct_label_for_lb_hairpin,
l_ctx_out->flow_table,
l_ctx_out->hairpin_lb_ids);
}
diff --git a/controller/lflow.h b/controller/lflow.h
index 28f49946d..ee503c071 100644
--- a/controller/lflow.h
+++ b/controller/lflow.h
@@ -152,6 +152,7 @@ struct lflow_ctx_in {
const struct sset *active_tunnels;
const struct sset *related_lport_ids;
const struct hmap *chassis_tunnels;
+ bool check_ct_label_for_lb_hairpin;
};
struct lflow_ctx_out {
diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
index 1457bb04d..dc51e0b89 100644
--- a/controller/ovn-controller.c
+++ b/controller/ovn-controller.c
@@ -486,6 +486,13 @@ get_ovs_chassis_id(const struct ovsrec_open_vswitch_table *ovs_table)
return chassis_id;
}
+static bool
+get_check_ct_label_for_lb_hairpin(const char *northd_internal_ver)
+{
+ unsigned int minor = ovn_parse_internal_version_minor(northd_internal_ver);
+ return (minor <= 3);
+}
+
static void
update_ssl_config(const struct ovsrec_ssl_table *ssl_table)
{
@@ -2348,6 +2355,10 @@ init_lflow_ctx(struct engine_node *node,
engine_get_input_data("port_groups", node);
struct shash *port_groups = &pg_data->port_groups_cs_local;
+ struct ed_type_northd_internal_version *n_ver =
+ engine_get_input_data("northd_internal_version", node);
+ ovs_assert(n_ver);
+
l_ctx_in->sbrec_multicast_group_by_name_datapath =
sbrec_mc_group_by_name_dp;
l_ctx_in->sbrec_logical_flow_by_logical_datapath =
@@ -2373,6 +2384,8 @@ init_lflow_ctx(struct engine_node *node,
l_ctx_in->active_tunnels = &rt_data->active_tunnels;
l_ctx_in->related_lport_ids = &rt_data->related_lports.lport_ids;
l_ctx_in->chassis_tunnels = &non_vif_data->chassis_tunnels;
+ l_ctx_in->check_ct_label_for_lb_hairpin =
+ get_check_ct_label_for_lb_hairpin(n_ver->ver);
l_ctx_out->flow_table = &fo->flow_table;
l_ctx_out->group_table = &fo->group_table;
diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h
index cdc758a6e..18516634e 100644
--- a/include/ovn/logical-fields.h
+++ b/include/ovn/logical-fields.h
@@ -174,6 +174,9 @@ const struct ovn_field *ovn_field_from_name(const char *name);
#define OVN_CT_BLOCKED 1
#define OVN_CT_NATTED 2
+#define OVN_CT_ECMP_ETH_1ST_BIT 32
+#define OVN_CT_ECMP_ETH_END_BIT 79
+
#define OVN_CT_STR(LABEL_VALUE) OVS_STRINGIZE(LABEL_VALUE)
#define OVN_CT_MASKED_STR(LABEL_VALUE) \
OVS_STRINGIZE(LABEL_VALUE) "/" OVS_STRINGIZE(LABEL_VALUE)
diff --git a/lib/logical-fields.c b/lib/logical-fields.c
index 352a48c89..ed3ec62e1 100644
--- a/lib/logical-fields.c
+++ b/lib/logical-fields.c
@@ -133,6 +133,18 @@ ovn_init_symtab(struct shash *symtab)
/* Connection tracking state. */
expr_symtab_add_field_scoped(symtab, "ct_mark", MFF_CT_MARK, NULL, false,
WR_CT_COMMIT);
+ expr_symtab_add_subfield_scoped(symtab, "ct_mark.blocked", NULL,
+ "ct_mark["
+ OVN_CT_STR(OVN_CT_BLOCKED_BIT)
+ "]",
+ WR_CT_COMMIT);
+ expr_symtab_add_subfield_scoped(symtab, "ct_mark.natted", NULL,
+ "ct_mark["
+ OVN_CT_STR(OVN_CT_NATTED_BIT)
+ "]",
+ WR_CT_COMMIT);
+ expr_symtab_add_subfield_scoped(symtab, "ct_mark.ecmp_reply_port", NULL,
+ "ct_mark[16..31]", WR_CT_COMMIT);
expr_symtab_add_field_scoped(symtab, "ct_label", MFF_CT_LABEL, NULL,
false, WR_CT_COMMIT);
@@ -147,7 +159,10 @@ ovn_init_symtab(struct shash *symtab)
"]",
WR_CT_COMMIT);
expr_symtab_add_subfield_scoped(symtab, "ct_label.ecmp_reply_eth", NULL,
- "ct_label[32..79]", WR_CT_COMMIT);
+ "ct_label["
+ OVN_CT_STR(OVN_CT_ECMP_ETH_1ST_BIT) ".."
+ OVN_CT_STR(OVN_CT_ECMP_ETH_END_BIT) "]",
+ WR_CT_COMMIT);
expr_symtab_add_subfield_scoped(symtab, "ct_label.ecmp_reply_port", NULL,
"ct_label[80..95]", WR_CT_COMMIT);
expr_symtab_add_subfield_scoped(symtab, "ct_label.label", NULL,
diff --git a/lib/ovn-util.c b/lib/ovn-util.c
index c3da413aa..d2ba43d66 100644
--- a/lib/ovn-util.c
+++ b/lib/ovn-util.c
@@ -766,8 +766,11 @@ ip_address_and_port_from_lb_key(const char *key, char **ip_address,
}
/* Increment this for any logical flow changes, if an existing OVN action is
- * modified or a stage is added to a logical pipeline. */
-#define OVN_INTERNAL_MINOR_VER 3
+ * modified or a stage is added to a logical pipeline.
+ *
+ * This value is also used to handle some backward compatibility during
+ * upgrading. It should never decrease or rewind. */
+#define OVN_INTERNAL_MINOR_VER 4
/* Returns the OVN version. The caller must free the returned value. */
char *
@@ -778,6 +781,24 @@ ovn_get_internal_version(void)
N_OVNACTS, OVN_INTERNAL_MINOR_VER);
}
+unsigned int
+ovn_parse_internal_version_minor(const char *ver)
+{
+ const char *p = ver + strlen(ver);
+ for (int i = 0; i < strlen(ver); i++) {
+ if (*p == '.') {
+ break;
+ }
+ p--;
+ }
+
+ unsigned int minor;
+ if (ovs_scan(p, ".%u", &minor)) {
+ return minor;
+ }
+ return 0;
+}
+
#ifdef DDLOG
/* Callbacks used by the ddlog northd code to print warnings and errors. */
void
diff --git a/lib/ovn-util.h b/lib/ovn-util.h
index b212c64b7..a4f3187e3 100644
--- a/lib/ovn-util.h
+++ b/lib/ovn-util.h
@@ -247,6 +247,10 @@ bool ip_address_and_port_from_lb_key(const char *key, char **ip_address,
* value. */
char *ovn_get_internal_version(void);
+/* Parse the provided internal version string and return the "minor" part which
+ * is expected to be an unsigned integer followed by the last "." in the
+ * string. Returns 0 if the string can't be parsed. */
+unsigned int ovn_parse_internal_version_minor(const char *ver);
/* OVN Packet definitions. These may eventually find a home in OVS's
* packets.h file. For the time being, they live here because OVN uses them
diff --git a/northd/northd.c b/northd/northd.c
index 016eb2f0d..7fe495e0c 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -238,6 +238,17 @@ enum ovn_stage {
/* Register used for setting a label for ACLs in a Logical Switch. */
#define REG_LABEL "reg3"
+/* Register used for temporarily store ECMP eth.src to avoid masked ct_label
+ * access. It doesn't really occupy registers because the content of the
+ * register is saved to stack and then restored in the same flow.
+ * Note: the bits must match ct_label.ecmp_reply_eth defined in
+ * logical-fields.c */
+#define REG_ECMP_ETH_FULL "xxreg1"
+#define REG_ECMP_ETH_FIELD REG_ECMP_ETH_FULL "[" \
+ OVN_CT_STR(OVN_CT_ECMP_ETH_1ST_BIT) \
+ ".." \
+ OVN_CT_STR(OVN_CT_ECMP_ETH_END_BIT) "]"
+
#define FLAGBIT_NOT_VXLAN "flags[1] == 0"
/*
@@ -3730,7 +3741,7 @@ build_lb_vip_actions(struct ovn_lb_vip *lb_vip,
bool skip_hash_fields = false, reject = false;
if (lb_vip_nb->lb_health_check) {
- ds_put_cstr(action, "ct_lb(backends=");
+ ds_put_cstr(action, "ct_lb_mark(backends=");
size_t n_active_backends = 0;
for (size_t i = 0; i < lb_vip->n_backends; i++) {
@@ -3763,7 +3774,8 @@ build_lb_vip_actions(struct ovn_lb_vip *lb_vip,
} else if (lb_vip->empty_backend_rej && !lb_vip->n_backends) {
reject = true;
} else {
- ds_put_format(action, "ct_lb(backends=%s);", lb_vip_nb->backend_ips);
+ ds_put_format(action, "ct_lb_mark(backends=%s);",
+ lb_vip_nb->backend_ips);
}
if (reject) {
@@ -5980,7 +5992,7 @@ build_pre_stateful(struct ovn_datapath *od, struct hmap *lflows)
ds_put_format(&match, REGBIT_CONNTRACK_NAT" == 1 && ip4 && %s",
lb_protocols[i]);
ds_put_format(&actions, REG_ORIG_DIP_IPV4 " = ip4.dst; "
- REG_ORIG_TP_DPORT " = %s.dst; ct_lb;",
+ REG_ORIG_TP_DPORT " = %s.dst; ct_lb_mark;",
lb_protocols[i]);
ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 120,
ds_cstr(&match), ds_cstr(&actions));
@@ -5990,7 +6002,7 @@ build_pre_stateful(struct ovn_datapath *od, struct hmap *lflows)
ds_put_format(&match, REGBIT_CONNTRACK_NAT" == 1 && ip6 && %s",
lb_protocols[i]);
ds_put_format(&actions, REG_ORIG_DIP_IPV6 " = ip6.dst; "
- REG_ORIG_TP_DPORT " = %s.dst; ct_lb;",
+ REG_ORIG_TP_DPORT " = %s.dst; ct_lb_mark;",
lb_protocols[i]);
ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 120,
ds_cstr(&match), ds_cstr(&actions));
@@ -6000,10 +6012,10 @@ build_pre_stateful(struct ovn_datapath *od, struct hmap *lflows)
ds_destroy(&match);
ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 110,
- REGBIT_CONNTRACK_NAT" == 1", "ct_lb;");
+ REGBIT_CONNTRACK_NAT" == 1", "ct_lb_mark;");
ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_STATEFUL, 110,
- REGBIT_CONNTRACK_NAT" == 1", "ct_lb;");
+ REGBIT_CONNTRACK_NAT" == 1", "ct_lb_mark;");
/* If REGBIT_CONNTRACK_DEFRAG is set as 1, then the packets should be
* sent to conntrack for tracking and defragmentation. */
@@ -6067,7 +6079,7 @@ build_acl_hints(struct ovn_datapath *od, struct hmap *lflows)
* - drop ACLs.
*/
ovn_lflow_add(lflows, od, stage, 6,
- "!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1",
+ "!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1",
REGBIT_ACL_HINT_ALLOW_NEW " = 1; "
REGBIT_ACL_HINT_DROP " = 1; "
"next;");
@@ -6083,11 +6095,11 @@ build_acl_hints(struct ovn_datapath *od, struct hmap *lflows)
* - allow ACLs in which case the traffic should be allowed so we set
* REGBIT_ACL_HINT_ALLOW.
* - drop ACLs in which case the traffic should be blocked and the
- * connection must be committed with ct_label.blocked set so we set
+ * connection must be committed with ct_mark.blocked set so we set
* REGBIT_ACL_HINT_BLOCK.
*/
ovn_lflow_add(lflows, od, stage, 4,
- "!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0",
+ "!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0",
REGBIT_ACL_HINT_ALLOW " = 1; "
REGBIT_ACL_HINT_BLOCK " = 1; "
"next;");
@@ -6098,15 +6110,15 @@ build_acl_hints(struct ovn_datapath *od, struct hmap *lflows)
ovn_lflow_add(lflows, od, stage, 3, "!ct.est",
REGBIT_ACL_HINT_DROP " = 1; "
"next;");
- ovn_lflow_add(lflows, od, stage, 2, "ct.est && ct_label.blocked == 1",
+ ovn_lflow_add(lflows, od, stage, 2, "ct.est && ct_mark.blocked == 1",
REGBIT_ACL_HINT_DROP " = 1; "
"next;");
/* Established connections that were previously allowed might hit
* drop ACLs in which case the connection must be committed with
- * ct_label.blocked set.
+ * ct_mark.blocked set.
*/
- ovn_lflow_add(lflows, od, stage, 1, "ct.est && ct_label.blocked == 0",
+ ovn_lflow_add(lflows, od, stage, 1, "ct.est && ct_mark.blocked == 0",
REGBIT_ACL_HINT_BLOCK " = 1; "
"next;");
}
@@ -6279,7 +6291,7 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od,
* It's also possible that a known connection was marked for
* deletion after a policy was deleted, but the policy was
* re-added while that connection is still known. We catch
- * that case here and un-set ct_label.blocked (which will be done
+ * that case here and un-set ct_mark.blocked (which will be done
* by ct_commit in the "stateful" stage) to indicate that the
* connection should be allowed to resume.
*/
@@ -6349,11 +6361,11 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od,
ds_cstr(match), ds_cstr(actions),
&acl->header_);
}
- /* For an existing connection without ct_label set, we've
+ /* For an existing connection without ct_mark.blocked set, we've
* encountered a policy change. ACLs previously allowed
* this connection and we committed the connection tracking
* entry. Current policy says that we should drop this
- * connection. First, we set bit 0 of ct_label to indicate
+ * connection. First, we set ct_mark.blocked to indicate
* that this connection is set for deletion. By not
* specifying "next;", we implicitly drop the packet after
* updating conntrack state. We would normally defer
@@ -6363,7 +6375,7 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od,
ds_clear(match);
ds_clear(actions);
ds_put_cstr(match, REGBIT_ACL_HINT_BLOCK " == 1");
- ds_put_cstr(actions, "ct_commit { ct_label.blocked = 1; }; ");
+ ds_put_cstr(actions, "ct_commit { ct_mark.blocked = 1; }; ");
if (!strcmp(acl->action, "reject")) {
build_reject_acl_rules(od, lflows, stage, acl, match,
actions, &acl->header_, meter_groups);
@@ -6570,29 +6582,29 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows,
* subsequent packets will hit the flow at priority 0 that just
* uses "next;"
*
- * We also check for established connections that have ct_label.blocked
+ * We also check for established connections that have ct_mark.blocked
* set on them. That's a connection that was disallowed, but is
* now allowed by policy again since it hit this default-allow flow.
- * We need to set ct_label.blocked=0 to let the connection continue,
+ * We need to set ct_mark.blocked=0 to let the connection continue,
* which will be done by ct_commit() in the "stateful" stage.
* Subsequent packets will hit the flow at priority 0 that just
* uses "next;". */
ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 1,
- "ip && (!ct.est || (ct.est && ct_label.blocked == 1))",
+ "ip && (!ct.est || (ct.est && ct_mark.blocked == 1))",
REGBIT_CONNTRACK_COMMIT" = 1; next;");
ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 1,
- "ip && (!ct.est || (ct.est && ct_label.blocked == 1))",
+ "ip && (!ct.est || (ct.est && ct_mark.blocked == 1))",
REGBIT_CONNTRACK_COMMIT" = 1; next;");
/* Ingress and Egress ACL Table (Priority 65532).
*
* Always drop traffic that's in an invalid state. Also drop
* reply direction packets for connections that have been marked
- * for deletion (bit 0 of ct_label is set).
+ * for deletion (ct_mark.blocked is set).
*
* This is enforced at a higher priority than ACLs can be defined. */
ds_clear(&match);
- ds_put_format(&match, "%s(ct.est && ct.rpl && ct_label.blocked == 1)",
+ ds_put_format(&match, "%s(ct.est && ct.rpl && ct_mark.blocked == 1)",
use_ct_inv_match ? "ct.inv || " : "");
ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3,
ds_cstr(&match), "drop;");
@@ -6603,14 +6615,14 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows,
*
* Allow reply traffic that is part of an established
* conntrack entry that has not been marked for deletion
- * (bit 0 of ct_label). We only match traffic in the
+ * (ct_mark.blocked). We only match traffic in the
* reply direction because we want traffic in the request
* direction to hit the currently defined policy from ACLs.
*
* This is enforced at a higher priority than ACLs can be defined. */
ds_clear(&match);
ds_put_format(&match, "ct.est && !ct.rel && !ct.new%s && "
- "ct.rpl && ct_label.blocked == 0",
+ "ct.rpl && ct_mark.blocked == 0",
use_ct_inv_match ? " && !ct.inv" : "");
ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3,
ds_cstr(&match), REGBIT_ACL_HINT_DROP" = 0; "
@@ -6621,7 +6633,7 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows,
/* Ingress and Egress ACL Table (Priority 65535).
*
* Allow traffic that is related to an existing conntrack entry that
- * has not been marked for deletion (bit 0 of ct_label).
+ * has not been marked for deletion (ct_mark.blocked).
*
* This is enforced at a higher priority than ACLs can be defined.
*
@@ -6631,7 +6643,7 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows,
* that's generated from a non-listening UDP port. */
ds_clear(&match);
ds_put_format(&match, "!ct.est && ct.rel && !ct.new%s && "
- "ct_label.blocked == 0",
+ "ct_mark.blocked == 0",
use_ct_inv_match ? " && !ct.inv" : "");
ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3,
ds_cstr(&match), "next;");
@@ -6912,26 +6924,26 @@ build_stateful(struct ovn_datapath *od, struct hmap *lflows)
ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, 100,
REGBIT_CONNTRACK_COMMIT" == 1 && "
REGBIT_ACL_LABEL" == 1",
- "ct_commit { ct_label.blocked = 0; "
+ "ct_commit { ct_mark.blocked = 0; "
"ct_label.label = " REG_LABEL "; }; next;");
ovn_lflow_add(lflows, od, S_SWITCH_OUT_STATEFUL, 100,
REGBIT_CONNTRACK_COMMIT" == 1 && "
REGBIT_ACL_LABEL" == 1",
- "ct_commit { ct_label.blocked = 0; "
+ "ct_commit { ct_mark.blocked = 0; "
"ct_label.label = " REG_LABEL "; }; next;");
/* If REGBIT_CONNTRACK_COMMIT is set as 1, then the packets should be
- * committed to conntrack. We always set ct_label.blocked to 0 here as
+ * committed to conntrack. We always set ct_mark.blocked to 0 here as
* any packet that makes it this far is part of a connection we
* want to allow to continue. */
ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, 100,
REGBIT_CONNTRACK_COMMIT" == 1 && "
REGBIT_ACL_LABEL" == 0",
- "ct_commit { ct_label.blocked = 0; }; next;");
+ "ct_commit { ct_mark.blocked = 0; }; next;");
ovn_lflow_add(lflows, od, S_SWITCH_OUT_STATEFUL, 100,
REGBIT_CONNTRACK_COMMIT" == 1 && "
REGBIT_ACL_LABEL" == 0",
- "ct_commit { ct_label.blocked = 0; }; next;");
+ "ct_commit { ct_mark.blocked = 0; }; next;");
}
static void
@@ -9414,7 +9426,7 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows,
ds_put_cstr(&match, " && (ct.new && !ct.est)");
ds_put_format(&actions, "ct_commit { ct_label.ecmp_reply_eth = eth.src;"
- " ct_label.ecmp_reply_port = %" PRId64 ";}; next;",
+ " ct_mark.ecmp_reply_port = %" PRId64 ";}; next;",
out_port->sb->tunnel_key);
ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
ds_cstr(&match), ds_cstr(&actions),
@@ -9423,7 +9435,7 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows,
/* Bypass ECMP selection if we already have ct_label information
* for where to route the packet.
*/
- ds_put_format(&ecmp_reply, "ct.rpl && ct_label.ecmp_reply_port == %"
+ ds_put_format(&ecmp_reply, "ct.rpl && ct_mark.ecmp_reply_port == %"
PRId64, out_port->sb->tunnel_key);
ds_clear(&match);
ds_put_format(&match, "%s && %s", ds_cstr(&ecmp_reply),
@@ -9443,7 +9455,18 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows,
ds_cstr(&ecmp_reply), "next;",
&st_route->header_);
- const char *action = "eth.dst = ct_label.ecmp_reply_eth; next;";
+ /* Use REG_ECMP_ETH_FULL to pass the eth field from ct_label to eth.dst to
+ * avoid masked access to ct_label. Otherwise it may prevent OVS flow
+ * HW offloading to work for some NICs because masked-access of ct_label is
+ * not supported on those NICs due to HW limitations.
+ *
+ * Use push/pop to save the value of the register before using it and
+ * restore it immediately afterwards, so that the use of the register is
+ * temporary and doesn't interfere with other stages. */
+ const char *action = "push(" REG_ECMP_ETH_FULL "); "
+ REG_ECMP_ETH_FULL " = ct_label;"
+ " eth.dst = " REG_ECMP_ETH_FIELD ";"
+ " pop(" REG_ECMP_ETH_FULL "); next;";
ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ARP_RESOLVE,
200, ds_cstr(&ecmp_reply),
action, &st_route->header_);
@@ -9720,7 +9743,7 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
/* Higher priority rules are added for load-balancing in DNAT
* table. For every match (on a VIP[:port]), we add two flows.
* One flow is for specific matching on ct.new with an action
- * of "ct_lb($targets);". The other flow is for ct.est with
+ * of "ct_lb_mark($targets);". The other flow is for ct.est with
* an action of "next;".
*/
if (IN6_IS_ADDR_V4MAPPED(&lb_vip->vip)) {
@@ -9748,11 +9771,11 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
ds_cstr(match), lb->proto, lb_vip->vip_port);
est_match = xasprintf("ct.est && %s && %s && "
REG_ORIG_TP_DPORT_ROUTER" == %d && "
- "ct_label.natted == 1",
+ "ct_mark.natted == 1",
ds_cstr(match), lb->proto, lb_vip->vip_port);
} else {
new_match = xasprintf("ct.new && %s", ds_cstr(match));
- est_match = xasprintf("ct.est && %s && ct_label.natted == 1",
+ est_match = xasprintf("ct.est && %s && ct_mark.natted == 1",
ds_cstr(match));
}
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
index 45aa91815..2b307cef3 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -550,7 +550,7 @@
-
Priority-120 flows that send the packets to connection tracker using
-
ct_lb;
as the action so that the already established
+ ct_lb_mark;
as the action so that the already established
traffic destined to the load balancer VIP gets DNATted based on a hint
provided by the previous tables (with a match
for reg0[2] == 1
and on supported load balancer protocols
@@ -565,7 +565,7 @@
A priority-110 flow sends the packets to connection tracker based
on a hint provided by the previous tables
(with a match for reg0[2] == 1
) by using the
- ct_lb;
action. This flow is added to handle
+ ct_lb_mark;
action. This flow is added to handle
the traffic for load balancer VIPs whose protocol is not defined
(mainly for ICMP traffic).
@@ -741,12 +741,12 @@
A priority-65532 flow that allows any traffic in the reply
direction for a connection that has been committed to the
connection tracker (i.e., established flows), as long as
- the committed flow does not have ct_label.blocked
set.
+ the committed flow does not have ct_mark.blocked
set.
We only handle traffic in the reply direction here because
we want all packets going in the request direction to still
go through the flows that implement the currently defined
policy based on ACLs. If a connection is no longer allowed by
- policy, ct_label.blocked
will get set and packets in the
+ policy, ct_mark.blocked
will get set and packets in the
reply direction will no longer be allowed, either. This flow also
clears the register bits reg0[9]
and
reg0[10]
.
@@ -756,7 +756,7 @@
A priority-65532 flow that allows any traffic that is considered
related to a committed flow in the connection tracker (e.g., an
ICMP Port Unreachable from a non-listening UDP port), as long
- as the committed flow does not have ct_label.blocked
set.
+ as the committed flow does not have ct_mark.blocked
set.