From patchwork Fri Apr 1 08:32:29 2022
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
X-Patchwork-Submitter: Vladislav Odintsov
X-Patchwork-Id: 1612089
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" (2048-bit key;
unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256
header.s=20210112 header.b=F6sbxoY1;
dkim-atps=neutral
Authentication-Results: ozlabs.org;
spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org
(client-ip=140.211.166.137; helo=smtp4.osuosl.org;
envelope-from=ovs-dev-bounces@openvswitch.org; receiver=)
Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest
SHA256)
(No client certificate requested)
by bilbo.ozlabs.org (Postfix) with ESMTPS id 4KVD235Jr8z9sG5
for ; Fri, 1 Apr 2022 19:32:43 +1100 (AEDT)
Received: from localhost (localhost [127.0.0.1])
by smtp4.osuosl.org (Postfix) with ESMTP id 71620418DC;
Fri, 1 Apr 2022 08:32:41 +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 UU8oHpHJBtAf; Fri, 1 Apr 2022 08:32:39 +0000 (UTC)
Received: from lists.linuxfoundation.org (lf-lists.osuosl.org
[IPv6:2605:bc80:3010:104::8cd3:938])
by smtp4.osuosl.org (Postfix) with ESMTPS id 08CE2418DB;
Fri, 1 Apr 2022 08:32:38 +0000 (UTC)
Received: from lf-lists.osuosl.org (localhost [127.0.0.1])
by lists.linuxfoundation.org (Postfix) with ESMTP id 94BE8C002C;
Fri, 1 Apr 2022 08:32:37 +0000 (UTC)
X-Original-To: dev@openvswitch.org
Delivered-To: ovs-dev@lists.linuxfoundation.org
Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137])
by lists.linuxfoundation.org (Postfix) with ESMTP id DB015C0012
for ; Fri, 1 Apr 2022 08:32:35 +0000 (UTC)
Received: from localhost (localhost [127.0.0.1])
by smtp4.osuosl.org (Postfix) with ESMTP id C269E418DC
for ; Fri, 1 Apr 2022 08:32:35 +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 iqt1Wvhn0BM8 for ;
Fri, 1 Apr 2022 08:32:34 +0000 (UTC)
X-Greylist: whitelisted by SQLgrey-1.8.0
Received: from mail-lj1-x236.google.com (mail-lj1-x236.google.com
[IPv6:2a00:1450:4864:20::236])
by smtp4.osuosl.org (Postfix) with ESMTPS id DAE44418DB
for ; Fri, 1 Apr 2022 08:32:33 +0000 (UTC)
Received: by mail-lj1-x236.google.com with SMTP id q5so2904854ljb.11
for ; Fri, 01 Apr 2022 01:32:33 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112;
h=from:to:cc:subject:date:message-id:mime-version
:content-transfer-encoding;
bh=ZkZTy6ZYH6P53HjVrnarrliXAndKws/4hykZXcP08ek=;
b=F6sbxoY1J1bTbp4DXUsZWXPUfkNofqCIZtAH0xyAb1DvzY5YyrX6gLIP+fVMJt2jwk
rY+PV5bZDwfWqd5MGJo3fKsnkMoG24pP5roWnKhyEqgcqLk9IwQGEpLw7hpC6pQ3B1+Q
XF86Km6c4UOGM2KQ1uRFrUmukFKs8zqJwWuSwsvxFqAcBxKWgIWPFbD4Zk6Rlo3hK/t+
bDLK77t1+tuu7bSWa/kvkgrvH0HCf4gke8v0wf9Hx5cRTsVWU8D5xn5WhtPwUdUZ+PPl
/+idCZktKri0l+47E9rkpSUDsjygX56XlEArba0obb+MIU6uN+MOd9bQ3e3v/Zcq+ZIG
GONA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20210112;
h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version
:content-transfer-encoding;
bh=ZkZTy6ZYH6P53HjVrnarrliXAndKws/4hykZXcP08ek=;
b=mioB4aHd4X+NCYeyypZ62+QGekfdcAIzxEZ9mlhzZPuvydb+BDbFvpx5nh/QFrjvlG
N5gSs4DuWRtFUmVCwwAs9fay2Z/iINwkNntXl2fAZYXEGOliG4TlZHR1dMXXqRs1KhCl
zTaRvbQ41BJStlBl3MMQPj9/P3sgfV8xc61i89xEGSkgJps2zKh+tIY3fq/G2a3UoAJ6
mEwQLt1teDzumejNNWyJDCM5ft4/E+fwYS3gITQBizlQVmG7vyeptqHmsPuiooLd+RFf
klNwQx7utfbkBf64zcm230El99CQmAtJ2q/zNJxcd8VRjEyCT4mJgcEQFazYAYYZ4b9j
6hOw==
X-Gm-Message-State: AOAM532B8GKaakhQfWguFckkPGehGWeHbNQIfJ+OUbUpUQ89+MFwyBIv
dR7JdKyEuJa35CIRLYjNVQm27u6Uu6E=
X-Google-Smtp-Source:
ABdhPJwG17Wg6rvsGhxjWBDT2H42LRTXR31ewVDVYIPqOGd6GyX+d+MEzyRKGV9J7ubBqv2jJcs6TA==
X-Received: by 2002:a2e:9990:0:b0:249:88f6:f637 with SMTP id
w16-20020a2e9990000000b0024988f6f637mr12611587lji.14.1648801951160;
Fri, 01 Apr 2022 01:32:31 -0700 (PDT)
Received: from ip-10-70-112-12.vpc-1e810be1.internal
(c2-217-73-63-80.elastic.cloud.croc.ru. [217.73.63.80])
by smtp.gmail.com with ESMTPSA id
q10-20020a196e4a000000b0044ac90ec3fcsm172168lfk.79.2022.04.01.01.32.30
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Fri, 01 Apr 2022 01:32:30 -0700 (PDT)
From: Vladislav Odintsov
To: dev@openvswitch.org
Date: Fri, 1 Apr 2022 11:32:29 +0300
Message-Id: <20220401083229.1583750-1-odivlad@gmail.com>
X-Mailer: git-send-email 2.26.3
MIME-Version: 1.0
Cc: Vladislav Odintsov
Subject: [ovs-dev] [PATCH ovn] controller, northd,
vtep: support routed networks with HW VTEP
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"
When HW VTEP is used with OVN logical networks routed by
Logical Routers, only directly-attached network can communicate
with external VLAN (via vtep LSP). There is no connectivity
between VLAN network which is located behind VTEP LSP and lswitch1
behind LR.
Visual description:
┌──────┐
┌─────► │ VM │
│ └───┬──┘
│ ┌──────┴───────┐
│ │ lswitch1 │
│ │192.168.0.0/24│
│ └──────┬───────┘
│ ┌─┴──┐
│ │ LR │
│ └─┬──┘
│ ┌──────┴───────┐
│ │ lswitch2 │
│ │192.168.1.0/24│ ◄──┐
│ └──────┬───────┘ │
│ ┌───┴────┐ │
│FAIL │vtep LSP│ OK│
│ └───┬────┘ │
│ ┌──┴────┐ │
└────────┤VLAN 10├───────┘
└───────┘
This patch adds support to have connectivity between such routed networks.
User must set LRP gateway chassis (or ha chassis group) in the lswitch2's
associated LRP, which will enable answering ARP requests for LR IP from
VLAN (lswitch2) side.
Traffic from VLAN to overlay will go from HW VTEP switch through gateway
chassis to hypervisor and return traffic will go directly from hypervisor
to HW VTEP switch and then got forwarded to VLAN.
Now chassis, on which chassis redirect LRP is claimed, will answer ARP requests
coming from HW VTEP switch. For this reason the hairpin traffic from VTEP switch
is allowed:
1. the blocking OF rule in table `OFTABLE_REMOTE_OUTPUT` which matched on
reg10=0x2/0x2 is changed to match on reg10=0x2/0x3. We check if traffic is
from VTEP (ramp) switch and also we check if loopback flag was not set and
only in this case such traffic is not allowed.
2. OF rule in table `OFTABLE_REMOTE_OUTPUT`, which directs traffic to HW VTEP
(ramp) switch is modified to flush IN_PORT in order to allow sending traffic
to OF port from which this traffic came (hairpin).
New flows are added to ls_in_ip_hairpin table to support ARP traffic hairpin
for VTEP switches:
1. if traffic has come from VTEP (ramp) switch AND l3dgw ports of associated
LSPs reside on current chassis (is_chassis_resident()), such traffic
is passed to next table for further ARP responder processing. Priority of
this flow is 2000.
2. if traffic has come from VTEP (ramp) switch, send it to L2_LKUP table to
skip ARP responder processing. We serve ARP requests from VTEP lports only
on gateway chassis. Priority of this flow is 1000.
Signed-off-by: Vladislav Odintsov
---
controller-vtep/vtep.c | 31 ++++++++++++++++++++---
controller/physical.c | 18 ++++++++++----
northd/northd.c | 50 +++++++++++++++++++++++++++++++++----
northd/ovn-northd.8.xml | 55 +++++++++++++++++++++++++++++------------
tests/ovn-northd.at | 9 ++++---
tests/ovn.at | 37 +++++++++++++++++++++------
6 files changed, 159 insertions(+), 41 deletions(-)
diff --git a/controller-vtep/vtep.c b/controller-vtep/vtep.c
index ecca00b54..c3d09425c 100644
--- a/controller-vtep/vtep.c
+++ b/controller-vtep/vtep.c
@@ -311,6 +311,9 @@ vtep_macs_run(struct ovsdb_idl_txn *vtep_idl_txn, struct shash *ucast_macs_rmts,
hash_uint64((uint64_t) vtep_ls->tunnel_key[0]));
}
+ const char *dp, *peer;
+ const struct sbrec_port_binding *lrp_pb, *peer_pb;
+
SHASH_FOR_EACH (node, non_vtep_pbs) {
const struct sbrec_port_binding *port_binding_rec = node->data;
const struct sbrec_chassis *chassis_rec;
@@ -324,7 +327,25 @@ vtep_macs_run(struct ovsdb_idl_txn *vtep_idl_txn, struct shash *ucast_macs_rmts,
continue;
}
- tnl_key = port_binding_rec->datapath->tunnel_key;
+ if (!strcmp(port_binding_rec->type, "chassisredirect")) {
+ dp = smap_get(&port_binding_rec->options, "distributed-port");
+ lrp_pb = shash_find_data(non_vtep_pbs, dp);
+ if (!lrp_pb) {
+ continue;
+ }
+
+ peer = smap_get(&lrp_pb->options, "peer");
+ if (!peer) {
+ continue;
+ }
+
+ peer_pb = shash_find_data(non_vtep_pbs, peer);
+ tnl_key = peer_pb->datapath->tunnel_key;
+ }
+ else {
+ tnl_key = port_binding_rec->datapath->tunnel_key;
+ }
+
HMAP_FOR_EACH_WITH_HASH (ls_node, hmap_node,
hash_uint64((uint64_t) tnl_key),
&ls_map) {
@@ -454,7 +475,7 @@ vtep_macs_run(struct ovsdb_idl_txn *vtep_idl_txn, struct shash *ucast_macs_rmts,
static bool
vtep_lswitch_cleanup(struct ovsdb_idl *vtep_idl)
{
- const struct vteprec_logical_switch *vtep_ls;
+ const struct vteprec_logical_switch *vtep_ls;
bool done = true;
VTEPREC_LOGICAL_SWITCH_FOR_EACH (vtep_ls, vtep_idl) {
@@ -572,9 +593,11 @@ vtep_run(struct controller_vtep_ctx *ctx)
/* Collects and classifies 'Port_Binding's. */
SBREC_PORT_BINDING_FOR_EACH(port_binding_rec, ctx->ovnsb_idl) {
struct shash *target =
- !strcmp(port_binding_rec->type, "vtep") ? &vtep_pbs : &non_vtep_pbs;
+ !strcmp(port_binding_rec->type, "vtep") ? &vtep_pbs
+ : &non_vtep_pbs;
- if (!port_binding_rec->chassis) {
+ if (!port_binding_rec->chassis &&
+ strcmp(port_binding_rec->type, "patch")) {
continue;
}
shash_add(target, port_binding_rec->logical_port, port_binding_rec);
diff --git a/controller/physical.c b/controller/physical.c
index 02fcd5ea8..2a70f4fe0 100644
--- a/controller/physical.c
+++ b/controller/physical.c
@@ -299,9 +299,16 @@ put_remote_port_redirect_overlay(const struct
if (!rem_tun) {
return;
}
+
+ bool is_vtep_port = !strcmp(binding->type, "vtep");
+ /* rewrite MFF_IN_PORT to bypass OpenFlow loopback check for ARP/ND
+ * responder in L3 networks. */
+ if (is_vtep_port) {
+ put_load(ofp_to_u16(OFPP_NONE), MFF_IN_PORT, 0, 16, ofpacts_p);
+ }
+
put_encapsulation(mff_ovn_geneve, tun, binding->datapath, port_key,
- !strcmp(binding->type, "vtep"),
- ofpacts_p);
+ is_vtep_port, ofpacts_p);
/* Output to tunnel. */
ofpact_put_OUTPUT(ofpacts_p)->port = rem_tun->ofport;
} else {
@@ -1841,12 +1848,13 @@ physical_run(struct physical_ctx *p_ctx,
* Handles packets received from a VXLAN tunnel which get resubmitted to
* OFTABLE_LOG_INGRESS_PIPELINE due to lack of needed metadata in VXLAN,
* explicitly skip sending back out any tunnels and resubmit to table 38
- * for local delivery.
+ * for local delivery, except packets which have MLF_ALLOW_LOOPBACK bit
+ * set.
*/
struct match match;
match_init_catchall(&match);
- match_set_reg_masked(&match, MFF_LOG_FLAGS - MFF_REG0,
- MLF_RCV_FROM_RAMP, MLF_RCV_FROM_RAMP);
+ match_set_reg_masked(&match, MFF_LOG_FLAGS - MFF_REG0, MLF_RCV_FROM_RAMP,
+ MLF_RCV_FROM_RAMP | MLF_ALLOW_LOOPBACK);
/* Resubmit to table 38. */
ofpbuf_clear(&ofpacts);
diff --git a/northd/northd.c b/northd/northd.c
index a2cf8d6fc..0a055b519 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -199,6 +199,7 @@ enum ovn_stage {
#define REGBIT_LKUP_FDB "reg0[11]"
#define REGBIT_HAIRPIN_REPLY "reg0[12]"
#define REGBIT_ACL_LABEL "reg0[13]"
+#define REGBIT_FROM_RAMP "reg0[14]"
#define REG_ORIG_DIP_IPV4 "reg1"
#define REG_ORIG_DIP_IPV6 "xxreg1"
@@ -5510,8 +5511,9 @@ build_lswitch_input_port_sec_op(
}
if (!strcmp(op->nbsp->type, "vtep")) {
+ ds_put_format(actions, REGBIT_FROM_RAMP" = 1; ");
ds_put_format(actions, "next(pipeline=ingress, table=%d);",
- ovn_stage_get_table(S_SWITCH_IN_L2_LKUP));
+ ovn_stage_get_table(S_SWITCH_IN_HAIRPIN));
} else {
ds_put_cstr(actions, "next;");
}
@@ -6960,6 +6962,45 @@ build_lb_hairpin(struct ovn_datapath *od, struct hmap *lflows)
}
}
+static void
+build_vtep_hairpin(struct ovn_datapath *od, struct hmap *lflows)
+{
+ /* Ingress Pre-ARP flows for VTEP hairpining traffic. Priority 1000:
+ * Packets that received from non-VTEP ports should continue processing. */
+
+ char *action = xasprintf("next(pipeline=ingress, table=%d);",
+ ovn_stage_get_table(S_SWITCH_IN_L2_LKUP));
+ /* send all traffic from VTEP directly to L2LKP table. */
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_HAIRPIN, 1000,
+ REGBIT_FROM_RAMP" == 1", action);
+ free(action);
+
+ struct ds match = DS_EMPTY_INITIALIZER;
+ int n_ports = od->n_router_ports;
+ bool dp_has_l3dgw_ports = false;
+ for (int i = 0; i < n_ports; i++) {
+ if (is_l3dgw_port(od->router_ports[i]->peer)) {
+ ds_put_format(&match, "%sis_chassis_resident(%s)%s",
+ i == 0 ? REGBIT_FROM_RAMP" == 1 && (" : "",
+ od->router_ports[i]->peer->cr_port->json_key,
+ i < n_ports - 1 ? " || " : ")");
+ dp_has_l3dgw_ports = true;
+ }
+ }
+
+ /* Ingress pre-arp flow for traffic from VTEP (ramp) switch.
+ * Priority 2000: Packets, that were received from VTEP (ramp) switch and
+ * router ports of current datapath are l3dgw ports and they reside on
+ * current chassis, should be passed to next table for ARP/ND hairpin
+ * processing.
+ */
+ if (dp_has_l3dgw_ports) {
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_HAIRPIN, 2000, ds_cstr(&match),
+ "next;");
+ }
+ ds_destroy(&match);
+}
+
/* Build logical flows for the forwarding groups */
static void
build_fwd_group_lflows(struct ovn_datapath *od, struct hmap *lflows)
@@ -7652,6 +7693,7 @@ build_lswitch_lflows_pre_acl_and_acl(struct ovn_datapath *od,
build_qos(od, lflows);
build_stateful(od, lflows);
build_lb_hairpin(od, lflows);
+ build_vtep_hairpin(od, lflows);
}
}
@@ -7680,8 +7722,7 @@ build_lswitch_lflows_admission_control(struct ovn_datapath *od,
}
/* Ingress table 18: ARP/ND responder, skip requests coming from localnet
- * and vtep ports. (priority 100); see ovn-northd.8.xml for the
- * rationale. */
+ * ports. (priority 100); see ovn-northd.8.xml for the rationale. */
static void
build_lswitch_arp_nd_responder_skip_local(struct ovn_port *op,
@@ -7689,8 +7730,7 @@ build_lswitch_arp_nd_responder_skip_local(struct ovn_port *op,
struct ds *match)
{
if (op->nbsp) {
- if ((!strcmp(op->nbsp->type, "localnet")) ||
- (!strcmp(op->nbsp->type, "vtep"))) {
+ if (!strcmp(op->nbsp->type, "localnet")) {
ds_clear(match);
ds_put_format(match, "inport == %s", op->json_key);
ovn_lflow_add_with_lport_and_hint(lflows, op->od,
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
index 4784bff04..08864acfe 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -1094,6 +1094,29 @@
Ingress Table 17: Hairpin
+ -
+ A priority-2000 flow that passes traffic to next table for hairpin ARP
+ processing with
+
next;
action, which matches on:
+
+ -
+
reg0[14]
register bit, that is set in
+ ls_in_port_sec_l2 table for traffic received from HW VTEP (ramp)
+ switch AND
+
+ -
+ all Distrubited Gateway ports, which are associated with current LS
+
router
type LSPs if is_chassis_resident()
+ for them is true.
+
+
+
+ -
+ A priority-1000 flow that matches on
reg0[14]
register
+ bit that is set in ls_in_port_sec_l2 table for traffic received from HW
+ VTEP (ramp) switch. This traffic is passed to ingress table
+ ls_in_l2_lkup.
+
-
A priority-1 flow that hairpins traffic matched by non-default
flows in the Pre-Hairpin table. Hairpinning is done at L2, Ethernet
@@ -1150,27 +1173,27 @@
- Note that ARP requests received from localnet
or
- vtep
logical inports can either go directly to VMs, in
- which case the VM responds or can hit an ARP responder for a logical
- router port if the packet is used to resolve a logical router port
- next hop address. In either case, logical switch ARP responder rules
- will not be hit. It contains these logical flows:
+ Note that ARP requests received from localnet
logical
+ inports can either go directly to VMs, in which case the VM responds or
+ can hit an ARP responder for a logical router port if the packet is used
+ to resolve a logical router port next hop address. In either case,
+ logical switch ARP responder rules will not be hit. It contains these
+ logical flows:
-
Priority-100 flows to skip the ARP responder if inport is of type
-
localnet
or vtep
and advances directly
- to the next table. ARP requests sent to localnet
or
- vtep
ports can be received by multiple hypervisors.
- Now, because the same mac binding rules are downloaded to all
- hypervisors, each of the multiple hypervisors will respond. This
- will confuse L2 learning on the source of the ARP requests. ARP
- requests received on an inport of type router
are not
- expected to hit any logical switch ARP responder flows. However,
- no skip flows are installed for these packets, as there would be
- some additional flow cost for this and the value appears limited.
+ localnet
advances directly to the next table. ARP
+ requests sent to localnet
ports can be received by
+ multiple hypervisors. Now, because the same mac binding rules are
+ downloaded to all hypervisors, each of the multiple hypervisors will
+ respond. This will confuse L2 learning on the source of the ARP
+ requests. ARP requests received on an inport of type
+ router
are not expected to hit any logical switch ARP
+ responder flows. However, no skip flows are installed for these
+ packets, as there would be some additional flow cost for this and the
+ value appears limited.
-
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index 17d4f31b3..eab84886a 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -2592,9 +2592,10 @@ AT_CHECK([ovn-sbctl lflow-list sw0 | grep ls_in_nat_hairpin | sort | sed 's/tabl
table=??(ls_in_nat_hairpin ), priority=90 , match=(ip && reg0[[12]] == 1), action=(ct_snat;)
])
-AT_CHECK([ovn-sbctl lflow-list sw0 | grep ls_in_hairpin | sort | sed 's/table=../table=??/'], [0], [dnl
+AT_CHECK([ovn-sbctl lflow-list sw0 | grep ls_in_hairpin | sort | sed 's/table=../table=??/g'], [0], [dnl
table=??(ls_in_hairpin ), priority=0 , match=(1), action=(next;)
table=??(ls_in_hairpin ), priority=1 , match=((reg0[[6]] == 1 || reg0[[12]] == 1)), action=(eth.dst <-> eth.src; outport = inport; flags.loopback = 1; output;)
+ table=??(ls_in_hairpin ), priority=1000 , match=(reg0[[14]] == 1), action=(next(pipeline=ingress, table=??);)
])
check ovn-nbctl -- ls-lb-del sw0 lb0
@@ -2608,8 +2609,9 @@ AT_CHECK([ovn-sbctl lflow-list sw0 | grep ls_in_nat_hairpin | sort | sed 's/tabl
table=??(ls_in_nat_hairpin ), priority=0 , match=(1), action=(next;)
])
-AT_CHECK([ovn-sbctl lflow-list sw0 | grep ls_in_hairpin | sort | sed 's/table=../table=??/'], [0], [dnl
+AT_CHECK([ovn-sbctl lflow-list sw0 | grep ls_in_hairpin | sort | sed 's/table=../table=??/g'], [0], [dnl
table=??(ls_in_hairpin ), priority=0 , match=(1), action=(next;)
+ table=??(ls_in_hairpin ), priority=1000 , match=(reg0[[14]] == 1), action=(next(pipeline=ingress, table=??);)
])
check ovn-nbctl -- add load_balancer_group $lbg load_balancer $lb0
@@ -2627,9 +2629,10 @@ AT_CHECK([ovn-sbctl lflow-list sw0 | grep ls_in_nat_hairpin | sort | sed 's/tabl
table=??(ls_in_nat_hairpin ), priority=90 , match=(ip && reg0[[12]] == 1), action=(ct_snat;)
])
-AT_CHECK([ovn-sbctl lflow-list sw0 | grep ls_in_hairpin | sort | sed 's/table=../table=??/'], [0], [dnl
+AT_CHECK([ovn-sbctl lflow-list sw0 | grep ls_in_hairpin | sort | sed 's/table=../table=??/g'], [0], [dnl
table=??(ls_in_hairpin ), priority=0 , match=(1), action=(next;)
table=??(ls_in_hairpin ), priority=1 , match=((reg0[[6]] == 1 || reg0[[12]] == 1)), action=(eth.dst <-> eth.src; outport = inport; flags.loopback = 1; output;)
+ table=??(ls_in_hairpin ), priority=1000 , match=(reg0[[14]] == 1), action=(next(pipeline=ingress, table=??);)
])
AT_CLEANUP
diff --git a/tests/ovn.at b/tests/ovn.at
index 166b5f72e..0e24f7abb 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -4023,10 +4023,20 @@ ovn-nbctl lsp-set-addresses lp-vtep unknown
ovn-nbctl lsp-add lsw0 lpr
ovn-nbctl lr-add lr
ovn-nbctl lrp-add lr lrp1 f0:00:00:00:00:f1 192.168.1.1/24
-ovn-nbctl set Logical_Switch_Port lpr type=router \
- options:router-port=lrp1 \
- addresses='"f0:00:00:00:00:f1 192.168.1.1"'
-
+ovn-nbctl set Logical_Switch_Port lpr \
+ type=router \
+ options:router-port=lrp1 \
+ addresses=router
+ovn-nbctl lrp-set-gateway-chassis lrp1 hv1
+
+ovn-nbctl lsp-add lsw0 lpr2
+ovn-nbctl lr-add lr2
+ovn-nbctl lrp-add lr lrp2 f0:00:00:00:00:f2 192.168.1.254/24
+ovn-nbctl set Logical_Switch_Port lpr2 \
+ type=router \
+ options:router-port=lrp2 \
+ addresses=router
+ovn-nbctl lrp-set-gateway-chassis lrp2 hv1
net_add n1 # Network to connect hv1, hv2, and vtep
net_add n2 # Network to connect vtep and hv3
@@ -4147,17 +4157,28 @@ for s in 1 2 3; do
test_packet $s f0000000ffff f0000000000$s 0${s}66 $unknown #3
done
-# ARP request should not be responded to by logical switch router
-# type arp responder on HV1 and HV2 and should reach directly to
-# vif1 and vif2
+# ARP request from VTEP to LRP should be responded by ARP responder.
sha=f00000000003
spa=`ip_to_hex 192 168 1 2`
tpa=`ip_to_hex 192 168 1 1`
request=ffffffffffff${sha}08060001080006040001${sha}${spa}ffffffffffff${tpa}
as hv3 ovs-appctl netdev-dummy/receive vif3 $request
-echo $request >> 1.expected
echo $request >> 2.expected
+lrpmac=f000000000f1
+response=${sha}${lrpmac}08060001080006040002${lrpmac}${tpa}${sha}${spa}
+# since lrp1 has gateway chassis set on hv1, hv1 will suppress arp request and
+# answer with arp reply by OVS directly to vtep lport. all other lports,
+# except lport from which this request was initiated, will receive arp request.
+# we expect arp reply packet on hv3
+echo $response >> 3.expected
+
+AT_CHECK([ovn-sbctl lflow-list lsw0 | grep 'reg0[\[14\]]' | sort | sed 's/table=../table=??/g'], [0], [dnl
+ table=??(ls_in_port_sec_l2 ), priority=50 , match=(inport == "lp-vtep"), action=(reg0[[14]] = 1; next(pipeline=ingress, table=??);)
+ table=??(ls_in_hairpin ), priority=1000 , match=(reg0[[14]] == 1), action=(next(pipeline=ingress, table=??);)
+ table=??(ls_in_hairpin ), priority=2000 , match=(reg0[[14]] == 1 && (is_chassis_resident("cr-lrp1") || is_chassis_resident("cr-lrp2"))), action=(next;)
+])
+
# dump information with counters
echo "------ OVN dump ------"
ovn-nbctl show