From patchwork Wed Jul 27 09:15:54 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chandra S Vejendla X-Patchwork-Id: 653215 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from archives.nicira.com (archives.nicira.com [96.126.127.54]) by ozlabs.org (Postfix) with ESMTP id 3rzq9S1pjlz9t23 for ; Wed, 27 Jul 2016 19:16:11 +1000 (AEST) Received: from archives.nicira.com (localhost [127.0.0.1]) by archives.nicira.com (Postfix) with ESMTP id D434A10E0E; Wed, 27 Jul 2016 02:16:09 -0700 (PDT) X-Original-To: dev@openvswitch.org Delivered-To: dev@openvswitch.org Received: from mx1e3.cudamail.com (mx1.cudamail.com [69.90.118.67]) by archives.nicira.com (Postfix) with ESMTPS id C3E5310E0C for ; Wed, 27 Jul 2016 02:16:08 -0700 (PDT) Received: from bar5.cudamail.com (localhost [127.0.0.1]) by mx1e3.cudamail.com (Postfix) with ESMTPS id 0ACEB420441 for ; Wed, 27 Jul 2016 03:16:08 -0600 (MDT) X-ASG-Debug-ID: 1469610966-09eadd7ae9c4160001-byXFYA Received: from mx1-pf1.cudamail.com ([192.168.24.1]) by bar5.cudamail.com with ESMTP id ldAAMAJextv88AYY (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Wed, 27 Jul 2016 03:16:06 -0600 (MDT) X-Barracuda-Envelope-From: chandra@Jarvis.local X-Barracuda-RBL-Trusted-Forwarder: 192.168.24.1 Received: from unknown (HELO mx0a-001b2d01.pphosted.com) (148.163.156.1) by mx1-pf1.cudamail.com with ESMTPS (AES256-SHA encrypted); 27 Jul 2016 09:16:06 -0000 Received-SPF: none (mx1-pf1.cudamail.com: domain at Jarvis.local does not designate permitted sender hosts) X-Barracuda-Apparent-Source-IP: 148.163.156.1 X-Barracuda-RBL-IP: 148.163.156.1 Received: from pps.filterd (m0098393.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.11/8.16.0.11) with SMTP id u6R9EcDs034313 for ; Wed, 27 Jul 2016 05:16:04 -0400 Received: from e38.co.us.ibm.com (e38.co.us.ibm.com [32.97.110.159]) by mx0a-001b2d01.pphosted.com with ESMTP id 24dyqpmc1v-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Wed, 27 Jul 2016 05:16:04 -0400 Received: from localhost by e38.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Wed, 27 Jul 2016 03:16:01 -0600 Received: from d03dlp02.boulder.ibm.com (9.17.202.178) by e38.co.us.ibm.com (192.168.1.138) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Wed, 27 Jul 2016 03:15:59 -0600 X-IBM-Helo: d03dlp02.boulder.ibm.com X-IBM-MailFrom: chandra@Jarvis.local Received: from b03cxnp07028.gho.boulder.ibm.com (b03cxnp07028.gho.boulder.ibm.com [9.17.130.15]) by d03dlp02.boulder.ibm.com (Postfix) with ESMTP id 0657C3E40041 for ; Wed, 27 Jul 2016 03:15:59 -0600 (MDT) Received: from d03av01.boulder.ibm.com (d03av01.boulder.ibm.com [9.17.195.167]) by b03cxnp07028.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id u6R9FwDN14483884 for ; Wed, 27 Jul 2016 02:15:58 -0700 Received: from d03av01.boulder.ibm.com (localhost [127.0.0.1]) by d03av01.boulder.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id u6R9FwFd029766 for ; Wed, 27 Jul 2016 03:15:58 -0600 Received: from Jarvis.local ([9.80.196.56]) by d03av01.boulder.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id u6R9Fvt0029763 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Wed, 27 Jul 2016 03:15:58 -0600 Received: by Jarvis.local (Postfix, from userid 501) id 8282A1262CD6; Wed, 27 Jul 2016 02:15:56 -0700 (PDT) X-CudaMail-Envelope-Sender: chandra@jarvis.local From: Chandra S Vejendla To: dev@openvswitch.org X-CudaMail-MID: CM-E1-726003399 X-CudaMail-DTE: 072716 X-CudaMail-Originating-IP: 148.163.156.1 Date: Wed, 27 Jul 2016 02:15:54 -0700 X-ASG-Orig-Subj: [##CM-E1-726003399##][PATCH v2] ovn: Support for GARP for NAT IPs via localnet X-Mailer: git-send-email 2.6.1 X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 16072709-0028-0000-0000-0000054031F8 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 16072709-0029-0000-0000-00002DE27E77 Message-Id: <1469610954-72643-1-git-send-email-csvejend@us.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2016-07-27_06:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 suspectscore=43 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1604210000 definitions=main-1607270096 X-Barracuda-Connect: UNKNOWN[192.168.24.1] X-Barracuda-Start-Time: 1469610966 X-Barracuda-Encrypted: ECDHE-RSA-AES256-GCM-SHA384 X-Barracuda-URL: https://web.cudamail.com:443/cgi-mod/mark.cgi X-Virus-Scanned: by bsmtpd at cudamail.com X-Barracuda-BRTS-Status: 1 X-Barracuda-Spam-Score: 1.10 X-Barracuda-Spam-Status: No, SCORE=1.10 using global scores of TAG_LEVEL=3.5 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=4.0 tests=BSF_RULE7568M, BSF_SC5_MJ1963, RDNS_NONE X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.3.31550 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- 0.50 BSF_RULE7568M Custom Rule 7568M 0.10 RDNS_NONE Delivered to trusted network by a host with no rDNS 0.50 BSF_SC5_MJ1963 Custom Rule MJ1963 Subject: [ovs-dev] [PATCH v2] ovn: Support for GARP for NAT IPs via localnet X-BeenThere: dev@openvswitch.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dev-bounces@openvswitch.org Sender: "dev" In cases where a DNAT IP is moved to a new router or the SNAT IP is reused with a new mac address, the NAT IPs become unreachable because the external switches/routers have stale ARP entries. This commit aims to fix the problem by sending GARPs for NAT IPs via locanet A new options key "nat-addresses" is added to the logical switch port of type router. The value for the key "nat-addresses" is the MAC address of the port followed by a list of SNAT & DNAT IPs. Signed-off-by: Chandra Sekhar Vejendla --- ovn/controller/binding.c | 6 ++ ovn/controller/ovn-controller.8.xml | 18 +++++- ovn/controller/patch.c | 8 ++- ovn/controller/physical.c | 6 ++ ovn/controller/pinctrl.c | 124 ++++++++++++++++++++++++++++++++---- ovn/northd/ovn-northd.c | 6 ++ ovn/ovn-nb.xml | 10 +++ tests/ovn.at | 49 ++++++++++++++ 8 files changed, 212 insertions(+), 15 deletions(-) diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c index e83c1d5..3139590 100644 --- a/ovn/controller/binding.c +++ b/ovn/controller/binding.c @@ -218,6 +218,12 @@ consider_local_datapath(struct controller_ctx *ctx, sbrec_port_binding_set_chassis(binding_rec, chassis_rec); add_local_datapath(local_datapaths, binding_rec); } + } else if (!strcmp(binding_rec->type, "gateway")) { + const char *chassis = smap_get(&binding_rec->options, + "gateway-chassis"); + if (!strcmp(chassis, chassis_rec->name) && ctx->ovnsb_idl_txn) { + add_local_datapath(local_datapaths, binding_rec); + } } else if (chassis_rec && binding_rec->chassis == chassis_rec && strcmp(binding_rec->type, "gateway")) { if (ctx->ovnsb_idl_txn) { diff --git a/ovn/controller/ovn-controller.8.xml b/ovn/controller/ovn-controller.8.xml index 3fda8e7..713045c 100644 --- a/ovn/controller/ovn-controller.8.xml +++ b/ovn/controller/ovn-controller.8.xml @@ -208,7 +208,7 @@ ovn-controller to connect the integration bridge and another bridge to implement a l2gateway logical port. Its value is the name of the logical port with type - set to l3gateway that the port implements. See + set to l2gateway that the port implements. See external_ids:ovn-bridge-mappings, above, for more information.

@@ -222,6 +222,22 @@
+ external-ids:ovn-l3gateway-port in the Port + table +
+ +
+

+ This key identifies a patch port as one created by + ovn-controller to implement a l3gateway + logical port. Its value is the name of the logical port with type + set to l3gateway. This patch port is similar to + the OVN logical patch port, except that l3gateway + port can only be bound to a paticular chassis. +

+
+ +
external-ids:ovn-logical-patch-port in the Port table
diff --git a/ovn/controller/patch.c b/ovn/controller/patch.c index 707d08b..4dc0d71 100644 --- a/ovn/controller/patch.c +++ b/ovn/controller/patch.c @@ -345,12 +345,14 @@ add_logical_patch_ports(struct controller_ctx *ctx, const struct sbrec_port_binding *binding; SBREC_PORT_BINDING_FOR_EACH (binding, ctx->ovnsb_idl) { + const char *patch_port_id = "ovn-logical-patch-port"; bool local_port = false; if (!strcmp(binding->type, "gateway")) { const char *chassis = smap_get(&binding->options, "gateway-chassis"); if (chassis && !strcmp(local_chassis_id, chassis)) { local_port = true; + patch_port_id = "ovn-l3gateway-port"; } } @@ -363,7 +365,7 @@ add_logical_patch_ports(struct controller_ctx *ctx, char *src_name = patch_port_name(local, peer); char *dst_name = patch_port_name(peer, local); - create_patch_port(ctx, "ovn-logical-patch-port", local, + create_patch_port(ctx, patch_port_id, local, br_int, src_name, br_int, dst_name, existing_ports); free(dst_name); @@ -394,6 +396,7 @@ patch_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int, OVSREC_PORT_FOR_EACH (port, ctx->ovs_idl) { if (smap_get(&port->external_ids, "ovn-localnet-port") || smap_get(&port->external_ids, "ovn-l2gateway-port") + || smap_get(&port->external_ids, "ovn-l3gateway-port") || smap_get(&port->external_ids, "ovn-logical-patch-port")) { shash_add(&existing_ports, port->name, port); } @@ -402,7 +405,8 @@ patch_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int, /* Create in the database any patch ports that should exist. Remove from * 'existing_ports' any patch ports that do exist in the database and * should be there. */ - add_bridge_mappings(ctx, br_int, &existing_ports, local_datapaths, chassis_id); + add_bridge_mappings(ctx, br_int, &existing_ports, local_datapaths, + chassis_id); add_logical_patch_ports(ctx, br_int, chassis_id, &existing_ports, patched_datapaths); diff --git a/ovn/controller/physical.c b/ovn/controller/physical.c index a104e33..fd40720 100644 --- a/ovn/controller/physical.c +++ b/ovn/controller/physical.c @@ -623,6 +623,8 @@ physical_run(struct controller_ctx *ctx, enum mf_field_id mff_ovn_geneve, "ovn-localnet-port"); const char *l2gateway = smap_get(&port_rec->external_ids, "ovn-l2gateway-port"); + const char *l3gateway = smap_get(&port_rec->external_ids, + "ovn-l3gateway-port"); const char *logpatch = smap_get(&port_rec->external_ids, "ovn-logical-patch-port"); @@ -649,6 +651,10 @@ physical_run(struct controller_ctx *ctx, enum mf_field_id mff_ovn_geneve, /* L2 gateway patch ports can be handled just like VIFs. */ simap_put(&new_localvif_to_ofport, l2gateway, ofport); break; + } else if (is_patch && l3gateway) { + /* L3 gateway patch ports can be handled just like VIFs. */ + simap_put(&new_localvif_to_ofport, l3gateway, ofport); + break; } else if (is_patch && logpatch) { /* Logical patch ports can be handled just like VIFs. */ simap_put(&new_localvif_to_ofport, logpatch, ofport); diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c index 0ae6501..174bbfb 100644 --- a/ovn/controller/pinctrl.c +++ b/ovn/controller/pinctrl.c @@ -712,7 +712,8 @@ destroy_send_garps(void) /* Add or update a vif for which GARPs need to be announced. */ static void send_garp_update(const struct sbrec_port_binding *binding_rec, - struct simap *localnet_ofports, struct hmap *local_datapaths) + struct simap *localnet_ofports, struct hmap *local_datapaths, + struct shash *nat_addresses) { /* Find the localnet ofport to send this GARP. */ struct local_datapath *ld @@ -724,9 +725,44 @@ send_garp_update(const struct sbrec_port_binding *binding_rec, ofp_port_t ofport = u16_to_ofp(simap_get(localnet_ofports, ld->localnet_port->logical_port)); - /* Update GARP if it exists. */ - struct garp_data *garp = shash_find_data(&send_garp_data, - binding_rec->logical_port); + volatile struct garp_data *garp = NULL; + /* Update GARP for NAT IP if it exists. */ + if (!strcmp(binding_rec->type, "gateway")) { + struct lport_addresses *laddrs = NULL; + laddrs = shash_find_data(nat_addresses, binding_rec->logical_port); + if (!laddrs) { + return; + } + int i; + for (i = 0; i < laddrs->n_ipv4_addrs; i++) { + char *name = xasprintf("%s-%s", binding_rec->logical_port, + laddrs->ipv4_addrs[i].addr_s); + garp = shash_find_data(&send_garp_data, name); + free(name); + + if (garp) { + garp->ofport = ofport; + continue; + } + else { + struct garp_data *garp = xmalloc(sizeof *garp); + garp->ea = laddrs->ea; + garp->ipv4 = laddrs->ipv4_addrs[i].addr; + garp->announce_time = time_msec() + 1000; + garp->backoff = 1; + garp->ofport = ofport; + char *name = xasprintf("%s-%s", binding_rec->logical_port, + laddrs->ipv4_addrs[i].addr_s); + shash_add(&send_garp_data, name, garp); + free(name); + } + } + destroy_lport_addresses(laddrs); + return; + } + + /* Update GARP for vif if it exists. */ + garp = shash_find_data(&send_garp_data, binding_rec->logical_port); if (garp) { garp->ofport = ofport; return; @@ -806,14 +842,15 @@ send_garp(struct garp_data *garp, long long int current_time) return garp->announce_time; } -/* Get localnet vifs, and ofport for localnet patch ports. */ +/* Get localnet vifs, local l3gw ports and ofport for localnet patch ports. */ static void -get_localnet_vifs(const struct ovsrec_bridge *br_int, +get_localnet_vifs_l3gwports(const struct ovsrec_bridge *br_int, const char *this_chassis_id, const struct lport_index *lports, struct hmap *local_datapaths, struct sset *localnet_vifs, - struct simap *localnet_ofports) + struct simap *localnet_ofports, + struct sset *local_l3gw_ports) { for (int i = 0; i < br_int->n_ports; i++) { const struct ovsrec_port *port_rec = br_int->ports[i]; @@ -827,6 +864,8 @@ get_localnet_vifs(const struct ovsrec_bridge *br_int, } const char *localnet = smap_get(&port_rec->external_ids, "ovn-localnet-port"); + const char *l3_gateway_port = smap_get(&port_rec->external_ids, + "ovn-l3gateway-port"); for (int j = 0; j < port_rec->n_interfaces; j++) { const struct ovsrec_interface *iface_rec = port_rec->interfaces[j]; if (!iface_rec->n_ofport) { @@ -840,6 +879,10 @@ get_localnet_vifs(const struct ovsrec_bridge *br_int, simap_put(localnet_ofports, localnet, ofport); continue; } + if (l3_gateway_port) { + sset_add(local_l3gw_ports, l3_gateway_port); + continue; + } const char *iface_id = smap_get(&iface_rec->external_ids, "iface-id"); if (!iface_id) { @@ -861,6 +904,41 @@ get_localnet_vifs(const struct ovsrec_bridge *br_int, } static void +get_nat_addresses_and_keys(struct sset *nat_address_keys, + struct sset *local_l3gw_ports, + const struct lport_index *lports, + struct shash *nat_addresses) +{ + const char *gw_port; + SSET_FOR_EACH(gw_port, local_l3gw_ports) { + const struct sbrec_port_binding *pb = lport_lookup_by_name(lports, + gw_port); + if (!pb) { + continue; + } + const char *nat_addresses_options = smap_get(&pb->options, + "nat-addresses"); + if (!nat_addresses_options) { + continue; + } + + struct lport_addresses *laddrs = xmalloc(sizeof *laddrs); + if (!extract_lsp_addresses((char *)nat_addresses_options, laddrs)) { + free(laddrs); + continue; + } + int i; + for (i = 0; i < laddrs->n_ipv4_addrs; i++) { + char *name = xasprintf("%s-%s", pb->logical_port, + laddrs->ipv4_addrs[i].addr_s); + sset_add(nat_address_keys, name); + free(name); + } + shash_add(nat_addresses, pb->logical_port, laddrs); + } +} + +static void send_garp_wait(void) { poll_timer_wait_until(send_garp_time); @@ -872,15 +950,23 @@ send_garp_run(const struct ovsrec_bridge *br_int, const char *chassis_id, struct hmap *local_datapaths) { struct sset localnet_vifs = SSET_INITIALIZER(&localnet_vifs); + struct sset local_l3gw_ports = SSET_INITIALIZER(&local_l3gw_ports); + struct sset nat_ip_keys = SSET_INITIALIZER(&nat_ip_keys); struct simap localnet_ofports = SIMAP_INITIALIZER(&localnet_ofports); + struct shash nat_addresses; + + shash_init(&nat_addresses); - get_localnet_vifs(br_int, chassis_id, lports, local_datapaths, - &localnet_vifs, &localnet_ofports); + get_localnet_vifs_l3gwports(br_int, chassis_id, lports, local_datapaths, + &localnet_vifs, &localnet_ofports, &local_l3gw_ports); - /* For deleted ports, remove from send_garp_data. */ + get_nat_addresses_and_keys(&nat_ip_keys, &local_l3gw_ports, lports, + &nat_addresses); + /* For deleted ports and deleted nat ips, remove from send_garp_data. */ struct shash_node *iter, *next; SHASH_FOR_EACH_SAFE (iter, next, &send_garp_data) { - if (!sset_contains(&localnet_vifs, iter->name)) { + if (!sset_contains(&localnet_vifs, iter->name) && + !sset_contains(&nat_ip_keys, iter->name)) { send_garp_delete(iter->name); } } @@ -891,7 +977,19 @@ send_garp_run(const struct ovsrec_bridge *br_int, const char *chassis_id, const struct sbrec_port_binding *pb = lport_lookup_by_name(lports, iface_id); if (pb) { - send_garp_update(pb, &localnet_ofports, local_datapaths); + send_garp_update(pb, &localnet_ofports, local_datapaths, + &nat_addresses); + } + } + + /* Update send_garp_data for nat-addresses */ + const char *gw_port; + SSET_FOR_EACH (gw_port, &local_l3gw_ports) { + const struct sbrec_port_binding *pb = lport_lookup_by_name(lports, + gw_port); + if (pb) { + send_garp_update(pb, &localnet_ofports, local_datapaths, + &nat_addresses); } } @@ -905,7 +1003,9 @@ send_garp_run(const struct ovsrec_bridge *br_int, const char *chassis_id, } } sset_destroy(&localnet_vifs); + sset_destroy(&local_l3gw_ports); simap_destroy(&localnet_ofports); + shash_destroy_free_data(&nat_addresses); } static void diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c index 1f77b63..0808c27 100644 --- a/ovn/northd/ovn-northd.c +++ b/ovn/northd/ovn-northd.c @@ -824,6 +824,12 @@ ovn_port_update_sbrec(const struct ovn_port *op) if (chassis) { smap_add(&new, "gateway-chassis", chassis); } + + const char *nat_ips = smap_get(&op->nbsp->options, + "nat-addresses"); + if (nat_ips) { + smap_add(&new, "nat-addresses", nat_ips); + } sbrec_port_binding_set_options(op->sb, &new); smap_destroy(&new); } diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml index abd0340..d5679b1 100644 --- a/ovn/ovn-nb.xml +++ b/ovn/ovn-nb.xml @@ -169,6 +169,16 @@ table="Logical_Router_Port"/> to which this logical switch port is connected. + + + MAC address of the router-port followed by a list of + SNAT and DNAT IP adddresses. This is used to send gratutious arps + for SNAT and DNAT IP addresses via localnet and is + valid for only l3 gateway ports. An examples for value is + "80:fa:5b:06:72:b7 158.36.44.22 158.36.44.24". This would result + in generation of gratutious arps for IP addresses 158.36.44.22 + and 158.36.44.24 with a mac address of 80:fa:5b:06:72:b7. + diff --git a/tests/ovn.at b/tests/ovn.at index 86efcf5..44af6a3 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -3818,3 +3818,52 @@ AT_CHECK([ovs-appctl -t ovn-controller version], [0], [ignore]) OVN_CLEANUP([hv1]) AT_CLEANUP + +AT_SETUP([ovn -- send gratutious arp for nat ips in localnet]) +AT_KEYWORDS([ovn]) +AT_SKIP_IF([test $HAVE_PYTHON = no]) +ovn_start +# Create logical switch +ovn-nbctl ls-add ls0 +# Create gateway router +ovn-nbctl create Logical_Router name=lr0 options:chassis=hv1 +# Add router port to gateway router +ovn-nbctl lrp-add lr0 lrp0 f0:00:00:00:00:01 192.168.0.1/24 +ovn-nbctl lsp-add ls0 lrp0-rp -- set Logical_Switch_Port lrp0-rp \ + type=router options:router-port=lrp0-rp addresses='"f0:00:00:00:00:01"' +# Add nat-address option +ovn-nbctl lsp-set-options lrp0-rp router-port=lrp0 nat-addresses="f0:00:00:00:00:01 192.168.0.2" + +net_add n1 +sim_add hv1 +as hv1 +ovs-vsctl \ + -- add-br br-phys \ + -- add-br br-eth0 + +ovn_attach n1 br-phys 192.168.0.1 + +AT_CHECK([ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=physnet1:br-eth0]) +AT_CHECK([ovs-vsctl add-port br-eth0 snoopvif -- set Interface snoopvif options:tx_pcap=hv1/snoopvif-tx.pcap options:rxq_pcap=hv1/snoopvif-rx.pcap]) + +# Create a localnet port. +AT_CHECK([ovn-nbctl lsp-add ls0 ln_port]) +AT_CHECK([ovn-nbctl lsp-set-addresses ln_port unknown]) +AT_CHECK([ovn-nbctl lsp-set-type ln_port localnet]) +AT_CHECK([ovn-nbctl lsp-set-options ln_port network_name=physnet1]) + + +# Wait for packet to be received. +OVS_WAIT_UNTIL([test `wc -c < "hv1/snoopvif-tx.pcap"` -ge 50]) +trim_zeros() { + sed 's/\(00\)\{1,\}$//' +} +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap | trim_zeros > packets +expected="fffffffffffff0000000000108060001080006040001f00000000001c0a80002000000000000c0a80002" +echo $expected > expout +AT_CHECK([sort packets], [0], [expout]) +cat packets + +OVN_CLEANUP([hv1]) + +AT_CLEANUP