From patchwork Wed Jun 14 13:17:11 2023
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Lorenzo Bianconi
X-Patchwork-Id: 1794962
Return-Path:
X-Original-To: incoming@patchwork.ozlabs.org
Delivered-To: patchwork-incoming@legolas.ozlabs.org
Authentication-Results: legolas.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=)
Authentication-Results: legolas.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=LPhILfhk;
dkim-atps=neutral
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 ECDSA (P-384) server-digest SHA384)
(No client certificate requested)
by legolas.ozlabs.org (Postfix) with ESMTPS id 4Qh5Z53V11z20QH
for ; Wed, 14 Jun 2023 23:17:33 +1000 (AEST)
Received: from localhost (localhost [127.0.0.1])
by smtp4.osuosl.org (Postfix) with ESMTP id 21BA44194E;
Wed, 14 Jun 2023 13:17:30 +0000 (UTC)
DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 21BA44194E
Authentication-Results: smtp4.osuosl.org;
dkim=fail reason="signature verification failed" (1024-bit key)
header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256
header.s=mimecast20190719 header.b=LPhILfhk
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 teClSGyheZ-L; Wed, 14 Jun 2023 13:17:28 +0000 (UTC)
Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56])
by smtp4.osuosl.org (Postfix) with ESMTPS id A24EC41B31;
Wed, 14 Jun 2023 13:17:27 +0000 (UTC)
DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org A24EC41B31
Received: from lf-lists.osuosl.org (localhost [127.0.0.1])
by lists.linuxfoundation.org (Postfix) with ESMTP id 5D2CDC007A;
Wed, 14 Jun 2023 13:17:27 +0000 (UTC)
X-Original-To: ovs-dev@openvswitch.org
Delivered-To: ovs-dev@lists.linuxfoundation.org
Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133])
by lists.linuxfoundation.org (Postfix) with ESMTP id 6BD8DC0029
for ; Wed, 14 Jun 2023 13:17:26 +0000 (UTC)
Received: from localhost (localhost [127.0.0.1])
by smtp2.osuosl.org (Postfix) with ESMTP id 31A24405FD
for ; Wed, 14 Jun 2023 13:17:26 +0000 (UTC)
DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 31A24405FD
Authentication-Results: smtp2.osuosl.org;
dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com
header.a=rsa-sha256 header.s=mimecast20190719 header.b=LPhILfhk
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 PvoME14Fw0AF for ;
Wed, 14 Jun 2023 13:17:24 +0000 (UTC)
X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0
DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org AB74E40550
Received: from us-smtp-delivery-124.mimecast.com
(us-smtp-delivery-124.mimecast.com [170.10.133.124])
by smtp2.osuosl.org (Postfix) with ESMTPS id AB74E40550
for ; Wed, 14 Jun 2023 13:17:24 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;
s=mimecast20190719; t=1686748643;
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;
bh=WHkOlkKWFkrZpxVNDoZpmzOWe7Ru0Iq38ZO6wi9eKx8=;
b=LPhILfhkXPS7nm0SHBy09VL7V0Zf68mnKPnXAlHaQ0m2pcmqMv9r7jIfh7+F/u13derPRf
vw4cRJR1ueTKhgApGZIJz9DzCTRDm5bbEOLsK2Z3bVOizieejt7KNwzk6w7WiWlI8TGjrv
fh0gONCvocVLixMgI648Ak8jBDqzn/g=
Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com
[209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS
(version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id
us-mta-138-2zaz-nj8MryCVxpp0Ag6Aw-1; Wed, 14 Jun 2023 09:17:22 -0400
X-MC-Unique: 2zaz-nj8MryCVxpp0Ag6Aw-1
Received: by mail-wm1-f70.google.com with SMTP id
5b1f17b1804b1-3f5ec8aac77so4388435e9.3
for ; Wed, 14 Jun 2023 06:17:19 -0700 (PDT)
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20221208; t=1686748639; x=1689340639;
h=content-transfer-encoding:mime-version:message-id:date:subject:cc
:to:from:x-gm-message-state:from:to:cc:subject:date:message-id
:reply-to;
bh=WHkOlkKWFkrZpxVNDoZpmzOWe7Ru0Iq38ZO6wi9eKx8=;
b=ieetu8NrAai5M/d6fsFUz7erHr7Ux4kEAawDkQuRchTwanLfuX0lgMOi2tb2Ww0JdT
YgM57vGkyIf+SaE26bd9WnOwQOWjCgD3snUK0yyGtAPeUAMgwOASUlkW46sCBxBYMYMr
oB9sjNFfWyXZRQlvJiPtFm7Yq7orOJ/a+xXkSOns/lXSyWSZfyxneceKq6NubNbtrM1x
DUM5vOF0aFN18BU/PEU4UfrslLk3a7NSa5jL1JVru7fFwjUEg9njREZ30QeXdq88SuZP
7LyNvEL5YmBmaPOyVnspZK0lRu6uDUCYbB9nptvwIg/1If7XcBAABo5+BVjJcp30NyRs
tE+w==
X-Gm-Message-State: AC+VfDxlA7PoSlxKlK86UweOv3caHvm9BlRNSoIScFqbStwv5R5PQQQZ
V9iCripODTybbONkzoVksFid8hN9Nteg2B+Jh0/duNWaECimodOp75jkiEndmnTd2C+2DsuGLmG
ZvLKxygJtbUXmlwh3HM3M/0NSZL2wxIlPdvadtehSMX8xf1DBDcXwkDIbiajEVG35zwCpnakFec
vI9Pyni+xsTsKv
X-Received: by 2002:a05:600c:211:b0:3f6:906:1195 with SMTP id
17-20020a05600c021100b003f609061195mr12057339wmi.35.1686748638518;
Wed, 14 Jun 2023 06:17:18 -0700 (PDT)
X-Google-Smtp-Source:
ACHHUZ4QlXK2D2b4QTlJ0OVbQwRDUJidXgRV1OV94DwFRfCSr69RhSSNDqklR60pPT80v2BN+deCeQ==
X-Received: by 2002:a05:600c:211:b0:3f6:906:1195 with SMTP id
17-20020a05600c021100b003f609061195mr12057302wmi.35.1686748637875;
Wed, 14 Jun 2023 06:17:17 -0700 (PDT)
Received: from localhost (net-130-25-106-149.cust.vodafonedsl.it.
[130.25.106.149]) by smtp.gmail.com with ESMTPSA id
26-20020a05600c029a00b003f7298a32ccsm17461878wmk.41.2023.06.14.06.17.17
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Wed, 14 Jun 2023 06:17:17 -0700 (PDT)
From: Lorenzo Bianconi
To: ovs-dev@openvswitch.org
Date: Wed, 14 Jun 2023 15:17:11 +0200
Message-Id:
<27eb277a456f7779dc527bc2b824ac931d41200b.1686747555.git.lorenzo.bianconi@redhat.com>
X-Mailer: git-send-email 2.40.1
MIME-Version: 1.0
X-Mimecast-Spam-Score: 0
X-Mimecast-Originator: redhat.com
Cc: i.maximets@ovn.org, dceara@redhat.com
Subject: [ovs-dev] [PATCH v6 ovn] northd: centralized reply lb traffic even
if FIP is defined
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"
In the current codebase for distributed gw router port use-case,
it is not possible to add a load balancer that redirects the traffic
to a back-end if it is used as internal IP of a FIP NAT rule since
the reply traffic is never centralized. Fix the issue centralizing the
traffic if it is the reply packet for the load balancer.
Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2023609
Acked-by: Mark Michelson
Reviewed-by: Simon Horman
Signed-off-by: Lorenzo Bianconi
---
Changes since v5:
- rely on fmt_pkt macro in unit-tests
Changes since v4:
- improve memory footprint
Changes since v3:
- add ovn unit-test and get rid of system-ovn unit-test.
- minor changes in ovn-northd unit-test.
Changes since v2:
- rebase on top of ovn main branch
- fix spelling
Changes since v1:
- add new system-test and unit-test
---
northd/northd.c | 20 ++++++-
northd/ovn-northd.8.xml | 16 ++++++
tests/ovn-northd.at | 50 +++++++++++++++++
tests/ovn.at | 117 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 202 insertions(+), 1 deletion(-)
diff --git a/northd/northd.c b/northd/northd.c
index d073c0b75..93ac644ad 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -11232,6 +11232,7 @@ struct lrouter_nat_lb_flows_ctx {
struct ds *new_match;
struct ds *undnat_match;
+ struct ds *gw_redir_action;
struct ovn_lb_vip *lb_vip;
struct ovn_northd_lb *lb;
@@ -11299,6 +11300,20 @@ build_distr_lrouter_nat_flows_for_lb(struct lrouter_nat_lb_flows_ctx *ctx,
return;
}
+ /* We need to centralize the LB traffic to properly perform
+ * the undnat stage.
+ */
+ ds_put_format(ctx->undnat_match, ") && outport == %s", dgp->json_key);
+ ds_clear(ctx->gw_redir_action);
+ ds_put_format(ctx->gw_redir_action, "outport = %s; next;",
+ dgp->cr_port->json_key);
+
+ ovn_lflow_add_with_hint(ctx->lflows, od, S_ROUTER_IN_GW_REDIRECT,
+ 200, ds_cstr(ctx->undnat_match),
+ ds_cstr(ctx->gw_redir_action),
+ &ctx->lb->nlb->header_);
+ ds_truncate(ctx->undnat_match, undnat_match_len);
+
ds_put_format(ctx->undnat_match, ") && (inport == %s || outport == %s)"
" && is_chassis_resident(%s)", dgp->json_key, dgp->json_key,
dgp->cr_port->json_key);
@@ -11369,6 +11384,7 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
struct ds force_snat_act = DS_EMPTY_INITIALIZER;
struct ds undnat_match = DS_EMPTY_INITIALIZER;
struct ds unsnat_match = DS_EMPTY_INITIALIZER;
+ struct ds gw_redir_action = DS_EMPTY_INITIALIZER;
ds_clear(match);
ds_clear(action);
@@ -11427,7 +11443,8 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
.lflows = lflows,
.meter_groups = meter_groups,
.new_match = match,
- .undnat_match = &undnat_match
+ .undnat_match = &undnat_match,
+ .gw_redir_action = &gw_redir_action,
};
ctx.new_action[LROUTER_NAT_LB_FLOW_NORMAL] = ds_cstr(action);
@@ -11521,6 +11538,7 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
ds_destroy(&undnat_match);
ds_destroy(&skip_snat_act);
ds_destroy(&force_snat_act);
+ ds_destroy(&gw_redir_action);
for (size_t i = 0; i < LROUTER_NAT_LB_FLOW_MAX + 2; i++) {
bitmap_free(dp_bitmap[i]);
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
index 8164be300..532c428e9 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -4582,6 +4582,22 @@ icmp6 {
+ -
+ For all the configured load balancing rules that include an IPv4
+ address VIP, and a list of IPv4 backend addresses
+ B0, B1 .. Bn defined for the
+ VIP a priority-200 flow is added that matches
+ ip4 && (ip4.src == B0 || ip4.src == B1
+ || ... || ip4.src == Bn)
with an action
+ outport = CR; next;
where CR is the
+ chassisredirect
port representing the instance of the
+ logical router distributed gateway port on the gateway chassis.
+ If the backend IPv4 address Bx is also configured with
+ L4 port PORT of protocol P, then the match
+ also includes P.src
== PORT.
+ Similar flows are added for IPv6.
+
+
-
For each NAT rule in the OVN Northbound database that can
be handled in a distributed manner, a priority-100 logical
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index 9f2f15abc..22c124f90 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -9541,3 +9541,53 @@ AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats northd recom
OVN_CLEANUP([hv1])
AT_CLEANUP
])
+
+OVN_FOR_EACH_NORTHD_NO_HV([
+AT_SETUP([check fip and lb flows])
+AT_KEYWORDS([fip-lb-flows])
+ovn_start
+
+check ovn-nbctl lr-add R1
+check ovn-nbctl lrp-add R1 R1-S0 02:ac:10:01:00:01 10.0.0.1/24 1000::a/64
+check ovn-nbctl lrp-add R1 R1-PUB 02:ac:20:01:01:01 172.16.0.1/24 3000::a/64
+check ovn-nbctl lrp-set-gateway-chassis R1-PUB hv1 20
+
+check ovn-nbctl ls-add S0
+check ovn-nbctl lsp-add S0 S0-R1
+check ovn-nbctl lsp-set-type S0-R1 router
+check ovn-nbctl lsp-set-addresses S0-R1 02:ac:10:01:00:01
+check ovn-nbctl lsp-set-options S0-R1 router-port=R1-S0
+check ovn-nbctl lsp-add S0 S0-P0
+check ovn-nbctl lsp-set-addresses S0-P0 "50:54:00:00:00:03 10.0.0.3 1000::3"
+
+check ovn-nbctl lr-nat-add R1 dnat_and_snat 172.16.0.110 10.0.0.3 S0-P0 30:54:00:00:00:03
+check ovn-nbctl lr-nat-add R1 dnat_and_snat 3000::c 1000::3 S0-P0 40:54:00:00:00:03
+
+ovn-sbctl dump-flows R1 > R1flows
+AT_CAPTURE_FILE([R1flows])
+
+AT_CHECK([grep "lr_in_gw_redirect" R1flows | sed s'/table=../table=??/' |sort], [0], [dnl
+ table=??(lr_in_gw_redirect ), priority=0 , match=(1), action=(next;)
+ table=??(lr_in_gw_redirect ), priority=100 , match=(ip4.src == 10.0.0.3 && outport == "R1-PUB" && is_chassis_resident("S0-P0")), action=(eth.src = 30:54:00:00:00:03; reg1 = 172.16.0.110; next;)
+ table=??(lr_in_gw_redirect ), priority=100 , match=(ip6.src == 1000::3 && outport == "R1-PUB" && is_chassis_resident("S0-P0")), action=(eth.src = 40:54:00:00:00:03; xxreg1 = 3000::c; next;)
+ table=??(lr_in_gw_redirect ), priority=50 , match=(outport == "R1-PUB"), action=(outport = "cr-R1-PUB"; next;)
+])
+
+check ovn-nbctl lb-add lb_tcp4 172.16.0.100:50001 10.0.0.2:50001,10.0.0.3:50001,10.0.0.4:50001 tcp
+check ovn-nbctl lb-add lb_tcp6 [[1000::1]]:50001 [[1000::3]]:8080
+check ovn-nbctl --wait=sb lr-lb-add R1 lb_tcp4
+check ovn-nbctl --wait=sb lr-lb-add R1 lb_tcp6
+
+ovn-sbctl dump-flows R1 > R1flows
+AT_CAPTURE_FILE([R1flows])
+AT_CHECK([grep "lr_in_gw_redirect" R1flows |sed s'/table=../table=??/' |sort], [0], [dnl
+ table=??(lr_in_gw_redirect ), priority=0 , match=(1), action=(next;)
+ table=??(lr_in_gw_redirect ), priority=100 , match=(ip4.src == 10.0.0.3 && outport == "R1-PUB" && is_chassis_resident("S0-P0")), action=(eth.src = 30:54:00:00:00:03; reg1 = 172.16.0.110; next;)
+ table=??(lr_in_gw_redirect ), priority=100 , match=(ip6.src == 1000::3 && outport == "R1-PUB" && is_chassis_resident("S0-P0")), action=(eth.src = 40:54:00:00:00:03; xxreg1 = 3000::c; next;)
+ table=??(lr_in_gw_redirect ), priority=200 , match=(ip4 && ((ip4.src == 10.0.0.2 && tcp.src == 50001) || (ip4.src == 10.0.0.3 && tcp.src == 50001) || (ip4.src == 10.0.0.4 && tcp.src == 50001)) && outport == "R1-PUB"), action=(outport = "cr-R1-PUB"; next;)
+ table=??(lr_in_gw_redirect ), priority=200 , match=(ip6 && ((ip6.src == 1000::3 && tcp.src == 8080)) && outport == "R1-PUB"), action=(outport = "cr-R1-PUB"; next;)
+ table=??(lr_in_gw_redirect ), priority=50 , match=(outport == "R1-PUB"), action=(outport = "cr-R1-PUB"; next;)
+])
+
+AT_CLEANUP
+])
diff --git a/tests/ovn.at b/tests/ovn.at
index e49148411..f94e5d155 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -36244,3 +36244,120 @@ wait_row_count fdb 0 mac='"00:00:00:00:10:20"'
OVN_CLEANUP([hv1])
AT_CLEANUP
])
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([DNAT_SNAT and LB traffic])
+AT_KEYWORDS([dnat-snat-lb])
+ovn_start
+
+test_ip_req_packet() {
+ local src_mac="50:54:00:00:00:88"
+ local dst_mac="$1"
+ local src_ip="172.168.0.200"
+ local dst_ip="$2"
+
+ local packet=$(fmt_pkt "Ether(dst='${dst_mac}', src='${src_mac}')/
+ IP(dst='${dst_ip}', src='${src_ip}')/ \
+ UDP(sport=53, dport=4369)")
+
+ as hv1 reset_pcap_file hv1-vif1 hv1/vif1
+ as hv2 reset_pcap_file hv2-vif1 hv2/vif1
+ check as hv2 ovs-appctl netdev-dummy/receive hv2-vif1 $packet
+}
+
+test_ip_rep_packet() {
+ local src_mac="50:54:00:00:00:01"
+ local dst_mac="00:00:00:00:ff:01"
+ local src_ip="10.0.0.2"
+ local dst_ip="172.168.0.200"
+
+ local packet=$(fmt_pkt "Ether(dst='${dst_mac}', src='${src_mac}')/
+ IP(dst='${dst_ip}', src='${src_ip}')/ \
+ UDP(sport=4369, dport=53)")
+
+ check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet
+}
+
+net_add n
+
+sim_add hv1
+as hv1
+check ovs-vsctl add-br br-phys
+ovn_attach n br-phys 192.168.0.1
+check ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
+check ovs-vsctl -- add-port br-int hv1-vif1 -- \
+ set interface hv1-vif1 external-ids:iface-id=sw0-port1 \
+ options:tx_pcap=hv1/vif1-tx.pcap \
+ options:rxq_pcap=hv1/vif1-rx.pcap
+
+sim_add hv2
+as hv2
+check ovs-vsctl add-br br-phys
+ovn_attach n br-phys 192.168.0.2
+check ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
+check ovs-vsctl -- add-port br-int hv2-vif1 -- \
+ set interface hv2-vif1 external-ids:iface-id=public-port1 \
+ options:tx_pcap=hv2/vif1-tx.pcap \
+ options:rxq_pcap=hv2/vif1-rx.pcap
+
+check ovn-nbctl ls-add sw0
+check ovn-nbctl lsp-add sw0 sw0-port1
+check ovn-nbctl lsp-set-addresses sw0-port1 "50:54:00:00:00:01 10.0.0.2"
+
+check ovn-nbctl ls-add public
+check ovn-nbctl lsp-add public ln-public
+check ovn-nbctl lsp-set-type ln-public localnet
+check ovn-nbctl lsp-set-addresses ln-public unknown
+check ovn-nbctl lsp-set-options ln-public network_name=phys
+check ovn-nbctl lsp-add public public-port1
+check ovn-nbctl lsp-set-addresses public-port1 "50:54:00:00:00:88 172.168.0.200"
+
+check ovn-nbctl lr-add lr0
+check ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24
+check ovn-nbctl lsp-add sw0 sw0-lr0
+check ovn-nbctl lsp-set-type sw0-lr0 router
+check ovn-nbctl lsp-set-addresses sw0-lr0 router
+check ovn-nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0
+check ovn-nbctl lrp-add lr0 lr0-public 00:00:20:20:12:13 172.168.0.1/24
+check ovn-nbctl lsp-add public public-lr0
+check ovn-nbctl lsp-set-type public-lr0 router
+check ovn-nbctl lsp-set-addresses public-lr0 router
+check ovn-nbctl lsp-set-options public-lr0 router-port=lr0-public
+
+check ovn-nbctl lrp-set-gateway-chassis lr0-public hv2 20
+
+check ovn-nbctl lr-nat-add lr0 snat 172.168.0.1 10.0.0.0/24
+check ovn-nbctl lr-nat-add lr0 dnat_and_snat 172.168.0.110 10.0.0.2 sw0-port1 f0:00:00:01:02:03
+
+wait_for_ports_up
+OVN_POPULATE_ARP
+
+# send UDP request to the FIP associated to sw0-port1
+test_ip_req_packet "f0:00:00:01:02:03" "172.168.0.110"
+OVS_WAIT_UNTIL([test $($PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap | wc -l) -ge 1])
+# send UDP reply from sw0-port1
+test_ip_rep_packet
+# packet sent by the FIP
+fip_packet=$(fmt_pkt "Ether(dst='50:54:00:00:00:88', src='f0:00:00:01:02:03')/
+ IP(dst='172.168.0.200', src='172.168.0.110', ttl=63)/ \
+ UDP(sport=4369, dport=53)")
+echo $fip_packet > expected
+OVN_CHECK_PACKETS_REMOVE_BROADCAST([hv2/vif1-tx.pcap], [expected])
+
+check ovn-nbctl lb-add lb0 172.168.0.1:4369 10.0.0.2:4369 udp
+check ovn-nbctl lr-lb-add lr0 lb0
+
+# send UDP request to the load-balancer VIP
+test_ip_req_packet "00:00:20:20:12:13" "172.168.0.1"
+OVS_WAIT_UNTIL([test $($PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap | wc -l) -ge 1])
+# send UDP reply from sw0-port1
+test_ip_rep_packet
+# packet sent by the load balancer VIP
+packet=$(fmt_pkt "Ether(dst='50:54:00:00:00:88', src='00:00:20:20:12:13')/
+ IP(dst='172.168.0.200', src='172.168.0.1', ttl=63)/ \
+ UDP(sport=4369, dport=53)")
+echo $packet > expected
+OVN_CHECK_PACKETS_REMOVE_BROADCAST([hv2/vif1-tx.pcap], [expected])
+
+AT_CLEANUP
+])