diff --git a/.ovn.metadata b/.ovn.metadata
index e8741e5..21e5af6 100644
--- a/.ovn.metadata
+++ b/.ovn.metadata
@@ -1,5 +1,5 @@
002450621b33c5690060345b0aac25bc2426d675 SOURCES/docutils-0.12.tar.gz
-c39c740cd246836bcb125432d2205d0f76504bc0 SOURCES/openvswitch-8986d4d.tar.gz
-4b5217eba8aa5b020946395afa94e48ae81957e8 SOURCES/ovn-23.03.0.tar.gz
+d5a30334edfe265936a26db900a8838c83ef4043 SOURCES/openvswitch-0187ead.tar.gz
+28d5de798f88964283b144cdd8cb226059d403dd SOURCES/ovn-23.06.1.tar.gz
d34f96421a86004aa5d26ecf975edefd09f948b1 SOURCES/Pygments-1.4.tar.gz
6beb30f18ffac3de7689b7fd63e9a8a7d9c8df3a SOURCES/Sphinx-1.1.3.tar.gz
diff --git a/SOURCES/ovn23.03.patch b/SOURCES/ovn23.03.patch
deleted file mode 100644
index 9478c3b..0000000
--- a/SOURCES/ovn23.03.patch
+++ /dev/null
@@ -1,10982 +0,0 @@
-diff --git a/.github/workflows/ovn-kubernetes.yml b/.github/workflows/ovn-kubernetes.yml
-index c82b23a1f..1d554cd03 100644
---- a/.github/workflows/ovn-kubernetes.yml
-+++ b/.github/workflows/ovn-kubernetes.yml
-@@ -56,7 +56,7 @@ jobs:
- name: e2e
- if: github.event_name != 'schedule'
- runs-on: ubuntu-20.04
-- timeout-minutes: 120
-+ timeout-minutes: 220
- strategy:
- fail-fast: false
- matrix:
-@@ -137,6 +137,9 @@ jobs:
- working-directory: src/github.com/ovn-org/ovn-kubernetes
-
- - name: Run Tests
-+ # e2e tests take ~60 minutes normally, 120 should be more than enough
-+ # set 180 for control-plane tests as these might take a while
-+ timeout-minutes: ${{ matrix.target == 'control-plane' && 180 || 120 }}
- run: |
- make -C test ${{ matrix.target }}
- working-directory: src/github.com/ovn-org/ovn-kubernetes
-diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
-index 0f8d9d193..edf4fb2fd 100644
---- a/.github/workflows/test.yml
-+++ b/.github/workflows/test.yml
-@@ -17,7 +17,8 @@ jobs:
- dependencies: |
- automake libtool gcc bc libjemalloc2 libjemalloc-dev \
- libssl-dev llvm-dev libelf-dev libnuma-dev libpcap-dev \
-- selinux-policy-dev ncat python3-scapy isc-dhcp-server
-+ selinux-policy-dev ncat python3-scapy isc-dhcp-server \
-+ iputils-arping
- m32_dependecies: gcc-multilib
- ARCH: ${{ matrix.cfg.arch }}
- CC: ${{ matrix.cfg.compiler }}
-diff --git a/NEWS b/NEWS
-index 5e8aed06d..d7ba71ef5 100644
---- a/NEWS
-+++ b/NEWS
-@@ -1,3 +1,17 @@
-+OVN v23.03.1 - xx xxx xxxx
-+--------------------------
-+ - CT entries are not flushed by default anymore whenever a load balancer
-+ backend is removed. A new, per-LB, option 'ct_flush' can be used to
-+ restore the previous behavior. Disabled by default.
-+ - Always allow IPv6 Router Discovery, Neighbor Discovery, and Multicast
-+ Listener Discovery protocols, regardless of ACLs defined.
-+ - Send ICMP Fragmentation Needed packets back to offending ports when
-+ communicating with multichassis ports using frames that don't fit through a
-+ tunnel. This is done only for logical switches that are attached to a
-+ physical network via a localnet port, in which case multichassis ports may
-+ have an effective MTU different from regular ports and hence may need this
-+ mechanism to maintain connectivity with other peers in the network.
-+
- OVN v23.03.0 - 03 Mar 2023
- --------------------------
- - ovn-controller: Experimental support for co-hosting multiple controller
-diff --git a/configure.ac b/configure.ac
-index b51d0f01e..0ba9e8d7e 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -13,7 +13,7 @@
- # limitations under the License.
-
- AC_PREREQ(2.63)
--AC_INIT(ovn, 23.03.0, bugs@openvswitch.org)
-+AC_INIT(ovn, 23.03.1, bugs@openvswitch.org)
- AC_CONFIG_MACRO_DIR([m4])
- AC_CONFIG_AUX_DIR([build-aux])
- AC_CONFIG_HEADERS([config.h])
-diff --git a/controller/binding.c b/controller/binding.c
-index 5df62baef..8fce6fc3f 100644
---- a/controller/binding.c
-+++ b/controller/binding.c
-@@ -57,6 +57,10 @@ struct claimed_port {
- static struct shash _claimed_ports = SHASH_INITIALIZER(&_claimed_ports);
- static struct sset _postponed_ports = SSET_INITIALIZER(&_postponed_ports);
-
-+static void
-+remove_additional_chassis(const struct sbrec_port_binding *pb,
-+ const struct sbrec_chassis *chassis_rec);
-+
- struct sset *
- get_postponed_ports(void)
- {
-@@ -746,6 +750,19 @@ local_binding_get_lport_ofport(const struct shash *local_bindings,
- u16_to_ofp(lbinding->iface->ofport[0]) : 0;
- }
-
-+bool
-+local_binding_is_ovn_installed(struct shash *local_bindings,
-+ const char *pb_name)
-+{
-+ struct local_binding *lbinding =
-+ local_binding_find(local_bindings, pb_name);
-+ if (lbinding && lbinding->iface) {
-+ return smap_get_bool(&lbinding->iface->external_ids,
-+ OVN_INSTALLED_EXT_ID, false);
-+ }
-+ return false;
-+}
-+
- bool
- local_binding_is_up(struct shash *local_bindings, const char *pb_name,
- const struct sbrec_chassis *chassis_rec)
-@@ -783,6 +800,7 @@ local_binding_is_down(struct shash *local_bindings, const char *pb_name,
- } else if (b_lport->pb->chassis) {
- VLOG_DBG("lport %s already claimed by other chassis",
- b_lport->pb->logical_port);
-+ return true;
- }
- }
-
-@@ -834,6 +852,38 @@ local_binding_set_up(struct shash *local_bindings, const char *pb_name,
- }
- }
-
-+void
-+local_binding_remove_ovn_installed(
-+ struct shash *local_bindings,
-+ const struct ovsrec_interface_table *iface_table,
-+ const char *pb_name, bool ovs_readonly)
-+{
-+ if (ovs_readonly) {
-+ return;
-+ }
-+ struct local_binding *lbinding =
-+ local_binding_find(local_bindings, pb_name);
-+ if (lbinding && lbinding->iface) {
-+ const struct uuid *iface_uuid = &lbinding->iface->header_.uuid;
-+ remove_ovn_installed_for_uuid(iface_table, iface_uuid);
-+ }
-+}
-+
-+void
-+remove_ovn_installed_for_uuid(const struct ovsrec_interface_table *iface_table,
-+ const struct uuid *iface_uuid)
-+{
-+ const struct ovsrec_interface *iface_rec =
-+ ovsrec_interface_table_get_for_uuid(iface_table, iface_uuid);
-+ if (iface_rec && smap_get_bool(&iface_rec->external_ids,
-+ OVN_INSTALLED_EXT_ID, false)) {
-+ VLOG_INFO("Removing iface %s ovn-installed in OVS",
-+ iface_rec->name);
-+ ovsrec_interface_update_external_ids_delkey(iface_rec,
-+ OVN_INSTALLED_EXT_ID);
-+ }
-+}
-+
- void
- local_binding_set_down(struct shash *local_bindings, const char *pb_name,
- const struct sbrec_chassis *chassis_rec,
-@@ -853,7 +903,6 @@ local_binding_set_down(struct shash *local_bindings, const char *pb_name,
-
- if (!sb_readonly && b_lport && b_lport->pb->n_up && b_lport->pb->up[0] &&
- (!b_lport->pb->chassis || b_lport->pb->chassis == chassis_rec)) {
-- VLOG_INFO("Setting lport %s down in Southbound", pb_name);
- binding_lport_set_down(b_lport, sb_readonly);
- LIST_FOR_EACH (b_lport, list_node, &lbinding->binding_lports) {
- binding_lport_set_down(b_lport, sb_readonly);
-@@ -1028,6 +1077,26 @@ set_pb_chassis_in_sbrec(const struct sbrec_port_binding *pb,
- }
- }
-
-+void
-+set_pb_additional_chassis_in_sbrec(const struct sbrec_port_binding *pb,
-+ const struct sbrec_chassis *chassis_rec,
-+ bool is_set)
-+{
-+ if (!is_additional_chassis(pb, chassis_rec)) {
-+ VLOG_INFO("Claiming lport %s for this additional chassis.",
-+ pb->logical_port);
-+ for (size_t i = 0; i < pb->n_mac; i++) {
-+ VLOG_INFO("%s: Claiming %s", pb->logical_port, pb->mac[i]);
-+ }
-+ sbrec_port_binding_update_additional_chassis_addvalue(pb, chassis_rec);
-+ if (pb->chassis == chassis_rec) {
-+ sbrec_port_binding_set_chassis(pb, NULL);
-+ }
-+ } else if (!is_set) {
-+ remove_additional_chassis(pb, chassis_rec);
-+ }
-+}
-+
- bool
- local_bindings_pb_chassis_is_set(struct shash *local_bindings,
- const char *pb_name,
-@@ -1228,8 +1297,8 @@ claim_lport(const struct sbrec_port_binding *pb,
- }
- set_pb_chassis_in_sbrec(pb, chassis_rec, true);
- } else {
-- if_status_mgr_claim_iface(if_mgr, pb, chassis_rec,
-- sb_readonly);
-+ if_status_mgr_claim_iface(if_mgr, pb, chassis_rec, iface_rec,
-+ sb_readonly, can_bind);
- }
- register_claim_timestamp(pb->logical_port, now);
- sset_find_and_delete(postponed_ports, pb->logical_port);
-@@ -1239,29 +1308,19 @@ claim_lport(const struct sbrec_port_binding *pb,
- return false;
- }
- } else {
-- if (pb->n_up && !pb->up[0]) {
-+ if ((pb->n_up && !pb->up[0]) ||
-+ !smap_get_bool(&iface_rec->external_ids,
-+ OVN_INSTALLED_EXT_ID, false)) {
- if_status_mgr_claim_iface(if_mgr, pb, chassis_rec,
-- sb_readonly);
-+ iface_rec, sb_readonly,
-+ can_bind);
- }
- }
- }
- } else if (can_bind == CAN_BIND_AS_ADDITIONAL) {
- if (!is_additional_chassis(pb, chassis_rec)) {
-- if (sb_readonly) {
-- return false;
-- }
--
-- VLOG_INFO("Claiming lport %s for this additional chassis.",
-- pb->logical_port);
-- for (size_t i = 0; i < pb->n_mac; i++) {
-- VLOG_INFO("%s: Claiming %s", pb->logical_port, pb->mac[i]);
-- }
--
-- sbrec_port_binding_update_additional_chassis_addvalue(pb,
-- chassis_rec);
-- if (pb->chassis == chassis_rec) {
-- sbrec_port_binding_set_chassis(pb, NULL);
-- }
-+ if_status_mgr_claim_iface(if_mgr, pb, chassis_rec, iface_rec,
-+ sb_readonly, can_bind);
- update_tracked = true;
- }
- }
-@@ -1464,9 +1523,11 @@ consider_vif_lport_(const struct sbrec_port_binding *pb,
- const char *requested_chassis_option = smap_get(
- &pb->options, "requested-chassis");
- VLOG_INFO_RL(&rl,
-- "Not claiming lport %s, chassis %s requested-chassis %s",
-+ "Not claiming lport %s, chassis %s requested-chassis %s "
-+ "pb->chassis %s",
- pb->logical_port, b_ctx_in->chassis_rec->name,
-- requested_chassis_option ? requested_chassis_option : "[]");
-+ requested_chassis_option ? requested_chassis_option : "[]",
-+ pb->chassis ? pb->chassis->name: "");
- }
- }
-
-@@ -2030,7 +2091,7 @@ binding_run(struct binding_ctx_in *b_ctx_in, struct binding_ctx_out *b_ctx_out)
- free(lnet_lport);
- }
-
-- /* Run through external lport list to see if these are external ports
-+ /* Run through external lport list to see if there are external ports
- * on local datapaths discovered from above loop, and update the
- * corresponding local datapath accordingly. */
- struct lport *ext_lport;
-@@ -2039,7 +2100,7 @@ binding_run(struct binding_ctx_in *b_ctx_in, struct binding_ctx_out *b_ctx_out)
- free(ext_lport);
- }
-
-- /* Run through multichassis lport list to see if these are ports
-+ /* Run through multichassis lport list to see if there are ports
- * on local datapaths discovered from above loop, and update the
- * corresponding local datapath accordingly. */
- struct lport *multichassis_lport;
-@@ -2288,6 +2349,11 @@ consider_iface_release(const struct ovsrec_interface *iface_rec,
- return false;
- }
- }
-+ if (lbinding->iface && lbinding->iface->name) {
-+ if_status_mgr_remove_ovn_installed(b_ctx_out->if_mgr,
-+ lbinding->iface->name,
-+ &lbinding->iface->header_.uuid);
-+ }
-
- } else if (lbinding && b_lport && b_lport->type == LP_LOCALPORT) {
- /* lbinding is associated with a localport. Remove it from the
-@@ -2558,6 +2624,7 @@ handle_deleted_lport(const struct sbrec_port_binding *pb,
- if (ld) {
- remove_pb_from_local_datapath(pb,
- b_ctx_out, ld);
-+ if_status_mgr_release_iface(b_ctx_out->if_mgr, pb->logical_port);
- return;
- }
-
-@@ -2581,6 +2648,7 @@ handle_deleted_lport(const struct sbrec_port_binding *pb,
- remove_pb_from_local_datapath(pb, b_ctx_out,
- ld);
- }
-+ if_status_mgr_release_iface(b_ctx_out->if_mgr, pb->logical_port);
- }
- }
-
-@@ -2627,6 +2695,11 @@ handle_deleted_vif_lport(const struct sbrec_port_binding *pb,
- }
-
- handle_deleted_lport(pb, b_ctx_in, b_ctx_out);
-+ if (lbinding && lbinding->iface && lbinding->iface->name) {
-+ if_status_mgr_remove_ovn_installed(b_ctx_out->if_mgr,
-+ lbinding->iface->name,
-+ &lbinding->iface->header_.uuid);
-+ }
- return true;
- }
-
-@@ -3314,6 +3387,24 @@ binding_lport_delete(struct shash *binding_lports,
- binding_lport_destroy(b_lport);
- }
-
-+void
-+port_binding_set_down(const struct sbrec_chassis *chassis_rec,
-+ const struct sbrec_port_binding_table *pb_table,
-+ const char *iface_id,
-+ const struct uuid *pb_uuid)
-+{
-+ const struct sbrec_port_binding *pb =
-+ sbrec_port_binding_table_get_for_uuid(pb_table, pb_uuid);
-+ if (!pb) {
-+ VLOG_DBG("port_binding already deleted for %s", iface_id);
-+ } else if (pb->n_up && pb->up[0]) {
-+ bool up = false;
-+ sbrec_port_binding_set_up(pb, &up, 1);
-+ VLOG_INFO("Setting lport %s down in Southbound", pb->logical_port);
-+ set_pb_chassis_in_sbrec(pb, chassis_rec, false);
-+ }
-+}
-+
- static void
- binding_lport_set_up(struct binding_lport *b_lport, bool sb_readonly)
- {
-@@ -3331,6 +3422,7 @@ binding_lport_set_down(struct binding_lport *b_lport, bool sb_readonly)
- if (sb_readonly || !b_lport || !b_lport->pb->n_up || !b_lport->pb->up[0]) {
- return;
- }
-+ VLOG_INFO("Setting lport %s down in Southbound", b_lport->name);
-
- bool up = false;
- sbrec_port_binding_set_up(b_lport->pb, &up, 1);
-diff --git a/controller/binding.h b/controller/binding.h
-index 6c3a98b02..46e618b97 100644
---- a/controller/binding.h
-+++ b/controller/binding.h
-@@ -159,6 +159,14 @@ bool local_binding_is_up(struct shash *local_bindings, const char *pb_name,
- bool local_binding_is_down(struct shash *local_bindings, const char *pb_name,
- const struct sbrec_chassis *);
-
-+bool local_binding_is_ovn_installed(struct shash *local_bindings,
-+ const char *pb_name);
-+void local_binding_remove_ovn_installed(
-+ struct shash *local_bindings,
-+ const struct ovsrec_interface_table *iface_table,
-+ const char *pb_name,
-+ bool ovs_readonly);
-+
- void local_binding_set_up(struct shash *local_bindings, const char *pb_name,
- const struct sbrec_chassis *chassis_rec,
- const char *ts_now_str, bool sb_readonly,
-@@ -194,6 +202,18 @@ bool is_additional_chassis(const struct sbrec_port_binding *pb,
- void set_pb_chassis_in_sbrec(const struct sbrec_port_binding *pb,
- const struct sbrec_chassis *chassis_rec,
- bool is_set);
-+void
-+set_pb_additional_chassis_in_sbrec(const struct sbrec_port_binding *pb,
-+ const struct sbrec_chassis *chassis_rec,
-+ bool is_set);
-+
-+void remove_ovn_installed_for_uuid(const struct ovsrec_interface_table *,
-+ const struct uuid *);
-+
-+void port_binding_set_down(const struct sbrec_chassis *chassis_rec,
-+ const struct sbrec_port_binding_table *pb_table,
-+ const char *iface_id,
-+ const struct uuid *pb_uuid);
-
- /* Corresponds to each Port_Binding.type. */
- enum en_lport_type {
-diff --git a/controller/encaps.c b/controller/encaps.c
-index 2662eaf98..b69d72584 100644
---- a/controller/encaps.c
-+++ b/controller/encaps.c
-@@ -36,6 +36,8 @@ VLOG_DEFINE_THIS_MODULE(encaps);
- */
- #define OVN_MVTEP_CHASSISID_DELIM '@'
-
-+static char *current_br_int_name = NULL;
-+
- void
- encaps_register_ovs_idl(struct ovsdb_idl *ovs_idl)
- {
-@@ -386,6 +388,21 @@ chassis_tzones_overlap(const struct sset *transport_zones,
- return false;
- }
-
-+static void
-+clear_old_tunnels(const struct ovsrec_bridge *old_br_int, const char *prefix,
-+ size_t prefix_len)
-+{
-+ for (size_t i = 0; i < old_br_int->n_ports; i++) {
-+ const struct ovsrec_port *port = old_br_int->ports[i];
-+ const char *id = smap_get(&port->external_ids, "ovn-chassis-id");
-+ if (id && !strncmp(port->name, prefix, prefix_len)) {
-+ VLOG_DBG("Clearing old tunnel port \"%s\" (%s) from bridge "
-+ "\"%s\".", port->name, id, old_br_int->name);
-+ ovsrec_bridge_update_ports_delvalue(old_br_int, port);
-+ }
-+ }
-+}
-+
- void
- encaps_run(struct ovsdb_idl_txn *ovs_idl_txn,
- const struct ovsrec_bridge *br_int,
-@@ -393,12 +410,42 @@ encaps_run(struct ovsdb_idl_txn *ovs_idl_txn,
- const struct sbrec_chassis *this_chassis,
- const struct sbrec_sb_global *sbg,
- const struct ovsrec_open_vswitch_table *ovs_table,
-- const struct sset *transport_zones)
-+ const struct sset *transport_zones,
-+ const struct ovsrec_bridge_table *bridge_table)
- {
- if (!ovs_idl_txn || !br_int) {
- return;
- }
-
-+ if (!current_br_int_name) {
-+ /* The controller has just started, we need to look through all
-+ * bridges for old tunnel ports. */
-+ char *tunnel_prefix = xasprintf("ovn%s-", get_chassis_idx(ovs_table));
-+ size_t prefix_len = strlen(tunnel_prefix);
-+
-+ const struct ovsrec_bridge *br;
-+ OVSREC_BRIDGE_TABLE_FOR_EACH (br, bridge_table) {
-+ if (!strcmp(br->name, br_int->name)) {
-+ continue;
-+ }
-+ clear_old_tunnels(br, tunnel_prefix, prefix_len);
-+ }
-+
-+ free(tunnel_prefix);
-+ current_br_int_name = xstrdup(br_int->name);
-+ } else if (strcmp(current_br_int_name, br_int->name)) {
-+ /* The integration bridge was changed, clear tunnel ports from
-+ * the old one. */
-+ const struct ovsrec_bridge *old_br_int =
-+ get_bridge(bridge_table, current_br_int_name);
-+ if (old_br_int) {
-+ clear_old_tunnels(old_br_int, "", 0);
-+ }
-+
-+ free(current_br_int_name);
-+ current_br_int_name = xstrdup(br_int->name);
-+ }
-+
- const struct sbrec_chassis *chassis_rec;
-
- struct tunnel_ctx tc = {
-@@ -511,3 +558,9 @@ encaps_cleanup(struct ovsdb_idl_txn *ovs_idl_txn,
-
- return !any_changes;
- }
-+
-+void
-+encaps_destroy(void)
-+{
-+ free(current_br_int_name);
-+}
-diff --git a/controller/encaps.h b/controller/encaps.h
-index 867c6f28c..3e58b3c82 100644
---- a/controller/encaps.h
-+++ b/controller/encaps.h
-@@ -35,7 +35,8 @@ void encaps_run(struct ovsdb_idl_txn *ovs_idl_txn,
- const struct sbrec_chassis *,
- const struct sbrec_sb_global *,
- const struct ovsrec_open_vswitch_table *,
-- const struct sset *transport_zones);
-+ const struct sset *transport_zones,
-+ const struct ovsrec_bridge_table *bridge_table);
-
- bool encaps_cleanup(struct ovsdb_idl_txn *ovs_idl_txn,
- const struct ovsrec_bridge *br_int);
-@@ -46,4 +47,6 @@ bool encaps_tunnel_id_parse(const char *tunnel_id, char **chassis_id,
- bool encaps_tunnel_id_match(const char *tunnel_id, const char *chassis_id,
- const char *encap_ip);
-
-+void encaps_destroy(void);
-+
- #endif /* controller/encaps.h */
-diff --git a/controller/if-status.c b/controller/if-status.c
-index d1c14ac30..2b2eb1679 100644
---- a/controller/if-status.c
-+++ b/controller/if-status.c
-@@ -18,12 +18,14 @@
- #include "binding.h"
- #include "if-status.h"
- #include "ofctrl-seqno.h"
-+#include "ovsport.h"
- #include "simap.h"
-
- #include "lib/hmapx.h"
- #include "lib/util.h"
- #include "timeval.h"
- #include "openvswitch/vlog.h"
-+#include "lib/vswitch-idl.h"
- #include "lib/ovn-sb-idl.h"
-
- VLOG_DEFINE_THIS_MODULE(if_status);
-@@ -54,44 +56,54 @@ VLOG_DEFINE_THIS_MODULE(if_status);
- */
-
- enum if_state {
-- OIF_CLAIMED, /* Newly claimed interface. pb->chassis update not yet
-- initiated. */
-- OIF_INSTALL_FLOWS, /* Claimed interface with pb->chassis update sent to
-- * SB (but update notification not confirmed, so the
-- * update may be resent in any of the following states)
-- * and for which flows are still being installed.
-- */
-- OIF_MARK_UP, /* Interface with flows successfully installed in OVS
-- * but not yet marked "up" in the binding module (in
-- * SB and OVS databases).
-- */
-- OIF_MARK_DOWN, /* Released interface but not yet marked "down" in the
-- * binding module (in SB and/or OVS databases).
-- */
-- OIF_INSTALLED, /* Interface flows programmed in OVS and binding marked
-- * "up" in the binding module.
-- */
-+ OIF_CLAIMED, /* Newly claimed interface. pb->chassis update not
-+ yet initiated. */
-+ OIF_INSTALL_FLOWS, /* Claimed interface with pb->chassis update sent to
-+ * SB (but update notification not confirmed, so the
-+ * update may be resent in any of the following
-+ * states and for which flows are still being
-+ * installed.
-+ */
-+ OIF_REM_OLD_OVN_INST, /* Interface with flows successfully installed in OVS
-+ * but with ovn-installed still in OVSDB.
-+ */
-+ OIF_MARK_UP, /* Interface with flows successfully installed in OVS
-+ * but not yet marked "up" in the binding module (in
-+ * SB and OVS databases).
-+ */
-+ OIF_MARK_DOWN, /* Released interface but not yet marked "down" in
-+ * the binding module (in SB and/or OVS databases).
-+ */
-+ OIF_INSTALLED, /* Interface flows programmed in OVS and binding
-+ * marked "up" in the binding module.
-+ */
-+ OIF_UPDATE_PORT, /* Logical ports need to be set down, and pb->chassis
-+ * removed.
-+ */
- OIF_MAX,
- };
-
- static const char *if_state_names[] = {
-- [OIF_CLAIMED] = "CLAIMED",
-- [OIF_INSTALL_FLOWS] = "INSTALL_FLOWS",
-- [OIF_MARK_UP] = "MARK_UP",
-- [OIF_MARK_DOWN] = "MARK_DOWN",
-- [OIF_INSTALLED] = "INSTALLED",
-+ [OIF_CLAIMED] = "CLAIMED",
-+ [OIF_INSTALL_FLOWS] = "INSTALL_FLOWS",
-+ [OIF_REM_OLD_OVN_INST] = "REM_OLD_OVN_INST",
-+ [OIF_MARK_UP] = "MARK_UP",
-+ [OIF_MARK_DOWN] = "MARK_DOWN",
-+ [OIF_INSTALLED] = "INSTALLED",
-+ [OIF_UPDATE_PORT] = "UPDATE_PORT",
- };
-
- /*
- * +----------------------+
- * +---> | |
-- * | +-> | NULL | <--------------------------------------+++-+
-- * | | +----------------------+ |
-- * | | ^ release_iface | claim_iface() |
-- * | | | V - sbrec_update_chassis(if sb is rw) |
-- * | | +----------------------+ |
-- * | | | | <----------------------------------------+ |
-- * | | | CLAIMED | <--------------------------------------+ | |
-+ * | +-> | NULL |
-+ * | | +----------------------+
-+ * | | ^ release_iface | claim_iface()
-+ * | | | V - sbrec_update_chassis(if sb is rw)
-+ * | | +----------------------+
-+ * | | | | <------------------------------------------+
-+ * | | | CLAIMED | <----------------------------------------+ |
-+ * | | | | <--------------------------------------+ | |
- * | | +----------------------+ | | |
- * | | | V ^ | | |
- * | | | | | handle_claims() | | |
-@@ -109,43 +121,69 @@ static const char *if_state_names[] = {
- * | | | - remove ovn-installed from ovsdb | | |
- * | | | mgr_update() | | |
- * | +----------------------+ - sbrec_update_chassis if needed | | |
-- * | | | | |
-- * | | mgr_run(seqno rcvd) | | |
-- * | | - set port up in sb | | |
-- * | release_iface | - set ovn-installed in ovs | | |
-- * | V | | |
-+ * | | | | | |
-+ * | | +----------------------------------------+ | | |
-+ * | | | | | |
-+ * | | mgr_run(seqno rcvd, ovn-installed present) | | | |
-+ * | V | | | |
-+ * | +--------------------+ | | | |
-+ * | | | mgr_run() | | | |
-+ * +--- | REM_OLD_OVN_INST | - remove ovn-installed in ovs | | | |
-+ * | +--------------------+ | | | |
-+ * | | | | | |
-+ * | | | | | |
-+ * | | mgr_update( ovn_installed not present) | | | |
-+ * | | | | | |
-+ * | | +-------------------------------------------+ | | |
-+ * | | | | | |
-+ * | | | mgr_run(seqno rcvd, ovn-installed not present) | | |
-+ * | | | - set port up in sb | | |
-+ * | | | - set ovn-installed in ovs | | |
-+ * |release_iface | | | | |
-+ * | V V | | |
- * | +----------------------+ | | |
- * | | | mgr_run() | | |
-- * +-- | MARK_UP | - set port up in sb | | |
-- * | | - set ovn-installed in ovs | | |
-- * | | mgr_update() | | |
-- * +----------------------+ - sbrec_update_chassis if needed | | |
-- * | | | |
-- * | mgr_update(rcvd port up / ovn_installed & chassis set) | | |
-- * V | | |
-- * +----------------------+ | | |
-- * | INSTALLED | ------------> claim_iface ---------------+ | |
-- * +----------------------+ | |
-- * | | |
-- * | release_iface | |
-- * V | |
-- * +----------------------+ | |
-- * | | ------------> claim_iface -----------------+ |
-- * | MARK_DOWN | ------> mgr_update(rcvd port down) ----------+
-- * | | mgr_run()
-- * | | - set port down in sb
-- * | | mgr_update()
-+ * +---| MARK_UP | - set port up in sb | | |
-+ * | | | - set ovn-installed in ovs | | |
-+ * | | | mgr_update() | | |
-+ * | +----------------------+ - sbrec_update_chassis if needed | | |
-+ * | | | | |
-+ * | | mgr_update(rcvd port up / ovn_installed & chassis set) | | |
-+ * | V | | |
-+ * | +----------------------+ | | |
-+ * | | INSTALLED | ------------> claim_iface ---------------+ | |
-+ * | +----------------------+ | |
-+ * | | | |
-+ * | | release_iface | |
-+ * |mgr_update( | | |
-+ * | rcvd port down) | | |
-+ * | V | |
-+ * | +----------------------+ | |
-+ * | | | ------------> claim_iface -----------------+ |
-+ * +---+ MARK_DOWN | mgr_run() |
-+ * | | | - set port down in sb |
-+ * | | | mgr_update(sb is rw) |
-+ * | +----------------------+ - sbrec_update_chassis(NULL) |
-+ * | | |
-+ * | | mgr_update(local binding not found) |
-+ * | | |
-+ * | V |
-+ * | +----------------------+ |
-+ * | | | ------------> claim_iface -------------------+
-+ * +---+ UPDATE_PORT | mgr_run()
- * +----------------------+ - sbrec_update_chassis(NULL)
- */
-
-
- struct ovs_iface {
- char *id; /* Extracted from OVS external_ids.iface_id. */
-+ struct uuid pb_uuid; /* Port_binding uuid */
- enum if_state state; /* State of the interface in the state machine. */
- uint32_t install_seqno; /* Seqno at which this interface is expected to
- * be fully programmed in OVS. Only used in state
- * OIF_INSTALL_FLOWS.
- */
-+ uint16_t mtu; /* Extracted from OVS interface.mtu field. */
- };
-
- static uint64_t ifaces_usage;
-@@ -155,6 +193,9 @@ struct if_status_mgr {
- /* All local interfaces, mapping from 'iface-id' to 'struct ovs_iface'. */
- struct shash ifaces;
-
-+ /* local interfaces which need ovn-install removal */
-+ struct shash ovn_uninstall_hash;
-+
- /* All local interfaces, stored per state. */
- struct hmapx ifaces_per_state[OIF_MAX];
-
-@@ -167,18 +208,24 @@ struct if_status_mgr {
- uint32_t iface_seqno;
- };
-
--static struct ovs_iface *ovs_iface_create(struct if_status_mgr *,
-- const char *iface_id,
-- enum if_state );
-+static struct ovs_iface *
-+ovs_iface_create(struct if_status_mgr *, const char *iface_id,
-+ const struct ovsrec_interface *iface_rec,
-+ enum if_state);
-+static void add_to_ovn_uninstall_hash(struct if_status_mgr *, const char *,
-+ const struct uuid *);
- static void ovs_iface_destroy(struct if_status_mgr *, struct ovs_iface *);
-+static void ovn_uninstall_hash_destroy(struct if_status_mgr *mgr, char *name);
- static void ovs_iface_set_state(struct if_status_mgr *, struct ovs_iface *,
- enum if_state);
-
- static void if_status_mgr_update_bindings(
- struct if_status_mgr *mgr, struct local_binding_data *binding_data,
- const struct sbrec_chassis *,
-+ const struct ovsrec_interface_table *iface_table,
- bool sb_readonly, bool ovs_readonly);
-
-+static void ovn_uninstall_hash_account_mem(const char *name, bool erase);
- struct if_status_mgr *
- if_status_mgr_create(void)
- {
-@@ -189,6 +236,7 @@ if_status_mgr_create(void)
- hmapx_init(&mgr->ifaces_per_state[i]);
- }
- shash_init(&mgr->ifaces);
-+ shash_init(&mgr->ovn_uninstall_hash);
- return mgr;
- }
-
-@@ -202,6 +250,11 @@ if_status_mgr_clear(struct if_status_mgr *mgr)
- }
- ovs_assert(shash_is_empty(&mgr->ifaces));
-
-+ SHASH_FOR_EACH_SAFE (node, &mgr->ovn_uninstall_hash) {
-+ ovn_uninstall_hash_destroy(mgr, node->data);
-+ }
-+ ovs_assert(shash_is_empty(&mgr->ovn_uninstall_hash));
-+
- for (size_t i = 0; i < ARRAY_SIZE(mgr->ifaces_per_state); i++) {
- ovs_assert(hmapx_is_empty(&mgr->ifaces_per_state[i]));
- }
-@@ -212,6 +265,7 @@ if_status_mgr_destroy(struct if_status_mgr *mgr)
- {
- if_status_mgr_clear(mgr);
- shash_destroy(&mgr->ifaces);
-+ shash_destroy(&mgr->ovn_uninstall_hash);
- for (size_t i = 0; i < ARRAY_SIZE(mgr->ifaces_per_state); i++) {
- hmapx_destroy(&mgr->ifaces_per_state[i]);
- }
-@@ -222,27 +276,35 @@ void
- if_status_mgr_claim_iface(struct if_status_mgr *mgr,
- const struct sbrec_port_binding *pb,
- const struct sbrec_chassis *chassis_rec,
-- bool sb_readonly)
-+ const struct ovsrec_interface *iface_rec,
-+ bool sb_readonly, enum can_bind bind_type)
- {
- const char *iface_id = pb->logical_port;
- struct ovs_iface *iface = shash_find_data(&mgr->ifaces, iface_id);
-
- if (!iface) {
-- iface = ovs_iface_create(mgr, iface_id, OIF_CLAIMED);
-+ iface = ovs_iface_create(mgr, iface_id, iface_rec, OIF_CLAIMED);
- }
-
-+ memcpy(&iface->pb_uuid, &pb->header_.uuid, sizeof(iface->pb_uuid));
- if (!sb_readonly) {
-- set_pb_chassis_in_sbrec(pb, chassis_rec, true);
-+ if (bind_type == CAN_BIND_AS_MAIN) {
-+ set_pb_chassis_in_sbrec(pb, chassis_rec, true);
-+ } else if (bind_type == CAN_BIND_AS_ADDITIONAL) {
-+ set_pb_additional_chassis_in_sbrec(pb, chassis_rec, true);
-+ }
- }
-
- switch (iface->state) {
- case OIF_CLAIMED:
- case OIF_INSTALL_FLOWS:
-+ case OIF_REM_OLD_OVN_INST:
- case OIF_MARK_UP:
- /* Nothing to do here. */
- break;
- case OIF_INSTALLED:
- case OIF_MARK_DOWN:
-+ case OIF_UPDATE_PORT:
- ovs_iface_set_state(mgr, iface, OIF_CLAIMED);
- break;
- case OIF_MAX:
-@@ -271,9 +333,10 @@ if_status_mgr_release_iface(struct if_status_mgr *mgr, const char *iface_id)
- switch (iface->state) {
- case OIF_CLAIMED:
- case OIF_INSTALL_FLOWS:
-- /* Not yet fully installed interfaces can be safely deleted. */
-- ovs_iface_destroy(mgr, iface);
-- break;
-+ /* Not yet fully installed interfaces:
-+ * pb->chassis still need to be deleted.
-+ */
-+ case OIF_REM_OLD_OVN_INST:
- case OIF_MARK_UP:
- case OIF_INSTALLED:
- /* Properly mark interfaces "down" if their flows were already
-@@ -282,6 +345,7 @@ if_status_mgr_release_iface(struct if_status_mgr *mgr, const char *iface_id)
- ovs_iface_set_state(mgr, iface, OIF_MARK_DOWN);
- break;
- case OIF_MARK_DOWN:
-+ case OIF_UPDATE_PORT:
- /* Nothing to do here. */
- break;
- case OIF_MAX:
-@@ -302,9 +366,10 @@ if_status_mgr_delete_iface(struct if_status_mgr *mgr, const char *iface_id)
- switch (iface->state) {
- case OIF_CLAIMED:
- case OIF_INSTALL_FLOWS:
-- /* Not yet fully installed interfaces can be safely deleted. */
-- ovs_iface_destroy(mgr, iface);
-- break;
-+ /* Not yet fully installed interfaces:
-+ * pb->chassis still need to be deleted.
-+ */
-+ case OIF_REM_OLD_OVN_INST:
- case OIF_MARK_UP:
- case OIF_INSTALLED:
- /* Properly mark interfaces "down" if their flows were already
-@@ -313,6 +378,7 @@ if_status_mgr_delete_iface(struct if_status_mgr *mgr, const char *iface_id)
- ovs_iface_set_state(mgr, iface, OIF_MARK_DOWN);
- break;
- case OIF_MARK_DOWN:
-+ case OIF_UPDATE_PORT:
- /* Nothing to do here. */
- break;
- case OIF_MAX:
-@@ -346,12 +412,34 @@ if_status_handle_claims(struct if_status_mgr *mgr,
- return rc;
- }
-
-+static void
-+clean_ovn_installed(struct if_status_mgr *mgr,
-+ const struct ovsrec_interface_table *iface_table)
-+{
-+ struct shash_node *node;
-+
-+ SHASH_FOR_EACH_SAFE (node, &mgr->ovn_uninstall_hash) {
-+ const struct uuid *iface_uuid = node->data;
-+ remove_ovn_installed_for_uuid(iface_table, iface_uuid);
-+ free(node->data);
-+ char *node_name = shash_steal(&mgr->ovn_uninstall_hash, node);
-+ ovn_uninstall_hash_account_mem(node_name, true);
-+ free(node_name);
-+ }
-+}
-+
- void
- if_status_mgr_update(struct if_status_mgr *mgr,
- struct local_binding_data *binding_data,
- const struct sbrec_chassis *chassis_rec,
-+ const struct ovsrec_interface_table *iface_table,
-+ const struct sbrec_port_binding_table *pb_table,
-+ bool ovs_readonly,
- bool sb_readonly)
- {
-+ if (!ovs_readonly) {
-+ clean_ovn_installed(mgr, iface_table);
-+ }
- if (!binding_data) {
- return;
- }
-@@ -359,6 +447,17 @@ if_status_mgr_update(struct if_status_mgr *mgr,
- struct shash *bindings = &binding_data->bindings;
- struct hmapx_node *node;
-
-+ /* Move all interfaces that have been confirmed without ovn-installed,
-+ * from OIF_REM_OLD_OVN_INST to OIF_MARK_UP.
-+ */
-+ HMAPX_FOR_EACH_SAFE (node, &mgr->ifaces_per_state[OIF_REM_OLD_OVN_INST]) {
-+ struct ovs_iface *iface = node->data;
-+
-+ if (!local_binding_is_ovn_installed(bindings, iface->id)) {
-+ ovs_iface_set_state(mgr, iface, OIF_MARK_UP);
-+ }
-+ }
-+
- /* Interfaces in OIF_MARK_UP/INSTALL_FLOWS state have already set their
- * pb->chassis. However, the update might still be in fly (confirmation
- * not received yet) or pb->chassis was overwitten by another chassis.
-@@ -390,6 +489,10 @@ if_status_mgr_update(struct if_status_mgr *mgr,
- HMAPX_FOR_EACH_SAFE (node, &mgr->ifaces_per_state[OIF_MARK_DOWN]) {
- struct ovs_iface *iface = node->data;
-
-+ if (!local_binding_find(bindings, iface->id)) {
-+ ovs_iface_set_state(mgr, iface, OIF_UPDATE_PORT);
-+ continue;
-+ }
- if (!sb_readonly) {
- local_binding_set_pb(bindings, iface->id, chassis_rec,
- NULL, false);
-@@ -437,6 +540,21 @@ if_status_mgr_update(struct if_status_mgr *mgr,
- }
- }
-
-+ if (!sb_readonly) {
-+ HMAPX_FOR_EACH_SAFE (node, &mgr->ifaces_per_state[OIF_UPDATE_PORT]) {
-+ struct ovs_iface *iface = node->data;
-+ port_binding_set_down(chassis_rec, pb_table, iface->id,
-+ &iface->pb_uuid);
-+ ovs_iface_destroy(mgr, node->data);
-+ }
-+ } else {
-+ HMAPX_FOR_EACH_SAFE (node, &mgr->ifaces_per_state[OIF_UPDATE_PORT]) {
-+ struct ovs_iface *iface = node->data;
-+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
-+ VLOG_INFO_RL(&rl, "Not setting lport %s down as sb is readonly",
-+ iface->id);
-+ }
-+ }
- /* Register for a notification about flows being installed in OVS for all
- * newly claimed interfaces for which pb->chassis has been updated.
- * Request a seqno update when the flows for new interfaces have been
-@@ -450,10 +568,23 @@ if_status_mgr_update(struct if_status_mgr *mgr,
- }
- }
-
-+void
-+if_status_mgr_remove_ovn_installed(struct if_status_mgr *mgr,
-+ const char *name,
-+ const struct uuid *uuid)
-+{
-+ VLOG_DBG("Adding %s to list of interfaces for which to remove "
-+ "ovn-installed", name);
-+ if (!shash_find_data(&mgr->ovn_uninstall_hash, name)) {
-+ add_to_ovn_uninstall_hash(mgr, name, uuid);
-+ }
-+}
-+
- void
- if_status_mgr_run(struct if_status_mgr *mgr,
- struct local_binding_data *binding_data,
- const struct sbrec_chassis *chassis_rec,
-+ const struct ovsrec_interface_table *iface_table,
- bool sb_readonly, bool ovs_readonly)
- {
- struct ofctrl_acked_seqnos *acked_seqnos =
-@@ -471,12 +602,25 @@ if_status_mgr_run(struct if_status_mgr *mgr,
- iface->install_seqno)) {
- continue;
- }
-- ovs_iface_set_state(mgr, iface, OIF_MARK_UP);
-+ /* Wait for ovn-installed to be absent before moving to MARK_UP state.
-+ * Most of the times ovn-installed is already absent and hence we will
-+ * not have to wait.
-+ * If there is no binding_data, we can't determine if ovn-installed is
-+ * present or not; hence also go to the OIF_REM_OLD_OVN_INST state.
-+ */
-+ if (!binding_data ||
-+ local_binding_is_ovn_installed(&binding_data->bindings,
-+ iface->id)) {
-+ ovs_iface_set_state(mgr, iface, OIF_REM_OLD_OVN_INST);
-+ } else {
-+ ovs_iface_set_state(mgr, iface, OIF_MARK_UP);
-+ }
- }
- ofctrl_acked_seqnos_destroy(acked_seqnos);
-
- /* Update binding states. */
- if_status_mgr_update_bindings(mgr, binding_data, chassis_rec,
-+ iface_table,
- sb_readonly, ovs_readonly);
- }
-
-@@ -492,8 +636,46 @@ ovs_iface_account_mem(const char *iface_id, bool erase)
- }
- }
-
-+static void
-+ovn_uninstall_hash_account_mem(const char *name, bool erase)
-+{
-+ uint32_t size = (strlen(name) + sizeof(struct uuid) +
-+ sizeof(struct shash_node));
-+ if (erase) {
-+ ifaces_usage -= size;
-+ } else {
-+ ifaces_usage += size;
-+ }
-+}
-+
-+uint16_t
-+if_status_mgr_iface_get_mtu(const struct if_status_mgr *mgr,
-+ const char *iface_id)
-+{
-+ const struct ovs_iface *iface = shash_find_data(&mgr->ifaces, iface_id);
-+ return iface ? iface->mtu : 0;
-+}
-+
-+bool
-+if_status_mgr_iface_update(const struct if_status_mgr *mgr,
-+ const struct ovsrec_interface *iface_rec)
-+{
-+ const char *iface_id = smap_get(&iface_rec->external_ids, "iface-id");
-+ if (!iface_id) {
-+ return false;
-+ }
-+ uint16_t mtu = get_iface_mtu(iface_rec);
-+ struct ovs_iface *iface = shash_find_data(&mgr->ifaces, iface_id);
-+ if (iface && iface->mtu != mtu) {
-+ iface->mtu = mtu;
-+ return true;
-+ }
-+ return false;
-+}
-+
- static struct ovs_iface *
- ovs_iface_create(struct if_status_mgr *mgr, const char *iface_id,
-+ const struct ovsrec_interface *iface_rec,
- enum if_state state)
- {
- struct ovs_iface *iface = xzalloc(sizeof *iface);
-@@ -503,9 +685,20 @@ ovs_iface_create(struct if_status_mgr *mgr, const char *iface_id,
- shash_add_nocopy(&mgr->ifaces, iface->id, iface);
- ovs_iface_set_state(mgr, iface, state);
- ovs_iface_account_mem(iface_id, false);
-+ if_status_mgr_iface_update(mgr, iface_rec);
- return iface;
- }
-
-+static void
-+add_to_ovn_uninstall_hash(struct if_status_mgr *mgr, const char *name,
-+ const struct uuid *uuid)
-+{
-+ struct uuid *new_uuid = xzalloc(sizeof *new_uuid);
-+ memcpy(new_uuid, uuid, sizeof(*new_uuid));
-+ shash_add(&mgr->ovn_uninstall_hash, name, new_uuid);
-+ ovn_uninstall_hash_account_mem(name, false);
-+}
-+
- static void
- ovs_iface_destroy(struct if_status_mgr *mgr, struct ovs_iface *iface)
- {
-@@ -521,6 +714,23 @@ ovs_iface_destroy(struct if_status_mgr *mgr, struct ovs_iface *iface)
- free(iface);
- }
-
-+static void
-+ovn_uninstall_hash_destroy(struct if_status_mgr *mgr, char *name)
-+{
-+ struct shash_node *node = shash_find(&mgr->ovn_uninstall_hash, name);
-+ char *node_name = NULL;
-+ if (node) {
-+ free(node->data);
-+ VLOG_DBG("Interface name %s destroy", name);
-+ node_name = shash_steal(&mgr->ovn_uninstall_hash, node);
-+ ovn_uninstall_hash_account_mem(name, true);
-+ free(node_name);
-+ } else {
-+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
-+ VLOG_WARN_RL(&rl, "Interface name %s not found", name);
-+ }
-+}
-+
- static void
- ovs_iface_set_state(struct if_status_mgr *mgr, struct ovs_iface *iface,
- enum if_state state)
-@@ -539,6 +749,7 @@ static void
- if_status_mgr_update_bindings(struct if_status_mgr *mgr,
- struct local_binding_data *binding_data,
- const struct sbrec_chassis *chassis_rec,
-+ const struct ovsrec_interface_table *iface_table,
- bool sb_readonly, bool ovs_readonly)
- {
- if (!binding_data) {
-@@ -558,7 +769,17 @@ if_status_mgr_update_bindings(struct if_status_mgr *mgr,
- sb_readonly, ovs_readonly);
- }
-
-- /* Notifiy the binding module to set "up" all bindings that have had
-+ /* Notify the binding module to remove "ovn-installed" for all bindings
-+ * in the OIF_REM_OLD_OVN_INST state.
-+ */
-+ HMAPX_FOR_EACH (node, &mgr->ifaces_per_state[OIF_REM_OLD_OVN_INST]) {
-+ struct ovs_iface *iface = node->data;
-+
-+ local_binding_remove_ovn_installed(bindings, iface_table, iface->id,
-+ ovs_readonly);
-+ }
-+
-+ /* Notify the binding module to set "up" all bindings that have had
- * their flows installed but are not yet marked "up" in the binding
- * module.
- */
-diff --git a/controller/if-status.h b/controller/if-status.h
-index 5bd187a25..15624bcfa 100644
---- a/controller/if-status.h
-+++ b/controller/if-status.h
-@@ -17,8 +17,10 @@
- #define IF_STATUS_H 1
-
- #include "openvswitch/shash.h"
-+#include "lib/vswitch-idl.h"
-
- #include "binding.h"
-+#include "lport.h"
-
- struct if_status_mgr;
- struct simap;
-@@ -29,15 +31,20 @@ void if_status_mgr_destroy(struct if_status_mgr *);
- void if_status_mgr_claim_iface(struct if_status_mgr *,
- const struct sbrec_port_binding *pb,
- const struct sbrec_chassis *chassis_rec,
-- bool sb_readonly);
-+ const struct ovsrec_interface *iface_rec,
-+ bool sb_readonly, enum can_bind bind_type);
- void if_status_mgr_release_iface(struct if_status_mgr *, const char *iface_id);
- void if_status_mgr_delete_iface(struct if_status_mgr *, const char *iface_id);
-
- void if_status_mgr_update(struct if_status_mgr *, struct local_binding_data *,
- const struct sbrec_chassis *chassis,
-+ const struct ovsrec_interface_table *iface_table,
-+ const struct sbrec_port_binding_table *pb_table,
-+ bool ovs_readonly,
- bool sb_readonly);
- void if_status_mgr_run(struct if_status_mgr *mgr, struct local_binding_data *,
- const struct sbrec_chassis *,
-+ const struct ovsrec_interface_table *iface_table,
- bool sb_readonly, bool ovs_readonly);
- void if_status_mgr_get_memory_usage(struct if_status_mgr *mgr,
- struct simap *usage);
-@@ -48,5 +55,12 @@ bool if_status_handle_claims(struct if_status_mgr *mgr,
- const struct sbrec_chassis *chassis_rec,
- struct hmap *tracked_datapath,
- bool sb_readonly);
-+void if_status_mgr_remove_ovn_installed(struct if_status_mgr *mgr,
-+ const char *name,
-+ const struct uuid *uuid);
-+uint16_t if_status_mgr_iface_get_mtu(const struct if_status_mgr *mgr,
-+ const char *iface_id);
-+bool if_status_mgr_iface_update(const struct if_status_mgr *mgr,
-+ const struct ovsrec_interface *iface_rec);
-
- # endif /* controller/if-status.h */
-diff --git a/controller/lflow.c b/controller/lflow.c
-index 6a98b19e1..22faaf013 100644
---- a/controller/lflow.c
-+++ b/controller/lflow.c
-@@ -397,7 +397,7 @@ consider_lflow_for_added_as_ips__(
- : OFTABLE_LOG_EGRESS_PIPELINE);
- uint8_t ptable = first_ptable + lflow->table_id;
- uint8_t output_ptable = (ingress
-- ? OFTABLE_REMOTE_OUTPUT
-+ ? OFTABLE_OUTPUT_INIT
- : OFTABLE_SAVE_INPORT);
-
- uint64_t ovnacts_stub[1024 / 8];
-@@ -1067,7 +1067,7 @@ consider_logical_flow__(const struct sbrec_logical_flow *lflow,
- : OFTABLE_LOG_EGRESS_PIPELINE);
- uint8_t ptable = first_ptable + lflow->table_id;
- uint8_t output_ptable = (ingress
-- ? OFTABLE_REMOTE_OUTPUT
-+ ? OFTABLE_OUTPUT_INIT
- : OFTABLE_SAVE_INPORT);
-
- /* Parse OVN logical actions.
-@@ -1729,6 +1729,7 @@ add_lb_vip_hairpin_flows(const struct ovn_controller_lb *lb,
-
- static void
- add_lb_ct_snat_hairpin_for_dp(const struct ovn_controller_lb *lb,
-+ bool has_vip_port,
- const struct sbrec_datapath_binding *datapath,
- const struct hmap *local_datapaths,
- struct match *dp_match,
-@@ -1742,15 +1743,21 @@ add_lb_ct_snat_hairpin_for_dp(const struct ovn_controller_lb *lb,
- match_set_metadata(dp_match, htonll(datapath->tunnel_key));
- }
-
-+ uint16_t priority = datapath ? 200 : 100;
-+ if (!has_vip_port) {
-+ /* If L4 ports are not specified for the current LB, we will decrease
-+ * the flow priority in order to not collide with other LBs with more
-+ * fine-grained configuration.
-+ */
-+ priority -= 10;
-+ }
- /* A flow added for the "hairpin_snat_ip" case will have an extra
- * datapath match, but it will also match on the less restrictive
- * general case. Therefore, we set the priority in the
- * "hairpin_snat_ip" case to be higher than the general case. */
-- ofctrl_add_or_append_flow(flow_table, OFTABLE_CT_SNAT_HAIRPIN,
-- datapath ? 200 : 100,
-- lb->slb->header_.uuid.parts[0],
-- dp_match, dp_acts, &lb->slb->header_.uuid,
-- NX_CTLR_NO_METER, NULL);
-+ ofctrl_add_flow(flow_table, OFTABLE_CT_SNAT_HAIRPIN,
-+ priority, lb->slb->header_.uuid.parts[0],
-+ dp_match, dp_acts, &lb->slb->header_.uuid);
- }
-
- /* Add a ct_snat flow for each VIP of the LB. If this LB does not use
-@@ -1836,8 +1843,8 @@ add_lb_ct_snat_hairpin_vip_flow(const struct ovn_controller_lb *lb,
- }
- }
-
-- match_set_nw_proto(&match, lb->proto);
- if (lb_vip->vip_port) {
-+ match_set_nw_proto(&match, lb->proto);
- if (!lb->hairpin_orig_tuple) {
- match_set_ct_nw_proto(&match, lb->proto);
- match_set_ct_tp_dst(&match, htons(lb_vip->vip_port));
-@@ -1854,18 +1861,20 @@ add_lb_ct_snat_hairpin_vip_flow(const struct ovn_controller_lb *lb,
- }
-
- if (!use_hairpin_snat_ip) {
-- add_lb_ct_snat_hairpin_for_dp(lb, NULL, NULL,
-+ add_lb_ct_snat_hairpin_for_dp(lb, !!lb_vip->vip_port, NULL, NULL,
- &match, &ofpacts, flow_table);
- } else {
- for (size_t i = 0; i < lb->slb->n_datapaths; i++) {
-- add_lb_ct_snat_hairpin_for_dp(lb, lb->slb->datapaths[i],
-- local_datapaths,
-- &match, &ofpacts, flow_table);
-+ add_lb_ct_snat_hairpin_for_dp(lb, !!lb_vip->vip_port,
-+ lb->slb->datapaths[i],
-+ local_datapaths, &match,
-+ &ofpacts, flow_table);
- }
- if (lb->slb->datapath_group) {
- for (size_t i = 0; i < lb->slb->datapath_group->n_datapaths; i++) {
- add_lb_ct_snat_hairpin_for_dp(
-- lb, lb->slb->datapath_group->datapaths[i],
-+ lb, !!lb_vip->vip_port,
-+ lb->slb->datapath_group->datapaths[i],
- local_datapaths, &match, &ofpacts, flow_table);
- }
- }
-diff --git a/controller/lflow.h b/controller/lflow.h
-index dd742257b..2472dec29 100644
---- a/controller/lflow.h
-+++ b/controller/lflow.h
-@@ -63,27 +63,36 @@ struct uuid;
- *
- * These are heavily documented in ovn-architecture(7), please update it if
- * you make any changes. */
--#define OFTABLE_PHY_TO_LOG 0
--#define OFTABLE_LOG_INGRESS_PIPELINE 8 /* First of LOG_PIPELINE_LEN tables. */
--#define OFTABLE_REMOTE_OUTPUT 37
--#define OFTABLE_LOCAL_OUTPUT 38
--#define OFTABLE_CHECK_LOOPBACK 39
--#define OFTABLE_LOG_EGRESS_PIPELINE 40 /* First of LOG_PIPELINE_LEN tables. */
--#define OFTABLE_SAVE_INPORT 64
--#define OFTABLE_LOG_TO_PHY 65
--#define OFTABLE_MAC_BINDING 66
--#define OFTABLE_MAC_LOOKUP 67
--#define OFTABLE_CHK_LB_HAIRPIN 68
--#define OFTABLE_CHK_LB_HAIRPIN_REPLY 69
--#define OFTABLE_CT_SNAT_HAIRPIN 70
--#define OFTABLE_GET_FDB 71
--#define OFTABLE_LOOKUP_FDB 72
--#define OFTABLE_CHK_IN_PORT_SEC 73
--#define OFTABLE_CHK_IN_PORT_SEC_ND 74
--#define OFTABLE_CHK_OUT_PORT_SEC 75
--#define OFTABLE_ECMP_NH_MAC 76
--#define OFTABLE_ECMP_NH 77
--#define OFTABLE_CHK_LB_AFFINITY 78
-+#define OFTABLE_PHY_TO_LOG 0
-+
-+/* Start of LOG_PIPELINE_LEN tables. */
-+#define OFTABLE_LOG_INGRESS_PIPELINE 8
-+#define OFTABLE_OUTPUT_LARGE_PKT_DETECT 37
-+#define OFTABLE_OUTPUT_LARGE_PKT_PROCESS 38
-+#define OFTABLE_REMOTE_OUTPUT 39
-+#define OFTABLE_LOCAL_OUTPUT 40
-+#define OFTABLE_CHECK_LOOPBACK 41
-+
-+/* Start of the OUTPUT section of the pipeline. */
-+#define OFTABLE_OUTPUT_INIT OFTABLE_OUTPUT_LARGE_PKT_DETECT
-+
-+/* Start of LOG_PIPELINE_LEN tables. */
-+#define OFTABLE_LOG_EGRESS_PIPELINE 42
-+#define OFTABLE_SAVE_INPORT 64
-+#define OFTABLE_LOG_TO_PHY 65
-+#define OFTABLE_MAC_BINDING 66
-+#define OFTABLE_MAC_LOOKUP 67
-+#define OFTABLE_CHK_LB_HAIRPIN 68
-+#define OFTABLE_CHK_LB_HAIRPIN_REPLY 69
-+#define OFTABLE_CT_SNAT_HAIRPIN 70
-+#define OFTABLE_GET_FDB 71
-+#define OFTABLE_LOOKUP_FDB 72
-+#define OFTABLE_CHK_IN_PORT_SEC 73
-+#define OFTABLE_CHK_IN_PORT_SEC_ND 74
-+#define OFTABLE_CHK_OUT_PORT_SEC 75
-+#define OFTABLE_ECMP_NH_MAC 76
-+#define OFTABLE_ECMP_NH 77
-+#define OFTABLE_CHK_LB_AFFINITY 78
-
- struct lflow_ctx_in {
- struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath;
-diff --git a/controller/local_data.c b/controller/local_data.c
-index acaf1de6d..cf0b21bb1 100644
---- a/controller/local_data.c
-+++ b/controller/local_data.c
-@@ -22,6 +22,7 @@
- #include "lib/util.h"
- #include "lib/vswitch-idl.h"
- #include "openvswitch/vlog.h"
-+#include "socket-util.h"
-
- /* OVN includes. */
- #include "encaps.h"
-@@ -447,6 +448,7 @@ local_nonvif_data_run(const struct ovsrec_bridge *br_int,
- tun->chassis_id = xstrdup(tunnel_id);
- tun->ofport = u16_to_ofp(ofport);
- tun->type = tunnel_type;
-+ tun->is_ipv6 = ip ? addr_is_ipv6(ip) : false;
-
- free(hash_id);
- free(ip);
-diff --git a/controller/local_data.h b/controller/local_data.h
-index 748f009aa..ad0fa7f94 100644
---- a/controller/local_data.h
-+++ b/controller/local_data.h
-@@ -133,6 +133,7 @@ struct chassis_tunnel {
- char *chassis_id;
- ofp_port_t ofport;
- enum chassis_tunnel_type type;
-+ bool is_ipv6;
- };
-
- void local_nonvif_data_run(const struct ovsrec_bridge *br_int,
-diff --git a/controller/mirror.c b/controller/mirror.c
-index 665736966..0e5885e9b 100644
---- a/controller/mirror.c
-+++ b/controller/mirror.c
-@@ -22,6 +22,7 @@
-
- /* OVS includes. */
- #include "lib/vswitch-idl.h"
-+#include "lib/socket-util.h"
- #include "include/openvswitch/shash.h"
- #include "openvswitch/vlog.h"
-
-@@ -69,6 +70,7 @@ static void set_mirror_iface_options(struct ovsrec_interface *,
- static const struct ovsrec_port *get_iface_port(
- const struct ovsrec_interface *, const struct ovsrec_bridge *);
-
-+char *get_mirror_tunnel_type(const struct sbrec_mirror *);
-
- void
- mirror_register_ovs_idl(struct ovsdb_idl *ovs_idl)
-@@ -244,24 +246,26 @@ set_mirror_iface_options(struct ovsrec_interface *iface,
- smap_destroy(&options);
- }
-
-+char *
-+get_mirror_tunnel_type(const struct sbrec_mirror *sb_mirror)
-+{
-+ bool is_ipv6 = addr_is_ipv6(sb_mirror->sink);
-+
-+ return xasprintf(is_ipv6 ? "ip6%s" : "%s", sb_mirror->type);
-+}
-+
- static void
- check_and_update_interface_table(const struct sbrec_mirror *sb_mirror,
- const struct ovsrec_mirror *ovs_mirror)
- {
-- char *type;
-- struct ovsrec_interface *iface =
-- ovs_mirror->output_port->interfaces[0];
-- struct smap *opts = &iface->options;
-- const char *erspan_ver = smap_get(opts, "erspan_ver");
-- if (erspan_ver) {
-- type = "erspan";
-- } else {
-- type = "gre";
-- }
-- if (strcmp(type, sb_mirror->type)) {
-- ovsrec_interface_set_type(iface, sb_mirror->type);
-+ struct ovsrec_interface *iface = ovs_mirror->output_port->interfaces[0];
-+ char *type = get_mirror_tunnel_type(sb_mirror);
-+
-+ if (strcmp(type, iface->type)) {
-+ ovsrec_interface_set_type(iface, type);
- }
- set_mirror_iface_options(iface, sb_mirror);
-+ free(type);
- }
-
- static void
-@@ -327,8 +331,11 @@ create_ovs_mirror(struct ovn_mirror *m, struct ovsdb_idl_txn *ovs_idl_txn,
- char *port_name = xasprintf("ovn-%s", m->name);
-
- ovsrec_interface_set_name(iface, port_name);
-- ovsrec_interface_set_type(iface, m->sb_mirror->type);
-+
-+ char *type = get_mirror_tunnel_type(m->sb_mirror);
-+ ovsrec_interface_set_type(iface, type);
- set_mirror_iface_options(iface, m->sb_mirror);
-+ free(type);
-
- struct ovsrec_port *port = ovsrec_port_insert(ovs_idl_txn);
- ovsrec_port_set_name(port, port_name);
-diff --git a/controller/ofctrl.c b/controller/ofctrl.c
-index b1ba1c743..64a444ff6 100644
---- a/controller/ofctrl.c
-+++ b/controller/ofctrl.c
-@@ -766,13 +766,18 @@ ofctrl_get_mf_field_id(void)
-
- /* Runs the OpenFlow state machine against 'br_int', which is local to the
- * hypervisor on which we are running. Attempts to negotiate a Geneve option
-- * field for class OVN_GENEVE_CLASS, type OVN_GENEVE_TYPE. */
--void
-+ * field for class OVN_GENEVE_CLASS, type OVN_GENEVE_TYPE.
-+ *
-+ * Returns 'true' if an OpenFlow reconnect happened; 'false' otherwise.
-+ */
-+bool
- ofctrl_run(const struct ovsrec_bridge *br_int,
- const struct ovsrec_open_vswitch_table *ovs_table,
- struct shash *pending_ct_zones)
- {
- char *target = xasprintf("unix:%s/%s.mgmt", ovs_rundir(), br_int->name);
-+ bool reconnected = false;
-+
- if (strcmp(target, rconn_get_target(swconn))) {
- VLOG_INFO("%s: connecting to switch", target);
- rconn_connect(swconn, target, target);
-@@ -782,10 +787,12 @@ ofctrl_run(const struct ovsrec_bridge *br_int,
- rconn_run(swconn);
-
- if (!rconn_is_connected(swconn)) {
-- return;
-+ return reconnected;
- }
-+
- if (seqno != rconn_get_connection_seqno(swconn)) {
- seqno = rconn_get_connection_seqno(swconn);
-+ reconnected = true;
- state = S_NEW;
-
- /* Reset the state of any outstanding ct flushes to resend them. */
-@@ -855,6 +862,8 @@ ofctrl_run(const struct ovsrec_bridge *br_int,
- * point, so ensure that we come back again without waiting. */
- poll_immediate_wake();
- }
-+
-+ return reconnected;
- }
-
- void
-@@ -909,6 +918,7 @@ ofctrl_recv(const struct ofp_header *oh, enum ofptype type)
- } else if (type == OFPTYPE_ERROR) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
- log_openflow_rl(&rl, VLL_INFO, oh, "OpenFlow error");
-+ rconn_reconnect(swconn);
- } else {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
- log_openflow_rl(&rl, VLL_DBG, oh, "OpenFlow packet ignored");
-diff --git a/controller/ofctrl.h b/controller/ofctrl.h
-index f5751e3ee..105f9370b 100644
---- a/controller/ofctrl.h
-+++ b/controller/ofctrl.h
-@@ -51,7 +51,7 @@ struct ovn_desired_flow_table {
- void ofctrl_init(struct ovn_extend_table *group_table,
- struct ovn_extend_table *meter_table,
- int inactivity_probe_interval);
--void ofctrl_run(const struct ovsrec_bridge *br_int,
-+bool ofctrl_run(const struct ovsrec_bridge *br_int,
- const struct ovsrec_open_vswitch_table *,
- struct shash *pending_ct_zones);
- enum mf_field_id ofctrl_get_mf_field_id(void);
-diff --git a/controller/ovn-controller.8.xml b/controller/ovn-controller.8.xml
-index ab52e2d34..f61f43008 100644
---- a/controller/ovn-controller.8.xml
-+++ b/controller/ovn-controller.8.xml
-@@ -121,11 +121,11 @@
- that is needed in the current chassis.
-
-
-- It is more optimal to set it to true
in use cases when
-- the chassis would anyway need to monitor most of the records in
-- ovs-database, which would save the overhead of conditions
-- processing, especially for server side. Typically, set it to
-- true
for environments that all workloads need to be
-+ It is more efficient to set it to true
in use cases
-+ where the chassis would anyway need to monitor most of the records in
-+ OVN Southbound database, which would save the overhead of
-+ conditions processing, especially for server side. Typically, set it
-+ to true
for environments that all workloads need to be
- reachable from each other.
-
-
-@@ -171,16 +171,14 @@
-
-
-
-- Supported tunnel types for connecting hypervisors
-- are geneve
and stt
. Gateways may
-- use geneve
, vxlan
, or
-- stt
.
-+ Supported tunnel types for connecting hypervisors and gateways
-+ are geneve
, vxlan
, and stt
.
-
-
-
- Due to the limited amount of metadata in vxlan
,
-- the capabilities and performance of connected gateways will be
-- reduced versus other tunnel formats.
-+ the capabilities and performance of connected gateways and
-+ hypervisors will be reduced versus other tunnel formats.
-
-
-
-diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
-index 2d18bbfca..ead789fb9 100644
---- a/controller/ovn-controller.c
-+++ b/controller/ovn-controller.c
-@@ -60,6 +60,7 @@
- #include "lib/ovn-dirs.h"
- #include "lib/ovn-sb-idl.h"
- #include "lib/ovn-util.h"
-+#include "ovsport.h"
- #include "patch.h"
- #include "vif-plug.h"
- #include "vif-plug-provider.h"
-@@ -712,7 +713,7 @@ get_snat_ct_zone(const struct sbrec_datapath_binding *dp)
- }
-
- static void
--update_ct_zones(const struct shash *binding_lports,
-+update_ct_zones(const struct sset *local_lports,
- const struct hmap *local_datapaths,
- struct simap *ct_zones, unsigned long *ct_zone_bitmap,
- struct shash *pending_ct_zones)
-@@ -725,9 +726,9 @@ update_ct_zones(const struct shash *binding_lports,
- unsigned long unreq_snat_zones_map[BITMAP_N_LONGS(MAX_CT_ZONES)];
- struct simap unreq_snat_zones = SIMAP_INITIALIZER(&unreq_snat_zones);
-
-- struct shash_node *shash_node;
-- SHASH_FOR_EACH (shash_node, binding_lports) {
-- sset_add(&all_users, shash_node->name);
-+ const char *local_lport;
-+ SSET_FOR_EACH (local_lport, local_lports) {
-+ sset_add(&all_users, local_lport);
- }
-
- /* Local patched datapath (gateway routers) need zones assigned. */
-@@ -1060,6 +1061,7 @@ ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl)
- ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_name);
- ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_bfd);
- ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_bfd_status);
-+ ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_mtu);
- ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_type);
- ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_options);
- ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_ofport);
-@@ -1158,6 +1160,56 @@ en_ofctrl_is_connected_run(struct engine_node *node, void *data)
- engine_set_node_state(node, EN_UNCHANGED);
- }
-
-+struct ed_type_if_status_mgr {
-+ const struct if_status_mgr *manager;
-+ const struct ovsrec_interface_table *iface_table;
-+};
-+
-+static void *
-+en_if_status_mgr_init(struct engine_node *node OVS_UNUSED,
-+ struct engine_arg *arg OVS_UNUSED)
-+{
-+ struct ed_type_if_status_mgr *data = xzalloc(sizeof *data);
-+ return data;
-+}
-+
-+static void
-+en_if_status_mgr_cleanup(void *data OVS_UNUSED)
-+{
-+}
-+
-+static void
-+en_if_status_mgr_run(struct engine_node *node, void *data_)
-+{
-+ enum engine_node_state state = EN_UNCHANGED;
-+ struct ed_type_if_status_mgr *data = data_;
-+ struct controller_engine_ctx *ctrl_ctx = engine_get_context()->client_ctx;
-+ data->manager = ctrl_ctx->if_mgr;
-+ data->iface_table = EN_OVSDB_GET(engine_get_input("OVS_interface", node));
-+
-+ const struct ovsrec_interface *iface;
-+ OVSREC_INTERFACE_TABLE_FOR_EACH (iface, data->iface_table) {
-+ if (if_status_mgr_iface_update(data->manager, iface)) {
-+ state = EN_UPDATED;
-+ }
-+ }
-+ engine_set_node_state(node, state);
-+}
-+
-+static bool
-+if_status_mgr_ovs_interface_handler(struct engine_node *node, void *data)
-+{
-+ struct ed_type_if_status_mgr *data_ = data;
-+
-+ const struct ovsrec_interface *iface;
-+ OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface, data_->iface_table) {
-+ if (if_status_mgr_iface_update(data_->manager, iface)) {
-+ engine_set_node_state(node, EN_UPDATED);
-+ }
-+ }
-+ return true;
-+}
-+
- /* This engine node is to wrap the OVS_interface input and maintain a copy of
- * the old version of data for the column external_ids.
- *
-@@ -2010,7 +2062,11 @@ addr_sets_update(const struct sbrec_address_set_table *address_set_table,
- if (sbrec_address_set_is_deleted(as)) {
- expr_const_sets_remove(addr_sets, as->name);
- sset_add(deleted, as->name);
-- } else {
-+ }
-+ }
-+
-+ SBREC_ADDRESS_SET_TABLE_FOR_EACH_TRACKED (as, address_set_table) {
-+ if (!sbrec_address_set_is_deleted(as)) {
- struct expr_constant_set *cs_old = shash_find_data(addr_sets,
- as->name);
- if (!cs_old) {
-@@ -2381,7 +2437,7 @@ en_ct_zones_run(struct engine_node *node, void *data)
- EN_OVSDB_GET(engine_get_input("OVS_bridge", node));
-
- restore_ct_zones(bridge_table, ovs_table, ct_zones_data);
-- update_ct_zones(&rt_data->lbinding_data.lports, &rt_data->local_datapaths,
-+ update_ct_zones(&rt_data->local_lports, &rt_data->local_datapaths,
- &ct_zones_data->current, ct_zones_data->bitmap,
- &ct_zones_data->pending);
-
-@@ -2471,8 +2527,10 @@ ct_zones_runtime_data_handler(struct engine_node *node, void *data)
- SHASH_FOR_EACH (shash_node, &tdp->lports) {
- struct tracked_lport *t_lport = shash_node->data;
- if (strcmp(t_lport->pb->type, "")
-- && strcmp(t_lport->pb->type, "localport")) {
-- /* We allocate zone-id's only to VIF and localport lports. */
-+ && strcmp(t_lport->pb->type, "localport")
-+ && strcmp(t_lport->pb->type, "localnet")) {
-+ /* We allocate zone-id's only to VIF, localport, and localnet
-+ * lports. */
- continue;
- }
-
-@@ -2697,7 +2755,8 @@ static void
- lb_data_removed_five_tuples_add(struct ed_type_lb_data *lb_data,
- const struct ovn_controller_lb *lb)
- {
-- if (!ovs_feature_is_supported(OVS_CT_TUPLE_FLUSH_SUPPORT)) {
-+ if (!ovs_feature_is_supported(OVS_CT_TUPLE_FLUSH_SUPPORT) ||
-+ !lb->ct_flush) {
- return;
- }
-
-@@ -2716,7 +2775,8 @@ static void
- lb_data_removed_five_tuples_remove(struct ed_type_lb_data *lb_data,
- const struct ovn_controller_lb *lb)
- {
-- if (!ovs_feature_is_supported(OVS_CT_TUPLE_FLUSH_SUPPORT)) {
-+ if (!ovs_feature_is_supported(OVS_CT_TUPLE_FLUSH_SUPPORT) ||
-+ !lb->ct_flush) {
- return;
- }
-
-@@ -4048,6 +4108,9 @@ static void init_physical_ctx(struct engine_node *node,
- const struct ed_type_mff_ovn_geneve *ed_mff_ovn_geneve =
- engine_get_input_data("mff_ovn_geneve", node);
-
-+ const struct ovsrec_interface_table *ovs_interface_table =
-+ EN_OVSDB_GET(engine_get_input("if_status_mgr", node));
-+
- const struct ovsrec_open_vswitch_table *ovs_table =
- EN_OVSDB_GET(engine_get_input("OVS_open_vswitch", node));
- const struct ovsrec_bridge_table *bridge_table =
-@@ -4072,6 +4135,7 @@ static void init_physical_ctx(struct engine_node *node,
- p_ctx->sbrec_port_binding_by_name = sbrec_port_binding_by_name;
- p_ctx->sbrec_port_binding_by_datapath = sbrec_port_binding_by_datapath;
- p_ctx->port_binding_table = port_binding_table;
-+ p_ctx->ovs_interface_table = ovs_interface_table;
- p_ctx->mc_group_table = multicast_group_table;
- p_ctx->br_int = br_int;
- p_ctx->chassis_table = chassis_table;
-@@ -4085,6 +4149,9 @@ static void init_physical_ctx(struct engine_node *node,
- p_ctx->patch_ofports = &non_vif_data->patch_ofports;
- p_ctx->chassis_tunnels = &non_vif_data->chassis_tunnels;
-
-+ struct controller_engine_ctx *ctrl_ctx = engine_get_context()->client_ctx;
-+ p_ctx->if_mgr = ctrl_ctx->if_mgr;
-+
- pflow_output_get_debug(node, &p_ctx->debug);
- }
-
-@@ -4128,6 +4195,63 @@ en_pflow_output_run(struct engine_node *node, void *data)
- engine_set_node_state(node, EN_UPDATED);
- }
-
-+static bool
-+pflow_output_if_status_mgr_handler(struct engine_node *node,
-+ void *data)
-+{
-+ struct ed_type_pflow_output *pfo = data;
-+ struct ed_type_runtime_data *rt_data =
-+ engine_get_input_data("runtime_data", node);
-+ struct ed_type_non_vif_data *non_vif_data =
-+ engine_get_input_data("non_vif_data", node);
-+ struct ed_type_if_status_mgr *if_mgr_data =
-+ engine_get_input_data("if_status_mgr", node);
-+
-+ struct physical_ctx p_ctx;
-+ init_physical_ctx(node, rt_data, non_vif_data, &p_ctx);
-+
-+ const struct ovsrec_interface *iface;
-+ OVSREC_INTERFACE_TABLE_FOR_EACH_TRACKED (iface, if_mgr_data->iface_table) {
-+ const char *iface_id = smap_get(&iface->external_ids, "iface-id");
-+ if (!iface_id) {
-+ continue;
-+ }
-+
-+ const struct sbrec_port_binding *pb = lport_lookup_by_name(
-+ p_ctx.sbrec_port_binding_by_name, iface_id);
-+ if (!pb) {
-+ continue;
-+ }
-+ if (pb->n_additional_chassis) {
-+ /* Update flows for all ports in datapath. */
-+ struct sbrec_port_binding *target =
-+ sbrec_port_binding_index_init_row(
-+ p_ctx.sbrec_port_binding_by_datapath);
-+ sbrec_port_binding_index_set_datapath(target, pb->datapath);
-+
-+ const struct sbrec_port_binding *binding;
-+ SBREC_PORT_BINDING_FOR_EACH_EQUAL (
-+ binding, target, p_ctx.sbrec_port_binding_by_datapath) {
-+ bool removed = sbrec_port_binding_is_deleted(binding);
-+ if (!physical_handle_flows_for_lport(binding, removed, &p_ctx,
-+ &pfo->flow_table)) {
-+ return false;
-+ }
-+ }
-+ sbrec_port_binding_index_destroy_row(target);
-+ } else {
-+ /* If any multichassis ports, update flows for the port. */
-+ bool removed = sbrec_port_binding_is_deleted(pb);
-+ if (!physical_handle_flows_for_lport(pb, removed, &p_ctx,
-+ &pfo->flow_table)) {
-+ return false;
-+ }
-+ }
-+ engine_set_node_state(node, EN_UPDATED);
-+ }
-+ return true;
-+}
-+
- static bool
- pflow_output_sb_port_binding_handler(struct engine_node *node,
- void *data)
-@@ -4611,6 +4735,7 @@ main(int argc, char *argv[])
- ENGINE_NODE_WITH_CLEAR_TRACK_DATA(port_groups, "port_groups");
- ENGINE_NODE(northd_options, "northd_options");
- ENGINE_NODE(dhcp_options, "dhcp_options");
-+ ENGINE_NODE(if_status_mgr, "if_status_mgr");
- ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lb_data, "lb_data");
-
- #define SB_NODE(NAME, NAME_STR) ENGINE_NODE_SB(NAME, NAME_STR);
-@@ -4649,6 +4774,9 @@ main(int argc, char *argv[])
- engine_add_input(&en_non_vif_data, &en_ovs_interface,
- non_vif_data_ovs_iface_handler);
-
-+ engine_add_input(&en_if_status_mgr, &en_ovs_interface,
-+ if_status_mgr_ovs_interface_handler);
-+
- /* Note: The order of inputs is important, all OVS interface changes must
- * be handled before any ct_zone changes.
- */
-@@ -4659,6 +4787,8 @@ main(int argc, char *argv[])
- engine_add_input(&en_pflow_output, &en_sb_chassis,
- pflow_lflow_output_sb_chassis_handler);
-
-+ engine_add_input(&en_pflow_output, &en_if_status_mgr,
-+ pflow_output_if_status_mgr_handler);
- engine_add_input(&en_pflow_output, &en_sb_port_binding,
- pflow_output_sb_port_binding_handler);
- engine_add_input(&en_pflow_output, &en_sb_multicast_group,
-@@ -5061,8 +5191,14 @@ main(int argc, char *argv[])
-
- if (br_int) {
- ct_zones_data = engine_get_data(&en_ct_zones);
-- if (ct_zones_data) {
-- ofctrl_run(br_int, ovs_table, &ct_zones_data->pending);
-+ if (ct_zones_data && ofctrl_run(br_int, ovs_table,
-+ &ct_zones_data->pending)) {
-+ static struct vlog_rate_limit rl
-+ = VLOG_RATE_LIMIT_INIT(1, 1);
-+
-+ VLOG_INFO_RL(&rl, "OVS OpenFlow connection reconnected,"
-+ "force recompute.");
-+ engine_set_force_recompute(true);
- }
-
- if (chassis) {
-@@ -5071,7 +5207,8 @@ main(int argc, char *argv[])
- chassis,
- sbrec_sb_global_first(ovnsb_idl_loop.idl),
- ovs_table,
-- &transport_zones);
-+ &transport_zones,
-+ bridge_table);
-
- stopwatch_start(CONTROLLER_LOOP_STOPWATCH_NAME,
- time_msec());
-@@ -5225,6 +5362,11 @@ main(int argc, char *argv[])
- stopwatch_start(IF_STATUS_MGR_UPDATE_STOPWATCH_NAME,
- time_msec());
- if_status_mgr_update(if_mgr, binding_data, chassis,
-+ ovsrec_interface_table_get(
-+ ovs_idl_loop.idl),
-+ sbrec_port_binding_table_get(
-+ ovnsb_idl_loop.idl),
-+ !ovs_idl_txn,
- !ovnsb_idl_txn);
- stopwatch_stop(IF_STATUS_MGR_UPDATE_STOPWATCH_NAME,
- time_msec());
-@@ -5254,11 +5396,12 @@ main(int argc, char *argv[])
- stopwatch_start(IF_STATUS_MGR_RUN_STOPWATCH_NAME,
- time_msec());
- if_status_mgr_run(if_mgr, binding_data, chassis,
-+ ovsrec_interface_table_get(
-+ ovs_idl_loop.idl),
- !ovnsb_idl_txn, !ovs_idl_txn);
- stopwatch_stop(IF_STATUS_MGR_RUN_STOPWATCH_NAME,
- time_msec());
- }
--
- }
-
- if (!engine_has_run()) {
-@@ -5449,6 +5592,7 @@ loop_done:
- binding_destroy();
- patch_destroy();
- mirror_destroy();
-+ encaps_destroy();
- if_status_mgr_destroy(if_mgr);
- shash_destroy(&vif_plug_deleted_iface_ids);
- shash_destroy(&vif_plug_changed_iface_ids);
-@@ -5466,6 +5610,7 @@ loop_done:
- free(cli_system_id);
- }
- service_stop();
-+ ovsrcu_exit();
-
- exit(retval);
- }
-diff --git a/controller/ovsport.c b/controller/ovsport.c
-index ec38c3fca..ebcb9cb6d 100644
---- a/controller/ovsport.c
-+++ b/controller/ovsport.c
-@@ -264,3 +264,12 @@ maintain_interface_smap_column(
- }
- }
- }
-+
-+uint16_t
-+get_iface_mtu(const struct ovsrec_interface *iface)
-+{
-+ if (!iface || !iface->n_mtu || iface->mtu[0] <= 0) {
-+ return 0;
-+ }
-+ return (uint16_t) iface->mtu[0];
-+}
-diff --git a/controller/ovsport.h b/controller/ovsport.h
-index e355ff7ff..c40c1855a 100644
---- a/controller/ovsport.h
-+++ b/controller/ovsport.h
-@@ -57,4 +57,6 @@ const struct ovsrec_port * ovsport_lookup_by_interfaces(
- const struct ovsrec_port * ovsport_lookup_by_interface(
- struct ovsdb_idl_index *, struct ovsrec_interface *);
-
-+uint16_t get_iface_mtu(const struct ovsrec_interface *);
-+
- #endif /* lib/ovsport.h */
-diff --git a/controller/physical.c b/controller/physical.c
-index ec861f49c..d19eb9200 100644
---- a/controller/physical.c
-+++ b/controller/physical.c
-@@ -41,6 +41,7 @@
- #include "lib/ovn-sb-idl.h"
- #include "lib/ovn-util.h"
- #include "ovn/actions.h"
-+#include "if-status.h"
- #include "physical.h"
- #include "pinctrl.h"
- #include "openvswitch/shash.h"
-@@ -91,6 +92,7 @@ physical_register_ovs_idl(struct ovsdb_idl *ovs_idl)
-
- ovsdb_idl_add_table(ovs_idl, &ovsrec_table_interface);
- ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_name);
-+ ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_mtu);
- ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_ofport);
- ovsdb_idl_track_add_column(ovs_idl, &ovsrec_interface_col_external_ids);
- }
-@@ -876,12 +878,12 @@ put_local_common_flows(uint32_t dp_key,
-
- uint32_t port_key = pb->tunnel_key;
-
-- /* Table 38, priority 100.
-+ /* Table 40, priority 100.
- * =======================
- *
- * Implements output to local hypervisor. Each flow matches a
- * logical output port on the local hypervisor, and resubmits to
-- * table 39.
-+ * table 41.
- */
-
- ofpbuf_clear(ofpacts_p);
-@@ -891,13 +893,13 @@ put_local_common_flows(uint32_t dp_key,
-
- put_zones_ofpacts(zone_ids, ofpacts_p);
-
-- /* Resubmit to table 39. */
-+ /* Resubmit to table 41. */
- put_resubmit(OFTABLE_CHECK_LOOPBACK, ofpacts_p);
- ofctrl_add_flow(flow_table, OFTABLE_LOCAL_OUTPUT, 100,
- pb->header_.uuid.parts[0], &match, ofpacts_p,
- &pb->header_.uuid);
-
-- /* Table 39, Priority 100.
-+ /* Table 41, Priority 100.
- * =======================
- *
- * Drop packets whose logical inport and outport are the same
-@@ -1104,6 +1106,240 @@ setup_activation_strategy(const struct sbrec_port_binding *binding,
- }
- }
-
-+/*
-+ * Insert a flow to determine if an IP packet is too big for the corresponding
-+ * egress interface.
-+ */
-+static void
-+determine_if_pkt_too_big(struct ovn_desired_flow_table *flow_table,
-+ const struct sbrec_port_binding *binding,
-+ const struct sbrec_port_binding *mcp,
-+ uint16_t mtu, bool is_ipv6, int direction)
-+{
-+ struct ofpbuf ofpacts;
-+ ofpbuf_init(&ofpacts, 0);
-+
-+ /* Store packet too large flag in reg9[1]. */
-+ struct match match;
-+ match_init_catchall(&match);
-+ match_set_dl_type(&match, htons(is_ipv6 ? ETH_TYPE_IPV6 : ETH_TYPE_IP));
-+ match_set_metadata(&match, htonll(binding->datapath->tunnel_key));
-+ match_set_reg(&match, direction - MFF_REG0, mcp->tunnel_key);
-+
-+ /* reg9[1] is REGBIT_PKT_LARGER as defined by northd */
-+ struct ofpact_check_pkt_larger *pkt_larger =
-+ ofpact_put_CHECK_PKT_LARGER(&ofpacts);
-+ pkt_larger->pkt_len = mtu;
-+ pkt_larger->dst.field = mf_from_id(MFF_REG9);
-+ pkt_larger->dst.ofs = 1;
-+
-+ put_resubmit(OFTABLE_OUTPUT_LARGE_PKT_PROCESS, &ofpacts);
-+ ofctrl_add_flow(flow_table, OFTABLE_OUTPUT_LARGE_PKT_DETECT, 100,
-+ binding->header_.uuid.parts[0], &match, &ofpacts,
-+ &binding->header_.uuid);
-+ ofpbuf_uninit(&ofpacts);
-+}
-+
-+/*
-+ * Insert a flow to reply with ICMP error for IP packets that are too big for
-+ * the corresponding egress interface.
-+ */
-+/*
-+ * NOTE(ihrachys) This reimplements icmp_error as found in
-+ * build_icmperr_pkt_big_flows. We may look into reusing the existing OVN
-+ * action for this flow in the future.
-+ */
-+static void
-+reply_imcp_error_if_pkt_too_big(struct ovn_desired_flow_table *flow_table,
-+ const struct sbrec_port_binding *binding,
-+ const struct sbrec_port_binding *mcp,
-+ uint16_t mtu, bool is_ipv6, int direction)
-+{
-+ struct match match;
-+ match_init_catchall(&match);
-+ match_set_dl_type(&match, htons(is_ipv6 ? ETH_TYPE_IPV6 : ETH_TYPE_IP));
-+ match_set_metadata(&match, htonll(binding->datapath->tunnel_key));
-+ match_set_reg(&match, direction - MFF_REG0, mcp->tunnel_key);
-+ match_set_reg_masked(&match, MFF_REG9 - MFF_REG0, 1 << 1, 1 << 1);
-+
-+ /* Return ICMP error with a part of the original IP packet included. */
-+ struct ofpbuf ofpacts;
-+ ofpbuf_init(&ofpacts, 0);
-+ size_t oc_offset = encode_start_controller_op(
-+ ACTION_OPCODE_ICMP, true, NX_CTLR_NO_METER, &ofpacts);
-+
-+ struct ofpbuf inner_ofpacts;
-+ ofpbuf_init(&inner_ofpacts, 0);
-+
-+ /* The error packet is no longer too large, set REGBIT_PKT_LARGER = 0 */
-+ /* reg9[1] is REGBIT_PKT_LARGER as defined by northd */
-+ ovs_be32 value = htonl(0);
-+ ovs_be32 mask = htonl(1 << 1);
-+ ofpact_put_set_field(
-+ &inner_ofpacts, mf_from_id(MFF_REG9), &value, &mask);
-+
-+ /* The new error packet is delivered locally */
-+ /* REGBIT_EGRESS_LOOPBACK = 1 */
-+ value = htonl(1 << MLF_ALLOW_LOOPBACK_BIT);
-+ mask = htonl(1 << MLF_ALLOW_LOOPBACK_BIT);
-+ ofpact_put_set_field(
-+ &inner_ofpacts, mf_from_id(MFF_LOG_FLAGS), &value, &mask);
-+
-+ /* eth.src <-> eth.dst */
-+ put_stack(MFF_ETH_DST, ofpact_put_STACK_PUSH(&inner_ofpacts));
-+ put_stack(MFF_ETH_SRC, ofpact_put_STACK_PUSH(&inner_ofpacts));
-+ put_stack(MFF_ETH_DST, ofpact_put_STACK_POP(&inner_ofpacts));
-+ put_stack(MFF_ETH_SRC, ofpact_put_STACK_POP(&inner_ofpacts));
-+
-+ /* ip.src <-> ip.dst */
-+ put_stack(is_ipv6 ? MFF_IPV6_DST : MFF_IPV4_DST,
-+ ofpact_put_STACK_PUSH(&inner_ofpacts));
-+ put_stack(is_ipv6 ? MFF_IPV6_SRC : MFF_IPV4_SRC,
-+ ofpact_put_STACK_PUSH(&inner_ofpacts));
-+ put_stack(is_ipv6 ? MFF_IPV6_DST : MFF_IPV4_DST,
-+ ofpact_put_STACK_POP(&inner_ofpacts));
-+ put_stack(is_ipv6 ? MFF_IPV6_SRC : MFF_IPV4_SRC,
-+ ofpact_put_STACK_POP(&inner_ofpacts));
-+
-+ /* ip.ttl = 255 */
-+ struct ofpact_ip_ttl *ip_ttl = ofpact_put_SET_IP_TTL(&inner_ofpacts);
-+ ip_ttl->ttl = 255;
-+
-+ uint16_t frag_mtu = mtu - ETHERNET_OVERHEAD;
-+ size_t frag_mtu_oc_offset;
-+ if (is_ipv6) {
-+ /* icmp6.type = 2 (Packet Too Big) */
-+ /* icmp6.code = 0 */
-+ uint8_t icmp_type = 2;
-+ uint8_t icmp_code = 0;
-+ ofpact_put_set_field(
-+ &inner_ofpacts, mf_from_id(MFF_ICMPV6_TYPE), &icmp_type, NULL);
-+ ofpact_put_set_field(
-+ &inner_ofpacts, mf_from_id(MFF_ICMPV6_CODE), &icmp_code, NULL);
-+
-+ /* icmp6.frag_mtu */
-+ frag_mtu_oc_offset = encode_start_controller_op(
-+ ACTION_OPCODE_PUT_ICMP6_FRAG_MTU, true, NX_CTLR_NO_METER,
-+ &inner_ofpacts);
-+ ovs_be32 frag_mtu_ovs = htonl(frag_mtu);
-+ ofpbuf_put(&inner_ofpacts, &frag_mtu_ovs, sizeof(frag_mtu_ovs));
-+ } else {
-+ /* icmp4.type = 3 (Destination Unreachable) */
-+ /* icmp4.code = 4 (Fragmentation Needed) */
-+ uint8_t icmp_type = 3;
-+ uint8_t icmp_code = 4;
-+ ofpact_put_set_field(
-+ &inner_ofpacts, mf_from_id(MFF_ICMPV4_TYPE), &icmp_type, NULL);
-+ ofpact_put_set_field(
-+ &inner_ofpacts, mf_from_id(MFF_ICMPV4_CODE), &icmp_code, NULL);
-+
-+ /* icmp4.frag_mtu = */
-+ frag_mtu_oc_offset = encode_start_controller_op(
-+ ACTION_OPCODE_PUT_ICMP4_FRAG_MTU, true, NX_CTLR_NO_METER,
-+ &inner_ofpacts);
-+ ovs_be16 frag_mtu_ovs = htons(frag_mtu);
-+ ofpbuf_put(&inner_ofpacts, &frag_mtu_ovs, sizeof(frag_mtu_ovs));
-+ }
-+ encode_finish_controller_op(frag_mtu_oc_offset, &inner_ofpacts);
-+
-+ /* Finally, submit the ICMP error back to the ingress pipeline */
-+ put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE, &inner_ofpacts);
-+
-+ /* Attach nested actions to ICMP error controller handler */
-+ ofpacts_put_openflow_actions(inner_ofpacts.data, inner_ofpacts.size,
-+ &ofpacts, OFP15_VERSION);
-+
-+ /* Finalize the ICMP error controller handler */
-+ encode_finish_controller_op(oc_offset, &ofpacts);
-+
-+ ofctrl_add_flow(flow_table, OFTABLE_OUTPUT_LARGE_PKT_PROCESS, 100,
-+ binding->header_.uuid.parts[0], &match, &ofpacts,
-+ &binding->header_.uuid);
-+
-+ ofpbuf_uninit(&inner_ofpacts);
-+ ofpbuf_uninit(&ofpacts);
-+}
-+
-+static uint16_t
-+get_tunnel_overhead(struct chassis_tunnel const *tun)
-+{
-+ uint16_t overhead = 0;
-+ enum chassis_tunnel_type type = tun->type;
-+ if (type == GENEVE) {
-+ overhead += GENEVE_TUNNEL_OVERHEAD;
-+ } else if (type == STT) {
-+ overhead += STT_TUNNEL_OVERHEAD;
-+ } else if (type == VXLAN) {
-+ overhead += VXLAN_TUNNEL_OVERHEAD;
-+ } else {
-+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
-+ VLOG_WARN_RL(&rl, "Unknown tunnel type %d, can't determine overhead "
-+ "size for Path MTU Discovery", type);
-+ return 0;
-+ }
-+ overhead += tun->is_ipv6? IPV6_HEADER_LEN : IP_HEADER_LEN;
-+ return overhead;
-+}
-+
-+static uint16_t
-+get_effective_mtu(const struct sbrec_port_binding *mcp,
-+ struct ovs_list *remote_tunnels,
-+ const struct if_status_mgr *if_mgr)
-+{
-+ /* Use interface MTU as a base for calculation */
-+ uint16_t iface_mtu = if_status_mgr_iface_get_mtu(if_mgr,
-+ mcp->logical_port);
-+ if (!iface_mtu) {
-+ return 0;
-+ }
-+
-+ /* Iterate over all peer tunnels and find the biggest tunnel overhead */
-+ uint16_t overhead = 0;
-+ struct tunnel *tun;
-+ LIST_FOR_EACH (tun, list_node, remote_tunnels) {
-+ overhead = MAX(overhead, get_tunnel_overhead(tun->tun));
-+ }
-+ if (!overhead) {
-+ return 0;
-+ }
-+
-+ return iface_mtu - overhead;
-+}
-+
-+static void
-+handle_pkt_too_big_for_ip_version(struct ovn_desired_flow_table *flow_table,
-+ const struct sbrec_port_binding *binding,
-+ const struct sbrec_port_binding *mcp,
-+ uint16_t mtu, bool is_ipv6)
-+{
-+ /* ingress */
-+ determine_if_pkt_too_big(flow_table, binding, mcp, mtu, is_ipv6,
-+ MFF_LOG_INPORT);
-+ reply_imcp_error_if_pkt_too_big(flow_table, binding, mcp, mtu, is_ipv6,
-+ MFF_LOG_INPORT);
-+
-+ /* egress */
-+ determine_if_pkt_too_big(flow_table, binding, mcp, mtu, is_ipv6,
-+ MFF_LOG_OUTPORT);
-+ reply_imcp_error_if_pkt_too_big(flow_table, binding, mcp, mtu, is_ipv6,
-+ MFF_LOG_OUTPORT);
-+}
-+
-+static void
-+handle_pkt_too_big(struct ovn_desired_flow_table *flow_table,
-+ struct ovs_list *remote_tunnels,
-+ const struct sbrec_port_binding *binding,
-+ const struct sbrec_port_binding *mcp,
-+ const struct if_status_mgr *if_mgr)
-+{
-+ uint16_t mtu = get_effective_mtu(mcp, remote_tunnels, if_mgr);
-+ if (!mtu) {
-+ return;
-+ }
-+ handle_pkt_too_big_for_ip_version(flow_table, binding, mcp, mtu, false);
-+ handle_pkt_too_big_for_ip_version(flow_table, binding, mcp, mtu, true);
-+}
-+
- static void
- enforce_tunneling_for_multichassis_ports(
- struct local_datapath *ld,
-@@ -1111,7 +1347,8 @@ enforce_tunneling_for_multichassis_ports(
- const struct sbrec_chassis *chassis,
- const struct hmap *chassis_tunnels,
- enum mf_field_id mff_ovn_geneve,
-- struct ovn_desired_flow_table *flow_table)
-+ struct ovn_desired_flow_table *flow_table,
-+ const struct if_status_mgr *if_mgr)
- {
- if (shash_is_empty(&ld->multichassis_ports)) {
- return;
-@@ -1156,6 +1393,8 @@ enforce_tunneling_for_multichassis_ports(
- binding->header_.uuid.parts[0], &match, &ofpacts,
- &binding->header_.uuid);
- ofpbuf_uninit(&ofpacts);
-+
-+ handle_pkt_too_big(flow_table, tuns, binding, mcp, if_mgr);
- }
-
- struct tunnel *tun_elem;
-@@ -1177,6 +1416,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name,
- const struct sbrec_port_binding *binding,
- const struct sbrec_chassis *chassis,
- const struct physical_debug *debug,
-+ const struct if_status_mgr *if_mgr,
- struct ovn_desired_flow_table *flow_table,
- struct ofpbuf *ofpacts_p)
- {
-@@ -1233,12 +1473,12 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name,
- || ha_chassis_group_is_active(binding->ha_chassis_group,
- active_tunnels, chassis))) {
-
-- /* Table 38, priority 100.
-+ /* Table 40, priority 100.
- * =======================
- *
- * Implements output to local hypervisor. Each flow matches a
- * logical output port on the local hypervisor, and resubmits to
-- * table 39. For ports of type "chassisredirect", the logical
-+ * table 41. For ports of type "chassisredirect", the logical
- * output port is changed from the "chassisredirect" port to the
- * underlying distributed port. */
-
-@@ -1275,7 +1515,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name,
- ct_zones);
- put_zones_ofpacts(&zone_ids, ofpacts_p);
-
-- /* Resubmit to table 39. */
-+ /* Resubmit to table 41. */
- put_resubmit(OFTABLE_CHECK_LOOPBACK, ofpacts_p);
- }
-
-@@ -1491,7 +1731,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name,
- ofport, flow_table);
- }
-
-- /* Table 39, priority 160.
-+ /* Table 41, priority 160.
- * =======================
- *
- * Do not forward local traffic from a localport to a localnet port.
-@@ -1561,13 +1801,13 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name,
- }
- }
-
-- /* Table 37, priority 150.
-+ /* Table 39, priority 150.
- * =======================
- *
- * Handles packets received from ports of type "localport". These
- * ports are present on every hypervisor. Traffic that originates at
- * one should never go over a tunnel to a remote hypervisor,
-- * so resubmit them to table 38 for local delivery. */
-+ * so resubmit them to table 40 for local delivery. */
- if (!strcmp(binding->type, "localport")) {
- ofpbuf_clear(ofpacts_p);
- put_resubmit(OFTABLE_LOCAL_OUTPUT, ofpacts_p);
-@@ -1581,7 +1821,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name,
- }
- } else if (access_type == PORT_LOCALNET) {
- /* Remote port connected by localnet port */
-- /* Table 38, priority 100.
-+ /* Table 40, priority 100.
- * =======================
- *
- * Implements switching to localnet port. Each flow matches a
-@@ -1596,14 +1836,16 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name,
-
- put_load(localnet_port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, ofpacts_p);
-
-- /* Resubmit to table 38. */
-+ /* Resubmit to table 40. */
- put_resubmit(OFTABLE_LOCAL_OUTPUT, ofpacts_p);
- ofctrl_add_flow(flow_table, OFTABLE_LOCAL_OUTPUT, 100,
- binding->header_.uuid.parts[0],
- &match, ofpacts_p, &binding->header_.uuid);
-
-- enforce_tunneling_for_multichassis_ports(
-- ld, binding, chassis, chassis_tunnels, mff_ovn_geneve, flow_table);
-+ enforce_tunneling_for_multichassis_ports(ld, binding, chassis,
-+ chassis_tunnels,
-+ mff_ovn_geneve, flow_table,
-+ if_mgr);
-
- /* No more tunneling to set up. */
- goto out;
-@@ -1613,7 +1855,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name,
- const char *redirect_type = smap_get(&binding->options,
- "redirect-type");
-
-- /* Table 38, priority 100.
-+ /* Table 40, priority 100.
- * =======================
- *
- * Handles traffic that needs to be sent to a remote hypervisor. Each
-@@ -1841,7 +2083,7 @@ consider_mc_group(struct ovsdb_idl_index *sbrec_port_binding_by_name,
- }
- }
-
-- /* Table 38, priority 100.
-+ /* Table 40, priority 100.
- * =======================
- *
- * Handle output to the local logical ports in the multicast group, if
-@@ -1857,7 +2099,7 @@ consider_mc_group(struct ovsdb_idl_index *sbrec_port_binding_by_name,
- &match, &ofpacts, &mc->header_.uuid);
- }
-
-- /* Table 37, priority 100.
-+ /* Table 39, priority 100.
- * =======================
- *
- * Handle output to the remote chassis in the multicast group, if
-@@ -1908,7 +2150,7 @@ physical_eval_port_binding(struct physical_ctx *p_ctx,
- p_ctx->patch_ofports,
- p_ctx->chassis_tunnels,
- pb, p_ctx->chassis, &p_ctx->debug,
-- flow_table, &ofpacts);
-+ p_ctx->if_mgr, flow_table, &ofpacts);
- ofpbuf_uninit(&ofpacts);
- }
-
-@@ -2032,10 +2274,10 @@ physical_run(struct physical_ctx *p_ctx,
- p_ctx->patch_ofports,
- p_ctx->chassis_tunnels, binding,
- p_ctx->chassis, &p_ctx->debug,
-- flow_table, &ofpacts);
-+ p_ctx->if_mgr, flow_table, &ofpacts);
- }
-
-- /* Handle output to multicast groups, in tables 37 and 38. */
-+ /* Handle output to multicast groups, in tables 40 and 41. */
- const struct sbrec_multicast_group *mc;
- SBREC_MULTICAST_GROUP_TABLE_FOR_EACH (mc, p_ctx->mc_group_table) {
- consider_mc_group(p_ctx->sbrec_port_binding_by_name,
-@@ -2056,7 +2298,7 @@ physical_run(struct physical_ctx *p_ctx,
- * encapsulations have metadata about the ingress and egress logical ports.
- * VXLAN encapsulations have metadata about the egress logical port only.
- * We set MFF_LOG_DATAPATH, MFF_LOG_INPORT, and MFF_LOG_OUTPORT from the
-- * tunnel key data where possible, then resubmit to table 38 to handle
-+ * tunnel key data where possible, then resubmit to table 40 to handle
- * packets to the local hypervisor. */
- struct chassis_tunnel *tun;
- HMAP_FOR_EACH (tun, hmap_node, p_ctx->chassis_tunnels) {
-@@ -2158,27 +2400,52 @@ physical_run(struct physical_ctx *p_ctx,
- */
- add_default_drop_flow(p_ctx, OFTABLE_PHY_TO_LOG, flow_table);
-
-- /* Table 37, priority 150.
-+ /* Table 37-38, priority 0.
-+ * ========================
-+ *
-+ * Default resubmit actions for OFTABLE_OUTPUT_LARGE_PKT_* tables.
-+ */
-+ struct match match;
-+ match_init_catchall(&match);
-+ ofpbuf_clear(&ofpacts);
-+ put_resubmit(OFTABLE_REMOTE_OUTPUT, &ofpacts);
-+ ofctrl_add_flow(flow_table, OFTABLE_OUTPUT_LARGE_PKT_DETECT, 0, 0, &match,
-+ &ofpacts, hc_uuid);
-+
-+ match_init_catchall(&match);
-+ match_set_reg_masked(&match, MFF_LOG_FLAGS - MFF_REG0,
-+ MLF_ALLOW_LOOPBACK, MLF_ALLOW_LOOPBACK);
-+ ofpbuf_clear(&ofpacts);
-+ put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts);
-+ ofctrl_add_flow(flow_table, OFTABLE_OUTPUT_LARGE_PKT_PROCESS, 10, 0,
-+ &match, &ofpacts, hc_uuid);
-+
-+ match_init_catchall(&match);
-+ ofpbuf_clear(&ofpacts);
-+ put_resubmit(OFTABLE_REMOTE_OUTPUT, &ofpacts);
-+ ofctrl_add_flow(flow_table, OFTABLE_OUTPUT_LARGE_PKT_PROCESS, 0, 0, &match,
-+ &ofpacts, hc_uuid);
-+
-+ /* Table 39, priority 150.
- * =======================
- *
- * 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
-+ * explicitly skip sending back out any tunnels and resubmit to table 40
- * 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 | MLF_ALLOW_LOOPBACK);
-
-- /* Resubmit to table 38. */
-+ /* Resubmit to table 40. */
- ofpbuf_clear(&ofpacts);
- put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts);
- ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150, 0,
- &match, &ofpacts, hc_uuid);
-
-- /* Table 37, priority 150.
-+ /* Table 39, priority 150.
- * =======================
- *
- * Packets that should not be sent to other hypervisors.
-@@ -2186,13 +2453,13 @@ physical_run(struct physical_ctx *p_ctx,
- match_init_catchall(&match);
- match_set_reg_masked(&match, MFF_LOG_FLAGS - MFF_REG0,
- MLF_LOCAL_ONLY, MLF_LOCAL_ONLY);
-- /* Resubmit to table 38. */
-+ /* Resubmit to table 40. */
- ofpbuf_clear(&ofpacts);
- put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts);
- ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150, 0,
- &match, &ofpacts, hc_uuid);
-
-- /* Table 37, Priority 0.
-+ /* Table 39, Priority 0.
- * =======================
- *
- * Resubmit packets that are not directed at tunnels or part of a
-@@ -2203,18 +2470,18 @@ physical_run(struct physical_ctx *p_ctx,
- ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 0, 0, &match,
- &ofpacts, hc_uuid);
-
-- /* Table 38, priority 0.
-+ /* Table 40, priority 0.
- * ======================
- *
- * Drop packets that do not match previous flows.
- */
- add_default_drop_flow(p_ctx, OFTABLE_LOCAL_OUTPUT, flow_table);
-
-- /* Table 39, Priority 0.
-+ /* Table 41, Priority 0.
- * =======================
- *
- * Resubmit packets that don't output to the ingress port (already checked
-- * in table 38) to the logical egress pipeline, clearing the logical
-+ * in table 40) to the logical egress pipeline, clearing the logical
- * registers (for consistent behavior with packets that get tunneled). */
- match_init_catchall(&match);
- ofpbuf_clear(&ofpacts);
-diff --git a/controller/physical.h b/controller/physical.h
-index f450dca94..1f1ed55ef 100644
---- a/controller/physical.h
-+++ b/controller/physical.h
-@@ -52,11 +52,13 @@ struct physical_ctx {
- struct ovsdb_idl_index *sbrec_port_binding_by_name;
- struct ovsdb_idl_index *sbrec_port_binding_by_datapath;
- const struct sbrec_port_binding_table *port_binding_table;
-+ const struct ovsrec_interface_table *ovs_interface_table;
- const struct sbrec_multicast_group_table *mc_group_table;
- const struct ovsrec_bridge *br_int;
- const struct sbrec_chassis_table *chassis_table;
- const struct sbrec_chassis *chassis;
- const struct sset *active_tunnels;
-+ const struct if_status_mgr *if_mgr;
- struct hmap *local_datapaths;
- struct sset *local_lports;
- const struct simap *ct_zones;
-diff --git a/controller/pinctrl.c b/controller/pinctrl.c
-index 795847729..cd9760f07 100644
---- a/controller/pinctrl.c
-+++ b/controller/pinctrl.c
-@@ -627,7 +627,7 @@ set_actions_and_enqueue_msg(struct rconn *swconn,
- }
-
- /* Forwards a packet to 'out_port_key' even if that's on a remote
-- * hypervisor, i.e., the packet is re-injected in table OFTABLE_REMOTE_OUTPUT.
-+ * hypervisor, i.e., the packet is re-injected in table OFTABLE_OUTPUT_INIT.
- */
- static void
- pinctrl_forward_pkt(struct rconn *swconn, int64_t dp_key,
-@@ -644,7 +644,7 @@ pinctrl_forward_pkt(struct rconn *swconn, int64_t dp_key,
-
- struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&ofpacts);
- resubmit->in_port = OFPP_CONTROLLER;
-- resubmit->table_id = OFTABLE_REMOTE_OUTPUT;
-+ resubmit->table_id = OFTABLE_OUTPUT_INIT;
-
- struct ofputil_packet_out po = {
- .packet = dp_packet_data(pkt),
-@@ -870,7 +870,7 @@ pinctrl_parse_dhcpv6_advt(struct rconn *swconn, const struct flow *ip_flow,
- 0, 32, &ofpacts);
- struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&ofpacts);
- resubmit->in_port = OFPP_CONTROLLER;
-- resubmit->table_id = OFTABLE_REMOTE_OUTPUT;
-+ resubmit->table_id = OFTABLE_OUTPUT_INIT;
-
- struct ofputil_packet_out po = {
- .packet = dp_packet_data(&packet),
-@@ -1499,7 +1499,7 @@ buffered_push_packet(struct buffered_packets *bp,
-
- struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&bi->ofpacts);
- resubmit->in_port = OFPP_CONTROLLER;
-- resubmit->table_id = OFTABLE_REMOTE_OUTPUT;
-+ resubmit->table_id = OFTABLE_OUTPUT_INIT;
-
- bi->p = packet;
-
-@@ -2444,19 +2444,19 @@ compose_out_dhcpv6_opts(struct ofpbuf *userdata,
- struct ofpbuf *out_dhcpv6_opts, ovs_be32 iaid)
- {
- while (userdata->size) {
-- struct dhcp_opt6_header *userdata_opt = ofpbuf_try_pull(
-+ struct dhcpv6_opt_header *userdata_opt = ofpbuf_try_pull(
- userdata, sizeof *userdata_opt);
- if (!userdata_opt) {
- return false;
- }
-
-- size_t size = ntohs(userdata_opt->size);
-+ size_t size = ntohs(userdata_opt->len);
- uint8_t *userdata_opt_data = ofpbuf_try_pull(userdata, size);
- if (!userdata_opt_data) {
- return false;
- }
-
-- switch (ntohs(userdata_opt->opt_code)) {
-+ switch (ntohs(userdata_opt->code)) {
- case DHCPV6_OPT_SERVER_ID_CODE:
- {
- /* The Server Identifier option carries a DUID
-@@ -2988,6 +2988,13 @@ pinctrl_handle_dns_lookup(
- goto exit;
- }
-
-+ /* Check if there is an additional record present, which is unsupported */
-+ if (in_dns_header->arcount) {
-+ VLOG_DBG_RL(&rl, "Received DNS query with additional records, which"
-+ " is unsupported");
-+ goto exit;
-+ }
-+
- struct udp_header *in_udp = dp_packet_l4(pkt_in);
- size_t udp_len = ntohs(in_udp->udp_len);
- size_t l4_len = dp_packet_l4_size(pkt_in);
-@@ -7190,7 +7197,9 @@ bfd_monitor_send_msg(struct rconn *swconn, long long int *bfd_time)
- pinctrl_send_bfd_tx_msg(swconn, entry, false);
-
- tx_timeout = MAX(entry->local_min_tx, entry->remote_min_rx);
-- tx_timeout -= random_range((tx_timeout * 25) / 100);
-+ if (tx_timeout >= 4) {
-+ tx_timeout -= random_range(tx_timeout / 4);
-+ }
- entry->next_tx = cur_time + tx_timeout;
- next:
- if (*bfd_time > entry->next_tx) {
-diff --git a/debian/changelog b/debian/changelog
-index 11a07dd38..02a9953ba 100644
---- a/debian/changelog
-+++ b/debian/changelog
-@@ -1,3 +1,9 @@
-+OVN (23.03.1-1) unstable; urgency=low
-+ [ OVN team ]
-+ * New upstream version
-+
-+ -- OVN team Fri, 03 Mar 2023 10:40:37 -0500
-+
- ovn (23.03.0-1) unstable; urgency=low
-
- * New upstream version
-diff --git a/include/ovn/actions.h b/include/ovn/actions.h
-index 28479ede1..c973fce9c 100644
---- a/include/ovn/actions.h
-+++ b/include/ovn/actions.h
-@@ -895,6 +895,9 @@ void ovnacts_free(struct ovnact[], size_t ovnacts_len);
- char *ovnact_op_to_string(uint32_t);
- int encode_ra_dnssl_opt(char *data, char *buf, int buf_len);
-
-+size_t encode_start_controller_op(enum action_opcode opcode, bool pause,
-+ uint32_t meter_id, struct ofpbuf *ofpacts);
-+void encode_finish_controller_op(size_t ofs, struct ofpbuf *ofpacts);
- void encode_controller_op(enum action_opcode opcode, uint32_t meter_id,
- struct ofpbuf *ofpacts);
-
-diff --git a/lib/actions.c b/lib/actions.c
-index 781549d75..ec27223f9 100644
---- a/lib/actions.c
-+++ b/lib/actions.c
-@@ -79,7 +79,7 @@ ovnact_init(struct ovnact *ovnact, enum ovnact_type type, size_t len)
- ovnact->len = len;
- }
-
--static size_t
-+size_t
- encode_start_controller_op(enum action_opcode opcode, bool pause,
- uint32_t meter_id, struct ofpbuf *ofpacts)
- {
-@@ -100,7 +100,7 @@ encode_start_controller_op(enum action_opcode opcode, bool pause,
- return ofs;
- }
-
--static void
-+void
- encode_finish_controller_op(size_t ofs, struct ofpbuf *ofpacts)
- {
- struct ofpact_controller *oc = ofpbuf_at_assert(ofpacts, ofs, sizeof *oc);
-@@ -2882,26 +2882,26 @@ static void
- encode_put_dhcpv6_option(const struct ovnact_gen_option *o,
- struct ofpbuf *ofpacts)
- {
-- struct dhcp_opt6_header *opt = ofpbuf_put_uninit(ofpacts, sizeof *opt);
-+ struct dhcpv6_opt_header *opt = ofpbuf_put_uninit(ofpacts, sizeof *opt);
- const union expr_constant *c = o->value.values;
- size_t n_values = o->value.n_values;
- size_t size;
-
-- opt->opt_code = htons(o->option->code);
-+ opt->code = htons(o->option->code);
-
- if (!strcmp(o->option->type, "ipv6")) {
- size = n_values * sizeof(struct in6_addr);
-- opt->size = htons(size);
-+ opt->len = htons(size);
- for (size_t i = 0; i < n_values; i++) {
- ofpbuf_put(ofpacts, &c[i].value.ipv6, sizeof(struct in6_addr));
- }
- } else if (!strcmp(o->option->type, "mac")) {
- size = sizeof(struct eth_addr);
-- opt->size = htons(size);
-+ opt->len = htons(size);
- ofpbuf_put(ofpacts, &c->value.mac, size);
- } else if (!strcmp(o->option->type, "str")) {
- size = strlen(c->string);
-- opt->size = htons(size);
-+ opt->len = htons(size);
- ofpbuf_put(ofpacts, c->string, size);
- }
- }
-diff --git a/lib/lb.c b/lib/lb.c
-index e941434c4..f88c1855b 100644
---- a/lib/lb.c
-+++ b/lib/lb.c
-@@ -38,6 +38,7 @@ static const char *lb_neighbor_responder_mode_names[] = {
- static struct nbrec_load_balancer_health_check *
- ovn_lb_get_health_check(const struct nbrec_load_balancer *nbrec_lb,
- const char *vip_port_str, bool template);
-+static void ovn_lb_backends_clear(struct ovn_lb_vip *vip);
-
- struct ovn_lb_ip_set *
- ovn_lb_ip_set_create(void)
-@@ -238,6 +239,8 @@ ovn_lb_backends_init_template(struct ovn_lb_vip *lb_vip, const char *value_)
- ds_put_format(&errors, "%s: should be a template of the form: "
- "'^backendip_variable1[:^port_variable1|:port]', ",
- atom);
-+ free(backend_port);
-+ free(backend_ip);
- }
- free(atom);
- }
-@@ -285,8 +288,27 @@ ovn_lb_vip_init_template(struct ovn_lb_vip *lb_vip, const char *lb_key_,
- lb_key_);
- }
-
-+ /* Backends can either be templates or explicit IPs and ports. */
- lb_vip->address_family = address_family;
-- return ovn_lb_backends_init_template(lb_vip, lb_value);
-+ lb_vip->template_backends = true;
-+ char *template_error = ovn_lb_backends_init_template(lb_vip, lb_value);
-+
-+ if (template_error) {
-+ lb_vip->template_backends = false;
-+ ovn_lb_backends_clear(lb_vip);
-+
-+ char *explicit_error = ovn_lb_backends_init_explicit(lb_vip, lb_value);
-+ if (explicit_error) {
-+ char *error =
-+ xasprintf("invalid backend: template (%s) OR explicit (%s)",
-+ template_error, explicit_error);
-+ free(explicit_error);
-+ free(template_error);
-+ return error;
-+ }
-+ free(template_error);
-+ }
-+ return NULL;
- }
-
- /* Returns NULL on success, an error string on failure. The caller is
-@@ -304,15 +326,29 @@ ovn_lb_vip_init(struct ovn_lb_vip *lb_vip, const char *lb_key,
- address_family);
- }
-
--void
--ovn_lb_vip_destroy(struct ovn_lb_vip *vip)
-+static void
-+ovn_lb_backends_destroy(struct ovn_lb_vip *vip)
- {
-- free(vip->vip_str);
-- free(vip->port_str);
- for (size_t i = 0; i < vip->n_backends; i++) {
- free(vip->backends[i].ip_str);
- free(vip->backends[i].port_str);
- }
-+}
-+
-+static void
-+ovn_lb_backends_clear(struct ovn_lb_vip *vip)
-+{
-+ ovn_lb_backends_destroy(vip);
-+ vip->backends = NULL;
-+ vip->n_backends = 0;
-+}
-+
-+void
-+ovn_lb_vip_destroy(struct ovn_lb_vip *vip)
-+{
-+ free(vip->vip_str);
-+ free(vip->port_str);
-+ ovn_lb_backends_destroy(vip);
- free(vip->backends);
- }
-
-@@ -357,11 +393,10 @@ ovn_lb_vip_format(const struct ovn_lb_vip *vip, struct ds *s, bool template)
- }
-
- void
--ovn_lb_vip_backends_format(const struct ovn_lb_vip *vip, struct ds *s,
-- bool template)
-+ovn_lb_vip_backends_format(const struct ovn_lb_vip *vip, struct ds *s)
- {
- bool needs_brackets = vip->address_family == AF_INET6 && vip->port_str
-- && !template;
-+ && !vip->template_backends;
- for (size_t i = 0; i < vip->n_backends; i++) {
- struct ovn_lb_backend *backend = &vip->backends[i];
-
-@@ -798,6 +833,7 @@ ovn_controller_lb_create(const struct sbrec_load_balancer *sbrec_lb,
- lb->hairpin_orig_tuple = smap_get_bool(&sbrec_lb->options,
- "hairpin_orig_tuple",
- false);
-+ lb->ct_flush = smap_get_bool(&sbrec_lb->options, "ct_flush", false);
- ovn_lb_get_hairpin_snat_ip(&sbrec_lb->header_.uuid, &sbrec_lb->options,
- &lb->hairpin_snat_ips);
- return lb;
-diff --git a/lib/lb.h b/lib/lb.h
-index 7a67b7426..e24f519db 100644
---- a/lib/lb.h
-+++ b/lib/lb.h
-@@ -96,6 +96,9 @@ struct ovn_lb_vip {
- */
- struct ovn_lb_backend *backends;
- size_t n_backends;
-+ bool template_backends; /* True if the backends are templates. False if
-+ * they're explicitly specified.
-+ */
- bool empty_backend_rej;
- int address_family;
- };
-@@ -188,6 +191,7 @@ struct ovn_controller_lb {
- bool hairpin_orig_tuple; /* True if ovn-northd stores the original
- * destination tuple in registers.
- */
-+ bool ct_flush; /* True if we should flush CT after backend removal. */
-
- struct lport_addresses hairpin_snat_ips; /* IP (v4 and/or v6) to be used
- * as source for hairpinned
-@@ -210,8 +214,7 @@ char *ovn_lb_vip_init(struct ovn_lb_vip *lb_vip, const char *lb_key,
- void ovn_lb_vip_destroy(struct ovn_lb_vip *vip);
- void ovn_lb_vip_format(const struct ovn_lb_vip *vip, struct ds *s,
- bool template);
--void ovn_lb_vip_backends_format(const struct ovn_lb_vip *vip, struct ds *s,
-- bool template);
-+void ovn_lb_vip_backends_format(const struct ovn_lb_vip *vip, struct ds *s);
-
- struct ovn_lb_5tuple {
- struct hmap_node hmap_node;
-diff --git a/lib/ovn-l7.h b/lib/ovn-l7.h
-index 2b20bc380..d718ed39a 100644
---- a/lib/ovn-l7.h
-+++ b/lib/ovn-l7.h
-@@ -240,12 +240,6 @@ struct dhcp_opt_header {
- #define DHCP_OPT_PAYLOAD(hdr) \
- (void *)((char *)hdr + sizeof(struct dhcp_opt_header))
-
--/* Used in the OpenFlow PACKET_IN userdata */
--struct dhcp_opt6_header {
-- ovs_be16 opt_code;
-- ovs_be16 size;
--};
--
- /* These are not defined in ovs/lib/dhcp.h, hence defining here. */
- #define OVN_DHCP_MSG_DECLINE 4
- #define OVN_DHCP_MSG_RELEASE 7
-diff --git a/lib/ovn-util.h b/lib/ovn-util.h
-index a1a418a24..7510fda4b 100644
---- a/lib/ovn-util.h
-+++ b/lib/ovn-util.h
-@@ -28,6 +28,13 @@
- #define ROUTE_ORIGIN_CONNECTED "connected"
- #define ROUTE_ORIGIN_STATIC "static"
-
-+#define ETH_CRC_LENGTH 4
-+#define ETHERNET_OVERHEAD (ETH_HEADER_LEN + ETH_CRC_LENGTH)
-+
-+#define GENEVE_TUNNEL_OVERHEAD 38
-+#define STT_TUNNEL_OVERHEAD 18
-+#define VXLAN_TUNNEL_OVERHEAD 30
-+
- struct eth_addr;
- struct nbrec_logical_router_port;
- struct ovsrec_flow_sample_collector_set_table;
-diff --git a/northd/en-sync-sb.c b/northd/en-sync-sb.c
-index 6e33901a8..20f0d8a82 100644
---- a/northd/en-sync-sb.c
-+++ b/northd/en-sync-sb.c
-@@ -22,7 +22,6 @@
- #include "openvswitch/util.h"
-
- #include "en-sync-sb.h"
--#include "include/ovn/expr.h"
- #include "lib/inc-proc-eng.h"
- #include "lib/lb.h"
- #include "lib/ovn-nb-idl.h"
-@@ -34,8 +33,15 @@
-
- VLOG_DEFINE_THIS_MODULE(en_sync_to_sb);
-
-+/* This is just a type wrapper to enforce that it has to be sorted. */
-+struct sorted_addresses {
-+ const char **arr;
-+ size_t n;
-+};
-+
-+
- static void sync_addr_set(struct ovsdb_idl_txn *ovnsb_txn, const char *name,
-- const char **addrs, size_t n_addrs,
-+ struct sorted_addresses *addresses,
- struct shash *sb_address_sets);
- static void sync_addr_sets(const struct nbrec_address_set_table *,
- const struct nbrec_port_group_table *,
-@@ -44,11 +50,17 @@ static void sync_addr_sets(const struct nbrec_address_set_table *,
- struct hmap *datapaths);
- static const struct sbrec_address_set *sb_address_set_lookup_by_name(
- struct ovsdb_idl_index *, const char *name);
--static void update_sb_addr_set(const char **nb_addresses, size_t n_addresses,
-+static void update_sb_addr_set(struct sorted_addresses *,
- const struct sbrec_address_set *);
- static void build_port_group_address_set(const struct nbrec_port_group *,
- struct svec *ipv4_addrs,
- struct svec *ipv6_addrs);
-+static struct sorted_addresses
-+sorted_addresses_from_nbrec(const struct nbrec_address_set *nb_as);
-+static struct sorted_addresses
-+sorted_addresses_from_svec(struct svec *addresses);
-+static struct sorted_addresses
-+sorted_addresses_from_sset(struct sset *addresses);
-
- void *
- en_sync_to_sb_init(struct engine_node *node OVS_UNUSED,
-@@ -133,8 +145,9 @@ sync_to_sb_addr_set_nb_address_set_handler(struct engine_node *node,
- if (!sb_addr_set) {
- return false;
- }
-- update_sb_addr_set((const char **) nb_addr_set->addresses,
-- nb_addr_set->n_addresses, sb_addr_set);
-+ struct sorted_addresses addrs =
-+ sorted_addresses_from_nbrec(nb_addr_set);
-+ update_sb_addr_set(&addrs, sb_addr_set);
- }
-
- return true;
-@@ -180,10 +193,14 @@ sync_to_sb_addr_set_nb_port_group_handler(struct engine_node *node,
- struct svec ipv4_addrs = SVEC_EMPTY_INITIALIZER;
- struct svec ipv6_addrs = SVEC_EMPTY_INITIALIZER;
- build_port_group_address_set(nb_pg, &ipv4_addrs, &ipv6_addrs);
-- update_sb_addr_set((const char **) ipv4_addrs.names, ipv4_addrs.n,
-- sb_addr_set_v4);
-- update_sb_addr_set((const char **) ipv6_addrs.names, ipv6_addrs.n,
-- sb_addr_set_v6);
-+
-+ struct sorted_addresses ipv4_addrs_sorted =
-+ sorted_addresses_from_svec(&ipv4_addrs);
-+ struct sorted_addresses ipv6_addrs_sorted =
-+ sorted_addresses_from_svec(&ipv6_addrs);
-+
-+ update_sb_addr_set(&ipv4_addrs_sorted, sb_addr_set_v4);
-+ update_sb_addr_set(&ipv6_addrs_sorted, sb_addr_set_v6);
-
- free(ipv4_addrs_name);
- free(ipv6_addrs_name);
-@@ -197,7 +214,7 @@ sync_to_sb_addr_set_nb_port_group_handler(struct engine_node *node,
- /* static functions. */
- static void
- sync_addr_set(struct ovsdb_idl_txn *ovnsb_txn, const char *name,
-- const char **addrs, size_t n_addrs,
-+ struct sorted_addresses *addresses,
- struct shash *sb_address_sets)
- {
- const struct sbrec_address_set *sb_address_set;
-@@ -206,10 +223,10 @@ sync_addr_set(struct ovsdb_idl_txn *ovnsb_txn, const char *name,
- if (!sb_address_set) {
- sb_address_set = sbrec_address_set_insert(ovnsb_txn);
- sbrec_address_set_set_name(sb_address_set, name);
-- sbrec_address_set_set_addresses(sb_address_set,
-- addrs, n_addrs);
-+ sbrec_address_set_set_addresses(sb_address_set, addresses->arr,
-+ addresses->n);
- } else {
-- update_sb_addr_set(addrs, n_addrs, sb_address_set);
-+ update_sb_addr_set(addresses, sb_address_set);
- }
- }
-
-@@ -243,8 +260,11 @@ sync_addr_sets(const struct nbrec_address_set_table *nb_address_set_table,
-
- /* Service monitor MAC. */
- const char *svc_monitor_macp = northd_get_svc_monitor_mac();
-- sync_addr_set(ovnsb_txn, "svc_monitor_mac", &svc_monitor_macp, 1,
-- &sb_address_sets);
-+ struct sorted_addresses svc = {
-+ .arr = &svc_monitor_macp,
-+ .n = 1,
-+ };
-+ sync_addr_set(ovnsb_txn, "svc_monitor_mac", &svc, &sb_address_sets);
-
- /* sync port group generated address sets first */
- const struct nbrec_port_group *nb_port_group;
-@@ -255,14 +275,16 @@ sync_addr_sets(const struct nbrec_address_set_table *nb_address_set_table,
- build_port_group_address_set(nb_port_group, &ipv4_addrs, &ipv6_addrs);
- char *ipv4_addrs_name = xasprintf("%s_ip4", nb_port_group->name);
- char *ipv6_addrs_name = xasprintf("%s_ip6", nb_port_group->name);
-+
-+ struct sorted_addresses ipv4_addrs_sorted =
-+ sorted_addresses_from_svec(&ipv4_addrs);
-+ struct sorted_addresses ipv6_addrs_sorted =
-+ sorted_addresses_from_svec(&ipv6_addrs);
-+
- sync_addr_set(ovnsb_txn, ipv4_addrs_name,
-- /* "char **" is not compatible with "const char **" */
-- (const char **) ipv4_addrs.names,
-- ipv4_addrs.n, &sb_address_sets);
-+ &ipv4_addrs_sorted, &sb_address_sets);
- sync_addr_set(ovnsb_txn, ipv6_addrs_name,
-- /* "char **" is not compatible with "const char **" */
-- (const char **) ipv6_addrs.names,
-- ipv6_addrs.n, &sb_address_sets);
-+ &ipv6_addrs_sorted, &sb_address_sets);
- free(ipv4_addrs_name);
- free(ipv6_addrs_name);
- svec_destroy(&ipv4_addrs);
-@@ -279,27 +301,26 @@ sync_addr_sets(const struct nbrec_address_set_table *nb_address_set_table,
- if (sset_count(&od->lb_ips->ips_v4_reachable)) {
- char *ipv4_addrs_name = lr_lb_address_set_name(od->tunnel_key,
- AF_INET);
-- const char **ipv4_addrs =
-- sset_array(&od->lb_ips->ips_v4_reachable);
-
-- sync_addr_set(ovnsb_txn, ipv4_addrs_name, ipv4_addrs,
-- sset_count(&od->lb_ips->ips_v4_reachable),
-- &sb_address_sets);
-+ struct sorted_addresses ipv4_addrs_sorted =
-+ sorted_addresses_from_sset(&od->lb_ips->ips_v4_reachable);
-+
-+ sync_addr_set(ovnsb_txn, ipv4_addrs_name,
-+ &ipv4_addrs_sorted, &sb_address_sets);
-+ free(ipv4_addrs_sorted.arr);
- free(ipv4_addrs_name);
-- free(ipv4_addrs);
- }
-
- if (sset_count(&od->lb_ips->ips_v6_reachable)) {
- char *ipv6_addrs_name = lr_lb_address_set_name(od->tunnel_key,
- AF_INET6);
-- const char **ipv6_addrs =
-- sset_array(&od->lb_ips->ips_v6_reachable);
-+ struct sorted_addresses ipv6_addrs_sorted =
-+ sorted_addresses_from_sset(&od->lb_ips->ips_v6_reachable);
-
-- sync_addr_set(ovnsb_txn, ipv6_addrs_name, ipv6_addrs,
-- sset_count(&od->lb_ips->ips_v6_reachable),
-- &sb_address_sets);
-+ sync_addr_set(ovnsb_txn, ipv6_addrs_name,
-+ &ipv6_addrs_sorted, &sb_address_sets);
-+ free(ipv6_addrs_sorted.arr);
- free(ipv6_addrs_name);
-- free(ipv6_addrs);
- }
- }
-
-@@ -308,10 +329,10 @@ sync_addr_sets(const struct nbrec_address_set_table *nb_address_set_table,
- const struct nbrec_address_set *nb_address_set;
- NBREC_ADDRESS_SET_TABLE_FOR_EACH (nb_address_set,
- nb_address_set_table) {
-+ struct sorted_addresses addrs =
-+ sorted_addresses_from_nbrec(nb_address_set);
- sync_addr_set(ovnsb_txn, nb_address_set->name,
-- /* "char **" is not compatible with "const char **" */
-- (const char **) nb_address_set->addresses,
-- nb_address_set->n_addresses, &sb_address_sets);
-+ &addrs, &sb_address_sets);
- }
-
- struct shash_node *node;
-@@ -323,48 +344,39 @@ sync_addr_sets(const struct nbrec_address_set_table *nb_address_set_table,
- }
-
- static void
--update_sb_addr_set(const char **nb_addresses, size_t n_addresses,
-+update_sb_addr_set(struct sorted_addresses *nb_addresses,
- const struct sbrec_address_set *sb_as)
- {
-- struct expr_constant_set *cs_nb_as =
-- expr_constant_set_create_integers(
-- (const char *const *) nb_addresses, n_addresses);
-- struct expr_constant_set *cs_sb_as =
-- expr_constant_set_create_integers(
-- (const char *const *) sb_as->addresses, sb_as->n_addresses);
--
-- struct expr_constant_set *addr_added = NULL;
-- struct expr_constant_set *addr_deleted = NULL;
-- expr_constant_set_integers_diff(cs_sb_as, cs_nb_as, &addr_added,
-- &addr_deleted);
--
-- struct ds ds = DS_EMPTY_INITIALIZER;
-- if (addr_added && addr_added->n_values) {
-- for (size_t i = 0; i < addr_added->n_values; i++) {
-- ds_clear(&ds);
-- expr_constant_format(&addr_added->values[i], EXPR_C_INTEGER, &ds);
-- sbrec_address_set_update_addresses_addvalue(sb_as, ds_cstr(&ds));
-+ size_t nb_index, sb_index;
-+
-+ const char **nb_arr = nb_addresses->arr;
-+ char **sb_arr = sb_as->addresses;
-+ size_t nb_n = nb_addresses->n;
-+ size_t sb_n = sb_as->n_addresses;
-+
-+ for (nb_index = sb_index = 0; nb_index < nb_n && sb_index < sb_n;) {
-+ int cmp = strcmp(nb_arr[nb_index], sb_arr[sb_index]);
-+ if (cmp < 0) {
-+ sbrec_address_set_update_addresses_addvalue(sb_as,
-+ nb_arr[nb_index]);
-+ nb_index++;
-+ } else if (cmp > 0) {
-+ sbrec_address_set_update_addresses_delvalue(sb_as,
-+ sb_arr[sb_index]);
-+ sb_index++;
-+ } else {
-+ nb_index++;
-+ sb_index++;
- }
- }
-
-- if (addr_deleted && addr_deleted->n_values) {
-- for (size_t i = 0; i < addr_deleted->n_values; i++) {
-- ds_clear(&ds);
-- expr_constant_format(&addr_deleted->values[i],
-- EXPR_C_INTEGER, &ds);
-- sbrec_address_set_update_addresses_delvalue(sb_as, ds_cstr(&ds));
-- }
-+ for (; nb_index < nb_n; nb_index++) {
-+ sbrec_address_set_update_addresses_addvalue(sb_as, nb_arr[nb_index]);
- }
-
-- ds_destroy(&ds);
-- expr_constant_set_destroy(cs_nb_as);
-- free(cs_nb_as);
-- expr_constant_set_destroy(cs_sb_as);
-- free(cs_sb_as);
-- expr_constant_set_destroy(addr_added);
-- free(addr_added);
-- expr_constant_set_destroy(addr_deleted);
-- free(addr_deleted);
-+ for (; sb_index < sb_n; sb_index++) {
-+ sbrec_address_set_update_addresses_delvalue(sb_as, sb_arr[sb_index]);
-+ }
- }
-
- static void
-@@ -403,3 +415,32 @@ sb_address_set_lookup_by_name(struct ovsdb_idl_index *sbrec_addr_set_by_name,
-
- return retval;
- }
-+
-+static struct sorted_addresses
-+sorted_addresses_from_nbrec(const struct nbrec_address_set *nb_as)
-+{
-+ /* The DB is already sorted. */
-+ return (struct sorted_addresses) {
-+ .arr = (const char **) nb_as->addresses,
-+ .n = nb_as->n_addresses,
-+ };
-+}
-+
-+static struct sorted_addresses
-+sorted_addresses_from_svec(struct svec *addresses)
-+{
-+ svec_sort(addresses);
-+ return (struct sorted_addresses) {
-+ .arr = (const char **) addresses->names,
-+ .n = addresses->n,
-+ };
-+}
-+
-+static struct sorted_addresses
-+sorted_addresses_from_sset(struct sset *addresses)
-+{
-+ return (struct sorted_addresses) {
-+ .arr = sset_sort(addresses),
-+ .n = sset_count(addresses),
-+ };
-+}
-diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c
-index d23993a55..fd025c92b 100644
---- a/northd/inc-proc-northd.c
-+++ b/northd/inc-proc-northd.c
-@@ -34,10 +34,13 @@
- #include "en-lflow.h"
- #include "en-northd-output.h"
- #include "en-sync-sb.h"
-+#include "unixctl.h"
- #include "util.h"
-
- VLOG_DEFINE_THIS_MODULE(inc_proc_northd);
-
-+static unixctl_cb_func chassis_features_list;
-+
- #define NB_NODES \
- NB_NODE(nb_global, "nb_global") \
- NB_NODE(copp, "copp") \
-@@ -306,6 +309,12 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
- engine_ovsdb_node_add_index(&en_sb_address_set,
- "sbrec_address_set_by_name",
- sbrec_address_set_by_name);
-+
-+ struct northd_data *northd_data =
-+ engine_get_internal_data(&en_northd);
-+ unixctl_command_register("debug/chassis-features-list", "", 0, 0,
-+ chassis_features_list,
-+ &northd_data->features);
- }
-
- /* Returns true if the incremental processing ended up updating nodes. */
-@@ -356,3 +365,20 @@ void inc_proc_northd_cleanup(void)
- engine_cleanup();
- engine_set_context(NULL);
- }
-+
-+static void
-+chassis_features_list(struct unixctl_conn *conn, int argc OVS_UNUSED,
-+ const char *argv[] OVS_UNUSED, void *features_)
-+{
-+ struct chassis_features *features = features_;
-+ struct ds ds = DS_EMPTY_INITIALIZER;
-+
-+ ds_put_format(&ds, "ct_no_masked_label: %s\n",
-+ features->ct_no_masked_label ? "true" : "false");
-+ ds_put_format(&ds, "ct_lb_related: %s\n",
-+ features->ct_lb_related ? "true" : "false");
-+ ds_put_format(&ds, "mac_binding_timestamp: %s\n",
-+ features->mac_binding_timestamp ? "true" : "false");
-+ unixctl_command_reply(conn, ds_cstr(&ds));
-+ ds_destroy(&ds);
-+}
-diff --git a/northd/northd.c b/northd/northd.c
-index 7ad4cdfad..66f14e9dd 100644
---- a/northd/northd.c
-+++ b/northd/northd.c
-@@ -239,6 +239,8 @@ enum ovn_stage {
- * one of the logical router's own IP addresses. */
- #define REGBIT_EGRESS_LOOPBACK "reg9[0]"
- /* Register to store the result of check_pkt_larger action. */
-+/* This register is also used by ovn-controller in
-+ * OFTABLE_OUTPUT_LARGE_PKT_DETECT table, for a similar goal. */
- #define REGBIT_PKT_LARGER "reg9[1]"
- #define REGBIT_LOOKUP_NEIGHBOR_RESULT "reg9[2]"
- #define REGBIT_LOOKUP_NEIGHBOR_IP_RESULT "reg9[3]"
-@@ -432,6 +434,13 @@ build_chassis_features(const struct northd_input *input_data,
- const struct sbrec_chassis *chassis;
-
- SBREC_CHASSIS_TABLE_FOR_EACH (chassis, input_data->sbrec_chassis) {
-+ /* Only consider local AZ chassis. Remote ones don't install
-+ * flows generated by the local northd.
-+ */
-+ if (smap_get_bool(&chassis->other_config, "is-remote", false)) {
-+ continue;
-+ }
-+
- bool ct_no_masked_label =
- smap_get_bool(&chassis->other_config,
- OVN_FEATURE_CT_NO_MASKED_LABEL,
-@@ -552,7 +561,7 @@ free_chassis_queueid(struct hmap *set, const struct uuid *uuid,
- static inline bool
- port_has_qos_params(const struct smap *opts)
- {
-- return (smap_get(opts, "qos_max_rate") ||
-+ return (smap_get(opts, "qos_max_rate") || smap_get(opts, "qos_min_rate") ||
- smap_get(opts, "qos_burst"));
- }
-
-@@ -1641,6 +1650,10 @@ ovn_port_destroy(struct hmap *ports, struct ovn_port *port)
- * use it. */
- hmap_remove(ports, &port->key_node);
-
-+ if (port->peer) {
-+ port->peer->peer = NULL;
-+ }
-+
- for (int i = 0; i < port->n_lsp_addrs; i++) {
- destroy_lport_addresses(&port->lsp_addrs[i]);
- }
-@@ -3881,7 +3894,7 @@ build_lb_vip_actions(struct ovn_lb_vip *lb_vip,
- const char *ct_lb_action =
- features->ct_no_masked_label ? "ct_lb_mark" : "ct_lb";
- bool reject = !lb_vip->n_backends && lb_vip->empty_backend_rej;
-- bool drop = false;
-+ bool drop = !lb_vip->n_backends && !lb_vip->empty_backend_rej;
-
- if (lb_vip_nb->lb_health_check) {
- ds_put_format(action, "%s(backends=", ct_lb_action);
-@@ -5779,20 +5792,24 @@ skip_port_from_conntrack(struct ovn_datapath *od, struct ovn_port *op,
- * know about the connection, as the icmp request went through the logical
- * router on hostA, not hostB. This would only work with distributed
- * conntrack state across all chassis. */
-- struct ds match_in = DS_EMPTY_INITIALIZER;
-- struct ds match_out = DS_EMPTY_INITIALIZER;
-
-- ds_put_format(&match_in, "ip && inport == %s", op->json_key);
-- ds_put_format(&match_out, "ip && outport == %s", op->json_key);
-+ const char *ingress_action = "next;";
-+ const char *egress_action = od->has_stateful_acl
-+ ? "next;"
-+ : "ct_clear; next;";
-+
-+ char *ingress_match = xasprintf("ip && inport == %s", op->json_key);
-+ char *egress_match = xasprintf("ip && outport == %s", op->json_key);
-+
- ovn_lflow_add_with_lport_and_hint(lflows, od, in_stage, priority,
-- ds_cstr(&match_in), "next;", op->key,
-- &op->nbsp->header_);
-+ ingress_match, ingress_action,
-+ op->key, &op->nbsp->header_);
- ovn_lflow_add_with_lport_and_hint(lflows, od, out_stage, priority,
-- ds_cstr(&match_out), "next;", op->key,
-- &op->nbsp->header_);
-+ egress_match, egress_action,
-+ op->key, &op->nbsp->header_);
-
-- ds_destroy(&match_in);
-- ds_destroy(&match_out);
-+ free(ingress_match);
-+ free(egress_match);
- }
-
- static void
-@@ -5867,7 +5884,8 @@ build_pre_acls(struct ovn_datapath *od, const struct hmap *port_groups,
- }
- for (size_t i = 0; i < od->n_localnet_ports; i++) {
- skip_port_from_conntrack(od, od->localnet_ports[i],
-- S_SWITCH_IN_PRE_ACL, S_SWITCH_OUT_PRE_ACL,
-+ S_SWITCH_IN_PRE_ACL,
-+ S_SWITCH_OUT_PRE_ACL,
- 110, lflows);
- }
-
-@@ -6036,10 +6054,17 @@ build_pre_lb(struct ovn_datapath *od, const struct shash *meter_groups,
- S_SWITCH_IN_PRE_LB, S_SWITCH_OUT_PRE_LB,
- 110, lflows);
- }
-- for (size_t i = 0; i < od->n_localnet_ports; i++) {
-- skip_port_from_conntrack(od, od->localnet_ports[i],
-- S_SWITCH_IN_PRE_LB, S_SWITCH_OUT_PRE_LB,
-- 110, lflows);
-+ /* Localnet ports have no need for going through conntrack, unless
-+ * the logical switch has a load balancer. Then, conntrack is necessary
-+ * so that traffic arriving via the localnet port can be load
-+ * balanced.
-+ */
-+ if (!od->has_lb_vip) {
-+ for (size_t i = 0; i < od->n_localnet_ports; i++) {
-+ skip_port_from_conntrack(od, od->localnet_ports[i],
-+ S_SWITCH_IN_PRE_LB, S_SWITCH_OUT_PRE_LB,
-+ 110, lflows);
-+ }
- }
-
- /* Do not sent statless flows via conntrack */
-@@ -6700,6 +6725,8 @@ build_port_group_lswitches(struct northd_input *input_data,
- }
- }
-
-+#define IPV6_CT_OMIT_MATCH "nd || nd_ra || nd_rs || mldv1 || mldv2"
-+
- static void
- build_acls(struct ovn_datapath *od, const struct chassis_features *features,
- struct hmap *lflows, const struct hmap *port_groups,
-@@ -6847,20 +6874,26 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features,
- ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3,
- ds_cstr(&match), ct_out_acl_action);
-
-- /* Ingress and Egress ACL Table (Priority 65532).
-- *
-- * Not to do conntrack on ND packets. */
-- ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3,
-- "nd || nd_ra || nd_rs || mldv1 || mldv2", "next;");
-- ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3,
-- "nd || nd_ra || nd_rs || mldv1 || mldv2", "next;");
--
- /* Reply and related traffic matched by an "allow-related" ACL
- * should be allowed in the ls_in_acl_after_lb stage too. */
- ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, UINT16_MAX - 3,
- REGBIT_ACL_HINT_ALLOW_REL" == 1", "next;");
- }
-
-+ /* Ingress and Egress ACL Table (Priority 65532).
-+ *
-+ * Always allow service IPv6 protocols regardless of other ACLs defined.
-+ *
-+ * Also, don't send them to conntrack because session tracking
-+ * for these protocols is not working properly:
-+ * https://bugzilla.kernel.org/show_bug.cgi?id=11797. */
-+ ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3,
-+ IPV6_CT_OMIT_MATCH, "next;");
-+ ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3,
-+ IPV6_CT_OMIT_MATCH, "next;");
-+ ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, UINT16_MAX - 3,
-+ IPV6_CT_OMIT_MATCH, "next;");
-+
- /* Ingress or Egress ACL Table (Various priorities). */
- for (size_t i = 0; i < od->nbs->n_acls; i++) {
- struct nbrec_acl *acl = od->nbs->acls[i];
-@@ -7089,7 +7122,9 @@ build_lb_rules_pre_stateful(struct hmap *lflows, struct ovn_northd_lb *lb,
- * - load balancing affinity check:
- * table=lr_in_lb_aff_check, priority=100
- * match=(new_lb_match)
-- * action=(REGBIT_KNOWN_LB_SESSION = chk_lb_aff(); next;)
-+ * action=(REG_NEXT_HOP_IPV4 = ip4.dst;
-+ * REG_ORIG_TP_DPORT_ROUTER = tcp.dst;
-+ * REGBIT_KNOWN_LB_SESSION = chk_lb_aff(); next;)
- *
- * - load balancing:
- * table=lr_in_dnat, priority=150
-@@ -7130,16 +7165,11 @@ build_lb_affinity_lr_flows(struct hmap *lflows, struct ovn_northd_lb *lb,
- return;
- }
-
-- static char *aff_check = REGBIT_KNOWN_LB_SESSION" = chk_lb_aff(); next;";
--
-- ovn_lflow_add_with_dp_group(
-- lflows, dp_bitmap, S_ROUTER_IN_LB_AFF_CHECK, 100,
-- new_lb_match, aff_check, &lb->nlb->header_);
--
- struct ds aff_action = DS_EMPTY_INITIALIZER;
- struct ds aff_action_learn = DS_EMPTY_INITIALIZER;
- struct ds aff_match = DS_EMPTY_INITIALIZER;
- struct ds aff_match_learn = DS_EMPTY_INITIALIZER;
-+ struct ds aff_check_action = DS_EMPTY_INITIALIZER;
-
- bool ipv6 = !IN6_IS_ADDR_V4MAPPED(&lb_vip->vip);
- const char *ip_match = ipv6 ? "ip6" : "ip4";
-@@ -7155,6 +7185,20 @@ build_lb_affinity_lr_flows(struct hmap *lflows, struct ovn_northd_lb *lb,
- ct_flag = "; force_snat";
- }
-
-+ /* Create affinity check flow. */
-+ ds_put_format(&aff_check_action, "%s = %s.dst; ", reg_vip, ip_match);
-+
-+ if (lb_vip->port_str) {
-+ ds_put_format(&aff_check_action, REG_ORIG_TP_DPORT_ROUTER" = %s.dst; ",
-+ lb->proto);
-+ }
-+ ds_put_cstr(&aff_check_action, REGBIT_KNOWN_LB_SESSION
-+ " = chk_lb_aff(); next;");
-+
-+ ovn_lflow_add_with_dp_group(
-+ lflows, dp_bitmap, S_ROUTER_IN_LB_AFF_CHECK, 100,
-+ new_lb_match, ds_cstr(&aff_check_action), &lb->nlb->header_);
-+
- /* Prepare common part of affinity LB and affinity learn action. */
- ds_put_format(&aff_action, "%s = %s; ", reg_vip, lb_vip->vip_str);
- ds_put_cstr(&aff_action_learn, "commit_lb_aff(vip = \"");
-@@ -7252,6 +7296,7 @@ build_lb_affinity_lr_flows(struct hmap *lflows, struct ovn_northd_lb *lb,
- ds_destroy(&aff_action_learn);
- ds_destroy(&aff_match);
- ds_destroy(&aff_match_learn);
-+ ds_destroy(&aff_check_action);
- }
-
- /* Builds the logical switch flows related to load balancer affinity.
-@@ -7628,38 +7673,36 @@ 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. */
-+ if (!od->has_vtep_lports) {
-+ /* There is no need in these flows if datapath has no vtep lports. */
-+ return;
-+ }
-
-+ /* Ingress Pre-ARP flows for VTEP hairpining traffic. Priority 1000:
-+ * Packets received from VTEP ports must go directly to L2LKP table.
-+ */
- 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;
-- size_t 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;");
-+ * processing. */
-+ struct ds match = DS_EMPTY_INITIALIZER;
-+ for (int i = 0; i < od->n_router_ports; i++) {
-+ struct ovn_port *op = od->router_ports[i]->peer;
-+ if (is_l3dgw_port(op)) {
-+ ds_clear(&match);
-+ ds_put_format(&match,
-+ REGBIT_FROM_RAMP" == 1 && is_chassis_resident(%s)",
-+ op->cr_port->json_key);
-+ ovn_lflow_add(lflows, od, S_SWITCH_IN_HAIRPIN, 2000,
-+ ds_cstr(&match), "next;");
-+ }
- }
- ds_destroy(&match);
- }
-@@ -8877,7 +8920,7 @@ build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od,
- if (od->nbs) {
-
- ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 110,
-- "eth.dst == $svc_monitor_mac",
-+ "eth.dst == $svc_monitor_mac && (tcp || icmp || icmp6)",
- "handle_svc_check(inport);");
-
- struct mcast_switch_info *mcast_sw_info = &od->mcast_info.sw;
-@@ -10450,10 +10493,8 @@ enum lrouter_nat_lb_flow_type {
-
- struct lrouter_nat_lb_flows_ctx {
- const char *new_action[LROUTER_NAT_LB_FLOW_MAX];
-- const char *est_action[LROUTER_NAT_LB_FLOW_MAX];
-
- struct ds *new_match;
-- struct ds *est_match;
- struct ds *undnat_match;
-
- struct ovn_lb_vip *lb_vip;
-@@ -10471,10 +10512,22 @@ build_distr_lrouter_nat_flows_for_lb(struct lrouter_nat_lb_flows_ctx *ctx,
- enum lrouter_nat_lb_flow_type type,
- struct ovn_datapath *od)
- {
-- char *gw_action = od->is_gw_router ? "ct_dnat;" : "ct_dnat_in_czone;";
-+ const char *undnat_action;
-+
-+ switch (type) {
-+ case LROUTER_NAT_LB_FLOW_FORCE_SNAT:
-+ undnat_action = "flags.force_snat_for_lb = 1; next;";
-+ break;
-+ case LROUTER_NAT_LB_FLOW_SKIP_SNAT:
-+ undnat_action = "flags.skip_snat_for_lb = 1; next;";
-+ break;
-+ case LROUTER_NAT_LB_FLOW_NORMAL:
-+ case LROUTER_NAT_LB_FLOW_MAX:
-+ undnat_action = od->is_gw_router ? "ct_dnat;" : "ct_dnat_in_czone;";
-+ break;
-+ }
- /* Store the match lengths, so we can reuse the ds buffer. */
- size_t new_match_len = ctx->new_match->length;
-- size_t est_match_len = ctx->est_match->length;
- size_t undnat_match_len = ctx->undnat_match->length;
-
-
-@@ -10487,33 +10540,24 @@ build_distr_lrouter_nat_flows_for_lb(struct lrouter_nat_lb_flows_ctx *ctx,
- if (ctx->lb_vip->n_backends || !ctx->lb_vip->empty_backend_rej) {
- ds_put_format(ctx->new_match, " && is_chassis_resident(%s)",
- od->l3dgw_ports[0]->cr_port->json_key);
-- ds_put_format(ctx->est_match, " && is_chassis_resident(%s)",
-- od->l3dgw_ports[0]->cr_port->json_key);
- }
-
- ovn_lflow_add_with_hint__(ctx->lflows, od, S_ROUTER_IN_DNAT, ctx->prio,
- ds_cstr(ctx->new_match), ctx->new_action[type],
- NULL, meter, &ctx->lb->nlb->header_);
-- ovn_lflow_add_with_hint(ctx->lflows, od, S_ROUTER_IN_DNAT, ctx->prio,
-- ds_cstr(ctx->est_match), ctx->est_action[type],
-- &ctx->lb->nlb->header_);
-
- ds_truncate(ctx->new_match, new_match_len);
-- ds_truncate(ctx->est_match, est_match_len);
-
- if (!ctx->lb_vip->n_backends) {
- return;
- }
-
-- const char *action = (type == LROUTER_NAT_LB_FLOW_NORMAL)
-- ? gw_action : ctx->est_action[type];
--
- ds_put_format(ctx->undnat_match,
- ") && outport == %s && is_chassis_resident(%s)",
- od->l3dgw_ports[0]->json_key,
- od->l3dgw_ports[0]->cr_port->json_key);
- ovn_lflow_add_with_hint(ctx->lflows, od, S_ROUTER_OUT_UNDNAT, 120,
-- ds_cstr(ctx->undnat_match), action,
-+ ds_cstr(ctx->undnat_match), undnat_action,
- &ctx->lb->nlb->header_);
- ds_truncate(ctx->undnat_match, undnat_match_len);
- }
-@@ -10556,11 +10600,6 @@ build_gw_lrouter_nat_flows_for_lb(struct lrouter_nat_lb_flows_ctx *ctx,
- ctx->new_action[type], &ctx->lb->nlb->header_);
- }
- bitmap_free(dp_non_meter);
--
-- ovn_lflow_add_with_dp_group(
-- ctx->lflows, dp_bitmap, S_ROUTER_IN_DNAT, ctx->prio,
-- ds_cstr(ctx->est_match), ctx->est_action[type],
-- &ctx->lb->nlb->header_);
- }
-
- static void
-@@ -10572,19 +10611,13 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
- const struct shash *meter_groups,
- const struct chassis_features *features)
- {
-- const char *ct_natted = features->ct_no_masked_label
-- ? "ct_mark.natted"
-- : "ct_label.natted";
--
- bool ipv4 = lb_vip->address_family == AF_INET;
- const char *ip_match = ipv4 ? "ip4" : "ip6";
-- const char *ip_reg = ipv4 ? REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6;
-
- int prio = 110;
-
- struct ds skip_snat_act = DS_EMPTY_INITIALIZER;
- struct ds force_snat_act = DS_EMPTY_INITIALIZER;
-- struct ds est_match = DS_EMPTY_INITIALIZER;
- struct ds undnat_match = DS_EMPTY_INITIALIZER;
- struct ds unsnat_match = DS_EMPTY_INITIALIZER;
-
-@@ -10601,19 +10634,14 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
- * of "ct_lb_mark($targets);". The other flow is for ct.est with
- * an action of "next;".
- */
-- ds_put_format(match, "ct.new && !ct.rel && %s && %s == %s",
-- ip_match, ip_reg, lb_vip->vip_str);
-+ ds_put_format(match, "ct.new && !ct.rel && %s && %s.dst == %s",
-+ ip_match, ip_match, lb_vip->vip_str);
- if (lb_vip->port_str) {
- prio = 120;
-- ds_put_format(match, " && %s && "REG_ORIG_TP_DPORT_ROUTER" == %s",
-- lb->proto, lb_vip->port_str);
-+ ds_put_format(match, " && %s && %s.dst == %s",
-+ lb->proto, lb->proto, lb_vip->port_str);
- }
-
-- ds_put_cstr(&est_match, "ct.est");
-- /* Clone the match after initial "ct.new" (6 bytes). */
-- ds_put_cstr(&est_match, ds_cstr(match) + 6);
-- ds_put_format(&est_match, " && %s == 1", ct_natted);
--
- /* Add logical flows to UNDNAT the load balanced reverse traffic in
- * the router egress pipleine stage - S_ROUTER_OUT_UNDNAT if the logical
- * router has a gateway router port associated.
-@@ -10650,20 +10678,12 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
- .lflows = lflows,
- .meter_groups = meter_groups,
- .new_match = match,
-- .est_match = &est_match,
- .undnat_match = &undnat_match
- };
-
- ctx.new_action[LROUTER_NAT_LB_FLOW_NORMAL] = ds_cstr(action);
-- ctx.est_action[LROUTER_NAT_LB_FLOW_NORMAL] = "next;";
--
- ctx.new_action[LROUTER_NAT_LB_FLOW_SKIP_SNAT] = ds_cstr(&skip_snat_act);
-- ctx.est_action[LROUTER_NAT_LB_FLOW_SKIP_SNAT] =
-- "flags.skip_snat_for_lb = 1; next;";
--
- ctx.new_action[LROUTER_NAT_LB_FLOW_FORCE_SNAT] = ds_cstr(&force_snat_act);
-- ctx.est_action[LROUTER_NAT_LB_FLOW_FORCE_SNAT] =
-- "flags.force_snat_for_lb = 1; next;";
-
- enum {
- LROUTER_NAT_LB_AFF = LROUTER_NAT_LB_FLOW_MAX,
-@@ -10746,7 +10766,6 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
-
- ds_destroy(&unsnat_match);
- ds_destroy(&undnat_match);
-- ds_destroy(&est_match);
- ds_destroy(&skip_snat_act);
- ds_destroy(&force_snat_act);
-
-@@ -10820,39 +10839,19 @@ build_lrouter_defrag_flows_for_lb(struct ovn_northd_lb *lb,
- return;
- }
-
-- struct ds defrag_actions = DS_EMPTY_INITIALIZER;
- for (size_t i = 0; i < lb->n_vips; i++) {
- struct ovn_lb_vip *lb_vip = &lb->vips[i];
-+ bool ipv6 = lb_vip->address_family == AF_INET6;
- int prio = 100;
-
-- ds_clear(&defrag_actions);
- ds_clear(match);
--
-- if (lb_vip->address_family == AF_INET) {
-- ds_put_format(match, "ip && ip4.dst == %s", lb_vip->vip_str);
-- ds_put_format(&defrag_actions, REG_NEXT_HOP_IPV4" = %s; ",
-- lb_vip->vip_str);
-- } else {
-- ds_put_format(match, "ip && ip6.dst == %s", lb_vip->vip_str);
-- ds_put_format(&defrag_actions, REG_NEXT_HOP_IPV6" = %s; ",
-- lb_vip->vip_str);
-- }
--
-- if (lb_vip->port_str) {
-- ds_put_format(match, " && %s", lb->proto);
-- prio = 110;
--
-- ds_put_format(&defrag_actions, REG_ORIG_TP_DPORT_ROUTER
-- " = %s.dst; ", lb->proto);
-- }
--
-- ds_put_format(&defrag_actions, "ct_dnat;");
-+ ds_put_format(match, "ip && ip%c.dst == %s", ipv6 ? '6' : '4',
-+ lb_vip->vip_str);
-
- ovn_lflow_add_with_dp_group(
- lflows, lb->nb_lr_map, S_ROUTER_IN_DEFRAG, prio,
-- ds_cstr(match), ds_cstr(&defrag_actions), &lb->nlb->header_);
-+ ds_cstr(match), "ct_dnat;", &lb->nlb->header_);
- }
-- ds_destroy(&defrag_actions);
- }
-
- static void
-@@ -10991,15 +10990,10 @@ copy_ra_to_sb(struct ovn_port *op, const char *address_mode)
- }
-
- static inline bool
--lrouter_nat_is_stateless(const struct nbrec_nat *nat)
-+lrouter_dnat_and_snat_is_stateless(const struct nbrec_nat *nat)
- {
-- const char *stateless = smap_get(&nat->options, "stateless");
--
-- if (stateless && !strcmp(stateless, "true")) {
-- return true;
-- }
--
-- return false;
-+ return smap_get_bool(&nat->options, "stateless", false) &&
-+ !strcmp(nat->type, "dnat_and_snat");
- }
-
- /* Handles the match criteria and actions in logical flow
-@@ -11698,6 +11692,25 @@ build_neigh_learning_flows_for_lrouter(
- ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, "nd_na",
- ds_cstr(actions));
-
-+ if (!learn_from_arp_request) {
-+ /* Add flow to skip GARP LLA if we don't know it already.
-+ * From RFC 2461, section 4.4, Neighbor Advertisement Message
-+ * Format, the Destination Address should be:
-+ * For solicited advertisements, the Source Address of
-+ * an invoking Neighbor Solicitation or, if the
-+ * solicitation's Source Address is the unspecified
-+ * address, the all-nodes multicast address. */
-+ ds_clear(actions);
-+ ds_put_format(actions, REGBIT_LOOKUP_NEIGHBOR_RESULT
-+ " = lookup_nd(inport, ip6.src, nd.tll); "
-+ REGBIT_LOOKUP_NEIGHBOR_IP_RESULT
-+ " = lookup_nd_ip(inport, ip6.src); next;");
-+ ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 110,
-+ "nd_na && ip6.src == fe80::/10 "
-+ "&& ip6.dst == ff00::/8",
-+ ds_cstr(actions));
-+ }
-+
- ds_clear(actions);
- ds_put_format(actions, REGBIT_LOOKUP_NEIGHBOR_RESULT
- " = lookup_nd(inport, ip6.src, nd.sll); %snext;",
-@@ -12814,8 +12827,7 @@ build_gateway_redirect_flows_for_lrouter(
- for (int j = 0; j < od->n_nat_entries; j++) {
- const struct ovn_nat *nat = &od->nat_entries[j];
-
-- if (!lrouter_nat_is_stateless(nat->nb) ||
-- strcmp(nat->nb->type, "dnat_and_snat") ||
-+ if (!lrouter_dnat_and_snat_is_stateless(nat->nb) ||
- (!nat->nb->allowed_ext_ips && !nat->nb->exempted_ext_ips)) {
- continue;
- }
-@@ -13038,9 +13050,27 @@ build_misc_local_traffic_drop_flows_for_lrouter(
- ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 50,
- "eth.bcast", debug_drop_action());
-
-+ /* Avoid ICMP time exceeded for multicast, silent drop instead.
-+ * See RFC1812 section 5.3.1:
-+ * If the TTL is reduced to zero (or less), the packet MUST be
-+ * discarded, and if the destination is NOT A MULTICAST address the
-+ * router MUST send an ICMP Time Exceeded message ...
-+ *
-+ * The reason behind is that TTL has special meanings for multicast.
-+ * For example, TTL = 1 means restricted to the same subnet, not
-+ * forwarded by the router. So it is very common to see multicast
-+ * packets with ttl = 1, and generating ICMP for such packets is
-+ * harmful from both slowpath performance and functionality point of
-+ * view.
-+ *
-+ * (priority-31 flows will send ICMP time exceeded) */
-+ ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 32,
-+ "ip.ttl == {0, 1} && !ip.later_frag && "
-+ "(ip4.mcast || ip6.mcast)", debug_drop_action());
-+
- /* TTL discard */
- ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 30,
-- "ip4 && ip.ttl == {0, 1}", debug_drop_action());
-+ "ip.ttl == {0, 1}", debug_drop_action());
-
- /* Pass other traffic not already handled to the next table for
- * routing. */
-@@ -13224,7 +13254,7 @@ build_ipv6_input_flows_for_lrouter_port(
- "outport = %s; flags.loopback = 1; output; };",
- ds_cstr(&ip_ds), op->json_key);
- ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT,
-- 100, ds_cstr(match), ds_cstr(actions), NULL,
-+ 31, ds_cstr(match), ds_cstr(actions), NULL,
- copp_meter_get(COPP_ICMP6_ERR, op->od->nbr->copp,
- meter_groups),
- &op->nbrp->header_);
-@@ -13352,7 +13382,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
- "outport = %s; flags.loopback = 1; output; };",
- ds_cstr(&ip_ds), op->json_key);
- ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT,
-- 100, ds_cstr(match), ds_cstr(actions), NULL,
-+ 31, ds_cstr(match), ds_cstr(actions), NULL,
- copp_meter_get(COPP_ICMP4_ERR, op->od->nbr->copp,
- meter_groups),
- &op->nbrp->header_);
-@@ -13597,13 +13627,13 @@ build_lrouter_in_unsnat_flow(struct hmap *lflows, struct ovn_datapath *od,
- return;
- }
-
-- bool stateless = lrouter_nat_is_stateless(nat);
-+ bool stateless = lrouter_dnat_and_snat_is_stateless(nat);
- if (od->is_gw_router) {
- ds_clear(match);
- ds_clear(actions);
- ds_put_format(match, "ip && ip%s.dst == %s",
- is_v6 ? "6" : "4", nat->external_ip);
-- if (!strcmp(nat->type, "dnat_and_snat") && stateless) {
-+ if (stateless) {
- ds_put_format(actions, "next;");
- } else {
- ds_put_cstr(actions, "ct_snat;");
-@@ -13628,7 +13658,7 @@ build_lrouter_in_unsnat_flow(struct hmap *lflows, struct ovn_datapath *od,
- l3dgw_port->cr_port->json_key);
- }
-
-- if (!strcmp(nat->type, "dnat_and_snat") && stateless) {
-+ if (stateless) {
- ds_put_format(actions, "next;");
- } else {
- ds_put_cstr(actions, "ct_snat_in_czone;");
-@@ -13670,7 +13700,7 @@ build_lrouter_in_dnat_flow(struct hmap *lflows, struct ovn_datapath *od,
- * IP address that needs to be DNATted from a external IP address
- * to a logical IP address. */
- if (!strcmp(nat->type, "dnat") || !strcmp(nat->type, "dnat_and_snat")) {
-- bool stateless = lrouter_nat_is_stateless(nat);
-+ bool stateless = lrouter_dnat_and_snat_is_stateless(nat);
-
- if (od->is_gw_router) {
- /* Packet when it goes from the initiator to destination.
-@@ -13692,7 +13722,7 @@ build_lrouter_in_dnat_flow(struct hmap *lflows, struct ovn_datapath *od,
- ds_put_format(actions, "flags.force_snat_for_dnat = 1; ");
- }
-
-- if (!strcmp(nat->type, "dnat_and_snat") && stateless) {
-+ if (stateless) {
- ds_put_format(actions, "flags.loopback = 1; "
- "ip%s.dst=%s; next;",
- is_v6 ? "6" : "4", nat->logical_ip);
-@@ -13782,8 +13812,7 @@ build_lrouter_out_undnat_flow(struct hmap *lflows, struct ovn_datapath *od,
- ETH_ADDR_ARGS(mac));
- }
-
-- if (!strcmp(nat->type, "dnat_and_snat") &&
-- lrouter_nat_is_stateless(nat)) {
-+ if (lrouter_dnat_and_snat_is_stateless(nat)) {
- ds_put_format(actions, "next;");
- } else {
- ds_put_format(actions,
-@@ -13839,7 +13868,7 @@ build_lrouter_out_snat_flow(struct hmap *lflows, struct ovn_datapath *od,
- return;
- }
-
-- bool stateless = lrouter_nat_is_stateless(nat);
-+ bool stateless = lrouter_dnat_and_snat_is_stateless(nat);
- if (od->is_gw_router) {
- ds_clear(match);
- ds_put_format(match, "ip && ip%s.src == %s",
-@@ -13905,7 +13934,7 @@ build_lrouter_out_snat_flow(struct hmap *lflows, struct ovn_datapath *od,
- ETH_ADDR_ARGS(mac));
- }
-
-- if (!strcmp(nat->type, "dnat_and_snat") && stateless) {
-+ if (stateless) {
- ds_put_format(actions, "ip%s.src=%s; next;",
- is_v6 ? "6" : "4", nat->external_ip);
- } else {
-@@ -14217,10 +14246,10 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows,
- ovn_lflow_add(lflows, od, S_ROUTER_OUT_EGR_LOOP, 0, "1", "next;");
- ovn_lflow_add(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 0, "1", "next;");
-
-- /* Ingress DNAT and DEFRAG Table (Priority 50/70).
-- *
-- * The defrag stage needs to have flows for ICMP in order to get
-- * the correct ct_state that can be used by DNAT stage.
-+ const char *ct_flag_reg = features->ct_no_masked_label
-+ ? "ct_mark"
-+ : "ct_label";
-+ /* Ingress DNAT (Priority 50/70).
- *
- * Allow traffic that is related to an existing conntrack entry.
- * At the same time apply NAT for this traffic.
-@@ -14231,16 +14260,10 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows,
- * that's generated from a non-listening UDP port. */
- if (od->has_lb_vip && features->ct_lb_related) {
- ds_clear(match);
-- const char *ct_flag_reg = features->ct_no_masked_label
-- ? "ct_mark"
-- : "ct_label";
-
- ds_put_cstr(match, "ct.rel && !ct.est && !ct.new");
- size_t match_len = match->length;
-
-- ovn_lflow_add(lflows, od, S_ROUTER_IN_DEFRAG, 50, "icmp || icmp6",
-- "ct_dnat;");
--
- ds_put_format(match, " && %s.skip_snat == 1", ct_flag_reg);
- ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 70, ds_cstr(match),
- "flags.skip_snat_for_lb = 1; ct_commit_nat;");
-@@ -14251,10 +14274,34 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows,
- "flags.force_snat_for_lb = 1; ct_commit_nat;");
-
- ds_truncate(match, match_len);
-- ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 50,
-- "ct.rel && !ct.est && !ct.new", "ct_commit_nat;");
-+ ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 50, ds_cstr(match),
-+ "ct_commit_nat;");
-+ }
-
-+ /* Ingress DNAT (Priority 50/70).
-+ *
-+ * Pass the traffic that is already established to the next table with
-+ * proper flags set.
-+ */
-+ if (od->has_lb_vip) {
- ds_clear(match);
-+
-+ ds_put_format(match, "ct.est && !ct.rel && !ct.new && %s.natted",
-+ ct_flag_reg);
-+ size_t match_len = match->length;
-+
-+ ds_put_format(match, " && %s.skip_snat == 1", ct_flag_reg);
-+ ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 70, ds_cstr(match),
-+ "flags.skip_snat_for_lb = 1; next;");
-+
-+ ds_truncate(match, match_len);
-+ ds_put_format(match, " && %s.force_snat == 1", ct_flag_reg);
-+ ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 70, ds_cstr(match),
-+ "flags.force_snat_for_lb = 1; next;");
-+
-+ ds_truncate(match, match_len);
-+ ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 50, ds_cstr(match),
-+ "next;");
- }
-
- /* If the router has load balancer or DNAT rules, re-circulate every packet
-@@ -14267,6 +14314,9 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows,
- * flag set. Some NICs are unable to offload these flows.
- */
- if (od->is_gw_router && (od->nbr->n_nat || od->has_lb_vip)) {
-+ /* Do not send ND or ICMP packets to connection tracking. */
-+ ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 100,
-+ "nd || nd_rs || nd_ra", "next;");
- ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 50,
- "ip", "flags.loopback = 1; ct_dnat;");
- ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_UNDNAT, 50,
-diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
-index 2eab2c4ae..5b3559d45 100644
---- a/northd/ovn-northd.8.xml
-+++ b/northd/ovn-northd.8.xml
-@@ -748,6 +748,12 @@
- drop behavior.
-
-
-+
-+ A priority-65532 flow is added to allow IPv6 Neighbor solicitation,
-+ Neighbor discover, Router solicitation, Router advertisement and MLD
-+ packets regardless of other ACLs defined.
-+
-+
-
- If the logical datapath has a stateful ACL or a load balancer with VIP
- configured, the following flows will also be added:
-@@ -824,12 +830,6 @@
- in the request direction are skipped here to let a newly created
- ACL re-allow this connection.
-
--
--
-- A priority-65532 flow that allows IPv6 Neighbor solicitation,
-- Neighbor discover, Router solicitation, Router advertisement and MLD
-- packets.
--
-
-
-
-@@ -1090,24 +1090,28 @@
-
- -
-
-- For each distributed gateway router port RP attached to
-- the logical switch, a priority-2000 flow is added with the match
-- reg0[14] == 1 && is_chassis_resident(RP)
--
and action next;
to pass the traffic to the
-- next table to respond to the ARP requests for the router port IPs.
-+ If logical switch has attached logical switch port of vtep
-+ type, then for each distributed gateway router port RP
-+ attached to this logical switch and has chassis redirect port
-+ cr-RP, a priority-2000 flow is added with the match
-+
-+reg0[14] == 1 && is_chassis_resident(cr-RP)
-+
-+ and action next;
.
-
-
-
- reg0[14]
register bit is set in the ingress L2 port
-- security check table for traffic received from HW VTEP (ramp)
-- ports.
-+ security check table for traffic received from HW VTEP (ramp) ports.
-
-
-
- -
-- A priority-1000 flow that matches on
reg0[14]
register
-- bit for the traffic received from HW VTEP (ramp) ports. This traffic
-- is passed to ingress table ls_in_l2_lkup.
-+ If logical switch has attached logical switch port of vtep
-+ type, then a priority-1000 flow that matches on
-+ reg0[14]
register bit for the traffic received from HW
-+ VTEP (ramp) ports. This traffic is passed to ingress table
-+ ls_in_l2_lkup.
-
- -
- A priority-1 flow that hairpins traffic matched by non-default
-@@ -2056,6 +2060,16 @@ output;
- db="OVN_Northbound"/> table.
-
-
-+
-+ This table also has a priority-110 flow with the match
-+ outport == I
for all logical switch
-+ datapaths to move traffic to the next table, and, if there are no
-+ stateful_acl, clear the ct_state. Where I
-+ is the peer of a logical router port. This flow is added to
-+ skip the connection tracking of packets which will be entering
-+ logical router datapath from logical switch datapath for routing.
-+
-+
- Egress Table 2: Pre-stateful
-
-
-@@ -2098,6 +2112,12 @@ output;
- to-lport
ACLs.
-
-
-+
-+ Similar to ingress table, a priority-65532 flow is added to allow IPv6
-+ Neighbor solicitation, Neighbor discover, Router solicitation, Router
-+ advertisement and MLD packets regardless of other ACLs defined.
-+
-+
-
- In addition, the following flows are added.
-
-@@ -3066,10 +3086,18 @@ nd.tll = external_mac;
- broadcast address. By definition this traffic should not be forwarded.
-
-
-+ -
-+ Avoid ICMP time exceeded for multicast. A priority-32 flow with match
-+
ip.ttl == {0, 1} && !ip.later_frag &&
-+ (ip4.mcast || ip6.mcast)
and actions drop;
drops
-+ multicast packets whose TTL has expired without sending ICMP time
-+ exceeded.
-+
-+
- -
-
- ICMP time exceeded. For each router port P, whose IP
-- address is A, a priority-100 flow with match inport
-+ address is A, a priority-31 flow with match inport
- == P && ip.ttl == {0, 1} &&
- !ip.later_frag
matches packets whose TTL has expired, with the
- following actions to send an ICMP time exceeded reply for IPv4 and
-@@ -3282,35 +3310,16 @@ icmp6 {
-
-
-
-- If load balancing rules with only virtual IP addresses are configured in
-+ For all load balancing rules that are configured in
- OVN_Northbound
database for a Gateway router,
- a priority-100 flow is added for each configured virtual IP address
- VIP. For IPv4 VIPs the flow matches
- ip && ip4.dst == VIP
. For IPv6
- VIPs, the flow matches ip && ip6.dst ==
-- VIP
. The flow applies the action reg0 =
-- VIP; ct_dnat;
(or xxreg0
for IPv6) to
-- send IP packets to the connection tracker for packet de-fragmentation and
-- to dnat the destination IP for the committed connection before sending it
-- to the next table.
--
--
--
-- If load balancing rules with virtual IP addresses and ports are
-- configured in OVN_Northbound
database for a Gateway router,
-- a priority-110 flow is added for each configured virtual IP address
-- VIP, protocol PROTO and port PORT.
-- For IPv4 VIPs the flow matches
-- ip && ip4.dst == VIP &&
-- PROTO && PROTO.dst ==
-- PORT
. For IPv6 VIPs, the flow matches
-- ip && ip6.dst == VIP &&
-- PROTO && PROTO.dst ==
-- PORT
. The flow applies the action reg0 =
-- VIP; reg9[16..31] = PROTO.dst; ct_dnat;
-- (or xxreg0
for IPv6) to send IP packets to the connection
-- tracker for packet de-fragmentation and to dnat the destination IP for
-- the committed connection before sending it to the next table.
-+ VIP. The flow applies the action ct_dnat;
-+ to send IP packets to the connection tracker for packet de-fragmentation
-+ and to dnat the destination IP for the committed connection before
-+ sending it to the next table.
-
-
-
-@@ -3349,10 +3358,11 @@ icmp6 {
- column, that includes a L4 port PORT of protocol
- P and IPv4 or IPv6 address VIP, a priority-100
- flow that matches on ct.new && ip &&
-- reg0 == VIP && P && reg9[16..31]
-+ ip.dst == VIP && P && P.dst
- ==
PORT
(xxreg0 == VIP
--
in the IPv6 case) with an action of reg9[6] =
-- chk_lb_aff(); next;
-+ in the IPv6 case) with an action of reg0 = ip.dst;
-+ reg9[16..31] = P.dst; reg9[6] = chk_lb_aff(); next;
-+ (xxreg0 == ip6.dst
in the IPv6 case)
-
-
- -
-@@ -3385,9 +3395,8 @@ icmp6 {
- column, that includes a L4 port PORT of protocol
- P and IPv4 or IPv6 address VIP, a priority-150
- flow that matches on
reg9[6] == 1 && ct.new &&
-- ip && reg0 == VIP && P &&
-- reg9[16..31] ==
PORT
(xxreg0
-- == VIP
in the IPv6 case) with an action of
-+ ip && ip.dst == VIP && P &&
-+ P.dst == PORT
with an action of
- ct_lb_mark(args)
, where args
- contains comma separated IP addresses (and optional port numbers)
- to load balance to. The address family of the IP addresses of
-@@ -3410,56 +3419,25 @@ icmp6 {
- Router with gateway port in OVN_Northbound
database that
- includes a L4 port PORT of protocol P and IPv4
- or IPv6 address VIP, a priority-120 flow that matches on
-- ct.new && !ct.rel && ip && reg0 ==
-- VIP && P && reg9[16..31] ==
--
PORT
(xxreg0 == VIP
--
in the IPv6 case) with an action of
-+ ct.new && !ct.rel && ip && ip.dst ==
-+ VIP && P && P.dst ==
-+
PORT
with an action of
- ct_lb_mark(args)
, where args contains
- comma separated IPv4 or IPv6 addresses (and optional port numbers) to
- load balance to. If the router is configured to force SNAT any
- load-balanced packets, the above action will be replaced by
-- flags.force_snat_for_lb = 1; ct_lb_mark(args);
.
-+ flags.force_snat_for_lb = 1; ct_lb_mark(args;
-+ force_snat);
.
- If the load balancing rule is configured with skip_snat
- set to true, the above action will be replaced by
-- flags.skip_snat_for_lb = 1; ct_lb_mark(args);
.
-+ flags.skip_snat_for_lb = 1; ct_lb_mark(args;
-+ skip_snat);
.
- If health check is enabled, then
- args will only contain those endpoints whose service
- monitor status entry in OVN_Southbound
db is
- either online
or empty.
-
-
--
-- The previous table lr_in_defrag
sets the register
-- reg0
(or xxreg0
for IPv6) and does
-- ct_dnat
. Hence for established traffic, this
-- table just advances the packet to the next stage.
--
--
--
-- -
--
-- For all the configured load balancing rules for a router in
-- OVN_Northbound
database that includes a L4 port
-- PORT of protocol P and IPv4 or IPv6 address
-- VIP, a priority-120 flow that matches on
-- ct.est && !ct.rel && ip4 && reg0 ==
-- VIP && P && reg9[16..31] ==
--
PORT
(ip6
and
-- xxreg0 == VIP
in the IPv6 case) with an
-- action of next;
. If the router is configured to force
-- SNAT any load-balanced packets, the above action will be replaced by
-- flags.force_snat_for_lb = 1; next;
. If the load
-- balancing rule is configured with skip_snat
set to true,
-- the above action will be replaced by
-- flags.skip_snat_for_lb = 1; next;
.
--
--
--
-- The previous table lr_in_defrag
sets the register
-- reg0
(or xxreg0
for IPv6) and does
-- ct_dnat
. Hence for established traffic, this
-- table just advances the packet to the next stage.
--
-
-
- -
-@@ -3467,42 +3445,17 @@ icmp6 {
- For all the configured load balancing rules for a router in
-
OVN_Northbound
database that includes just an IP address
- VIP to match on, a priority-110 flow that matches on
-- ct.new && !ct.rel && ip4 && reg0 ==
-- VIP
(ip6
and xxreg0 ==
-- VIP
in the IPv6 case) with an action of
-+ ct.new && !ct.rel && ip4 && ip.dst ==
-+ VIP
with an action of
- ct_lb_mark(args)
, where args contains
- comma separated IPv4 or IPv6 addresses. If the router is configured
- to force SNAT any load-balanced packets, the above action will be
- replaced by flags.force_snat_for_lb = 1;
-- ct_lb_mark(args);
.
-- If the load balancing rule is configured with skip_snat
-- set to true, the above action will be replaced by
-- flags.skip_snat_for_lb = 1; ct_lb_mark(args);
.
--
--
--
-- The previous table lr_in_defrag
sets the register
-- reg0
(or xxreg0
for IPv6) and does
-- ct_dnat
. Hence for established traffic, this
-- table just advances the packet to the next stage.
--
--
--
--
-- -
--
-- For all the configured load balancing rules for a router in
-- OVN_Northbound
database that includes just an IP address
-- VIP to match on, a priority-110 flow that matches on
-- ct.est && !ct.rel && ip4 && reg0 ==
-- VIP
(or ip6
and
-- xxreg0 == VIP
) with an action of
-- next;
. If the router is configured to force SNAT any
-- load-balanced packets, the above action will be replaced by
-- flags.force_snat_for_lb = 1; next;
.
-+ ct_lb_mark(args; force_snat);.
- If the load balancing rule is configured with skip_snat
- set to true, the above action will be replaced by
-- flags.skip_snat_for_lb = 1; next;
.
-+ flags.skip_snat_for_lb = 1; ct_lb_mark(args;
-+ skip_snat);
.
-
-
-
-@@ -3529,7 +3482,20 @@ icmp6 {
- with an action of ct_commit_nat;
, if the router
- has load balancer assigned to it. Along with two priority 70 flows
- that match skip_snat
and force_snat
-- flags.
-+ flags, setting the flags.force_snat_for_lb = 1
or
-+ flags.skip_snat_for_lb = 1
accordingly.
-+
-+
-+ -
-+
-+ For the established traffic, a priority 50 flow that matches
-+ ct.est && !ct.rel && !ct.new &&
-+ ct_mark.natted
with an action of next;
,
-+ if the router has load balancer assigned to it. Along with two
-+ priority 70 flows that match skip_snat
and
-+ force_snat
flags, setting the
-+ flags.force_snat_for_lb = 1
or
-+ flags.skip_snat_for_lb = 1
accordingly.
-
-
-
-@@ -4721,6 +4687,11 @@ nd_ns {
- Egress Table 1: UNDNAT on Gateway Routers
-
-
-+ -
-+ For IPv6 Neighbor Discovery or Router Solicitation/Advertisement
-+ traffic, a priority-100 flow with action
next;
.
-+
-+
- -
- For all IP packets, a priority-50 flow with an action
-
flags.loopback = 1; ct_dnat;
.
-@@ -4998,7 +4969,19 @@ nd_ns {
-
-
-
-- Egress Table 4: Egress Loopback
-+ Egress Table 4: Post SNAT
-+
-+
-+ Packets reaching this table are processed according to the flows below:
-+
-+ -
-+ A priority-0 logical flow that matches all packets not already
-+ handled (match
1
) and action next;
.
-+
-+
-+
-+
-+ Egress Table 5: Egress Loopback
-
-
- For distributed logical routers where one of the logical router
-@@ -5070,7 +5053,7 @@ clone {
-
-
-
--
Egress Table 5: Delivery
-+ Egress Table 6: Delivery
-
-
- Packets that reach this table are ready for delivery. It contains:
-diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
-index 5f895b053..7d24648ff 100644
---- a/northd/ovn-northd.c
-+++ b/northd/ovn-northd.c
-@@ -33,6 +33,7 @@
- #include "lib/ovn-l7.h"
- #include "lib/ovn-nb-idl.h"
- #include "lib/ovn-sb-idl.h"
-+#include "lib/ovs-rcu.h"
- #include "openvswitch/poll-loop.h"
- #include "simap.h"
- #include "stopwatch.h"
-@@ -1048,6 +1049,8 @@ main(int argc, char *argv[])
- ovsdb_idl_loop_destroy(&ovnnb_idl_loop);
- ovsdb_idl_loop_destroy(&ovnsb_idl_loop);
- service_stop();
-+ run_update_worker_pool(0);
-+ ovsrcu_exit();
-
- exit(res);
- }
-diff --git a/ovn-architecture.7.xml b/ovn-architecture.7.xml
-index cb1064f71..a2a87ec28 100644
---- a/ovn-architecture.7.xml
-+++ b/ovn-architecture.7.xml
-@@ -1233,8 +1233,8 @@
- output port field, and since they do not carry a logical output port
- field in the tunnel key, when a packet is received from ramp switch
- VXLAN tunnel by an OVN hypervisor, the packet is resubmitted to table 8
-- to determine the output port(s); when the packet reaches table 37,
-- these packets are resubmitted to table 38 for local delivery by
-+ to determine the output port(s); when the packet reaches table 39,
-+ these packets are resubmitted to table 40 for local delivery by
- checking a MLF_RCV_FROM_RAMP flag, which is set when the packet
- arrives from a ramp tunnel.
-
-@@ -1318,7 +1318,7 @@
- output port is known. These pieces of information are obtained
- from the tunnel encapsulation metadata (see Tunnel
- Encapsulations
for encoding details). Then the actions resubmit
-- to table 33 to enter the logical egress pipeline.
-+ to table 38 to enter the logical egress pipeline.
-
-
-
-@@ -1439,38 +1439,42 @@
-
-
-
-- OpenFlow tables 37 through 39 implement the output
action
-- in the logical ingress pipeline. Specifically, table 37 handles
-- packets to remote hypervisors, table 38 handles packets to the local
-- hypervisor, and table 39 checks whether packets whose logical ingress
-- and egress port are the same should be discarded.
-+ OpenFlow tables 37 through 41 implement the output
action
-+ in the logical ingress pipeline. Specifically, table 37 serves as an
-+ entry point to egress pipeline. Table 37 detects IP packets that are
-+ too big for a corresponding interface. Table 38 produces ICMPv4
-+ Fragmentation Needed (or ICMPv6 Too Big) errors and deliver them back
-+ to the offending port. table 39 handles packets to remote hypervisors,
-+ table 40 handles packets to the local hypervisor, and table 41 checks
-+ whether packets whose logical ingress and egress port are the same
-+ should be discarded.
-
-
-
- Logical patch ports are a special case. Logical patch ports do not
- have a physical location and effectively reside on every hypervisor.
-- Thus, flow table 38, for output to ports on the local hypervisor,
-+ Thus, flow table 40, for output to ports on the local hypervisor,
- naturally implements output to unicast logical patch ports too.
- However, applying the same logic to a logical patch port that is part
- of a logical multicast group yields packet duplication, because each
- hypervisor that contains a logical port in the multicast group will
- also output the packet to the logical patch port. Thus, multicast
-- groups implement output to logical patch ports in table 37.
-+ groups implement output to logical patch ports in table 39.
-
-
-
-- Each flow in table 37 matches on a logical output port for unicast or
-+ Each flow in table 39 matches on a logical output port for unicast or
- multicast logical ports that include a logical port on a remote
- hypervisor. Each flow's actions implement sending a packet to the port
- it matches. For unicast logical output ports on remote hypervisors,
- the actions set the tunnel key to the correct value, then send the
- packet on the tunnel port to the correct hypervisor. (When the remote
- hypervisor receives the packet, table 0 there will recognize it as a
-- tunneled packet and pass it along to table 38.) For multicast logical
-+ tunneled packet and pass it along to table 40.) For multicast logical
- output ports, the actions send one copy of the packet to each remote
- hypervisor, in the same way as for unicast destinations. If a
- multicast group includes a logical port or ports on the local
-- hypervisor, then its actions also resubmit to table 38. Table 37 also
-+ hypervisor, then its actions also resubmit to table 40. Table 39 also
- includes:
-
-
-@@ -1478,7 +1482,7 @@
-
- A higher-priority rule to match packets received from ramp switch
- tunnels, based on flag MLF_RCV_FROM_RAMP, and resubmit these packets
-- to table 38 for local delivery. Packets received from ramp switch
-+ to table 40 for local delivery. Packets received from ramp switch
- tunnels reach here because of a lack of logical output port field in
- the tunnel key and thus these packets needed to be submitted to table
- 8 to determine the output port.
-@@ -1486,7 +1490,7 @@
-
- A higher-priority rule to match packets received from ports of type
- localport
, based on the logical input port, and resubmit
-- these packets to table 38 for local delivery. Ports of type
-+ these packets to table 40 for local delivery. Ports of type
- localport
exist on every hypervisor and by definition
- their traffic should never go out through a tunnel.
-
-@@ -1501,41 +1505,41 @@
- packets, the packets only need to be delivered to local ports.
-
-
-- A fallback flow that resubmits to table 38 if there is no other
-+ A fallback flow that resubmits to table 40 if there is no other
- match.
-
-
-
-
-- Flows in table 38 resemble those in table 37 but for logical ports that
-+ Flows in table 40 resemble those in table 39 but for logical ports that
- reside locally rather than remotely. For unicast logical output ports
-- on the local hypervisor, the actions just resubmit to table 39. For
-+ on the local hypervisor, the actions just resubmit to table 41. For
- multicast output ports that include one or more logical ports on the
- local hypervisor, for each such logical port P, the actions
- change the logical output port to P, then resubmit to table
-- 39.
-+ 41.
-
-
-
- A special case is that when a localnet port exists on the datapath,
- remote port is connected by switching to the localnet port. In this
-- case, instead of adding a flow in table 37 to reach the remote port, a
-- flow is added in table 38 to switch the logical outport to the localnet
-- port, and resubmit to table 38 as if it were unicasted to a logical
-+ case, instead of adding a flow in table 39 to reach the remote port, a
-+ flow is added in table 40 to switch the logical outport to the localnet
-+ port, and resubmit to table 40 as if it were unicasted to a logical
- port on the local hypervisor.
-
-
-
-- Table 39 matches and drops packets for which the logical input and
-+ Table 41 matches and drops packets for which the logical input and
- output ports are the same and the MLF_ALLOW_LOOPBACK flag is not
- set. It also drops MLF_LOCAL_ONLY packets directed to a localnet port.
-- It resubmits other packets to table 40.
-+ It resubmits other packets to table 42.
-
-
-
-
-
-- OpenFlow tables 40 through 63 execute the logical egress pipeline from
-+ OpenFlow tables 42 through 62 execute the logical egress pipeline from
- the Logical_Flow
table in the OVN Southbound database.
- The egress pipeline can perform a final stage of validation before
- packet delivery. Eventually, it may execute an output
-@@ -1554,7 +1558,7 @@
-
-
- Table 64 bypasses OpenFlow loopback when MLF_ALLOW_LOOPBACK is set.
-- Logical loopback was handled in table 39, but OpenFlow by default also
-+ Logical loopback was handled in table 41, but OpenFlow by default also
- prevents loopback to the OpenFlow ingress port. Thus, when
- MLF_ALLOW_LOOPBACK is set, OpenFlow table 64 saves the OpenFlow ingress
- port, sets it to zero, resubmits to table 65 for logical-to-physical
-@@ -1592,8 +1596,8 @@
- traverse tables 0 to 65 as described in the previous section
- Architectural Physical Life Cycle of a Packet
, using the
- logical datapath representing the logical switch that the sender is
-- attached to. At table 37, the packet will use the fallback flow that
-- resubmits locally to table 38 on the same hypervisor. In this case,
-+ attached to. At table 39, the packet will use the fallback flow that
-+ resubmits locally to table 40 on the same hypervisor. In this case,
- all of the processing from table 0 to table 65 occurs on the hypervisor
- where the sender resides.
-
-@@ -1624,7 +1628,7 @@
-
- The packet traverses tables 8 to 65 a third and final time. If the
- destination VM or container resides on a remote hypervisor, then table
-- 37 will send the packet on a tunnel port from the sender's hypervisor
-+ 39 will send the packet on a tunnel port from the sender's hypervisor
- to the remote hypervisor. Finally table 65 will output the packet
- directly to the destination VM or container.
-
-@@ -1651,9 +1655,9 @@
- When a hypervisor processes a packet on a logical datapath
- representing a logical switch, and the logical egress port is a
- l3gateway
port representing connectivity to a gateway
-- router, the packet will match a flow in table 37 that sends the
-+ router, the packet will match a flow in table 39 that sends the
- packet on a tunnel port to the chassis where the gateway router
-- resides. This processing in table 37 is done in the same manner as
-+ resides. This processing in table 39 is done in the same manner as
- for VIFs.
-
-
-@@ -1746,21 +1750,21 @@
- chassis, one additional mechanism is required. When a packet
- leaves the ingress pipeline and the logical egress port is the
- distributed gateway port, one of two different sets of actions is
-- required at table 37:
-+ required at table 39:
-
-
-
- -
- If the packet can be handled locally on the sender's hypervisor
- (e.g. one-to-one NAT traffic), then the packet should just be
-- resubmitted locally to table 38, in the normal manner for
-+ resubmitted locally to table 40, in the normal manner for
- distributed logical patch ports.
-
-
- -
- However, if the packet needs to be handled on the chassis
- associated with the distributed gateway port (e.g. one-to-many
-- SNAT traffic or non-NAT traffic), then table 37 must send the
-+ SNAT traffic or non-NAT traffic), then table 39 must send the
- packet on a tunnel port to that chassis.
-
-
-@@ -1772,11 +1776,11 @@
- egress port to the type chassisredirect
logical port is
- simply a way to indicate that although the packet is destined for
- the distributed gateway port, it needs to be redirected to a
-- different chassis. At table 37, packets with this logical egress
-- port are sent to a specific chassis, in the same way that table 37
-+ different chassis. At table 39, packets with this logical egress
-+ port are sent to a specific chassis, in the same way that table 39
- directs packets whose logical egress port is a VIF or a type
- l3gateway
port to different chassis. Once the packet
-- arrives at that chassis, table 38 resets the logical egress port to
-+ arrives at that chassis, table 40 resets the logical egress port to
- the value representing the distributed gateway port. For each
- distributed gateway port, there is one type
- chassisredirect
port, in addition to the distributed
-diff --git a/ovn-nb.xml b/ovn-nb.xml
-index 8d56d0c6e..35acda107 100644
---- a/ovn-nb.xml
-+++ b/ovn-nb.xml
-@@ -2036,6 +2036,14 @@ or
- the affinity timeslot. Max supported affinity_timeout is 65535
- seconds.
-
-+
-+
-+ The value indicates whether ovn-controller should flush CT entries
-+ that are related to this LB. The flush happens if the LB is removed,
-+ any of the backends is updated/removed or the LB is not considered
-+ local anymore by the ovn-controller. This option is set to
-+ false
by default.
-+
-
-
-
-diff --git a/ovn-sb.xml b/ovn-sb.xml
-index a77f8f4ef..8ca206109 100644
---- a/ovn-sb.xml
-+++ b/ovn-sb.xml
-@@ -472,9 +472,8 @@
-
-
- The encapsulation to use to transmit packets to this chassis.
-- Hypervisors must use either geneve
or
-- stt
. Gateways may use vxlan
,
-- geneve
, or stt
.
-+ Hypervisors and gateways must use one of: geneve
,
-+ vxlan
, or stt
.
-
-
-
-diff --git a/rhel/usr_lib_systemd_system_ovn-db@.service b/rhel/usr_lib_systemd_system_ovn-db@.service
-index 98556a673..c835e4967 100644
---- a/rhel/usr_lib_systemd_system_ovn-db@.service
-+++ b/rhel/usr_lib_systemd_system_ovn-db@.service
-@@ -33,7 +33,7 @@ EnvironmentFile=-/etc/sysconfig/ovn-%i
- ExecStartPre=-/usr/bin/chown -R ${OVN_USER_ID} ${OVN_DBDIR}
- ExecStart=/usr/share/ovn/scripts/ovn-ctl \
- --ovn-user=${OVN_USER_ID} start_%i_ovsdb $OPTIONS $ovn_%i_opts
--ExecStop=/usr/share/ovn/scripts/ovn-ctl stop_%i_ovsdb
-+ExecStop=/usr/share/ovn/scripts/ovn-ctl stop_%i_ovsdb $OPTIONS $ovn_%i_opts
-
- [Install]
- WantedBy=multi-user.target
-diff --git a/rhel/usr_lib_systemd_system_ovn-northd.service b/rhel/usr_lib_systemd_system_ovn-northd.service
-index d281f861c..6c4c6621c 100644
---- a/rhel/usr_lib_systemd_system_ovn-northd.service
-+++ b/rhel/usr_lib_systemd_system_ovn-northd.service
-@@ -26,7 +26,7 @@ EnvironmentFile=-/etc/sysconfig/ovn-northd
- ExecStartPre=-/usr/bin/chown -R ${OVN_USER_ID} ${OVN_DBDIR}
- ExecStart=/usr/share/ovn/scripts/ovn-ctl \
- --ovn-user=${OVN_USER_ID} start_northd $OVN_NORTHD_OPTS
--ExecStop=/usr/share/ovn/scripts/ovn-ctl stop_northd
-+ExecStop=/usr/share/ovn/scripts/ovn-ctl stop_northd $OVN_NORTHD_OPTS
-
- [Install]
- WantedBy=multi-user.target
-diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at
-index bbe142ae3..dd7eda516 100644
---- a/tests/ovn-controller.at
-+++ b/tests/ovn-controller.at
-@@ -493,7 +493,8 @@ check ovn-nbctl --wait=hv sync
-
- # And check that it gets propagated to br-int external_ids.
- as hv1
--OVS_WAIT_UNTIL([ovs-vsctl get Bridge br-int external_ids:ovn-nb-cfg], [0], [1])
-+OVS_WAIT_FOR_OUTPUT([ovs-vsctl get Bridge br-int external_ids:ovn-nb-cfg], [0], ["1"
-+])
-
- nb_cfg_ts=$(fetch_column Chassis_Private nb_cfg_timestamp name=hv1)
- as hv1
-@@ -672,22 +673,26 @@ check ovs-vsctl del-ssl
- start_daemon ovn-controller -p $key -c $cert -C $cacert
-
- # SSL should not connect because of key and cert mismatch
--OVS_WAIT_UNTIL([ovn-appctl -t ovn-controller connection-status], [0], [not connected])
-+OVS_WAIT_FOR_OUTPUT([ovn-appctl -t ovn-controller connection-status], [0], [not connected
-+])
-
- # Modify the files with the correct key and cert, and reconnect should succeed
- cp $PKIDIR/$key $key
- cp $PKIDIR/$cert $cert
-
--OVS_WAIT_UNTIL([ovn-appctl -t ovn-controller connection-status], [0], [connected])
-+OVS_WAIT_FOR_OUTPUT([ovn-appctl -t ovn-controller connection-status], [0], [connected
-+])
-
- # Remove the files and expect the connection to drop
- rm $key $cert
--OVS_WAIT_UNTIL([ovn-appctl -t ovn-controller connection-status], [0], [not connected])
-+OVS_WAIT_FOR_OUTPUT([ovn-appctl -t ovn-controller connection-status], [0], [not connected
-+])
-
- # Restore the files again and expect the connection to recover
- cp $PKIDIR/$key $key
- cp $PKIDIR/$cert $cert
--OVS_WAIT_UNTIL([ovn-appctl -t ovn-controller connection-status], [0], [connected])
-+OVS_WAIT_FOR_OUTPUT([ovn-appctl -t ovn-controller connection-status], [0], [connected
-+])
-
- cat hv1/ovn-controller.log
-
-@@ -868,7 +873,7 @@ meta=$(ovn-sbctl get datapath ls1 tunnel_key)
- port=$(ovn-sbctl get port_binding ls1-rp tunnel_key)
- check ovn-nbctl lrp-add lr0 rp-ls1 00:00:01:01:02:03 192.168.1.254/24
-
--OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int | grep table=38 | grep -q "reg15=0x${port},metadata=0x${meta}"])
-+OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int | grep table=40 | grep -q "reg15=0x${port},metadata=0x${meta}"])
-
- OVN_CLEANUP([hv1])
- AT_CLEANUP
-@@ -912,14 +917,14 @@ for i in $(seq 10); do
- check ovn-nbctl add address_set as1 addresses 10.0.0.$i
- check ovn-nbctl --wait=hv sync
- if test "$i" = 3; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
- priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=drop
- priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2 actions=drop
- priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3 actions=drop
- ])
- fi
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$i
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$i
- ])
- done
-
-@@ -934,15 +939,15 @@ for i in $(seq 10); do
- check ovn-nbctl remove address_set as1 addresses 10.0.0.$i
- check ovn-nbctl --wait=hv sync
- if test "$i" = 9; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}'], [0], [dnl
- priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10 actions=drop
- ])
- fi
- if test "$i" = 10; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep "priority=1100"], [1], [ignore])
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep "priority=1100"], [1], [ignore])
- else
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$((10 - $i))
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$((10 - $i))
- ])
- fi
- done
-@@ -960,7 +965,7 @@ for i in $(seq 10); do
- check ovn-nbctl add address_set as1 addresses 10.0.0.$i,10.0.1.$i
- check ovn-nbctl --wait=hv sync
- if test "$i" = 3; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
- priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=drop
- priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2 actions=drop
-@@ -970,7 +975,7 @@ priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.1.2 actions=dr
- priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.1.3 actions=drop
- ])
- fi
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$(($i * 2))
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$(($i * 2))
- ])
- done
-
-@@ -987,11 +992,11 @@ reprocess_count_old=$(read_counter consider_logical_flow)
- check ovn-nbctl add address_set as1 addresses 10.0.0.21,10.0.0.22 -- \
- remove address_set as1 addresses 10.0.0.10
- check ovn-nbctl --wait=hv sync
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep -c 10\.0\.0\.21], [0], [1
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep -c 10\.0\.0\.21], [0], [1
- ])
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep -c 10\.0\.0\.22], [0], [1
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep -c 10\.0\.0\.22], [0], [1
- ])
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10\.0\.0\.10], [1], [ignore])
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep 10\.0\.0\.10], [1], [ignore])
-
- reprocess_count_new=$(read_counter consider_logical_flow)
- AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0], [0
-@@ -1003,9 +1008,9 @@ reprocess_count_old=$(read_counter consider_logical_flow)
- check ovn-nbctl remove address_set as1 addresses 10.0.0.21,10.0.0.22 -- \
- add address_set as1 addresses 10.0.0.10
- check ovn-nbctl --wait=hv sync
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10\.0\.0\.21], [1], [ignore])
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10\.0\.0\.22], [1], [ignore])
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep -c 10\.0\.0\.10], [0], [1
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep 10\.0\.0\.21], [1], [ignore])
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep 10\.0\.0\.22], [1], [ignore])
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep -c 10\.0\.0\.10], [0], [1
- ])
-
- reprocess_count_new=$(read_counter consider_logical_flow)
-@@ -1018,9 +1023,9 @@ reprocess_count_old=$(read_counter consider_logical_flow)
- check ovn-nbctl add address_set as1 addresses 10.0.0.21 -- \
- remove address_set as1 addresses 10.0.0.10
- check ovn-nbctl --wait=hv sync
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep -c 10\.0\.0\.21], [0], [1
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep -c 10\.0\.0\.21], [0], [1
- ])
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10\.0\.0\.10], [1], [ignore])
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep 10\.0\.0\.10], [1], [ignore])
-
- reprocess_count_new=$(read_counter consider_logical_flow)
- AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0], [0
-@@ -1032,12 +1037,12 @@ reprocess_count_old=$(read_counter consider_logical_flow)
- check ovn-nbctl add address_set as1 addresses 10.0.0.22,10.0.0.23 -- \
- remove address_set as1 addresses 10.0.0.9,10.0.0.8
- check ovn-nbctl --wait=hv sync
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep -c 10\.0\.0\.22], [0], [1
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep -c 10\.0\.0\.22], [0], [1
- ])
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep -c 10\.0\.0\.23], [0], [1
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep -c 10\.0\.0\.23], [0], [1
- ])
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10\.0\.0\.8], [1], [ignore])
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10\.0\.0\.9], [1], [ignore])
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep 10\.0\.0\.8], [1], [ignore])
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep 10\.0\.0\.9], [1], [ignore])
-
- reprocess_count_new=$(read_counter consider_logical_flow)
- AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0], [0
-@@ -1085,7 +1090,7 @@ for i in $(seq 10); do
- check ovn-nbctl add address_set as1 addresses 10.0.0.$i
- check ovn-nbctl --wait=hv sync
- if test "$i" = 1; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
- priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,tp_dst=111 actions=drop
- priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,tp_dst=222 actions=drop
-@@ -1093,12 +1098,12 @@ priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,tp_dst=33
- ])
- else
- # (1 conj_id flow + 3 tp_dst flows) = 4 extra flows
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$(($i + 4))
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$(($i + 4))
- ])
- fi
-
- if test "$i" = 3; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | \
- sed -r 's/conjunction.*,/conjunction,/' | \
- sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-@@ -1124,17 +1129,17 @@ for i in $(seq 10); do
- check ovn-nbctl remove address_set as1 addresses 10.0.0.$i
- check ovn-nbctl --wait=hv sync
- if test "$i" = 10; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep "priority=1100"], [1], [ignore])
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep "priority=1100"], [1], [ignore])
- elif test "$i" = 9; then
- # no conjunction left
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
- priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,tp_dst=111 actions=drop
- priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,tp_dst=222 actions=drop
- priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,tp_dst=333 actions=drop
- ])
- else
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$((14 - $i))
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$((14 - $i))
- ])
- fi
- done
-@@ -1150,7 +1155,7 @@ for i in $(seq 10); do
- check ovn-nbctl add address_set as1 addresses 10.0.0.$i,10.0.1.$i
- check ovn-nbctl --wait=hv sync
- if test "$i" = 3; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | \
- sed -r 's/conjunction.*,/conjunction,/' | \
- sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-@@ -1166,7 +1171,7 @@ priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,tp_dst=222 actions=conjun
- priority=1100,tcp,reg15=0x$port_key,metadata=0x$dp_key,tp_dst=333 actions=conjunction,2/2)
- ])
- fi
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$(($i * 2 + 4))
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$(($i * 2 + 4))
- ])
- done
-
-@@ -1182,11 +1187,11 @@ reprocess_count_old=$(read_counter consider_logical_flow)
- check ovn-nbctl add address_set as1 addresses 10.0.0.21,10.0.0.22 -- \
- remove address_set as1 addresses 10.0.0.10
- check ovn-nbctl --wait=hv sync
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep -c 10\.0\.0\.21], [0], [1
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep -c 10\.0\.0\.21], [0], [1
- ])
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep -c 10\.0\.0\.22], [0], [1
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep -c 10\.0\.0\.22], [0], [1
- ])
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10\.0\.0\.10], [1], [ignore])
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep 10\.0\.0\.10], [1], [ignore])
-
- reprocess_count_new=$(read_counter consider_logical_flow)
- AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0], [0
-@@ -1198,9 +1203,9 @@ reprocess_count_old=$(read_counter consider_logical_flow)
- check ovn-nbctl remove address_set as1 addresses 10.0.0.21,10.0.0.22 -- \
- add address_set as1 addresses 10.0.0.10
- check ovn-nbctl --wait=hv sync
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10\.0\.0\.21], [1], [ignore])
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10\.0\.0\.22], [1], [ignore])
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep -c 10\.0\.0\.10], [0], [1
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep 10\.0\.0\.21], [1], [ignore])
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep 10\.0\.0\.22], [1], [ignore])
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep -c 10\.0\.0\.10], [0], [1
- ])
-
- reprocess_count_new=$(read_counter consider_logical_flow)
-@@ -1213,9 +1218,9 @@ reprocess_count_old=$(read_counter consider_logical_flow)
- check ovn-nbctl add address_set as1 addresses 10.0.0.21 -- \
- remove address_set as1 addresses 10.0.0.10
- check ovn-nbctl --wait=hv sync
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep -c 10\.0\.0\.21], [0], [1
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep -c 10\.0\.0\.21], [0], [1
- ])
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10\.0\.0\.10], [1], [ignore])
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep 10\.0\.0\.10], [1], [ignore])
-
- reprocess_count_new=$(read_counter consider_logical_flow)
- AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0], [0
-@@ -1227,12 +1232,12 @@ reprocess_count_old=$(read_counter consider_logical_flow)
- check ovn-nbctl add address_set as1 addresses 10.0.0.22,10.0.0.23 -- \
- remove address_set as1 addresses 10.0.0.9,10.0.0.8
- check ovn-nbctl --wait=hv sync
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep -c 10\.0\.0\.22], [0], [1
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep -c 10\.0\.0\.22], [0], [1
- ])
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep -c 10\.0\.0\.23], [0], [1
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep -c 10\.0\.0\.23], [0], [1
- ])
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10\.0\.0\.8], [1], [ignore])
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10\.0\.0\.9], [1], [ignore])
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep 10\.0\.0\.8], [1], [ignore])
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep 10\.0\.0\.9], [1], [ignore])
-
- reprocess_count_new=$(read_counter consider_logical_flow)
- AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0], [0
-@@ -1282,18 +1287,18 @@ for i in $(seq 10); do
- add address_set as2 addresses 10.0.0.$j
- check ovn-nbctl --wait=hv sync
- if test "$i" = 1; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
- priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,nw_dst=10.0.0.6 actions=drop
- ])
- else
- # (1 conj_id + nw_src * i + nw_dst * i) = 1 + i*2 flows
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$(($i*2 + 1))
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$(($i*2 + 1))
- ])
- fi
-
- if test "$i" = 3; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | \
- sed -r 's/conjunction.*,/conjunction,/' | \
- sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-@@ -1321,15 +1326,15 @@ for i in $(seq 10); do
- remove address_set as2 addresses 10.0.0.$j
- check ovn-nbctl --wait=hv sync
- if test "$i" = 10; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep "priority=1100"], [1], [ignore])
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep "priority=1100"], [1], [ignore])
- elif test "$i" = 9; then
- # no conjunction left
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
- priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,nw_dst=10.0.0.15 actions=drop
- ])
- else
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$((21 - $i*2))
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$((21 - $i*2))
- ])
- fi
- done
-@@ -1350,14 +1355,14 @@ for i in $(seq 2 10); do
- check ovn-nbctl add address_set as1 addresses 10.0.0.$i
- check ovn-nbctl --wait=hv sync
- if test "$i" = 3; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
- priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,nw_dst=10.0.0.6 actions=drop
- priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.2,nw_dst=10.0.0.6 actions=drop
- priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3,nw_dst=10.0.0.6 actions=drop
- ])
- fi
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$i
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$i
- ])
- done
-
-@@ -1376,16 +1381,16 @@ for i in $(seq 10); do
- check ovn-nbctl remove address_set as1 addresses 10.0.0.$i
- check ovn-nbctl --wait=hv sync
- if test "$i" = 9; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}'], [0], [dnl
- priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,nw_dst=10.0.0.6 actions=drop
- priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,nw_dst=10.0.0.7 actions=drop
- ])
- elif test "$i" = 10; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep "priority=1100"], [1], [ignore])
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep "priority=1100"], [1], [ignore])
- else
- # 2 dst + (10 - i) src + 1 conj_id
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$((10 - $i + 3))
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$((10 - $i + 3))
- ])
- fi
- done
-@@ -1439,18 +1444,18 @@ for i in $(seq 10); do
- add address_set as2 addresses 10.0.0.$j
- check ovn-nbctl --wait=hv sync
- if test "$i" = 1; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
- priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_dst=10.0.0.6 actions=drop
- priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=drop
- ])
- else
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$(($i*2))
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$(($i*2))
- ])
- fi
-
- if test "$i" = 3; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | \
- sed -r 's/conjunction.*,/conjunction,/' | \
- sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-@@ -1477,9 +1482,9 @@ for i in $(seq 10); do
- remove address_set as2 addresses 10.0.0.$j
- check ovn-nbctl --wait=hv sync
- if test "$i" = 10; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep "priority=1100"], [1], [ignore])
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep "priority=1100"], [1], [ignore])
- else
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$((20 - $i*2))
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$((20 - $i*2))
- ])
- fi
- done
-@@ -1535,21 +1540,21 @@ for i in $(seq 10); do
- add address_set as2 addresses 10.0.0.$j
- check ovn-nbctl --wait=hv sync
- if test "$i" = 1; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
- priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1 actions=drop
- priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.6 actions=drop
- ])
- elif test "$i" -lt 6; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$(($i*2))
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$(($i*2))
- ])
- else
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$((5 + $i))
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$((5 + $i))
- ])
- fi
-
- if test "$i" = 3; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | \
- sed -r 's/conjunction.*,/conjunction,/' | \
- sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-@@ -1576,12 +1581,12 @@ for i in $(seq 10); do
- remove address_set as2 addresses 10.0.0.$j
- check ovn-nbctl --wait=hv sync
- if test "$i" = 10; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep "priority=1100"], [1], [ignore])
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep "priority=1100"], [1], [ignore])
- elif test "$i" -lt 6; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$((15 - $i))
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$((15 - $i))
- ])
- else
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$((10 - ($i - 5)*2))
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$((10 - ($i - 5)*2))
- ])
- fi
- done
-@@ -1633,18 +1638,18 @@ for i in $(seq 10); do
- check ovn-nbctl add address_set as1 addresses 10.0.0.$i
- check ovn-nbctl --wait=hv sync
- if test "$i" = 1; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
- priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.1,nw_dst=10.0.0.1 actions=drop
- ])
- else
- # (1 conj_id + nw_src * i + nw_dst * i) = 1 + i*2 flows
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$(($i*2 + 1))
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$(($i*2 + 1))
- ])
- fi
-
- if test "$i" = 3; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | \
- sed -r 's/conjunction.*,/conjunction,/' | \
- sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-@@ -1670,15 +1675,15 @@ for i in $(seq 10); do
- check ovn-nbctl remove address_set as1 addresses 10.0.0.$i
- check ovn-nbctl --wait=hv sync
- if test "$i" = 10; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep "priority=1100"], [1], [ignore])
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep "priority=1100"], [1], [ignore])
- elif test "$i" = 9; then
- # no conjunction left
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
- priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.10,nw_dst=10.0.0.10 actions=drop
- ])
- else
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$((21 - $i*2))
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$((21 - $i*2))
- ])
- fi
- done
-@@ -1694,7 +1699,7 @@ for i in $(seq 10); do
- check ovn-nbctl add address_set as1 addresses 10.0.0.$i,10.0.1.$i
- check ovn-nbctl --wait=hv sync
- if test "$i" = 3; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | \
- sed -r 's/conjunction.*,/conjunction,/' | \
- sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-@@ -1713,7 +1718,7 @@ priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.1.2 actions=co
- priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.1.3 actions=conjunction,2/2)
- ])
- fi
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$(($i * 4 + 1))
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$(($i * 4 + 1))
- ])
- done
-
-@@ -1734,7 +1739,7 @@ check ovn-nbctl --wait=hv sync
- reprocess_count_old=$(read_counter consider_logical_flow)
- check ovn-nbctl add address_set as1 addresses 10.0.0.4,10.0.0.5
- check ovn-nbctl --wait=hv sync
--AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | \
- sed -r 's/conjunction.*,/conjunction,/' | \
- sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-@@ -1758,7 +1763,7 @@ AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0], [1
- # Delete 2 IPs
- reprocess_count_old=$(read_counter consider_logical_flow)
- check ovn-nbctl --wait=hv remove address_set as1 addresses 10.0.0.4,10.0.0.5
--AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | \
- sed -r 's/conjunction.*,/conjunction,/' | \
- sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-@@ -1816,7 +1821,7 @@ check ovn-nbctl acl-add ls1 to-lport 100 'outport == "ls1-lp1" && ip4.src == $as
- check ovn-nbctl acl-add ls1 to-lport 100 'outport == "ls1-lp1" && ip4.src == $as2 && tcp && tcp.dst == {201, 202}' drop
-
- check ovn-nbctl --wait=hv sync
--AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | \
- sed -r 's/conjunction.[[0-9]]*,/conjunction,/g' | \
- sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-@@ -1841,7 +1846,7 @@ reprocess_count_old=$(read_counter consider_logical_flow)
- check ovn-nbctl add address_set as1 addresses 10.0.0.14,10.0.0.33 -- \
- add address_set as2 addresses 10.0.0.24,10.0.0.33
- check ovn-nbctl --wait=hv sync
--AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | \
- sed -r 's/conjunction.[[0-9]]*,/conjunction,/g' | \
- sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-@@ -1872,7 +1877,7 @@ reprocess_count_old=$(read_counter consider_logical_flow)
- check ovn-nbctl remove address_set as1 addresses 10.0.0.14,10.0.0.33 -- \
- remove address_set as2 addresses 10.0.0.24,10.0.0.33
- check ovn-nbctl --wait=hv sync
--AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | \
- sed -r 's/conjunction.[[0-9]]*,/conjunction,/g' | \
- sed -r 's/conj_id=.*,/conj_id=,/' | sort], [0], [dnl
-@@ -1937,14 +1942,14 @@ for i in $(seq 5); do
- check ovn-nbctl add address_set as1 addresses "aa\:aa\:aa\:aa\:aa\:0$i"
- check ovn-nbctl --wait=hv sync
- if test "$i" = 3; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
- priority=1100,reg15=0x$port_key,metadata=0x$dp_key,dl_src=aa:aa:aa:aa:aa:01 actions=drop
- priority=1100,reg15=0x$port_key,metadata=0x$dp_key,dl_src=aa:aa:aa:aa:aa:02 actions=drop
- priority=1100,reg15=0x$port_key,metadata=0x$dp_key,dl_src=aa:aa:aa:aa:aa:03 actions=drop
- ])
- fi
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$i
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$i
- ])
- done
-
-@@ -1958,17 +1963,17 @@ reprocess_count_old=$(read_counter consider_logical_flow)
- for i in $(seq 5); do
- check ovn-nbctl remove address_set as1 addresses "aa\:aa\:aa\:aa\:aa\:0$i"
- check ovn-nbctl --wait=hv sync
-- ovs-ofctl dump-flows br-int table=44 | grep "priority=1100"
-+ ovs-ofctl dump-flows br-int table=46 | grep "priority=1100"
- if test "$i" = 4; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}'], [0], [dnl
- priority=1100,reg15=0x$port_key,metadata=0x$dp_key,dl_src=aa:aa:aa:aa:aa:05 actions=drop
- ])
- fi
- if test "$i" = 5; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep "priority=1100"], [1], [ignore])
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep "priority=1100"], [1], [ignore])
- else
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$((5 - $i))
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$((5 - $i))
- ])
- fi
- done
-@@ -2018,14 +2023,14 @@ for i in $(seq 5); do
- check ovn-nbctl add address_set as1 addresses "ff\:\:0$i"
- check ovn-nbctl --wait=hv sync
- if test "$i" = 3; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}' | sort], [0], [dnl
- priority=1100,ipv6,reg15=0x$port_key,metadata=0x$dp_key,ipv6_src=ff::1 actions=drop
- priority=1100,ipv6,reg15=0x$port_key,metadata=0x$dp_key,ipv6_src=ff::2 actions=drop
- priority=1100,ipv6,reg15=0x$port_key,metadata=0x$dp_key,ipv6_src=ff::3 actions=drop
- ])
- fi
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$i
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$i
- ])
- done
-
-@@ -2040,15 +2045,15 @@ for i in $(seq 5); do
- check ovn-nbctl remove address_set as1 addresses "ff\:\:0$i"
- check ovn-nbctl --wait=hv sync
- if test "$i" = 4; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44,reg15=0x$port_key | \
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46,reg15=0x$port_key | \
- grep -v reply | awk '{print $7, $8}'], [0], [dnl
- priority=1100,ipv6,reg15=0x$port_key,metadata=0x$dp_key,ipv6_src=ff::5 actions=drop
- ])
- fi
- if test "$i" = 5; then
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep "priority=1100"], [1], [ignore])
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep "priority=1100"], [1], [ignore])
- else
-- AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [$((5 - $i))
-+ AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [$((5 - $i))
- ])
- fi
- done
-@@ -2060,6 +2065,57 @@ AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0], [2
- OVN_CLEANUP([hv1])
- AT_CLEANUP
-
-+AT_SETUP([ovn-controller - address set del-and-add])
-+
-+ovn_start
-+
-+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
-+
-+ovn-nbctl create address_set name=as1 addresses=8.8.8.8
-+check ovn-nbctl acl-add ls1 to-lport 100 'outport == "ls1-lp1" && ip4.src == $as1' drop
-+check ovn-nbctl --wait=hv sync
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [1
-+])
-+
-+# pause ovn-northd
-+check as northd ovn-appctl -t ovn-northd pause
-+check as northd-backup ovn-appctl -t ovn-northd pause
-+
-+# Simulate a SB address set "del and add" notification to ovn-controller in the
-+# same IDL iteration. The flows programmed by ovn-controller should reflect the
-+# newly added address set. In reality it can happen when CMS deletes an
-+# address-set and immediately creates a new address-set with the same name
-+# (with same or different content). The notification of the changes can come to
-+# ovn-controller in one shot and the order of the "del" and "add" in the IDL is
-+# undefined. This test runs the scenario ten times to make sure different
-+# orders are covered and handled properly.
-+
-+flow_count=$(ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100")
-+for i in $(seq 10); do
-+ # Delete and recreate the SB address set with same name and an extra IP.
-+ addrs_=$(fetch_column address_set addresses name=as1)
-+ addrs=${addrs_// /,}
-+ AT_CHECK([ovn-sbctl destroy address_set as1 -- create address_set name=as1 addresses=$addrs,1.1.1.$i], [0], [ignore])
-+ OVS_WAIT_UNTIL([test $(as hv1 ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100") = "$(($i + 1))"])
-+done
-+
-+OVN_CLEANUP([hv1])
-+AT_CLEANUP
-+
- AT_SETUP([ovn-controller - I-P handle lb_hairpin_use_ct_mark change])
-
- ovn_start --backup-northd=none
-@@ -2161,7 +2217,7 @@ AT_CHECK([ovs-ofctl dump-flows br-int | grep 10.1.2.3], [0], [ignore])
- sleep 5
-
- # Check after the wait
--OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep 10.1.2.4], [0], [ignore])
-+OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep 10.1.2.4])
- lflow_run_2=$(ovn-appctl -t ovn-controller coverage/read-counter lflow_run)
-
- # Verify that the flow compute completed during the wait (after the wait it
-@@ -2172,7 +2228,7 @@ AT_CHECK_UNQUOTED([echo $lflow_run_1], [0], [$lflow_run_2
- # Restart OVS this time, and wait until flows are reinstalled
- OVS_APP_EXIT_AND_WAIT([ovs-vswitchd])
- start_daemon ovs-vswitchd --enable-dummy=system -vvconn -vofproto_dpif -vunixctl
--OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep 10.1.2.4], [0], [ignore])
-+OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep 10.1.2.4])
-
- check ovn-nbctl --wait=hv lb-add lb3 2.2.2.2 10.1.2.5 \
- -- ls-lb-add ls1 lb3
-diff --git a/tests/ovn-macros.at b/tests/ovn-macros.at
-index ee942e8a6..6f2d085ae 100644
---- a/tests/ovn-macros.at
-+++ b/tests/ovn-macros.at
-@@ -817,6 +817,29 @@ ovn_trace_client() {
- ovs-appctl -t $target trace "$@" | tee trace | sed '/^# /d'
- }
-
-+# Receives a string with scapy python code that represents a packet.
-+# Returns a hex-string that contains bytes that reflect the packet symbolic
-+# description.
-+#
-+# Scapy docs: https://scapy.readthedocs.io/en/latest/usage.html
-+#
-+# Example of usage:
-+#
-+# packet=$(fmt_pkt "
-+# Ether(dst='ff:ff:ff:ff:ff:ff', src='50:64:00:00:00:01') /
-+# IPv6(src='abed::1', dst='ff02::1:ff00:2') /
-+# ICMPv6ND_NS(tgt='abed::2')
-+# ")
-+#
-+# ovs-appctl netdev-dummy/receive $vif $packet
-+#
-+fmt_pkt() {
-+ echo "from scapy.all import *; \
-+ import binascii; \
-+ out = binascii.hexlify(raw($1)); \
-+ print(out.decode())" | $PYTHON3
-+}
-+
- OVS_END_SHELL_HELPERS
-
- m4_define([OVN_POPULATE_ARP], [AT_CHECK(ovn_populate_arp__, [0], [ignore])])
-diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at
-index 2fffe1850..478a32f5a 100644
---- a/tests/ovn-nbctl.at
-+++ b/tests/ovn-nbctl.at
-@@ -1482,6 +1482,32 @@ UUID LB PROTO VIP
-
- dnl ---------------------------------------------------------------------
-
-+OVN_NBCTL_TEST([ovn_nbctl_template_lbs], [Template LBs], [
-+check ovn-nbctl --template lb-add lb0 ^vip ^backend
-+check ovn-nbctl --template lb-add lb1 ^vip:^vport ^backend udp
-+check ovn-nbctl --template lb-add lb2 ^vip:^vport ^backend udp ipv4
-+check ovn-nbctl --template lb-add lb3 ^vip:^vport ^backend udp ipv6
-+check ovn-nbctl --template lb-add lb4 ^vip:^vport ^backend:^bport udp ipv4
-+check ovn-nbctl --template lb-add lb5 ^vip:^vport ^backend:^bport udp ipv6
-+check ovn-nbctl --template lb-add lb6 ^vip:^vport 1.1.1.1:111 udp ipv4
-+check ovn-nbctl --template lb-add lb7 ^vip:^vport [[1::1]]:111 udp ipv6
-+
-+AT_CHECK([ovn-nbctl lb-list | uuidfilt], [0], [dnl
-+UUID LB PROTO VIP IPs
-+<0> lb0 tcp ^vip ^backend
-+<1> lb1 udp ^vip:^vport ^backend
-+<2> lb2 udp ^vip:^vport ^backend
-+<3> lb3 udp ^vip:^vport ^backend
-+<4> lb4 udp ^vip:^vport ^backend:^bport
-+<5> lb5 udp ^vip:^vport ^backend:^bport
-+<6> lb6 udp ^vip:^vport 1.1.1.1:111
-+<7> lb7 udp ^vip:^vport [[1::1]]:111
-+])
-+
-+])
-+
-+dnl ---------------------------------------------------------------------
-+
- OVN_NBCTL_TEST([ovn_nbctl_basic_lr], [basic logical router commands], [
- AT_CHECK([ovn-nbctl lr-add lr0])
- AT_CHECK([ovn-nbctl lr-list | uuidfilt], [0], [dnl
-@@ -2599,6 +2625,7 @@ OVN_NBCTL_TEST_STOP "/terminating with signal 15/d"
- AT_CLEANUP
-
- AT_SETUP([ovn-nbctl - daemon ssl files change])
-+AT_SKIP_IF([test "$HAVE_OPENSSL" = no])
- dnl Create ovn-nb database.
- AT_CHECK([ovsdb-tool create ovn-nb.db $abs_top_srcdir/ovn-nb.ovsschema])
-
-diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
-index 3fa02d2b3..93854dfdc 100644
---- a/tests/ovn-northd.at
-+++ b/tests/ovn-northd.at
-@@ -2486,6 +2486,7 @@ check ovn-nbctl --wait=sb \
-
- AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e ls_in_acl -e ls_out_acl | sort], [0], [dnl
- table=17(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;)
-+ table=17(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=17(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
- table=3 (ls_out_acl_hint ), priority=0 , match=(1), action=(next;)
- table=3 (ls_out_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
-@@ -2530,9 +2531,12 @@ ovn-nbctl --wait=sb clear logical_switch ls load_balancer
-
- AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e ls_in_acl -e ls_out_acl | sort], [0], [dnl
- table=17(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;)
-+ table=17(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=3 (ls_out_acl_hint ), priority=65535, match=(1), action=(next;)
-+ table=4 (ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=4 (ls_out_acl ), priority=65535, match=(1), action=(next;)
- table=7 (ls_in_acl_hint ), priority=65535, match=(1), action=(next;)
-+ table=8 (ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=8 (ls_in_acl ), priority=65535, match=(1), action=(next;)
- ])
-
-@@ -2871,7 +2875,6 @@ AT_CHECK([ovn-sbctl lflow-list sw0 | grep ls_in_nat_hairpin | sort | sed 's/tabl
- 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
-@@ -2887,7 +2890,6 @@ AT_CHECK([ovn-sbctl lflow-list sw0 | grep ls_in_nat_hairpin | sort | sed 's/tabl
-
- 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
-@@ -2908,7 +2910,6 @@ AT_CHECK([ovn-sbctl lflow-list sw0 | grep ls_in_nat_hairpin | sort | sed 's/tabl
- 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
-@@ -3757,18 +3758,18 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
-
- AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl
- table=5 (lr_in_defrag ), priority=0 , match=(1), action=(next;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.10 && tcp), action=(reg0 = 10.0.0.10; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.100 && tcp), action=(reg0 = 10.0.0.100; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.100), action=(ct_dnat;)
- ])
-
- AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
- table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(ct_lb_mark(backends=10.0.0.4:8080);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(ct_lb_mark(backends=10.0.0.40:8080);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.4:8080);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.100 && tcp && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.40:8080);)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
- table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
- ])
-@@ -3788,18 +3789,18 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
-
- AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl
- table=5 (lr_in_defrag ), priority=0 , match=(1), action=(next;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.10 && tcp), action=(reg0 = 10.0.0.10; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.100 && tcp), action=(reg0 = 10.0.0.100; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.100), action=(ct_dnat;)
- ])
-
- AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
- table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080; force_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.100 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080; force_snat);)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
- table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
- ])
-@@ -3813,6 +3814,7 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [
-
- AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
- table=? (lr_out_undnat ), priority=0 , match=(1), action=(next;)
-+ table=? (lr_out_undnat ), priority=100 , match=(nd || nd_rs || nd_ra), action=(next;)
- table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;)
- ])
-
-@@ -3838,18 +3840,18 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
-
- AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl
- table=5 (lr_in_defrag ), priority=0 , match=(1), action=(next;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.10 && tcp), action=(reg0 = 10.0.0.10; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.100 && tcp), action=(reg0 = 10.0.0.100; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.100), action=(ct_dnat;)
- ])
-
- AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
- table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080; force_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.100 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080; force_snat);)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
- table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
- ])
-@@ -3864,6 +3866,7 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [
-
- AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
- table=? (lr_out_undnat ), priority=0 , match=(1), action=(next;)
-+ table=? (lr_out_undnat ), priority=100 , match=(nd || nd_rs || nd_ra), action=(next;)
- table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;)
- ])
-
-@@ -3902,18 +3905,18 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
-
- AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl
- table=5 (lr_in_defrag ), priority=0 , match=(1), action=(next;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.10 && tcp), action=(reg0 = 10.0.0.10; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.100 && tcp), action=(reg0 = 10.0.0.100; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.100), action=(ct_dnat;)
- ])
-
- AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
- table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080; force_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.100 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080; force_snat);)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
- table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
- ])
-@@ -3929,6 +3932,7 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [
-
- AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
- table=? (lr_out_undnat ), priority=0 , match=(1), action=(next;)
-+ table=? (lr_out_undnat ), priority=100 , match=(nd || nd_rs || nd_ra), action=(next;)
- table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;)
- ])
-
-@@ -3953,14 +3957,13 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
-
- AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl
- table=5 (lr_in_defrag ), priority=0 , match=(1), action=(next;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.100 && tcp), action=(reg0 = 10.0.0.100; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.20 && tcp), action=(reg0 = 10.0.0.20; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.100), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.20), action=(ct_dnat;)
- ])
-
- AT_CHECK([grep "lr_in_dnat" lr0flows | grep skip_snat_for_lb | sort], [0], [dnl
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.20 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.skip_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.20 && tcp && reg9[[16..31]] == 80), action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080; skip_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.20 && tcp && tcp.dst == 80), action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080; skip_snat);)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
- ])
-
-@@ -3970,6 +3973,7 @@ AT_CHECK([grep "lr_out_snat" lr0flows | grep skip_snat_for_lb | sed 's/table=./t
-
- AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
- table=? (lr_out_undnat ), priority=0 , match=(1), action=(next;)
-+ table=? (lr_out_undnat ), priority=100 , match=(nd || nd_rs || nd_ra), action=(next;)
- table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;)
- ])
-
-@@ -4111,6 +4115,7 @@ check ovn-nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0
- check ovn-nbctl --wait=sb sync
-
- check_stateful_flows() {
-+ action=$1
- ovn-sbctl dump-flows sw0 > sw0flows
- AT_CAPTURE_FILE([sw0flows])
-
-@@ -4144,12 +4149,12 @@ check_stateful_flows() {
- table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
- ])
-
-- AT_CHECK([grep "ls_out_pre_lb" sw0flows | sort], [0], [dnl
-+ AT_CHECK_UNQUOTED([grep "ls_out_pre_lb" sw0flows | sort], [0], [dnl
- table=1 (ls_out_pre_lb ), priority=0 , match=(1), action=(next;)
- table=1 (ls_out_pre_lb ), priority=100 , match=(ip), action=(reg0[[2]] = 1; next;)
- table=1 (ls_out_pre_lb ), priority=110 , match=(eth.mcast), action=(next;)
-- table=1 (ls_out_pre_lb ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;)
-- table=1 (ls_out_pre_lb ), priority=110 , match=(ip && outport == "sw0-lr0"), action=(next;)
-+ table=1 (ls_out_pre_lb ), priority=110 , match=(eth.src == \$svc_monitor_mac), action=(next;)
-+ table=1 (ls_out_pre_lb ), priority=110 , match=(ip && outport == "sw0-lr0"), action=($action)
- table=1 (ls_out_pre_lb ), priority=110 , match=(nd || nd_rs || nd_ra || mldv1 || mldv2), action=(next;)
- table=1 (ls_out_pre_lb ), priority=110 , match=(reg0[[16]] == 1), action=(next;)
- ])
-@@ -4169,13 +4174,13 @@ check_stateful_flows() {
- ])
- }
-
--check_stateful_flows
-+check_stateful_flows "ct_clear; next;"
-
- # Add few ACLs
- check ovn-nbctl --wait=sb acl-add sw0 from-lport 1002 "ip4 && tcp && tcp.dst == 80" allow-related
- check ovn-nbctl --wait=sb acl-add sw0 to-lport 1002 "ip4 && tcp && tcp.src == 80" drop
-
--check_stateful_flows
-+check_stateful_flows "next;"
-
- # Remove load balancers from sw0
- check ovn-nbctl ls-lb-del sw0 lb0
-@@ -4231,6 +4236,15 @@ AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl
- table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;)
- ])
-
-+# LB with event=false and reject=false
-+AT_CHECK([ovn-nbctl create load_balancer name=lb1 options:reject=false options:event=false vips:\"10.0.0.20\"=\"\" protocol=tcp], [0], [ignore])
-+check ovn-nbctl --wait=sb ls-lb-add sw0 lb1
-+
-+AT_CHECK([ovn-sbctl dump-flows sw0 | grep "ls_in_lb " | sort ], [0], [dnl
-+ table=12(ls_in_lb ), priority=0 , match=(1), action=(next;)
-+ table=12(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 10.0.0.20), action=(drop;)
-+])
-+
- AT_CLEANUP
- ])
-
-@@ -4871,7 +4885,7 @@ check ovn-nbctl lsp-set-options ls2-ro2 router-port=ro2-ls2
- ovn-sbctl lflow-list ls1 > ls1_lflows
- AT_CHECK([grep "ls_in_l2_lkup" ls1_lflows | sed 's/table=../table=??/' | sort], [0], [dnl
- table=??(ls_in_l2_lkup ), priority=0 , match=(1), action=(outport = get_fdb(eth.dst); next;)
-- table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
-+ table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac && (tcp || icmp || icmp6)), action=(handle_svc_check(inport);)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:01:01), action=(outport = "ls1-ro1"; output;)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:01:02), action=(outport = "vm1"; output;)
- table=??(ls_in_l2_lkup ), priority=70 , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
-@@ -4883,7 +4897,7 @@ AT_CHECK([grep "ls_in_l2_lkup" ls1_lflows | sed 's/table=../table=??/' | sort],
- ovn-sbctl lflow-list ls2 > ls2_lflows
- AT_CHECK([grep "ls_in_l2_lkup" ls2_lflows | sed 's/table=../table=??/' | sort], [0], [dnl
- table=??(ls_in_l2_lkup ), priority=0 , match=(1), action=(outport = get_fdb(eth.dst); next;)
-- table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
-+ table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac && (tcp || icmp || icmp6)), action=(handle_svc_check(inport);)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:02:01), action=(outport = "ls2-ro2"; output;)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:02:02), action=(outport = "vm2"; output;)
- table=??(ls_in_l2_lkup ), priority=70 , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
-@@ -4903,7 +4917,7 @@ check ovn-nbctl --wait=sb lr-nat-add ro2 snat 20.0.0.200 192.168.2.200/30
- ovn-sbctl lflow-list ls1 > ls1_lflows
- AT_CHECK([grep "ls_in_l2_lkup" ls1_lflows | sed 's/table=../table=??/' | sort], [0], [dnl
- table=??(ls_in_l2_lkup ), priority=0 , match=(1), action=(outport = get_fdb(eth.dst); next;)
-- table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
-+ table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac && (tcp || icmp || icmp6)), action=(handle_svc_check(inport);)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:01:01), action=(outport = "ls1-ro1"; output;)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:01:02), action=(outport = "vm1"; output;)
- table=??(ls_in_l2_lkup ), priority=70 , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
-@@ -4916,7 +4930,7 @@ AT_CHECK([grep "ls_in_l2_lkup" ls1_lflows | sed 's/table=../table=??/' | sort],
- ovn-sbctl lflow-list ls2 > ls2_lflows
- AT_CHECK([grep "ls_in_l2_lkup" ls2_lflows | sed 's/table=../table=??/' | sort], [0], [dnl
- table=??(ls_in_l2_lkup ), priority=0 , match=(1), action=(outport = get_fdb(eth.dst); next;)
-- table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
-+ table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac && (tcp || icmp || icmp6)), action=(handle_svc_check(inport);)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:02:01), action=(outport = "ls2-ro2"; output;)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:02:02), action=(outport = "vm2"; output;)
- table=??(ls_in_l2_lkup ), priority=70 , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
-@@ -4937,7 +4951,7 @@ check ovn-nbctl --wait=sb lr-nat-add ro2 snat 40.0.0.200 192.168.2.148/30
- ovn-sbctl lflow-list ls1 > ls1_lflows
- AT_CHECK([grep "ls_in_l2_lkup" ls1_lflows | sed 's/table=../table=??/' | sort], [0], [dnl
- table=??(ls_in_l2_lkup ), priority=0 , match=(1), action=(outport = get_fdb(eth.dst); next;)
-- table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
-+ table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac && (tcp || icmp || icmp6)), action=(handle_svc_check(inport);)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:01:01), action=(outport = "ls1-ro1"; output;)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:01:02), action=(outport = "vm1"; output;)
- table=??(ls_in_l2_lkup ), priority=70 , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
-@@ -4951,7 +4965,7 @@ AT_CHECK([grep "ls_in_l2_lkup" ls1_lflows | sed 's/table=../table=??/' | sort],
- ovn-sbctl lflow-list ls2 > ls2_lflows
- AT_CHECK([grep "ls_in_l2_lkup" ls2_lflows | sed 's/table=../table=??/' | sort], [0], [dnl
- table=??(ls_in_l2_lkup ), priority=0 , match=(1), action=(outport = get_fdb(eth.dst); next;)
-- table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
-+ table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac && (tcp || icmp || icmp6)), action=(handle_svc_check(inport);)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:02:01), action=(outport = "ls2-ro2"; output;)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:02:02), action=(outport = "vm2"; output;)
- table=??(ls_in_l2_lkup ), priority=70 , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
-@@ -4970,7 +4984,7 @@ ovn-nbctl --wait=sb lr-lb-add ro1 lb1
- ovn-sbctl lflow-list ls1 > ls1_lflows
- AT_CHECK([grep "ls_in_l2_lkup" ls1_lflows | sed 's/table=../table=??/' | sort], [0], [dnl
- table=??(ls_in_l2_lkup ), priority=0 , match=(1), action=(outport = get_fdb(eth.dst); next;)
-- table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
-+ table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac && (tcp || icmp || icmp6)), action=(handle_svc_check(inport);)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:01:01), action=(outport = "ls1-ro1"; output;)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:01:02), action=(outport = "vm1"; output;)
- table=??(ls_in_l2_lkup ), priority=70 , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
-@@ -4988,7 +5002,7 @@ ovn-nbctl --wait=sb lb-add lb1 192.168.4.100:80 10.0.0.10:80
- ovn-sbctl lflow-list ls1 > ls1_lflows
- AT_CHECK([grep "ls_in_l2_lkup" ls1_lflows | sed 's/table=../table=??/' | sort], [0], [dnl
- table=??(ls_in_l2_lkup ), priority=0 , match=(1), action=(outport = get_fdb(eth.dst); next;)
-- table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
-+ table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac && (tcp || icmp || icmp6)), action=(handle_svc_check(inport);)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:01:01), action=(outport = "ls1-ro1"; output;)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:01:02), action=(outport = "vm1"; output;)
- table=??(ls_in_l2_lkup ), priority=70 , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
-@@ -5012,7 +5026,7 @@ ovn-nbctl --wait=sb lrp-set-gateway-chassis ro1-ls1 chassis-1 30
- ovn-sbctl lflow-list ls1 > ls1_lflows
- AT_CHECK([grep "ls_in_l2_lkup" ls1_lflows | sed 's/table=../table=??/' | sort], [0], [dnl
- table=??(ls_in_l2_lkup ), priority=0 , match=(1), action=(outport = get_fdb(eth.dst); next;)
-- table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
-+ table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac && (tcp || icmp || icmp6)), action=(handle_svc_check(inport);)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:01:01), action=(outport = "ls1-ro1"; output;)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:01:02), action=(outport = "vm1"; output;)
- table=??(ls_in_l2_lkup ), priority=70 , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
-@@ -5211,25 +5225,23 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
-
- AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl
- table=5 (lr_in_defrag ), priority=0 , match=(1), action=(next;)
-- table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.200), action=(reg0 = 172.168.0.200; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.10 && tcp), action=(reg0 = 10.0.0.10; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.100 && tcp), action=(reg0 = 172.168.0.100; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.210 && udp), action=(reg0 = 172.168.0.210; reg9[[16..31]] = udp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.100), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.200), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.210), action=(ct_dnat;)
- ])
-
- AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
- table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
- table=7 (lr_in_dnat ), priority=100 , match=(ip && ip4.dst == 172.168.0.20 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_dnat_in_czone(10.0.0.3);)
-- table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.200 && ct_mark.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;)
-- table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.200 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.80,10.0.0.81);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_mark.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.4:8080);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062);)
-+ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.200 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.80,10.0.0.81);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.4:8080);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.100 && tcp && tcp.dst == 8082 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.210 && udp && udp.dst == 60 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062);)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
- table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
- ])
-@@ -5284,25 +5296,23 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
-
- AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl
- table=5 (lr_in_defrag ), priority=0 , match=(1), action=(next;)
-- table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.200), action=(reg0 = 172.168.0.200; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.10 && tcp), action=(reg0 = 10.0.0.10; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.100 && tcp), action=(reg0 = 172.168.0.100; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.210 && udp), action=(reg0 = 172.168.0.210; reg9[[16..31]] = udp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.100), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.200), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.210), action=(ct_dnat;)
- ])
-
- AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
- table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
- table=7 (lr_in_dnat ), priority=100 , match=(ip && ip4.dst == 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);)
-- table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.200 && ct_mark.natted == 1), action=(next;)
-- table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.200), action=(ct_lb_mark(backends=10.0.0.80,10.0.0.81);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_mark.natted == 1), action=(next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(ct_lb_mark(backends=10.0.0.4:8080);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062);)
-+ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.200), action=(ct_lb_mark(backends=10.0.0.80,10.0.0.81);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.4:8080);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.100 && tcp && tcp.dst == 8082), action=(ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.210 && udp && udp.dst == 60), action=(ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062);)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
- table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
- ])
-@@ -5314,6 +5324,7 @@ AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sor
-
- AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
- table=? (lr_out_undnat ), priority=0 , match=(1), action=(next;)
-+ table=? (lr_out_undnat ), priority=100 , match=(nd || nd_rs || nd_ra), action=(next;)
- table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;)
- ])
-
-@@ -5349,25 +5360,23 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
-
- AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl
- table=5 (lr_in_defrag ), priority=0 , match=(1), action=(next;)
-- table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.200), action=(reg0 = 172.168.0.200; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.10 && tcp), action=(reg0 = 10.0.0.10; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.100 && tcp), action=(reg0 = 172.168.0.100; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.210 && udp), action=(reg0 = 172.168.0.210; reg9[[16..31]] = udp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.100), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.200), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.210), action=(ct_dnat;)
- ])
-
- AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
- table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
- table=7 (lr_in_dnat ), priority=100 , match=(ip && ip4.dst == 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);)
-- table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.200 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.80,10.0.0.81; force_snat);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82; force_snat);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062; force_snat);)
-+ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.80,10.0.0.81; force_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.100 && tcp && tcp.dst == 8082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82; force_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.210 && udp && udp.dst == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062; force_snat);)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
- table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
- ])
-@@ -5379,6 +5388,7 @@ AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sor
-
- AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
- table=? (lr_out_undnat ), priority=0 , match=(1), action=(next;)
-+ table=? (lr_out_undnat ), priority=100 , match=(nd || nd_rs || nd_ra), action=(next;)
- table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;)
- ])
-
-@@ -5416,28 +5426,25 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
-
- AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl
- table=5 (lr_in_defrag ), priority=0 , match=(1), action=(next;)
-- table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.200), action=(reg0 = 172.168.0.200; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.10 && tcp), action=(reg0 = 10.0.0.10; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.10 && tcp), action=(reg0 = 172.168.0.10; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.100 && tcp), action=(reg0 = 172.168.0.100; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.210 && udp), action=(reg0 = 172.168.0.210; reg9[[16..31]] = udp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.10), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.100), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.200), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.210), action=(ct_dnat;)
- ])
-
- AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
- table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
- table=7 (lr_in_dnat ), priority=100 , match=(ip && ip4.dst == 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);)
-- table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.200 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.80,10.0.0.81; force_snat);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82; force_snat);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82; force_snat);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062; force_snat);)
-+ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.80,10.0.0.81; force_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.10 && tcp && tcp.dst == 9082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82; force_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.100 && tcp && tcp.dst == 8082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82; force_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.210 && udp && udp.dst == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062; force_snat);)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
- table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
- ])
-@@ -5449,6 +5456,7 @@ AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sor
-
- AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
- table=? (lr_out_undnat ), priority=0 , match=(1), action=(next;)
-+ table=? (lr_out_undnat ), priority=100 , match=(nd || nd_rs || nd_ra), action=(next;)
- table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;)
- ])
-
-@@ -5496,31 +5504,27 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
-
- AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl
- table=5 (lr_in_defrag ), priority=0 , match=(1), action=(next;)
-- table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.200), action=(reg0 = 172.168.0.200; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.10 && tcp), action=(reg0 = 10.0.0.10; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.10 && tcp), action=(reg0 = 172.168.0.10; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.100 && tcp), action=(reg0 = 172.168.0.100; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.210 && udp), action=(reg0 = 172.168.0.210; reg9[[16..31]] = udp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip6.dst == def0::2 && tcp), action=(xxreg0 = def0::2; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.10), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.100), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.200), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.210), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip6.dst == def0::2), action=(ct_dnat;)
- ])
-
- AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
- table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
- table=7 (lr_in_dnat ), priority=100 , match=(ip && ip4.dst == 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);)
-- table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.200 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.80,10.0.0.81; force_snat);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip6 && xxreg0 == def0::2 && tcp && reg9[[16..31]] == 8000 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82; force_snat);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82; force_snat);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062; force_snat);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip6 && xxreg0 == def0::2 && tcp && reg9[[16..31]] == 8000), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=[[aef0::2]]:80,[[aef0::3]]:80; force_snat);)
-+ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.80,10.0.0.81; force_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.10 && tcp && tcp.dst == 9082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82; force_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.100 && tcp && tcp.dst == 8082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82; force_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.210 && udp && udp.dst == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062; force_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip6 && ip6.dst == def0::2 && tcp && tcp.dst == 8000), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=[[aef0::2]]:80,[[aef0::3]]:80; force_snat);)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
- table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
- ])
-@@ -5532,6 +5536,7 @@ AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sor
-
- AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
- table=? (lr_out_undnat ), priority=0 , match=(1), action=(next;)
-+ table=? (lr_out_undnat ), priority=100 , match=(nd || nd_rs || nd_ra), action=(next;)
- table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;)
- ])
-
-@@ -5572,18 +5577,17 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
-
- AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl
- table=5 (lr_in_defrag ), priority=0 , match=(1), action=(next;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.210 && tcp), action=(reg0 = 172.168.0.210; reg9[[16..31]] = tcp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.210 && udp), action=(reg0 = 172.168.0.210; reg9[[16..31]] = udp.dst; ct_dnat;)
-- table=5 (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;)
-+ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.210), action=(ct_dnat;)
- ])
-
- AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
- table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.210 && tcp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.210 && tcp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062; force_snat);)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062; force_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.210 && tcp && tcp.dst == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062; force_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.210 && udp && udp.dst == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062; force_snat);)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
- table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
- ])
-@@ -5594,6 +5598,7 @@ AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sor
-
- AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
- table=? (lr_out_undnat ), priority=0 , match=(1), action=(next;)
-+ table=? (lr_out_undnat ), priority=100 , match=(nd || nd_rs || nd_ra), action=(next;)
- table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;)
- ])
-
-@@ -5634,9 +5639,11 @@ ovn-sbctl set service_monitor $sm_vip2 status=offline
-
- AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" | sort], [0], [dnl
- table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
-- table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.10.10 && ct_mark.natted == 1), action=(next;)
-- table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.10.10), action=(reg0 = 0; reject { outport <-> inport; next(pipeline=egress,table=3);};)
-+ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.10.10), action=(reg0 = 0; reject { outport <-> inport; next(pipeline=egress,table=3);};)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
- table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
- ])
-@@ -5646,9 +5653,11 @@ check ovn-nbctl --wait=sb set load_balancer lb5 options:skip_snat=true
-
- AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" | sort], [0], [dnl
- table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
-- table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.10.10 && ct_mark.natted == 1), action=(flags.skip_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.10.10), action=(flags.skip_snat_for_lb = 1; reg0 = 0; reject { outport <-> inport; next(pipeline=egress,table=3);};)
-+ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.10.10), action=(flags.skip_snat_for_lb = 1; reg0 = 0; reject { outport <-> inport; next(pipeline=egress,table=3);};)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
- table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
- ])
-@@ -5660,9 +5669,58 @@ check ovn-nbctl --wait=sb set logical_router lr0 options:lb_force_snat_ip="route
-
- AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" | sort], [0], [dnl
- table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
-- table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.10.10 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.10.10), action=(flags.force_snat_for_lb = 1; reg0 = 0; reject { outport <-> inport; next(pipeline=egress,table=3);};)
-+ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.10.10), action=(flags.force_snat_for_lb = 1; reg0 = 0; reject { outport <-> inport; next(pipeline=egress,table=3);};)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
-+])
-+
-+# LB with event=false and reject=false
-+check ovn-nbctl lr-lb-del lr0
-+check ovn-nbctl remove logical_router lr0 options lb_force_snat_ip
-+AT_CHECK([ovn-nbctl create load_balancer name=lb6 options:reject=false options:event=false vips:\"172.168.10.30\"=\"\" protocol=tcp], [0], [ignore])
-+check ovn-nbctl --wait=sb lr-lb-add lr0 lb6
-+
-+AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" | sort], [0], [dnl
-+ table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
-+ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.10.30), action=(drop;)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
-+])
-+
-+# LB with event=false, reject=false and skip_snat
-+check ovn-nbctl --wait=sb set load_balancer lb6 options:skip_snat=true
-+
-+AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" | sort], [0], [dnl
-+ table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
-+ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.10.30), action=(flags.skip_snat_for_lb = 1; drop;)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
-+])
-+
-+check ovn-nbctl remove load_balancer lb6 options skip_snat
-+
-+# LB with event=false, reject=false and force_snat
-+check ovn-nbctl --wait=sb set logical_router lr0 options:lb_force_snat_ip="router_ip"
-+
-+AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" | sort], [0], [dnl
-+ table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
-+ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.10.30), action=(flags.force_snat_for_lb = 1; drop;)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
- table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
- ])
-@@ -6692,11 +6750,12 @@ dnl Flows to skip TTL == {0, 1} check for IGMP and MLD packets.
- AT_CHECK([grep -e 'lr_in_ip_input ' lrflows | grep -e 'igmp' -e 'mld' -e 'ip.ttl == {0, 1}' | sed 's/table=../table=??/'], [0], [dnl
- table=??(lr_in_ip_input ), priority=120 , match=((mldv1 || mldv2) && ip.ttl == 1), action=(next;)
- table=??(lr_in_ip_input ), priority=120 , match=(igmp && ip.ttl == 1), action=(next;)
-- table=??(lr_in_ip_input ), priority=100 , match=(inport == "lrp1" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 10.10.10.1 ; ip.ttl = 254; outport = "lrp1"; flags.loopback = 1; output; };)
-- table=??(lr_in_ip_input ), priority=100 , match=(inport == "lrp1" && ip6 && ip6.src == 1010::/64 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst <-> eth.src; ip6.dst = ip6.src; ip6.src = 1010::1 ; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = "lrp1"; flags.loopback = 1; output; };)
-- table=??(lr_in_ip_input ), priority=100 , match=(inport == "lrp2" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 20.20.20.1 ; ip.ttl = 254; outport = "lrp2"; flags.loopback = 1; output; };)
-- table=??(lr_in_ip_input ), priority=100 , match=(inport == "lrp2" && ip6 && ip6.src == 2020::/64 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst <-> eth.src; ip6.dst = ip6.src; ip6.src = 2020::1 ; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = "lrp2"; flags.loopback = 1; output; };)
-- table=??(lr_in_ip_input ), priority=30 , match=(ip4 && ip.ttl == {0, 1}), action=(drop;)
-+ table=??(lr_in_ip_input ), priority=32 , match=(ip.ttl == {0, 1} && !ip.later_frag && (ip4.mcast || ip6.mcast)), action=(drop;)
-+ table=??(lr_in_ip_input ), priority=31 , match=(inport == "lrp1" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 10.10.10.1 ; ip.ttl = 254; outport = "lrp1"; flags.loopback = 1; output; };)
-+ table=??(lr_in_ip_input ), priority=31 , match=(inport == "lrp1" && ip6 && ip6.src == 1010::/64 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst <-> eth.src; ip6.dst = ip6.src; ip6.src = 1010::1 ; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = "lrp1"; flags.loopback = 1; output; };)
-+ table=??(lr_in_ip_input ), priority=31 , match=(inport == "lrp2" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 20.20.20.1 ; ip.ttl = 254; outport = "lrp2"; flags.loopback = 1; output; };)
-+ table=??(lr_in_ip_input ), priority=31 , match=(inport == "lrp2" && ip6 && ip6.src == 2020::/64 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst <-> eth.src; ip6.dst = ip6.src; ip6.src = 2020::1 ; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = "lrp2"; flags.loopback = 1; output; };)
-+ table=??(lr_in_ip_input ), priority=30 , match=(ip.ttl == {0, 1}), action=(drop;)
- ])
-
- dnl Flows to "route" (statically forward) without decrementing TTL for
-@@ -6755,6 +6814,7 @@ AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0],
- table=??(ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
- table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;)
-+ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
- table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
-@@ -6809,6 +6869,7 @@ AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0],
- table=??(ls_in_acl_after_lb ), priority=2003 , match=(reg0[[8]] == 1 && (ip4 && icmp)), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */)
- table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(/* drop */)
-+ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
- table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
-@@ -6863,6 +6924,7 @@ AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0],
- table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[9]] == 1 && (ip4)), action=(/* drop */)
- table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */)
- table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(/* drop */)
-+ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
- table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
-@@ -7154,11 +7216,14 @@ flow="inport == \"lsp1\" && eth.src == 00:00:00:00:00:01 && eth.dst == 00:00:00:
- AS_BOX([No ACL, default_acl_drop not set])
- check ovn-nbctl --wait=sb sync
- AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
-+ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl ), priority=65535, match=(1), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;)
-+ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_hint ), priority=65535, match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;)
-+ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_out_acl ), priority=65535, match=(1), action=(next;)
- table=??(ls_out_acl_hint ), priority=65535, match=(1), action=(next;)
- table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;)
-@@ -7173,11 +7238,14 @@ output("lsp2");
- AS_BOX([No ACL, default_acl_drop false])
- check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=false
- AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
-+ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl ), priority=65535, match=(1), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;)
-+ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_hint ), priority=65535, match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;)
-+ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_out_acl ), priority=65535, match=(1), action=(next;)
- table=??(ls_out_acl_hint ), priority=65535, match=(1), action=(next;)
- table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;)
-@@ -7192,11 +7260,14 @@ output("lsp2");
- AS_BOX([No ACL, default_acl_drop true])
- check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=true
- AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
-+ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl ), priority=65535, match=(1), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;)
-+ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_hint ), priority=65535, match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;)
-+ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_out_acl ), priority=65535, match=(1), action=(next;)
- table=??(ls_out_acl_hint ), priority=65535, match=(1), action=(next;)
- table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;)
-@@ -7218,12 +7289,15 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/
- table=??(ls_in_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_acl ), priority=1001 , match=(ip4 && tcp), action=(next;)
- table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
-+ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;)
-+ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;)
- table=??(ls_out_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
-+ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;)
-@@ -7240,12 +7314,15 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/
- table=??(ls_in_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_acl ), priority=1001 , match=(ip4 && tcp), action=(next;)
- table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
-+ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;)
-+ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;)
- table=??(ls_out_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
-+ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;)
-@@ -7262,12 +7339,15 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/
- table=??(ls_in_acl ), priority=0 , match=(1), action=(drop;)
- table=??(ls_in_acl ), priority=1001 , match=(ip4 && tcp), action=(next;)
- table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
-+ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(drop;)
-+ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;)
- table=??(ls_out_acl ), priority=0 , match=(1), action=(drop;)
- table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
-+ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;)
-@@ -7292,6 +7372,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/
- table=??(ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
- table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(drop;)
-+ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
- table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
-@@ -7343,13 +7424,16 @@ check ovn-nbctl --wait=sb remove NB_Global . options default_acl_drop
- AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
- table=??(ls_in_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
-+ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=1001 , match=(ip4 && tcp), action=(next;)
-+ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;)
- table=??(ls_out_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
-+ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;)
-@@ -7365,13 +7449,16 @@ check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=false
- AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
- table=??(ls_in_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
-+ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=1001 , match=(ip4 && tcp), action=(next;)
-+ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;)
- table=??(ls_out_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
-+ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;)
-@@ -7387,13 +7474,16 @@ check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=true
- AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
- table=??(ls_in_acl ), priority=0 , match=(1), action=(drop;)
- table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
-+ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(drop;)
- table=??(ls_in_acl_after_lb ), priority=1001 , match=(ip4 && tcp), action=(next;)
-+ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;)
- table=??(ls_out_acl ), priority=0 , match=(1), action=(drop;)
- table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
-+ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;)
-@@ -7418,6 +7508,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/
- table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(drop;)
- table=??(ls_in_acl_after_lb ), priority=1001 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg0[[1]] = 1; next;)
- table=??(ls_in_acl_after_lb ), priority=1001 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(next;)
-+ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
- table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
-@@ -7469,13 +7560,16 @@ check ovn-nbctl --wait=sb remove NB_Global . options default_acl_drop
- AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
- table=??(ls_in_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
-+ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;)
-+ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;)
- table=??(ls_out_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_acl ), priority=1001 , match=(ip4 && tcp), action=(next;)
- table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
-+ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;)
-@@ -7491,13 +7585,16 @@ check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=false
- AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
- table=??(ls_in_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
-+ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;)
-+ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;)
- table=??(ls_out_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_acl ), priority=1001 , match=(ip4 && tcp), action=(next;)
- table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
-+ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;)
-@@ -7513,13 +7610,16 @@ check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=true
- AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl
- table=??(ls_in_acl ), priority=0 , match=(1), action=(drop;)
- table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;)
-+ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(drop;)
-+ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;)
- table=??(ls_out_acl ), priority=0 , match=(1), action=(drop;)
- table=??(ls_out_acl ), priority=1001 , match=(ip4 && tcp), action=(next;)
- table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;)
-+ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;)
- table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;)
-@@ -7542,6 +7642,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/
- table=??(ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
- table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(drop;)
-+ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
- table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;)
- table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
-@@ -7719,7 +7820,7 @@ sort | sed 's/table=../table=??/' ], [0], [dnl
- table=??(ls_in_apply_port_sec), priority=0 , match=(1), action=(next;)
- table=??(ls_in_apply_port_sec), priority=50 , match=(reg0[[15]] == 1), action=(drop;)
- table=??(ls_in_l2_lkup ), priority=0 , match=(1), action=(outport = get_fdb(eth.dst); next;)
-- table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
-+ table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac && (tcp || icmp || icmp6)), action=(handle_svc_check(inport);)
- table=??(ls_in_l2_lkup ), priority=70 , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
- table=??(ls_in_l2_unknown ), priority=0 , match=(1), action=(output;)
- table=??(ls_in_l2_unknown ), priority=50 , match=(outport == "none"), action=(drop;)
-@@ -7744,7 +7845,7 @@ sort | sed 's/table=../table=??/' ], [0], [dnl
- table=??(ls_in_apply_port_sec), priority=0 , match=(1), action=(next;)
- table=??(ls_in_apply_port_sec), priority=50 , match=(reg0[[15]] == 1), action=(drop;)
- table=??(ls_in_l2_lkup ), priority=0 , match=(1), action=(outport = get_fdb(eth.dst); next;)
-- table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
-+ table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac && (tcp || icmp || icmp6)), action=(handle_svc_check(inport);)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:00:01), action=(outport = "sw0p1"; output;)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:00:02), action=(outport = "sw0p2"; output;)
- table=??(ls_in_l2_lkup ), priority=70 , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
-@@ -7770,7 +7871,7 @@ sort | sed 's/table=../table=??/' ], [0], [dnl
- table=??(ls_in_apply_port_sec), priority=0 , match=(1), action=(next;)
- table=??(ls_in_apply_port_sec), priority=50 , match=(reg0[[15]] == 1), action=(drop;)
- table=??(ls_in_l2_lkup ), priority=0 , match=(1), action=(outport = get_fdb(eth.dst); next;)
-- table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
-+ table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac && (tcp || icmp || icmp6)), action=(handle_svc_check(inport);)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:00:01), action=(outport = "sw0p1"; output;)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:00:02), action=(outport = "sw0p2"; output;)
- table=??(ls_in_l2_lkup ), priority=70 , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
-@@ -7797,7 +7898,7 @@ sort | sed 's/table=../table=??/' ], [0], [dnl
- table=??(ls_in_apply_port_sec), priority=0 , match=(1), action=(next;)
- table=??(ls_in_apply_port_sec), priority=50 , match=(reg0[[15]] == 1), action=(drop;)
- table=??(ls_in_l2_lkup ), priority=0 , match=(1), action=(outport = get_fdb(eth.dst); next;)
-- table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
-+ table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac && (tcp || icmp || icmp6)), action=(handle_svc_check(inport);)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:00:01), action=(drop;)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:00:02), action=(outport = "sw0p2"; output;)
- table=??(ls_in_l2_lkup ), priority=70 , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
-@@ -7824,7 +7925,7 @@ sort | sed 's/table=../table=??/' ], [0], [dnl
- table=??(ls_in_apply_port_sec), priority=0 , match=(1), action=(next;)
- table=??(ls_in_apply_port_sec), priority=50 , match=(reg0[[15]] == 1), action=(drop;)
- table=??(ls_in_l2_lkup ), priority=0 , match=(1), action=(outport = get_fdb(eth.dst); next;)
-- table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
-+ table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac && (tcp || icmp || icmp6)), action=(handle_svc_check(inport);)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:00:01), action=(drop;)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:00:02), action=(outport = "sw0p2"; output;)
- table=??(ls_in_l2_lkup ), priority=70 , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
-@@ -7854,7 +7955,7 @@ sort | sed 's/table=../table=??/' ], [0], [dnl
- table=??(ls_in_apply_port_sec), priority=0 , match=(1), action=(next;)
- table=??(ls_in_apply_port_sec), priority=50 , match=(reg0[[15]] == 1), action=(drop;)
- table=??(ls_in_l2_lkup ), priority=0 , match=(1), action=(outport = get_fdb(eth.dst); next;)
-- table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(handle_svc_check(inport);)
-+ table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == $svc_monitor_mac && (tcp || icmp || icmp6)), action=(handle_svc_check(inport);)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:00:01), action=(outport = "sw0p1"; output;)
- table=??(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:00:02), action=(outport = "sw0p2"; output;)
- table=??(ls_in_l2_lkup ), priority=70 , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
-@@ -7886,8 +7987,10 @@ check ovn-nbctl \
- AS_BOX([No chassis registered - use ct_lb_mark and ct_mark.natted])
- check ovn-nbctl --wait=sb sync
- AT_CHECK([ovn-sbctl lflow-list | grep -e natted -e ct_lb], [0], [dnl
-- table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 66.66.66.66 && ct_mark.natted == 1), action=(next;)
-- table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 66.66.66.66), action=(ct_lb_mark(backends=42.42.42.2);)
-+ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 66.66.66.66), action=(ct_lb_mark(backends=42.42.42.2);)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
- table=6 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4.dst == 66.66.66.66), action=(reg1 = 66.66.66.66; ct_lb_mark;)
- table=6 (ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb_mark;)
- table=12(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 66.66.66.66), action=(reg0[[1]] = 0; ct_lb_mark(backends=42.42.42.2);)
-@@ -7898,8 +8001,10 @@ AS_BOX([Chassis registered that doesn't support ct_lb_mark - use ct_lb and ct_la
- check ovn-sbctl chassis-add hv geneve 127.0.0.1
- check ovn-nbctl --wait=sb sync
- AT_CHECK([ovn-sbctl lflow-list | grep -e natted -e ct_lb], [0], [dnl
-- table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 66.66.66.66 && ct_label.natted == 1), action=(next;)
-- table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 66.66.66.66), action=(ct_lb(backends=42.42.42.2);)
-+ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 66.66.66.66), action=(ct_lb(backends=42.42.42.2);)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_label.natted && ct_label.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_label.natted && ct_label.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_label.natted), action=(next;)
- table=6 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4.dst == 66.66.66.66), action=(reg1 = 66.66.66.66; ct_lb;)
- table=6 (ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb;)
- table=12(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 66.66.66.66), action=(reg0[[1]] = 0; ct_lb(backends=42.42.42.2);)
-@@ -7910,8 +8015,10 @@ AS_BOX([Chassis upgrades and supports ct_lb_mark - use ct_lb_mark and ct_mark.na
- check ovn-sbctl set chassis hv other_config:ct-no-masked-label=true
- check ovn-nbctl --wait=sb sync
- AT_CHECK([ovn-sbctl lflow-list | grep -e natted -e ct_lb], [0], [dnl
-- table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 66.66.66.66 && ct_mark.natted == 1), action=(next;)
-- table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 66.66.66.66), action=(ct_lb_mark(backends=42.42.42.2);)
-+ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 66.66.66.66), action=(ct_lb_mark(backends=42.42.42.2);)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
- table=6 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4.dst == 66.66.66.66), action=(reg1 = 66.66.66.66; ct_lb_mark;)
- table=6 (ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb_mark;)
- table=12(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 66.66.66.66), action=(reg0[[1]] = 0; ct_lb_mark(backends=42.42.42.2);)
-@@ -8244,15 +8351,17 @@ AT_CAPTURE_FILE([R1flows])
-
- AT_CHECK([grep "lr_in_lb_aff_check" R1flows | sort], [0], [dnl
- table=6 (lr_in_lb_aff_check ), priority=0 , match=(1), action=(next;)
-- table=6 (lr_in_lb_aff_check ), priority=100 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.16.0.10 && tcp && reg9[[16..31]] == 80), action=(reg9[[6]] = chk_lb_aff(); next;)
-+ table=6 (lr_in_lb_aff_check ), priority=100 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(reg0 = ip4.dst; reg9[[16..31]] = tcp.dst; reg9[[6]] = chk_lb_aff(); next;)
- ])
- AT_CHECK([grep "lr_in_dnat " R1flows | sort], [0], [dnl
- table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.16.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.16.0.10 && tcp && reg9[[16..31]] == 80), action=(ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80);)
- table=7 (lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; ct_lb_mark(backends=10.0.0.2:80);)
- table=7 (lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; ct_lb_mark(backends=20.0.0.2:80);)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
- table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
- ])
-@@ -8270,11 +8379,13 @@ AT_CAPTURE_FILE([R1flows_skip_snat])
-
- AT_CHECK([grep "lr_in_dnat " R1flows_skip_snat | sort], [0], [dnl
- table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.16.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.skip_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.16.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; skip_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; skip_snat);)
- table=7 (lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; skip_snat);)
- table=7 (lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; skip_snat);)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
- table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
- ])
-@@ -8289,11 +8400,13 @@ AT_CAPTURE_FILE([R1flows_force_snat])
-
- AT_CHECK([grep "lr_in_dnat " R1flows_force_snat | sort], [0], [dnl
- table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.16.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;)
-- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.16.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; force_snat);)
-+ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; force_snat);)
- table=7 (lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; force_snat);)
- table=7 (lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.force_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; force_snat);)
-+ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
- table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
- table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
- ])
-@@ -8330,8 +8443,9 @@ rm -f northd/ovn-northd.log
- check as northd ovn-appctl -t NORTHD_TYPE vlog/reopen
- check as northd ovn-appctl -t NORTHD_TYPE vlog/set jsonrpc:dbg
- check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats
--check ovn-nbctl add address_set $foo_as_uuid addresses 1.1.1.3
--wait_column '1.1.1.1 1.1.1.2 1.1.1.3' Address_Set addresses name=foo
-+check ovn-nbctl add address_set $foo_as_uuid addresses 1.1.1.3 -- \
-+ add address_set $foo_as_uuid addresses 1.1.2.1/4
-+wait_column '1.1.1.1 1.1.1.2 1.1.1.3 1.1.2.1/4' Address_Set addresses name=foo
-
- # There should be no recompute of the sync_to_sb_addr_set engine node .
- AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats sync_to_sb_addr_set recompute], [0], [0
-@@ -8341,8 +8455,9 @@ AT_CHECK([grep transact northd/ovn-northd.log | grep Address_Set | \
- grep -c mutate], [0], [1
- ])
-
--check ovn-nbctl add address_set $foo_as_uuid addresses \
--1.1.1.4 -- remove address_set $foo_as_uuid addresses 1.1.1.1
-+check ovn-nbctl add address_set $foo_as_uuid addresses 1.1.1.4 -- \
-+ remove address_set $foo_as_uuid addresses 1.1.1.1 -- \
-+ remove address_set $foo_as_uuid addresses 1.1.2.1/4
- wait_column '1.1.1.2 1.1.1.3 1.1.1.4' Address_Set addresses name=foo
-
- # There should be no recompute of the sync_to_sb_addr_set engine node .
-@@ -8569,12 +8684,13 @@ ovn-sbctl dump-flows | DUMP_FLOWS_SORTED > lflows0
-
- AT_CHECK([grep -e "lr_in_defrag" -e "lr_in_dnat" lflows0], [0], [dnl
- table=? (lr_in_defrag ), priority=0 , match=(1), action=(next;)
-- table=? (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 192.168.0.1), action=(reg0 = 192.168.0.1; ct_dnat;)
-- table=? (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;)
-+ table=? (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 192.168.0.1), action=(ct_dnat;)
- table=? (lr_in_dnat ), priority=0 , match=(1), action=(next;)
-- table=? (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 192.168.0.1 && ct_mark.natted == 1), action=(next;)
-- table=? (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 192.168.0.1), action=(ct_lb_mark(backends=192.168.1.10);)
-+ table=? (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 192.168.0.1), action=(ct_lb_mark(backends=192.168.1.10);)
-+ table=? (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
- table=? (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-+ table=? (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=? (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
- table=? (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
- table=? (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
- ])
-@@ -8588,6 +8704,7 @@ AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows0 | grep "priority=65532"],
- table=? (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(next;)
- table=? (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
- table=? (ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-+ table=?(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=?(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
- ])
-
-@@ -8599,10 +8716,12 @@ ovn-sbctl dump-flows | DUMP_FLOWS_SORTED > lflows1
-
- AT_CHECK([grep -e "lr_in_defrag" -e "lr_in_dnat" lflows1], [0], [dnl
- table=? (lr_in_defrag ), priority=0 , match=(1), action=(next;)
-- table=? (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 192.168.0.1), action=(reg0 = 192.168.0.1; ct_dnat;)
-+ table=? (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 192.168.0.1), action=(ct_dnat;)
- table=? (lr_in_dnat ), priority=0 , match=(1), action=(next;)
-- table=? (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 192.168.0.1 && ct_label.natted == 1), action=(next;)
-- table=? (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 192.168.0.1), action=(ct_lb(backends=192.168.1.10);)
-+ table=? (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 192.168.0.1), action=(ct_lb(backends=192.168.1.10);)
-+ table=? (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_label.natted), action=(next;)
-+ table=? (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_label.natted && ct_label.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=? (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_label.natted && ct_label.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
- ])
-
- AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows1 | grep "priority=65532"], [0], [dnl
-@@ -8614,6 +8733,7 @@ AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows1 | grep "priority=65532"],
- table=? (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;)
- table=? (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;)
- table=? (ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-+ table=?(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=?(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
- ])
-
-@@ -8625,12 +8745,13 @@ ovn-sbctl dump-flows | DUMP_FLOWS_SORTED > lflows2
-
- AT_CHECK([grep -e "lr_in_defrag" -e "lr_in_dnat" lflows2], [0], [dnl
- table=? (lr_in_defrag ), priority=0 , match=(1), action=(next;)
-- table=? (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 192.168.0.1), action=(reg0 = 192.168.0.1; ct_dnat;)
-- table=? (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;)
-+ table=? (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 192.168.0.1), action=(ct_dnat;)
- table=? (lr_in_dnat ), priority=0 , match=(1), action=(next;)
-- table=? (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 192.168.0.1 && ct_mark.natted == 1), action=(next;)
-- table=? (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 192.168.0.1), action=(ct_lb_mark(backends=192.168.1.10);)
-+ table=? (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 192.168.0.1), action=(ct_lb_mark(backends=192.168.1.10);)
-+ table=? (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
- table=? (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
-+ table=? (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
-+ table=? (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
- table=? (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
- table=? (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
- ])
-@@ -8644,8 +8765,104 @@ AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows2 | grep "priority=65532"],
- table=? (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(next;)
- table=? (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;)
- table=? (ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
-+ table=?(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;)
- table=?(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
- ])
-
- AT_CLEANUP
- ])
-+
-+OVN_FOR_EACH_NORTHD_NO_HV([
-+AT_SETUP([Chassis-feature compatibitility - remote chassis])
-+ovn_start
-+
-+AS_BOX([Local chassis])
-+check ovn-sbctl chassis-add hv1 geneve 127.0.0.1 \
-+ -- set chassis hv1 other_config:ct-no-masked-label=true \
-+ -- set chassis hv1 other_config:ovn-ct-lb-related=true \
-+ -- set chassis hv1 other_config:mac-binding-timestamp=true
-+
-+check ovn-nbctl --wait=sb sync
-+
-+AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE debug/chassis-features-list], [0], [dnl
-+ct_no_masked_label: true
-+ct_lb_related: true
-+mac_binding_timestamp: true
-+])
-+
-+AS_BOX([Remote chassis])
-+check ovn-sbctl chassis-add hv2 geneve 127.0.0.2 \
-+ -- set chassis hv2 other_config:is-remote=true \
-+ -- set chassis hv2 other_config:ct-no-masked-label=false \
-+ -- set chassis hv2 other_config:ovn-ct-lb-related=false \
-+ -- set chassis hv2 other_config:mac-binding-timestamp=false
-+
-+check ovn-nbctl --wait=sb sync
-+
-+AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE debug/chassis-features-list], [0], [dnl
-+ct_no_masked_label: true
-+ct_lb_related: true
-+mac_binding_timestamp: true
-+])
-+
-+AT_CLEANUP
-+])
-+
-+AT_SETUP([Localnet ports on LS with LB])
-+ovn_start
-+# In the past, traffic arriving on localnet ports has skipped conntrack.
-+# This test ensures that we still skip conntrack for localnet ports,
-+# *except* for the case where the logical switch has a load balancer
-+# configured. In this case, the localnet port will not skip conntrack,
-+# allowing for traffic to be load balanced on the localnet port.
-+
-+check ovn-nbctl ls-add sw
-+check ovn-nbctl lsp-add sw sw-ln
-+check ovn-nbctl lsp-set-type sw-ln localnet
-+check ovn-nbctl lsp-set-addresses sw-ln unknown
-+check ovn-nbctl --wait=sb sync
-+
-+# Since this test is only concerned with logical flows, we don't need to
-+# configure anything else that we normally would with regards to localnet
-+# ports
-+
-+
-+# First, ensure that conntrack is skipped for the localnet port since there
-+# isn't a load balancer configured.
-+
-+AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_pre_lb | grep priority=110 | grep sw-ln | sed 's/table=../table=??/'], [0], [dnl
-+ table=??(ls_in_pre_lb ), priority=110 , match=(ip && inport == "sw-ln"), action=(next;)
-+])
-+
-+AT_CHECK([ovn-sbctl lflow-list sw | grep ls_out_pre_lb | grep priority=110 | grep sw-ln | sed 's/table=../table=??/'], [0], [dnl
-+ table=??(ls_out_pre_lb ), priority=110 , match=(ip && outport == "sw-ln"), action=(ct_clear; next;)
-+])
-+
-+# Now add a load balancer and ensure that we no longer are skipping conntrack
-+# for the localnet port
-+
-+check ovn-nbctl lb-add lb 10.0.0.1:80 10.0.0.100:8080 tcp
-+check ovn-nbctl ls-lb-add sw lb
-+check ovn-nbctl --wait=sb sync
-+
-+AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_pre_lb | grep priority=110 | grep sw-ln | sed 's/table=../table=??/'], [0], [dnl
-+])
-+
-+AT_CHECK([ovn-sbctl lflow-list sw | grep ls_out_pre_lb | grep priority=110 | grep sw-ln | sed 's/table=../table=??/'], [0], [dnl
-+])
-+
-+# And ensure that removing the load balancer from the switch results in skipping
-+# conntrack again
-+check ovn-nbctl ls-lb-del sw lb
-+check ovn-nbctl --wait=sb sync
-+
-+AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_pre_lb | grep priority=110 | grep sw-ln | sed 's/table=../table=??/'], [0], [dnl
-+ table=??(ls_in_pre_lb ), priority=110 , match=(ip && inport == "sw-ln"), action=(next;)
-+])
-+
-+AT_CHECK([ovn-sbctl lflow-list sw | grep ls_out_pre_lb | grep priority=110 | grep sw-ln | sed 's/table=../table=??/'], [0], [dnl
-+ table=??(ls_out_pre_lb ), priority=110 , match=(ip && outport == "sw-ln"), action=(ct_clear; next;)
-+])
-+
-+AT_CLEANUP
-+])
-diff --git a/tests/ovn.at b/tests/ovn.at
-index 55de7c85b..ed91d32d0 100644
---- a/tests/ovn.at
-+++ b/tests/ovn.at
-@@ -992,10 +992,10 @@ next(pipeline=ingress, table=11);
-
- next(pipeline=egress);
- formats as next(pipeline=egress, table=11);
-- encodes as resubmit(,51)
-+ encodes as resubmit(,53)
-
- next(pipeline=egress, table=5);
-- encodes as resubmit(,45)
-+ encodes as resubmit(,47)
-
- next(table=10);
- formats as next(10);
-@@ -4414,24 +4414,13 @@ response=${sha}${lrpmac}08060001080006040002${lrpmac}${tpa}${sha}${spa}
- echo $response >> 3.expected
-
- # First ensure basic flow contents are as we expect.
--AT_CHECK([ovn-sbctl lflow-list lsw0 | grep 'reg0[\[14\]]' | sort | sed 's/table=../table=??/g' | sed 's/is_chassis_resident([[^)]]*)/is_chassis_resident("??")/g'], [0], [dnl
-+AT_CHECK([ovn-sbctl lflow-list lsw0 | grep 'reg0[\[14\]]' | sort | sed 's/table=../table=??/g'], [0], [dnl
- table=??(ls_in_check_port_sec), priority=70 , 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("??") || is_chassis_resident("??"))), action=(next;)
-+ table=??(ls_in_hairpin ), priority=2000 , match=(reg0[[14]] == 1 && is_chassis_resident("cr-lrp1")), action=(next;)
-+ table=??(ls_in_hairpin ), priority=2000 , match=(reg0[[14]] == 1 && is_chassis_resident("cr-lrp2")), action=(next;)
- ])
-
--# We've ensured that the expected hairpin flows are present
--# and that the expected number of "is_chassis_resident" fields are in
--# the flow. Now we need to ensure the contents are correct.
--# Unfortunately, the order of the "is_chassis_resident" fields is
--# unpredictable. Therefore we sort them so the order is predictable.
--actual_chassis=$(ovn-sbctl lflow-list lsw0 | grep 'ls_in_hairpin' | grep 'priority=2000' | grep -o 'is_chassis_resident([[^)]]*)' | sort)
--
--expected_chassis='is_chassis_resident("cr-lrp1")
--is_chassis_resident("cr-lrp2")'
--
--check test "$expected_chassis" = "$actual_chassis"
--
- # dump information with counters
- echo "------ OVN dump ------"
- ovn-nbctl show
-@@ -5055,6 +5044,7 @@ AT_CLEANUP
-
- OVN_FOR_EACH_NORTHD([
- AT_SETUP([IP relocation using GARP request])
-+AT_SKIP_IF([test $HAVE_SCAPY = no])
- ovn_start
-
- # Logical network:
-@@ -5154,7 +5144,9 @@ done
- test_ip() {
- # This packet has bad checksums but logical L3 routing doesn't check.
- local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5
-- local packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000
-+ local packet=$(fmt_pkt "Ether(dst='${dst_mac}', src='${src_mac}')/ \
-+ IP(dst='${dst_ip}', src='${src_ip}')/ \
-+ UDP(sport=53, dport=4369)")
- shift; shift; shift; shift; shift
- hv=hv`vif_to_hv $inport`
- as $hv ovs-appctl netdev-dummy/receive vif$inport $packet
-@@ -5169,7 +5161,9 @@ test_ip() {
- # Routing decrements TTL and updates source and dest MAC
- # (and checksum).
- out_lrp=`vif_to_lrp $outport`
-- echo f000000000${outport}00000000ff0${out_lrp}08004500001c00000000"3f1101"00${src_ip}${dst_ip}0035111100080000
-+ echo $(fmt_pkt "Ether(dst='f0:00:00:00:00:${outport}', src='00:00:00:00:ff:${out_lrp}')/ \
-+ IP(src='${src_ip}', dst='${dst_ip}', ttl=63)/ \
-+ UDP(sport=53, dport=4369)")
- fi >> $outport.expected
- done
- }
-@@ -5185,8 +5179,10 @@ test_ip() {
- # SHA and REPLY_HA are each 12 hex digits.
- # SPA and TPA are each 8 hex digits.
- test_arp() {
-- local inport=$1 sha=$2 spa=$3 tpa=$4 reply_ha=$5
-- local request=ffffffffffff${sha}08060001080006040001${sha}${spa}ffffffffffff${tpa}
-+ local inport=$1 sha=$2 spa=$3 tpa=$3
-+ local request=$(fmt_pkt "Ether(dst='ff:ff:ff:ff:ff:ff', src='${sha}')/ \
-+ ARP(hwsrc='${sha}', hwdst='ff:ff:ff:ff:ff:ff', psrc='${spa}', pdst='${tpa}')")
-+
- hv=hv`vif_to_hv $inport`
- as $hv ovs-appctl netdev-dummy/receive vif$inport $request
-
-@@ -5199,53 +5195,72 @@ test_arp() {
- echo $request >> $i$j$k.expected
- fi
- done
-+}
-
-- # Expect to receive the reply, if any.
-- if test X$reply_ha != X; then
-- lrp=`vif_to_lrp $inport`
-- local reply=${sha}00000000ff0${lrp}08060001080006040002${reply_ha}${tpa}${sha}${spa}
-- echo $reply >> $inport.expected
-- fi
-+test_na() {
-+ local inport=$1 sha=$2 spa=$3
-+ local request=$(fmt_pkt "Ether(dst='ff:ff:ff:ff:ff:ff', src='${sha}')/ \
-+ IPv6(dst='ff01::1', src='${spa}')/ \
-+ ICMPv6ND_NA(tgt='${spa}')")
-+
-+ hv=hv`vif_to_hv $inport`
-+ as $hv ovs-appctl netdev-dummy/receive vif$inport $request
-+
-+ # Expect to receive the broadcast ARP on the other logical switch ports if
-+ # IP address is not configured to the switch patch port.
-+ local i=`vif_to_ls $inport`
-+ local j
-+ for j in 1 2; do
-+ if test $i$j != $inport; then
-+ echo $request >> $i$j$k.expected
-+ fi
-+ done
- }
-
--# lp11 send GARP request to announce ownership of 192.168.1.100.
-+# lp11 send GARP request to announce ownership of 192.168.1.100 and fe80::abcd:1.
-
--sha=f00000000011
--spa=`ip_to_hex 192 168 1 100`
--tpa=$spa
-+sha="f0:00:00:00:00:11"
-+spa="192.168.1.100"
-+spa6="fe80::abcd:1"
-
- # When always_learn_from_arp_request=false, the new mac-binding will not be learned
- # through GARP request.
- ovn-nbctl --wait=hv set logical_router lr0 options:always_learn_from_arp_request=false
-
--test_arp 11 $sha $spa $tpa
-+test_arp 11 $sha $spa
-+test_na 11 $sha $spa6
- sleep 1
--check_row_count MAC_Binding 0 ip="192.168.1.100"
-+check_row_count MAC_Binding 0 ip="$spa"
-+check_row_count MAC_Binding 0 ip=\"$spa6\"
-
- # When always_learn_from_arp_request=true, the new mac-binding will be learned.
- ovn-nbctl --wait=hv set logical_router lr0 options:always_learn_from_arp_request=true
-
--test_arp 11 $sha $spa $tpa
--OVS_WAIT_UNTIL([test `ovn-sbctl find mac_binding ip="192.168.1.100" | wc -l` -gt 0])
-+test_arp 11 $sha $spa
-+test_na 11 $sha $spa6
-+wait_row_count MAC_Binding 1 ip="$spa" mac=\"$sha\"
-+wait_row_count MAC_Binding 1 ip=\"$spa6\" mac=\"$sha\"
- ovn-nbctl --wait=hv sync
-
- # Send an IP packet from lp21 to 192.168.1.100, which should go to lp11.
-
--smac=f00000000021
--dmac=00000000ff02
--sip=`ip_to_hex 192 168 2 11`
--dip=`ip_to_hex 192 168 1 100`
-+smac="f0:00:00:00:00:21"
-+dmac="00:00:00:00:ff:02"
-+sip="192.168.2.11"
-+dip="192.168.1.100"
- test_ip 21 $smac $dmac $sip $dip 11
-
--# lp12 send GARP request to announce ownership of 192.168.1.100.
-+# lp12 send GARP request to announce ownership of 192.168.1.100 and fe80::abcd:1.
-
- # Even when always_learn_from_arp_request=false, the existing mac-binding should be
- # updated through GARP request.
- ovn-nbctl --wait=hv set logical_router lr0 options:always_learn_from_arp_request=false
-
--sha=f00000000012
--test_arp 12 $sha $spa $tpa
--wait_row_count MAC_Binding 1 ip="192.168.1.100" mac='"f0:00:00:00:00:12"'
-+sha="f0:00:00:00:00:12"
-+test_arp 12 $sha $spa
-+test_na 11 $sha $spa6
-+wait_row_count MAC_Binding 1 ip="$spa" mac=\"$sha\"
-+wait_row_count MAC_Binding 1 ip=\"$spa6\" mac=\"$sha\"
- ovn-nbctl --wait=hv sync
- # give to the hv the time to send queued ip packets
- sleep 1
-@@ -5753,7 +5768,7 @@ check ovn-nbctl --wait=hv sync
- packet="inport==\"ls1-lp1\" && eth.src==$ls1_lp1_mac && eth.dst==$rp_ls1_mac &&
- ip4 && ip.ttl==64 && ip4.src==$ls1_lp1_ip && ip4.dst==$ls2_lp1_ip &&
- udp && udp.src==53 && udp.dst==4369"
--AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-+OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
-
- echo "---------NB dump-----"
-@@ -5803,7 +5818,7 @@ packet="inport==\"ls1-lp1\" && eth.src==$ls1_lp1_mac && eth.dst==$rp_ls1_mac &&
- ip4 && ip.ttl==64 && ip4.src==$ls1_lp1_ip && ip4.dst==$ls2_lp1_ip &&
- udp && udp.src==53 && udp.dst==4369"
-
--as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
- # The 2nd packet sent shound not be received.
- OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
-
-@@ -7741,7 +7756,6 @@ ls3_p1_mac=00:00:00:01:02:05
- check ovn-nbctl --wait=hv lr-policy-add R1 10 "ip4.src==192.168.1.0/24 && ip4.dst==172.16.1.0/24" drop
-
- # Check logical flow
--ovn-sbctl dump-flows > sbflows
- AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | grep "192.168.1.0" | wc -l], [0], [dnl
- 1
- ])
-@@ -7751,15 +7765,12 @@ packet="inport==\"ls1-lp1\" && eth.src==$ls1_p1_mac && eth.dst==$ls1_ro_mac &&
- ip4 && ip.ttl==64 && ip4.src==$ls1_p1_ip && ip4.dst==$ls2_p1_ip &&
- udp && udp.src==53 && udp.dst==4369"
-
--as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Check if packet hit the drop policy
--AT_CHECK([ovs-ofctl dump-flows br-int | \
-+OVS_WAIT_UNTIL([test "1" = "$(ovs-ofctl dump-flows br-int | \
- grep "nw_src=192.168.1.0/24,nw_dst=172.16.1.0/24 actions=drop" | \
-- grep "priority=10" | \
-- grep "n_packets=1" | wc -l], [0], [dnl
--1
--])
-+ grep "priority=10" | grep "n_packets=1" -c)"])
-
- # Expected to drop the packet.
- $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" pbr-hv/vif2-tx.pcap > vif2.packets
-@@ -7770,7 +7781,7 @@ AT_FAIL_IF([test "$rcvd_packet" != ""])
- check ovn-nbctl --wait=hv lr-policy-add R1 20 "ip4.src==192.168.1.0/24 && ip4.dst==172.16.1.0/24" allow
-
- # Check logical flow
--AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | grep "192.168.1.0" | wc -l], [0], [dnl
-+AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | grep "192.168.1.0" -c], [0], [dnl
- 2
- ])
-
-@@ -7778,15 +7789,12 @@ AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | grep "192.168.1.0" | wc -l]
- packet="inport==\"ls1-lp1\" && eth.src==$ls1_p1_mac && eth.dst==$ls1_ro_mac &&
- ip4 && ip.ttl==64 && ip4.src==$ls1_p1_ip && ip4.dst==$ls2_p1_ip &&
- udp && udp.src==53 && udp.dst==4369"
--as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Check if packet hit the allow policy
--sleep 1
--AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | \
-- grep "192.168.1.0" | \
-- grep "priority=20" | wc -l], [0], [dnl
--1
--])
-+OVS_WAIT_UNTIL([test "1" = "$(ovs-ofctl dump-flows br-int | \
-+ grep "nw_src=192.168.1.0/24,nw_dst=172.16.1.0/24" | \
-+ grep "priority=20" | grep "n_packets=1" -c)"])
-
- # Expected packet has TTL decreased by 1
- expected="eth.src==$ls2_ro_mac && eth.dst==$ls2_p1_mac &&
-@@ -7802,7 +7810,7 @@ check ovn-nbctl --wait=hv lr-policy-add R1 30 "ip4.src==192.168.1.0/24 && ip4.ds
- # Check logical flow
- AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | \
- grep "192.168.1.0" | \
-- grep "priority=30" | wc -l], [0], [dnl
-+ grep "priority=30" -c], [0], [dnl
- 1
- ])
-
-@@ -7810,21 +7818,12 @@ AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | \
- packet="inport==\"ls1-lp1\" && eth.src==$ls1_p1_mac && eth.dst==$ls1_ro_mac &&
- ip4 && ip.ttl==64 && ip4.src==$ls1_p1_ip && ip4.dst==$ls2_p1_ip &&
- udp && udp.src==53 && udp.dst==4369"
--as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet"
--sleep 1
-+OVS_WAIT_UNTIL([as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
--echo "southbound flows"
--ovn-sbctl --ovs dump-flows > sbflows
--AT_CAPTURE_FILE([sbflows])
--echo "ovs flows"
--ovs-ofctl dump-flows br-int > brflows
--AT_CAPTURE_FILE([brflows])
- # Check if packet hit the allow policy
--AT_CHECK([grep "nw_src=192.168.1.0/24,nw_dst=172.16.1.0/24" brflows | \
-- grep "priority=30" | \
-- grep "n_packets=1" | wc -l], [0], [dnl
--1
--])
-+OVS_WAIT_UNTIL([test "1" = "$(ovs-ofctl dump-flows br-int | \
-+ grep "nw_src=192.168.1.0/24,nw_dst=172.16.1.0/24" | \
-+ grep "priority=30" | grep "n_packets=1" -c)"])
- echo "packet hit reroute policy"
-
- # Expected packet has TTL decreased by 1
-@@ -7927,9 +7926,7 @@ ls3_p1_mac=00:00:00:01:02:05
- check ovn-nbctl --wait=sb lr-policy-add R1 10 "ip6.src==2001::/64 && ip6.dst==2002::/64" drop
-
- # Check logical flow
--ovn-sbctl dump-flows > sbflows
--AT_CAPTURE_FILE([sbflows])
--AT_CHECK([grep lr_in_policy sbflows | grep "2001" | wc -l], [0], [dnl
-+AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | grep "2001" -c], [0], [dnl
- 1
- ])
-
-@@ -7938,15 +7935,12 @@ packet="inport==\"ls1-lp1\" && eth.src==$ls1_p1_mac && eth.dst==$ls1_ro_mac &&
- ip6 && ip.ttl==64 && ip6.src==$ls1_p1_ip && ip6.dst==$ls2_p1_ip &&
- udp && udp.src==53 && udp.dst==4369"
-
--as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Check if packet hit the drop policy
--AT_CHECK([ovs-ofctl dump-flows br-int | \
-+OVS_WAIT_UNTIL([test "1" = "$(ovs-ofctl dump-flows br-int | \
- grep "ipv6_src=2001::/64,ipv6_dst=2002::/64 actions=drop" | \
-- grep "priority=10" | \
-- grep "n_packets=1" | wc -l], [0], [dnl
--1
--])
-+ grep "priority=10" | grep "n_packets=1" -c)"])
-
- # Expected to drop the packet.
- $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" pbr-hv/vif2-tx.pcap > vif2.packets
-@@ -7956,9 +7950,7 @@ AT_FAIL_IF([test -s vif2.packets])
- check ovn-nbctl --wait=sb lr-policy-add R1 20 "ip6.src==2001::/64 && ip6.dst==2002::/64" allow
-
- # Check logical flow
--ovn-sbctl dump-flows > sbflows2
--AT_CAPTURE_FILE([sbflows2])
--AT_CHECK([grep lr_in_policy sbflows2 | grep "2001" | wc -l], [0], [dnl
-+AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | grep "2001" -c], [0], [dnl
- 2
- ])
-
-@@ -7966,16 +7958,12 @@ AT_CHECK([grep lr_in_policy sbflows2 | grep "2001" | wc -l], [0], [dnl
- packet="inport==\"ls1-lp1\" && eth.src==$ls1_p1_mac && eth.dst==$ls1_ro_mac &&
- ip6 && ip.ttl==64 && ip6.src==$ls1_p1_ip && ip6.dst==$ls2_p1_ip &&
- udp && udp.src==53 && udp.dst==4369"
--as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Check if packet hit the allow policy
--ovn-sbctl dump-flows > sbflows3
--AT_CAPTURE_FILE([sbflows3])
--AT_CHECK([grep lr_in_policy sbflows3 | \
-- grep "2001" | \
-- grep "priority=20" | wc -l], [0], [dnl
--1
--])
-+OVS_WAIT_UNTIL([test "1" = "$(ovs-ofctl dump-flows br-int | \
-+ grep "ipv6_src=2001::/64,ipv6_dst=2002::/64" | \
-+ grep "priority=20" | grep "n_packets=1" -c)"])
-
- # Expected packet has TTL decreased by 1
- expected="eth.src==$ls2_ro_mac && eth.dst==$ls2_p1_mac &&
-@@ -7989,11 +7977,9 @@ OVN_CHECK_PACKETS([pbr-hv/vif2-tx.pcap], [expected])
- check ovn-nbctl --wait=sb lr-policy-add R1 30 "ip6.src==2001::/64 && ip6.dst==2002::/64" reroute 2003::2
-
- # Check logical flow
--ovn-sbctl dump-flows > sbflows4
--AT_CAPTURE_FILE([sbflows4])
--AT_CHECK([grep lr_in_policy sbflows4 | \
-+AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | \
- grep "2001" | \
-- grep "priority=30" | wc -l], [0], [dnl
-+ grep "priority=30" -c], [0], [dnl
- 1
- ])
-
-@@ -8001,19 +7987,12 @@ AT_CHECK([grep lr_in_policy sbflows4 | \
- packet="inport==\"ls1-lp1\" && eth.src==$ls1_p1_mac && eth.dst==$ls1_ro_mac &&
- ip6 && ip.ttl==64 && ip6.src==$ls1_p1_ip && ip6.dst==$ls2_p1_ip &&
- udp && udp.src==53 && udp.dst==4369"
--as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet"
--sleep 1
-+OVS_WAIT_UNTIL([as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
--ovn-sbctl dump-flows > sbflows5
--ovs-ofctl dump-flows br-int > offlows5
--AT_CAPTURE_FILE([sbflows5])
--AT_CAPTURE_FILE([offlows5])
- # Check if packet hit the allow policy
--AT_CHECK([grep "ipv6_src=2001::/64,ipv6_dst=2002::/64" offlows5 | \
-- grep "priority=30" | \
-- grep "n_packets=1" | wc -l], [0], [dnl
--1
--])
-+OVS_WAIT_UNTIL([test "1" = "$(ovs-ofctl dump-flows br-int | \
-+ grep "ipv6_src=2001::/64,ipv6_dst=2002::/64" | \
-+ grep "priority=30" | grep "n_packets=1" -c)"])
-
- # Expected packet has TTL decreased by 1
- expected="eth.src==$ls3_ro_mac && eth.dst==$ls3_p1_mac &&
-@@ -9531,73 +9510,73 @@ AT_CAPTURE_FILE([sbflows])
- packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac &&
- ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip &&
- tcp && tcp.flags==2 && tcp.src==4360 && tcp.dst==80"
--as hv ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Send packet that should be dropped with logging in the ingress pipeline.
- packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac &&
- ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip &&
- tcp && tcp.flags==2 && tcp.src==4361 && tcp.dst==81"
--as hv ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Send packet that should be dropped without logging in the eggress pipeline.
- packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac &&
- ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip &&
- tcp && tcp.flags==2 && tcp.src==4360 && tcp.dst==180"
--as hv ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Send packet that should be dropped with logging in the egress pipeline.
- packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac &&
- ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip &&
- tcp && tcp.flags==2 && tcp.src==4361 && tcp.dst==181"
--as hv ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Send packet that should be allowed without logging.
- packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac &&
- ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip &&
- tcp && tcp.flags==2 && tcp.src==4362 && tcp.dst==82"
--as hv ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Send packet that should be allowed with logging.
- packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac &&
- ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip &&
- tcp && tcp.flags==2 && tcp.src==4363 && tcp.dst==83"
--as hv ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Send packet that should allow related flows without logging.
- packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac &&
- ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip &&
- tcp && tcp.flags==2 && tcp.src==4364 && tcp.dst==84"
--as hv ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Send packet that should allow related flows with logging.
- packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac &&
- ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip &&
- tcp && tcp.flags==2 && tcp.src==4365 && tcp.dst==85"
--as hv ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Send packet that should be rejected without logging in the ingress pipeline.
- packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac &&
- ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip &&
- tcp && tcp.flags==2 && tcp.src==4366 && tcp.dst==86"
--as hv ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Send packet that should be rejected with logging in the ingress pipeline.
- packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac &&
- ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip &&
- tcp && tcp.flags==2 && tcp.src==4367 && tcp.dst==87"
--as hv ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Send packet that should be rejected without logging in the egress pipeline.
- packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac &&
- ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip &&
- tcp && tcp.flags==2 && tcp.src==4366 && tcp.dst==186"
--as hv ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Send packet that should be rejected with logging in the egress pipeline.
- packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac &&
- ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip &&
- tcp && tcp.flags==2 && tcp.src==4367 && tcp.dst==187"
--as hv ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- OVS_WAIT_UNTIL([ test 8 = $(grep -c 'acl_log' hv/ovn-controller.log) ])
-
-@@ -10206,14 +10185,21 @@ AT_CHECK([test ! -z $foo2_zoneid])
- bar2_zoneid=$(as hv2 ovs-vsctl get bridge br-int external_ids:ct-zone-bar2)
- AT_CHECK([test ! -z $bar2_zoneid])
-
--ovn-nbctl lsp-del bar2
-+# When a port is removed from a logical switch, the ct-zone is flushed, then
-+# the ct-zone-id is removed from external_ids. This is done in two steps(
-+# ct-zone-id is removed when the transaction flushing the ct_zone is complete).
-+# ovn-nbctl --wait=hv sync does not take this into account, and hence we need
-+# two "wait=hv" before we are sure that the ct-zone-id is removed from
-+# external_ids.
-+ovn-nbctl --wait=hv lsp-del bar2
- ovn-nbctl --wait=hv sync
-
- bar2_zoneid=$(as hv2 ovs-vsctl get bridge br-int external_ids:ct-zone-bar2)
- AT_CHECK([test -z $bar2_zoneid])
-
- # Add back bar2
--ovn-nbctl lsp-add bar bar2 vm2 1 \
-+# Same comment as above: two "wait=hv" are needed.
-+ovn-nbctl --wait=hv lsp-add bar bar2 vm2 1 \
- -- lsp-set-addresses bar2 "f0:00:00:01:02:08 192.168.2.3"
- wait_for_ports_up
- ovn-nbctl --wait=hv sync
-@@ -11214,7 +11200,7 @@ hv1_gw1_ofport=$(as hv1 ovs-vsctl --bare --columns ofport find Interface name=ov
- hv1_gw2_ofport=$(as hv1 ovs-vsctl --bare --columns ofport find Interface name=ovn-gw2-0)
-
- OVS_WAIT_UNTIL([
-- test 1 = $(as hv1 ovs-ofctl dump-flows br-int table=37 | grep -c "active_backup,ofport,members:$hv1_gw1_ofport,$hv1_gw2_ofport")
-+ test 1 = $(as hv1 ovs-ofctl dump-flows br-int table=39 | grep -c "active_backup,ofport,members:$hv1_gw1_ofport,$hv1_gw2_ofport")
- ])
-
- test_ip_packet()
-@@ -11324,7 +11310,7 @@ AT_CHECK(
- ])
-
- OVS_WAIT_UNTIL([
-- test 1 = $(as hv1 ovs-ofctl dump-flows br-int table=37 | grep -c "active_backup,ofport,members:$hv1_gw2_ofport,$hv1_gw1_ofport")
-+ test 1 = $(as hv1 ovs-ofctl dump-flows br-int table=39 | grep -c "active_backup,ofport,members:$hv1_gw2_ofport,$hv1_gw1_ofport")
- ])
-
- test_ip_packet gw2 gw1 0
-@@ -11502,7 +11488,7 @@ hv1_gw1_ofport=$(as hv1 ovs-vsctl --bare --columns ofport find Interface name=ov
- hv1_gw2_ofport=$(as hv1 ovs-vsctl --bare --columns ofport find Interface name=ovn-gw2-0)
-
- OVS_WAIT_UNTIL([
-- test 1 = $(as hv1 ovs-ofctl dump-flows br-int table=37 | grep -c "active_backup,ofport,members:$hv1_gw1_ofport,$hv1_gw2_ofport")
-+ test 1 = $(as hv1 ovs-ofctl dump-flows br-int table=39 | grep -c "active_backup,ofport,members:$hv1_gw1_ofport,$hv1_gw2_ofport")
- ])
-
- test_ip_packet()
-@@ -11582,7 +11568,7 @@ AT_CHECK([ovn-nbctl --wait=hv \
- ])
-
- OVS_WAIT_UNTIL([
-- test 1 = $(as hv1 ovs-ofctl dump-flows br-int table=37 | grep -c "active_backup,ofport,members:$hv1_gw2_ofport,$hv1_gw1_ofport")
-+ test 1 = $(as hv1 ovs-ofctl dump-flows br-int table=39 | grep -c "active_backup,ofport,members:$hv1_gw2_ofport,$hv1_gw1_ofport")
- ])
-
- test_ip_packet gw2 gw1
-@@ -11748,12 +11734,12 @@ AT_CAPTURE_FILE([hv2flows])
-
- AT_CHECK(
- [# Check that redirect mapping is programmed only on hv2
-- grep table=38 hv1flows | grep =0x3,metadata=0x1 | wc -l
-- grep table=38 hv2flows | grep =0x3,metadata=0x1 | grep load:0x2- | wc -l
-+ grep table=40 hv1flows | grep =0x3,metadata=0x1 | wc -l
-+ grep table=40 hv2flows | grep =0x3,metadata=0x1 | grep load:0x2- | wc -l
-
- # Check that hv1 sends chassisredirect port traffic to hv2
-- grep table=37 hv1flows | grep =0x3,metadata=0x1 | grep output | wc -l
-- grep table=37 hv2flows | grep =0x3,metadata=0x1 | wc -l
-+ grep table=39 hv1flows | grep =0x3,metadata=0x1 | grep output | wc -l
-+ grep table=39 hv2flows | grep =0x3,metadata=0x1 | wc -l
-
- # Check that arp reply on distributed gateway port is only programmed on hv2
- grep arp hv1flows | grep load:0x2- | grep =0x2,metadata=0x1 | wc -l
-@@ -12254,7 +12240,7 @@ nexthop_mac="f00000010204"
- AS_BOX([Send ip packet from foo1 to 8.8.8.8])
- src_mac="f00000010203"
- dst_mac="000001010203"
--packet=${foo_mac}${foo1_mac}08004500001c0000000040110000${foo1_ip}${dst_ip}0035111100080000
-+packet=${foo_mac}${foo1_mac}080045000028000000004006a916${foo1_ip}${dst_ip}0035111112345678000000005002faf069450000
-
- AS_BOX([Wait for GARPs announcing gw IP to arrive])
- OVS_WAIT_UNTIL([
-@@ -12265,15 +12251,12 @@ grep actions=mod_dl_dst:f0:00:00:01:02:04 | wc -l` -eq 1
- AS_BOX([Verify VLAN tagged packet on bridge connecting hv1 and hv2])
- # VLAN tagged packet with router port(192.168.1.1) MAC as destination MAC
- # is expected on bridge connecting hv1 and hv2
--expected=${foo_mac}${foo1_mac}8100000208004500001c0000000040110000${foo1_ip}${dst_ip}0035111100080000
-+expected=${foo_mac}${foo1_mac}81000002080045000028000000004006a916${foo1_ip}${dst_ip}0035111112345678000000005002faf069450000
- echo $expected > hv1-br-ex_n2.expected
-
- AS_BOX([Verify packet at outside1 i.e nexthop(172.16.1.1) port])
- # Packet to Expect at outside1 i.e nexthop(172.16.1.1) port.
--# As connection tracking not enabled for this test, snat can't be done on the packet.
--# We still see foo1 as the source ip address. But source mac(gateway MAC) and
--# dest mac(nexthop mac) are properly configured.
--expected=${nexthop_mac}${gw_mac}08004500001c000000003f110100${foo1_ip}${dst_ip}0035111100080000
-+expected=${nexthop_mac}${gw_mac}080045000028000000003f06beaa${gw_ip}${dst_ip}0035111112345678000000005002faf07dd90000
- echo $expected > hv3-vif1.expected
-
- check as hv1 ovs-appctl dpctl/del-flows
-@@ -12284,8 +12267,8 @@ as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet
- as hv1 ovs-appctl ofproto/trace br-int in_port=hv1-vif1 $packet
- sleep 2
-
--AS_BOX([On hv1, table 37 check that no packet goes via the tunnel port])
--OVS_WAIT_FOR_OUTPUT([as hv1 ovs-ofctl dump-flows br-int table=37 \
-+AS_BOX([On hv1, table 40 check that no packet goes via the tunnel port])
-+OVS_WAIT_FOR_OUTPUT([as hv1 ovs-ofctl dump-flows br-int table=39 \
- | grep "NXM_NX_TUN_ID" | grep -v n_packets=0 | wc -l], [0], [[0
- ]])
-
-@@ -12304,7 +12287,7 @@ cat hv1-br-ex_n2.expected > expout
- AT_CHECK([sort hv1-br-ex_n2], [0], [expout])
-
- AS_BOX([Check expected packet on nexthop interface])
--$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv3/vif1-tx.pcap | grep ${foo1_ip}${dst_ip} | uniq > hv3-vif1
-+$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv3/vif1-tx.pcap | grep ${gw_ip}${dst_ip} | uniq > hv3-vif1
- cat hv3-vif1.expected > expout
- AT_CHECK([sort hv3-vif1], [0], [expout])
-
-@@ -13260,38 +13243,35 @@ echo $hv2_gw1_ofport
- echo $hv2_gw2_ofport
-
- echo "--- hv1 ---"
--as hv1 ovs-ofctl dump-flows br-int table=37
-+as hv1 ovs-ofctl dump-flows br-int table=39
-
- echo "--- hv2 ---"
--as hv2 ovs-ofctl dump-flows br-int table=37
-+as hv2 ovs-ofctl dump-flows br-int table=39
-
- gw1_chassis=$(fetch_column Chassis _uuid name=gw1)
- gw2_chassis=$(fetch_column Chassis _uuid name=gw2)
-
--OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int table=37 | \
--grep active_backup | grep slaves:$hv1_gw1_ofport,$hv1_gw2_ofport \
-+OVS_WAIT_FOR_OUTPUT([as hv1 ovs-ofctl dump-flows br-int table=39 | \
-+grep active_backup | grep members:$hv1_gw1_ofport,$hv1_gw2_ofport \
- | wc -l], [0], [1
- ])
-
--OVS_WAIT_UNTIL([as hv2 ovs-ofctl dump-flows br-int table=37 | \
--grep active_backup | grep slaves:$hv2_gw1_ofport,$hv2_gw2_ofport \
-+OVS_WAIT_FOR_OUTPUT([as hv2 ovs-ofctl dump-flows br-int table=39 | \
-+grep active_backup | grep members:$hv2_gw1_ofport,$hv2_gw2_ofport \
- | wc -l], [0], [1
- ])
-
--# make sure that flows for handling the outside router port reside on gw1
--OVS_WAIT_UNTIL([as gw1 ovs-ofctl dump-flows br-int table=25 | \
--grep 00:00:02:01:02:04 | wc -l], [0], [[1
-+# make sure that flows for handling the outside router port reside on gw1 through ls_in_l2_lkup table
-+OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \
-+grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1
- ]])
--OVS_WAIT_UNTIL([as gw2 ovs-ofctl dump-flows br-int table=25 | \
--grep 00:00:02:01:02:04 | wc -l], [0], [[0
-+OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \
-+grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[0
- ]])
-
--# make sure ARP responder flows for outside router port reside on gw1 too
--OVS_WAIT_UNTIL([as gw1 ovs-ofctl dump-flows br-int table=9 | \
--grep arp_tpa=192.168.0.101 | wc -l], [0], [[1
--]])
--OVS_WAIT_UNTIL([as gw2 ovs-ofctl dump-flows br-int table=9 | grep arp_tpa=192.168.0.101 | wc -l], [0], [[0
--]])
-+# make sure ARP responder flows for outside router port reside on gw1 too through ls_in_arp_rsp table
-+OVS_WAIT_UNTIL([test `as gw1 ovs-ofctl dump-flows br-int table=27 | \
-+grep arp_tpa=192.168.0.101 | wc -l` -ge 1])
-
- # check that the chassis redirect port has been claimed by the gw1 chassis
- wait_row_count Port_Binding 1 logical_port=cr-outside chassis=$gw1_chassis
-@@ -13314,13 +13294,13 @@ wait_for_ports_up
- check ovn-nbctl --wait=hv sync
-
- # we make sure that the hypervisors noticed, and inverted the slave ports
--OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int table=37 | \
--grep active_backup | grep slaves:$hv1_gw2_ofport,$hv1_gw1_ofport \
-+OVS_WAIT_FOR_OUTPUT([as hv1 ovs-ofctl dump-flows br-int table=39 | \
-+grep active_backup | grep members:$hv1_gw2_ofport,$hv1_gw1_ofport \
- | wc -l], [0], [1
- ])
-
--OVS_WAIT_UNTIL([as hv2 ovs-ofctl dump-flows br-int table=37 | \
--grep active_backup | grep slaves:$hv2_gw2_ofport,$hv2_gw1_ofport \
-+OVS_WAIT_FOR_OUTPUT([as hv2 ovs-ofctl dump-flows br-int table=39 | \
-+grep active_backup | grep members:$hv2_gw2_ofport,$hv2_gw1_ofport \
- | wc -l], [0], [1
- ])
-
-@@ -13372,11 +13352,11 @@ AT_CHECK([ovs-vsctl --bare --columns bfd find Interface name=ovn-hv1-0],[0],
- ]])
-
- # make sure that flows for handling the outside router port reside on gw2 now
--OVS_WAIT_UNTIL([as gw2 ovs-ofctl dump-flows br-int table=25 | \
--grep 00:00:02:01:02:04 | wc -l], [0], [[1
-+OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \
-+grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1
- ]])
--OVS_WAIT_UNTIL([as gw1 ovs-ofctl dump-flows br-int table=25 | \
--grep 00:00:02:01:02:04 | wc -l], [0], [[0
-+OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \
-+grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[0
- ]])
-
- # disconnect GW2 from the network, GW1 should take over
-@@ -13386,12 +13366,12 @@ as main ovs-vsctl del-port n1 $port
-
- bfd_dump
-
--# make sure that flows for handling the outside router port reside on gw2 now
--OVS_WAIT_UNTIL([as gw1 ovs-ofctl dump-flows br-int table=25 | \
--grep 00:00:02:01:02:04 | wc -l], [0], [[1
-+# make sure that flows for handling the outside router port reside on gw1 now
-+OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \
-+grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1
- ]])
--OVS_WAIT_UNTIL([as gw2 ovs-ofctl dump-flows br-int table=25 | \
--grep 00:00:02:01:02:04 | wc -l], [0], [[0
-+OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \
-+grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[0
- ]])
-
- # check that the chassis redirect port has been reclaimed by the gw1 chassis
-@@ -13470,45 +13450,16 @@ ovn-nbctl set Logical_Router_Port outside ha_chassis_group=$hagrp1_uuid
- wait_row_count HA_Chassis_Group 1
- wait_row_count HA_Chassis 2
-
--OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int table=37 | \
--grep active_backup | grep slaves:$hv1_gw1_ofport,$hv1_gw2_ofport \
--| wc -l], [0], [1
-+OVS_WAIT_FOR_OUTPUT([as hv1 ovs-ofctl dump-flows br-int table=39 | \
-+grep active_backup | grep members:$hv1_gw1_ofport,$hv1_gw2_ofport \
-+| wc -l], [0], [0
- ])
-
--OVS_WAIT_UNTIL([as hv2 ovs-ofctl dump-flows br-int table=37 | \
--grep active_backup | grep slaves:$hv2_gw1_ofport,$hv2_gw2_ofport \
--| wc -l], [0], [1
-+OVS_WAIT_FOR_OUTPUT([as hv2 ovs-ofctl dump-flows br-int table=39 | \
-+grep active_backup | grep members:$hv2_gw1_ofport,$hv2_gw2_ofport \
-+| wc -l], [0], [0
- ])
-
--# make sure that flows for handling the outside router port reside on gw1
--OVS_WAIT_UNTIL([as gw1 ovs-ofctl dump-flows br-int table=24 | \
--grep 00:00:02:01:02:04 | wc -l], [0], [[1
--]])
--OVS_WAIT_UNTIL([as gw2 ovs-ofctl dump-flows br-int table=24 | \
--grep 00:00:02:01:02:04 | wc -l], [0], [[0
--]])
--
--# make sure ARP responder flows for outside router port reside on gw1 too
--OVS_WAIT_UNTIL([as gw1 ovs-ofctl dump-flows br-int table=9 | \
--grep arp_tpa=192.168.0.101 | wc -l], [0], [[1
--]])
--OVS_WAIT_UNTIL([as gw2 ovs-ofctl dump-flows br-int table=9 | grep arp_tpa=192.168.0.101 | wc -l], [0], [[0
--]])
--
--# check that the chassis redirect port has been claimed by the gw1 chassis
--#
--# XXX actually it doesn't happen, the test has always been wrong here
--# because the following just checks that "wc -l" succeeds (and it always
--# does):
--#
--# OVS_WAIT_UNTIL([ovn-sbctl --columns chassis --bare find Port_Binding \
--# logical_port=cr-outside | grep $gw1_chassis | wc -l], [0],[[1
--# ]])
--#
--# If it were correct, then the following would be a good substitute:
--#
--# wait_row_count Port_Binding 1 logical_port=cr-outside chassis=$gw1_chassis
--
- # Re add the ovs ports.
- for i in 1 2; do
- as hv$i
-@@ -13519,6 +13470,34 @@ for i in 1 2; do
- ofport-request=1
- done
-
-+# Re-add gw2
-+as gw2 ovn_attach n1 br-phys 192.168.0.1
-+
-+OVS_WAIT_FOR_OUTPUT([as hv1 ovs-ofctl dump-flows br-int table=39 | \
-+grep active_backup | grep members:$hv1_gw1_ofport,$hv1_gw2_ofport \
-+| wc -l], [0], [1
-+])
-+
-+OVS_WAIT_FOR_OUTPUT([as hv2 ovs-ofctl dump-flows br-int table=39 | \
-+grep active_backup | grep members:$hv2_gw1_ofport,$hv2_gw2_ofport \
-+| wc -l], [0], [1
-+])
-+
-+# make sure that flows for handling the outside router port reside on gw1
-+OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \
-+grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1
-+]])
-+OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \
-+grep "dl_dst:00:00:02:01:02:04" | wc -l], [0], [[0
-+]])
-+
-+# make sure ARP responder flows for outside router port reside on gw1 too
-+OVS_WAIT_UNTIL([test `as gw1 ovs-ofctl dump-flows br-int table=27 | \
-+grep arp_tpa=192.168.0.101 | wc -l` -ge 1 ])
-+
-+# check that the chassis redirect port has been claimed by the gw1 chassis
-+wait_row_count Port_Binding 1 logical_port=cr-outside chassis=$gw1_chassis
-+
- hv1_ch_uuid=$(fetch_column Chassis _uuid name=hv1)
- hv2_ch_uuid=$(fetch_column Chassis _uuid name=hv2)
- exp_ref_ch_list="$hv1_ch_uuid $hv2_ch_uuid"
-@@ -13527,29 +13506,18 @@ wait_column "$exp_ref_ch_list" HA_Chassis_Group ref_chassis
- # Increase the priority of gw2
- ovn-nbctl --wait=sb ha-chassis-group-add-chassis hagrp1 gw2 40
-
--OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int table=37 | \
--grep active_backup | grep slaves:$hv1_gw2_ofport,$hv1_gw1_ofport \
-+OVS_WAIT_FOR_OUTPUT([as hv1 ovs-ofctl dump-flows br-int table=39 | \
-+grep active_backup | grep members:$hv1_gw2_ofport,$hv1_gw1_ofport \
- | wc -l], [0], [1
- ])
-
--OVS_WAIT_UNTIL([as hv2 ovs-ofctl dump-flows br-int table=37 | \
--grep active_backup | grep slaves:$hv2_gw2_ofport,$hv2_gw1_ofport \
-+OVS_WAIT_FOR_OUTPUT([as hv2 ovs-ofctl dump-flows br-int table=39 | \
-+grep active_backup | grep members:$hv2_gw2_ofport,$hv2_gw1_ofport \
- | wc -l], [0], [1
- ])
-
- # check that the chassis redirect port has been reclaimed by the gw2 chassis
--#
--# XXX actually it doesn't happen, the test has always been wrong here
--# because the following just checks that "wc -l" succeeds (and it always
--# does):
--#
--# OVS_WAIT_UNTIL([ovn-sbctl --columns chassis --bare find Port_Binding \
--# logical_port=cr-outside | grep $gw2_chassis | wc -l], [0],[[1
--# ]])
--#
--# If it were correct, then the following would be a good substitute:
--#
--# wait_row_count Port_Binding 1 logical_port=cr-outside chassis=$gw2_chassis
-+wait_row_count Port_Binding 1 logical_port=cr-outside chassis=$gw2_chassis
-
- # check BFD enablement on tunnel ports from gw1 #########
- as gw1
-@@ -13588,11 +13556,11 @@ AT_CHECK([ovs-vsctl --bare --columns bfd find Interface name=ovn-hv1-0],[0],
- ]])
-
- # make sure that flows for handling the outside router port reside on gw2 now
--OVS_WAIT_UNTIL([as gw2 ovs-ofctl dump-flows br-int table=24 | \
--grep 00:00:02:01:02:04 | wc -l], [0], [[1
-+OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \
-+grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1
- ]])
--OVS_WAIT_UNTIL([as gw1 ovs-ofctl dump-flows br-int table=24 | \
--grep 00:00:02:01:02:04 | wc -l], [0], [[0
-+OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \
-+grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[0
- ]])
-
- # disconnect GW2 from the network, GW1 should take over
-@@ -13603,11 +13571,11 @@ as main ovs-vsctl del-port n1 $port
- bfd_dump
-
- # make sure that flows for handling the outside router port reside on gw2 now
--OVS_WAIT_UNTIL([as gw1 ovs-ofctl dump-flows br-int table=24 | \
--grep 00:00:02:01:02:04 | wc -l], [0], [[1
-+OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \
-+grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1
- ]])
--OVS_WAIT_UNTIL([as gw2 ovs-ofctl dump-flows br-int table=24 | \
--grep 00:00:02:01:02:04 | wc -l], [0], [[0
-+OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \
-+grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[0
- ]])
-
- # check that the chassis redirect port has been reclaimed by the gw1 chassis
-@@ -13889,6 +13857,133 @@ OVN_CLEANUP([gw1],[gw2],[hv1])
- AT_CLEANUP
- ])
-
-+OVN_FOR_EACH_NORTHD([
-+AT_SETUP([allow IPv6 RA / NA / MLD by default])
-+AT_SKIP_IF([test $HAVE_SCAPY = no])
-+ovn_start
-+net_add n1
-+sim_add hv1
-+as hv1
-+ovs-vsctl add-br br-phys
-+ovn_attach n1 br-phys 192.168.0.1
-+
-+lsp_mac_prefix=50:64:00:00:00:0
-+lsp_ip_prefix=10.0.0.
-+lsp_ip6_prefix=aef0::5264:00ff:fe00:000
-+
-+check ovn-nbctl ls-add ls0
-+for i in 1 2; do
-+ check ovn-nbctl lsp-add ls0 lsp$i
-+ check ovn-nbctl lsp-set-addresses lsp$i \
-+ "${lsp_mac_prefix}$i ${lsp_ip_prefix}$i ${lsp_ip6_prefix}$i"
-+
-+ # forbid all traffic for the ports
-+ check ovn-nbctl acl-add ls0 \
-+ from-lport 1000 "inport == \"lsp$i\"" drop
-+ check ovn-nbctl --apply-after-lb acl-add ls0\
-+ from-lport 1000 "inport == \"lsp$i\"" drop
-+ check ovn-nbctl acl-add ls0 \
-+ to-lport 1000 "outport == \"lsp$i\"" drop
-+
-+ check ovs-vsctl -- add-port br-int vif$i -- \
-+ set interface vif$i external-ids:iface-id=lsp$i \
-+ options:tx_pcap=hv1/vif$i-tx.pcap \
-+ options:rxq_pcap=hv1/vif$i-rx.pcap
-+ : > $i.expected
-+done
-+
-+router_mac=fa:16:3e:00:00:01
-+router_prefix=fdad:1234:5678::
-+router_ip=${router_prefix}1
-+check ovn-nbctl lr-add lr0
-+check ovn-nbctl lrp-add lr0 lrp0 ${router_mac} ${router_ip}/64
-+check ovn-nbctl set Logical_Router_Port lrp0 ipv6_ra_configs:address_mode="slaac"
-+check ovn-nbctl \
-+ -- lsp-add ls0 rp0 \
-+ -- set Logical_Switch_Port rp0 type=router \
-+ options:router-port=lrp0 \
-+ addresses='"${router_mac} ${router_ip}"'
-+
-+wait_for_ports_up
-+
-+test_ns_na() {
-+ local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5
-+
-+ packet=$(fmt_pkt "
-+ Ether(dst='ff:ff:ff:ff:ff:ff', src='${src_mac}') /
-+ IPv6(src='${src_ip}', dst='ff02::1:ff00:2') /
-+ ICMPv6ND_NS(tgt='${dst_ip}')
-+ ")
-+ as hv1 ovs-appctl netdev-dummy/receive vif${inport} $packet
-+
-+ expected_packet=$(fmt_pkt "
-+ Ether(dst='${src_mac}', src='${dst_mac}') /
-+ IPv6(src='${dst_ip}', dst='${src_ip}') /
-+ ICMPv6ND_NA(tgt='${dst_ip}', R=0, S=1) /
-+ ICMPv6NDOptDstLLAddr(lladdr='${dst_mac}')
-+ ")
-+ echo $expected_packet >> $inport.expected
-+}
-+
-+test_rs_ra() {
-+ local inport=$1 src_mac=$2 src_ip=$3
-+ local router_mac=$4 router_prefix=$5 router_ip=$6
-+
-+ packet=$(fmt_pkt "
-+ Ether(dst='ff:ff:ff:ff:ff:ff', src='${src_mac}') /
-+ IPv6(src='${src_ip}', dst='ff02::2') /
-+ ICMPv6ND_RS()
-+ ")
-+ as hv1 ovs-appctl netdev-dummy/receive vif${inport} $packet
-+
-+ expected_packet=$(fmt_pkt "
-+ Ether(dst='${src_mac}', src='${router_mac}') /
-+ IPv6(src='${router_ip}', dst='${src_ip}') /
-+ ICMPv6ND_RA(chlim=255, prf=0, routerlifetime=65535) /
-+ ICMPv6NDOptSrcLLAddr(lladdr='${router_mac}') /
-+ ICMPv6NDOptPrefixInfo(prefix='${router_prefix}')
-+ ")
-+ echo $expected_packet >> $inport.expected
-+}
-+
-+test_mldv2() {
-+ local inport=$1 outport=$2 src_mac=$3 src_ip=$4
-+
-+ packet=$(fmt_pkt "
-+ Ether(dst='ff:ff:ff:ff:ff:ff', src='${src_mac}') /
-+ IPv6(src='${src_ip}', dst='ff02::2') /
-+ ICMPv6MLQuery2()
-+ ")
-+ as hv1 ovs-appctl netdev-dummy/receive vif${inport} $packet
-+
-+ expected_packet=$packet
-+ echo $expected_packet >> $outport.expected
-+}
-+
-+src_mac=${lsp_mac_prefix}1
-+dst_mac=${lsp_mac_prefix}2
-+src_ip=${lsp_ip6_prefix}1
-+dst_ip=${lsp_ip6_prefix}2
-+
-+as hv1
-+test_ns_na 1 $src_mac $dst_mac $src_ip $dst_ip
-+
-+as hv1
-+router_local_ip=fe80::f816:3eff:fe00:1
-+test_rs_ra 1 $src_mac $src_ip $router_mac $router_prefix $router_local_ip
-+
-+as hv1
-+src_ip=fe80::1
-+test_mldv2 1 2 $src_mac $src_ip
-+
-+OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [1.expected])
-+OVN_CHECK_PACKETS([hv1/vif2-tx.pcap], [2.expected])
-+
-+OVN_CLEANUP([hv1])
-+
-+AT_CLEANUP
-+])
-+
- OVN_FOR_EACH_NORTHD([
- AT_SETUP([IPv6 Neighbor Solicitation for unknown MAC])
- AT_KEYWORDS([ovn-nd_ns for unknown mac])
-@@ -14162,10 +14257,12 @@ wait_column "$hv1_uuid" Port_Binding requested_chassis logical_port=lsp0
- wait_column "$hv2_uuid" Port_Binding additional_chassis logical_port=lsp0
- wait_column "$hv2_uuid" Port_Binding requested_additional_chassis logical_port=lsp0
-
--# Check ovn-installed updated for main chassis
-+# Check ovn-installed updated for both chassis
- wait_for_ports_up
--OVS_WAIT_UNTIL([test `as hv1 ovs-vsctl get Interface lsp0 external_ids:ovn-installed` = '"true"'])
--OVS_WAIT_UNTIL([test x`as hv2 ovs-vsctl get Interface lsp0 external_ids:ovn-installed` = x])
-+
-+for hv in hv1 hv2; do
-+ OVS_WAIT_UNTIL([test `as $hv ovs-vsctl get Interface lsp0 external_ids:ovn-installed` = '"true"'])
-+done
-
- # Check that setting iface:encap-ip populates Port_Binding:additional_encap
- wait_row_count Encap 2 chassis_name=hv1
-@@ -14192,7 +14289,7 @@ wait_column "$hv2_uuid" Port_Binding requested_chassis logical_port=lsp0
- wait_column "" Port_Binding additional_chassis logical_port=lsp0
- wait_column "" Port_Binding requested_additional_chassis logical_port=lsp0
-
--# Check ovn-installed updated for main chassis and not for other chassis
-+# Check ovn-installed updated for main chassis and removed from additional chassis
- wait_for_ports_up
- OVS_WAIT_UNTIL([test `as hv2 ovs-vsctl get Interface lsp0 external_ids:ovn-installed` = '"true"'])
- OVS_WAIT_UNTIL([test x`as hv1 ovs-vsctl get Interface lsp0 external_ids:ovn-installed` = x])
-@@ -15071,6 +15168,327 @@ OVN_CLEANUP([hv1],[hv2],[hv3])
- AT_CLEANUP
- ])
-
-+m4_define([MULTICHASSIS_PATH_MTU_DISCOVERY_TEST],
-+ [OVN_FOR_EACH_NORTHD([
-+ AT_SETUP([localnet connectivity with multiple requested-chassis, path mtu discovery (ip=$1, tunnel=$2, mtu=$3)])
-+ AT_KEYWORDS([multi-chassis])
-+ AT_SKIP_IF([test $HAVE_SCAPY = no])
-+
-+ ovn_start
-+
-+ net_add n1
-+ for i in 1 2; do
-+ sim_add hv$i
-+ as hv$i
-+ check ovs-vsctl add-br br-phys
-+ if test "x$1" = "xipv6"; then
-+ ovn_attach n1 br-phys fd00::$i 64 $2
-+ else
-+ ovn_attach n1 br-phys 192.168.0.$i 24 $2
-+ fi
-+ check ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
-+ done
-+
-+ first_mac=00:00:00:00:00:01
-+ second_mac=00:00:00:00:00:02
-+ multi1_mac=00:00:00:00:00:f0
-+ multi2_mac=00:00:00:00:00:f1
-+ first_ip=10.0.0.1
-+ second_ip=10.0.0.2
-+ multi1_ip=10.0.0.10
-+ multi2_ip=10.0.0.20
-+ first_ip6=abcd::1
-+ second_ip6=abcd::2
-+ multi1_ip6=abcd::f0
-+ multi2_ip6=abcd::f1
-+
-+ check ovn-nbctl ls-add ls0
-+ check ovn-nbctl lsp-add ls0 first
-+ check ovn-nbctl lsp-add ls0 second
-+ check ovn-nbctl lsp-add ls0 multi1
-+ check ovn-nbctl lsp-add ls0 multi2
-+ check ovn-nbctl lsp-set-addresses first "${first_mac} ${first_ip} ${first_ip6}"
-+ check ovn-nbctl lsp-set-addresses second "${second_mac} ${second_ip} ${second_ip6}"
-+ check ovn-nbctl lsp-set-addresses multi1 "${multi1_mac} ${multi1_ip} ${multi1_ip6}"
-+ check ovn-nbctl lsp-set-addresses multi2 "${multi2_mac} ${multi2_ip} ${multi2_ip6}"
-+
-+ check ovn-nbctl lsp-add ls0 public
-+ check ovn-nbctl lsp-set-type public localnet
-+ check ovn-nbctl lsp-set-addresses public unknown
-+ check ovn-nbctl lsp-set-options public network_name=phys
-+
-+ check ovn-nbctl lsp-set-options first requested-chassis=hv1
-+ check ovn-nbctl lsp-set-options second requested-chassis=hv2
-+ check ovn-nbctl lsp-set-options multi1 requested-chassis=hv1,hv2
-+ check ovn-nbctl lsp-set-options multi2 requested-chassis=hv1,hv2
-+
-+ as hv1 check ovs-vsctl -- add-port br-int first -- \
-+ set Interface first external-ids:iface-id=first \
-+ options:tx_pcap=hv1/first-tx.pcap \
-+ options:rxq_pcap=hv1/first-rx.pcap \
-+ ofport-request=1
-+ as hv2 check ovs-vsctl -- add-port br-int second -- \
-+ set Interface second external-ids:iface-id=second \
-+ options:tx_pcap=hv2/second-tx.pcap \
-+ options:rxq_pcap=hv2/second-rx.pcap \
-+ ofport-request=2
-+
-+ # Create interfaces for multichassis ports on both hv1 and hv2
-+ for hv in hv1 hv2; do
-+ for i in 1 2; do
-+ as $hv check ovs-vsctl -- add-port br-int multi${i} -- \
-+ set Interface multi${i} external-ids:iface-id=multi${i} \
-+ options:tx_pcap=$hv/multi${i}-tx.pcap \
-+ options:rxq_pcap=$hv/multi${i}-rx.pcap \
-+ ofport-request=${i}00
-+ done
-+ done
-+
-+ send_ip_packet() {
-+ local inport=${1} hv=${2} eth_src=${3} eth_dst=${4} ipv4_src=${5} ipv4_dst=${6} data=${7} fail=${8} mtu=${9:-$3}
-+ packet=$(fmt_pkt "
-+ Ether(dst='${eth_dst}', src='${eth_src}') /
-+ IP(src='${ipv4_src}', dst='${ipv4_dst}') /
-+ ICMP(type=8) / bytes.fromhex('${data}')
-+ ")
-+ as hv${hv} ovs-appctl netdev-dummy/receive ${inport} ${packet}
-+ if [[ x"${fail}" != x0 ]]; then
-+ original_ip_frame=$(fmt_pkt "
-+ IP(src='${ipv4_src}', dst='${ipv4_dst}') /
-+ ICMP(type=8) / bytes.fromhex('${data}')
-+ ")
-+ # IP(flags=2) means DF (Don't Fragment) = 1
-+ # ICMP(type=3, code=4) means Destination Unreachable, Fragmentation Needed
-+ packet=$(fmt_pkt "
-+ Ether(dst='${eth_src}', src='${eth_dst}') /
-+ IP(src='${ipv4_dst}', dst='${ipv4_src}', ttl=255, flags=2, id=0) /
-+ ICMP(type=3, code=4, nexthopmtu=${mtu}) /
-+ bytes.fromhex('${original_ip_frame:0:$((534 * 2))}')
-+ ")
-+ fi
-+ echo ${packet}
-+ }
-+
-+ send_ip6_packet() {
-+ local inport=${1} hv=${2} eth_src=${3} eth_dst=${4} ipv6_src=${5} ipv6_dst=${6} data=${7} fail=${8} mtu=${9:-$3}
-+ packet=$(fmt_pkt "
-+ Ether(dst='${eth_dst}', src='${eth_src}') /
-+ IPv6(src='${ipv6_src}', dst='${ipv6_dst}') /
-+ ICMPv6EchoRequest() / bytes.fromhex('${data}')
-+ ")
-+ as hv${hv} ovs-appctl netdev-dummy/receive ${inport} ${packet}
-+ if [[ x"${fail}" != x0 ]]; then
-+ original_ip_frame=$(fmt_pkt "
-+ IPv6(src='${ipv6_src}', dst='${ipv6_dst}') /
-+ ICMPv6EchoRequest() / bytes.fromhex('${data}')
-+ ")
-+ packet=$(fmt_pkt "
-+ Ether(dst='${eth_src}', src='${eth_dst}') /
-+ IPv6(src='${ipv6_dst}', dst='${ipv6_src}', hlim=255) /
-+ ICMPv6PacketTooBig(mtu=${mtu}) /
-+ bytes.fromhex('${original_ip_frame:0:$((1218 * 2))}')
-+ ")
-+ fi
-+ echo ${packet}
-+ }
-+
-+ reset_env() {
-+ for port in first multi1 multi2; do
-+ as hv1 reset_pcap_file $port hv1/$port
-+ done
-+ for port in second multi1 multi2; do
-+ as hv2 reset_pcap_file $port hv2/$port
-+ done
-+ for port in hv1/multi1 hv2/multi1 hv1/multi2 hv2/multi2 hv1/first hv2/second; do
-+ : > $port.expected
-+ done
-+ }
-+
-+ check_pkts() {
-+ for port in hv1/multi1 hv2/multi1 hv1/multi2 hv2/multi2 hv1/first hv2/second; do
-+ OVN_CHECK_PACKETS_REMOVE_BROADCAST([${port}-tx.pcap], [${port}.expected])
-+ done
-+ }
-+
-+ payload() {
-+ echo $(cat /dev/urandom | tr -cd 'a-f0-9' | head -c ${1})
-+ }
-+
-+ wait_for_ports_up
-+ OVN_POPULATE_ARP
-+
-+ reset_env
-+
-+ AS_BOX([Packets of proper size are delivered from multichassis to regular ports])
-+
-+ len=1000
-+ packet=$(send_ip_packet multi1 1 $multi1_mac $first_mac $multi1_ip $first_ip $(payload $len) 0)
-+ echo $packet >> hv1/first.expected
-+
-+ packet=$(send_ip_packet multi1 1 $multi1_mac $second_mac $multi1_ip $second_ip $(payload $len) 0)
-+ echo $packet >> hv2/second.expected
-+
-+ packet=$(send_ip6_packet multi1 1 $multi1_mac $first_mac $multi1_ip6 $first_ip6 $(payload $len) 0)
-+ echo $packet >> hv1/first.expected
-+
-+ packet=$(send_ip6_packet multi1 1 $multi1_mac $second_mac $multi1_ip6 $second_ip6 $(payload $len) 0)
-+ echo $packet >> hv2/second.expected
-+
-+ check_pkts
-+ reset_env
-+
-+ AS_BOX([Oversized packets are not delivered from multichassis to regular ports])
-+
-+ len=3000
-+ packet=$(send_ip_packet multi1 1 $multi1_mac $first_mac $multi1_ip $first_ip $(payload $len) 1)
-+ echo $packet >> hv1/multi1.expected
-+
-+ packet=$(send_ip_packet multi1 1 $multi1_mac $second_mac $multi1_ip $second_ip $(payload $len) 1)
-+ echo $packet >> hv1/multi1.expected
-+
-+ packet=$(send_ip6_packet multi1 1 $multi1_mac $first_mac $multi1_ip6 $first_ip6 $(payload $len) 1)
-+ echo $packet >> hv1/multi1.expected
-+
-+ packet=$(send_ip6_packet multi1 1 $multi1_mac $second_mac $multi1_ip6 $second_ip6 $(payload $len) 1)
-+ echo $packet >> hv1/multi1.expected
-+
-+ check_pkts
-+ reset_env
-+
-+ AS_BOX([Packets of proper size are delivered from regular to multichassis ports])
-+
-+ len=1000
-+ packet=$(send_ip_packet first 1 $first_mac $multi1_mac $first_ip $multi1_ip $(payload $len) 0)
-+ echo $packet >> hv1/multi1.expected
-+ echo $packet >> hv2/multi1.expected
-+
-+ packet=$(send_ip_packet second 2 $second_mac $multi1_mac $second_ip $multi1_ip $(payload $len) 0)
-+ echo $packet >> hv1/multi1.expected
-+ echo $packet >> hv2/multi1.expected
-+
-+ packet=$(send_ip6_packet first 1 $first_mac $multi1_mac $first_ip6 $multi1_ip6 $(payload $len) 0)
-+ echo $packet >> hv1/multi1.expected
-+ echo $packet >> hv2/multi1.expected
-+
-+ packet=$(send_ip6_packet second 2 $second_mac $multi1_mac $second_ip6 $multi1_ip6 $(payload $len) 0)
-+ echo $packet >> hv1/multi1.expected
-+ echo $packet >> hv2/multi1.expected
-+
-+ check_pkts
-+ reset_env
-+
-+ AS_BOX([Oversized packets are not delivered from regular to multichassis ports])
-+
-+ len=3000
-+ packet=$(send_ip_packet first 1 $first_mac $multi1_mac $first_ip $multi1_ip $(payload $len) 1)
-+ echo $packet >> hv1/first.expected
-+
-+ packet=$(send_ip_packet second 2 $second_mac $multi1_mac $second_ip $multi1_ip $(payload $len) 1)
-+ echo $packet >> hv2/second.expected
-+
-+ packet=$(send_ip6_packet first 1 $first_mac $multi1_mac $first_ip6 $multi1_ip6 $(payload $len) 1)
-+ echo $packet >> hv1/first.expected
-+
-+ packet=$(send_ip6_packet second 2 $second_mac $multi1_mac $second_ip6 $multi1_ip6 $(payload $len) 1)
-+ echo $packet >> hv2/second.expected
-+
-+ check_pkts
-+ reset_env
-+
-+ AS_BOX([Packets of proper size are delivered from multichassis to multichassis ports])
-+
-+ len=1000
-+ packet=$(send_ip_packet multi1 1 $multi1_mac $multi2_mac $multi1_ip $multi2_ip $(payload $len) 0)
-+ echo $packet >> hv1/multi2.expected
-+ echo $packet >> hv2/multi2.expected
-+
-+ packet=$(send_ip6_packet multi1 1 $multi1_mac $multi2_mac $multi1_ip6 $multi2_ip6 $(payload $len) 0)
-+ echo $packet >> hv1/multi2.expected
-+ echo $packet >> hv2/multi2.expected
-+
-+ check_pkts
-+ reset_env
-+
-+ AS_BOX([Oversized packets are not delivered from multichassis to multichassis ports])
-+
-+ len=3000
-+ packet=$(send_ip_packet multi1 1 $multi1_mac $multi2_mac $multi1_ip $multi2_ip $(payload $len) 1)
-+ echo $packet >> hv1/multi1.expected
-+
-+ packet=$(send_ip6_packet multi1 1 $multi1_mac $multi2_mac $multi1_ip6 $multi2_ip6 $(payload $len) 1)
-+ echo $packet >> hv1/multi1.expected
-+
-+ check_pkts
-+ reset_env
-+
-+ AS_BOX([MTU updates are honored in ICMP Path MTU calculation])
-+
-+ set_mtu() {
-+ local hv=${1} iface=${2} new_mtu=${3}
-+
-+ iface_uuid=$(as ${hv} ovs-vsctl --bare --columns _uuid find Interface name=${iface})
-+ check as ${hv} ovs-vsctl set interface ${iface_uuid} mtu_request=${new_mtu}
-+ }
-+
-+ set_mtu_for_all_ports() {
-+ for port in multi1 multi2 first; do
-+ set_mtu hv1 ${port} ${1}
-+ done
-+ for port in multi1 multi2 second; do
-+ set_mtu hv2 ${port} ${1}
-+ done
-+ }
-+
-+ initial_mtu=1500 # all interfaces are 1500 by default
-+ new_mtu=1400
-+ set_mtu_for_all_ports ${new_mtu}
-+ mtu_diff=$((${initial_mtu} - ${new_mtu}))
-+
-+ len=3000
-+ expected_ip_mtu=$(($3 - ${mtu_diff}))
-+ packet=$(send_ip_packet first 1 $first_mac $multi1_mac $first_ip $multi1_ip $(payload $len) 1 ${expected_ip_mtu})
-+ echo $packet >> hv1/first.expected
-+
-+ packet=$(send_ip_packet second 2 $second_mac $multi1_mac $second_ip $multi1_ip $(payload $len) 1 ${expected_ip_mtu})
-+ echo $packet >> hv2/second.expected
-+
-+ packet=$(send_ip6_packet first 1 $first_mac $multi1_mac $first_ip6 $multi1_ip6 $(payload $len) 1 ${expected_ip_mtu})
-+ echo $packet >> hv1/first.expected
-+
-+ packet=$(send_ip6_packet second 2 $second_mac $multi1_mac $second_ip6 $multi1_ip6 $(payload $len) 1 ${expected_ip_mtu})
-+ echo $packet >> hv2/second.expected
-+
-+ packet=$(send_ip_packet multi1 1 $multi1_mac $first_mac $multi1_ip $first_ip $(payload $len) 1 ${expected_ip_mtu})
-+ echo $packet >> hv1/multi1.expected
-+
-+ packet=$(send_ip_packet multi1 1 $multi1_mac $second_mac $multi1_ip $second_ip $(payload $len) 1 ${expected_ip_mtu})
-+ echo $packet >> hv1/multi1.expected
-+
-+ packet=$(send_ip6_packet multi1 1 $multi1_mac $first_mac $multi1_ip6 $first_ip6 $(payload $len) 1 ${expected_ip_mtu})
-+ echo $packet >> hv1/multi1.expected
-+
-+ packet=$(send_ip6_packet multi1 1 $multi1_mac $second_mac $multi1_ip6 $second_ip6 $(payload $len) 1 ${expected_ip_mtu})
-+ echo $packet >> hv1/multi1.expected
-+
-+ packet=$(send_ip_packet multi1 1 $multi1_mac $multi2_mac $multi1_ip $multi2_ip $(payload $len) 1 ${expected_ip_mtu})
-+ echo $packet >> hv1/multi1.expected
-+
-+ packet=$(send_ip6_packet multi1 1 $multi1_mac $multi2_mac $multi1_ip6 $multi2_ip6 $(payload $len) 1 ${expected_ip_mtu})
-+ echo $packet >> hv1/multi1.expected
-+
-+ check_pkts
-+
-+ OVN_CLEANUP([hv1],[hv2])
-+
-+ AT_CLEANUP
-+ ])])
-+
-+# NOTE(ihar) no STT variants because it's not supported by upstream kernels
-+MULTICHASSIS_PATH_MTU_DISCOVERY_TEST([ipv4], [geneve], [1424])
-+MULTICHASSIS_PATH_MTU_DISCOVERY_TEST([ipv6], [geneve], [1404])
-+MULTICHASSIS_PATH_MTU_DISCOVERY_TEST([ipv4], [vxlan], [1432])
-+MULTICHASSIS_PATH_MTU_DISCOVERY_TEST([ipv6], [vxlan], [1412])
-+
- OVN_FOR_EACH_NORTHD([
- AT_SETUP([options:activation-strategy for logical port])
- AT_KEYWORDS([multi-chassis])
-@@ -16278,25 +16696,25 @@ sleep 2
- # Get total number of ipv4 packets that received on ovs
-
- # sender side
--flow=$(as hv1 ovs-ofctl dump-flows br-int table=44 | grep priority=2002|grep ip,metadata=0x1)
-+flow=$(as hv1 ovs-ofctl dump-flows br-int table=46 | grep priority=2002|grep ip,metadata=0x1)
- n_pkts="$(echo $flow|awk -F',' '{ print $4 }'|awk -F'=' '{ print $2 }')"
- check test $n_pkts -eq 1
-
- # receiver side
--flow=$(as hv2 ovs-ofctl dump-flows br-int table=44 | grep priority=2002|grep ip,metadata=0x1)
-+flow=$(as hv2 ovs-ofctl dump-flows br-int table=46 | grep priority=2002|grep ip,metadata=0x1)
- n_pkts="$(echo $flow|awk -F',' '{ print $4 }'|awk -F'=' '{ print $2 }')"
- check test $n_pkts -eq 1
-
- # Get total number of ipv6 packets that received on ovs
-
- # sender side
--flow=$(as hv1 ovs-ofctl dump-flows br-int table=44 | grep priority=2002|grep ipv6,metadata=0x1)
-+flow=$(as hv1 ovs-ofctl dump-flows br-int table=46 | grep priority=2002|grep ipv6,metadata=0x1)
- n_pkts="$(echo $flow|awk -F',' '{ print $4 }'|awk -F'=' '{ print $2 }')"
- check test $n_pkts -eq 1
-
-
- # receiver side
--flow=$(as hv2 ovs-ofctl dump-flows br-int table=44 | grep priority=2002|grep ipv6,metadata=0x1)
-+flow=$(as hv2 ovs-ofctl dump-flows br-int table=46 | grep priority=2002|grep ipv6,metadata=0x1)
- n_pkts="$(echo $flow|awk -F',' '{ print $4 }'|awk -F'=' '{ print $2 }')"
- check test $n_pkts -eq 1
-
-@@ -17210,7 +17628,7 @@ test_icmp() {
- icmp4.code==0"
- shift; shift; shift; shift; shift; shift
- hv=hv`vif_to_hv $inport`
-- as $hv ovs-appctl -t ovn-controller inject-pkt "$packet"
-+ OVS_WAIT_UNTIL([as $hv ovs-appctl -t ovn-controller inject-pkt "$packet"])
- in_ls=`vif_to_ls $inport`
- in_lrp=`vif_to_lrp $inport`
- for outport; do
-@@ -17856,17 +18274,17 @@ check ovn-nbctl acl-add ls1 to-lport 3 'ip4.src==10.0.0.1' allow
- check ovn-nbctl --wait=hv sync
-
- # Check OVS flows, the less restrictive flows should have been installed.
--AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=44 | ofctl_strip_all | \
-+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=46 | ofctl_strip_all | \
- grep "priority=1003" | \
- sed 's/conjunction([[^)]]*)/conjunction()/g' | \
- sed 's/conj_id=[[0-9]]*,/conj_id=xxx,/g' | sort], [0], [dnl
-- table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
-- table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
-- table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.3 actions=conjunction(),conjunction()
-- table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.4 actions=conjunction(),conjunction()
-- table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=resubmit(,45)
-- table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.2 actions=conjunction()
-- table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.42 actions=conjunction()
-+ table=46, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,47)
-+ table=46, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,47)
-+ table=46, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.3 actions=conjunction(),conjunction()
-+ table=46, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.4 actions=conjunction(),conjunction()
-+ table=46, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=resubmit(,47)
-+ table=46, priority=1003,ip,metadata=0x1,nw_src=10.0.0.2 actions=conjunction()
-+ table=46, priority=1003,ip,metadata=0x1,nw_src=10.0.0.42 actions=conjunction()
- ])
-
- # Traffic 10.0.0.1, 10.0.0.2 -> 10.0.0.3, 10.0.0.4 should be allowed.
-@@ -17901,17 +18319,17 @@ check ovn-nbctl acl-del ls1 to-lport 3 'ip4.src==10.0.0.1 || ip4.src==10.0.0.1'
- check ovn-nbctl --wait=hv sync
-
- # Check OVS flows, the second less restrictive allow ACL should have been installed.
--AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=44 | ofctl_strip_all | \
-+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=46 | ofctl_strip_all | \
- grep "priority=1003" | \
- sed 's/conjunction([[^)]]*)/conjunction()/g' | \
- sed 's/conj_id=[[0-9]]*,/conj_id=xxx,/g' | sort], [0], [dnl
-- table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
-- table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
-- table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.3 actions=conjunction(),conjunction()
-- table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.4 actions=conjunction(),conjunction()
-- table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=resubmit(,45)
-- table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.2 actions=conjunction()
-- table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.42 actions=conjunction()
-+ table=46, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,47)
-+ table=46, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,47)
-+ table=46, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.3 actions=conjunction(),conjunction()
-+ table=46, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.4 actions=conjunction(),conjunction()
-+ table=46, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=resubmit(,47)
-+ table=46, priority=1003,ip,metadata=0x1,nw_src=10.0.0.2 actions=conjunction()
-+ table=46, priority=1003,ip,metadata=0x1,nw_src=10.0.0.42 actions=conjunction()
- ])
-
- # Remove the less restrictive allow ACL.
-@@ -17919,17 +18337,17 @@ check ovn-nbctl acl-del ls1 to-lport 3 'ip4.src==10.0.0.1'
- check ovn-nbctl --wait=hv sync
-
- # Check OVS flows, the 10.0.0.1 conjunction should have been reinstalled.
--AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=44 | ofctl_strip_all | \
-+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=46 | ofctl_strip_all | \
- grep "priority=1003" | \
- sed 's/conjunction([[^)]]*)/conjunction()/g' | \
- sed 's/conj_id=[[0-9]]*,/conj_id=xxx,/g' | sort], [0], [dnl
-- table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
-- table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
-- table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.3 actions=conjunction(),conjunction()
-- table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.4 actions=conjunction(),conjunction()
-- table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=conjunction(),conjunction()
-- table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.2 actions=conjunction()
-- table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.42 actions=conjunction()
-+ table=46, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,47)
-+ table=46, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,47)
-+ table=46, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.3 actions=conjunction(),conjunction()
-+ table=46, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.4 actions=conjunction(),conjunction()
-+ table=46, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=conjunction(),conjunction()
-+ table=46, priority=1003,ip,metadata=0x1,nw_src=10.0.0.2 actions=conjunction()
-+ table=46, priority=1003,ip,metadata=0x1,nw_src=10.0.0.42 actions=conjunction()
- ])
-
- # Traffic 10.0.0.1, 10.0.0.2 -> 10.0.0.3, 10.0.0.4 should be allowed.
-@@ -17959,17 +18377,17 @@ check ovn-nbctl acl-add ls1 to-lport 3 'ip4.src==10.0.0.1' allow
- check ovn-nbctl --wait=hv sync
-
- # Check OVS flows, the less restrictive flows should have been installed.
--AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=44 | ofctl_strip_all | \
-+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=46 | ofctl_strip_all | \
- grep "priority=1003" | \
- sed 's/conjunction([[^)]]*)/conjunction()/g' | \
- sed 's/conj_id=[[0-9]]*,/conj_id=xxx,/g' | sort], [0], [dnl
-- table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
-- table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
-- table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.3 actions=conjunction(),conjunction()
-- table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.4 actions=conjunction(),conjunction()
-- table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=resubmit(,45)
-- table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.2 actions=conjunction()
-- table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.42 actions=conjunction()
-+ table=46, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,47)
-+ table=46, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,47)
-+ table=46, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.3 actions=conjunction(),conjunction()
-+ table=46, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.4 actions=conjunction(),conjunction()
-+ table=46, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=resubmit(,47)
-+ table=46, priority=1003,ip,metadata=0x1,nw_src=10.0.0.2 actions=conjunction()
-+ table=46, priority=1003,ip,metadata=0x1,nw_src=10.0.0.42 actions=conjunction()
- ])
-
- # Add another ACL that overlaps with the existing less restrictive ones.
-@@ -17980,20 +18398,20 @@ check ovn-nbctl --wait=hv sync
- # with an additional conjunction action.
- #
- # New non-conjunctive flows should be added to match on 'udp'.
--AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=44 | ofctl_strip_all | \
-+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=46 | ofctl_strip_all | \
- grep "priority=1003" | \
- sed 's/conjunction([[^)]]*)/conjunction()/g' | \
- sed 's/conj_id=[[0-9]]*,/conj_id=xxx,/g' | sort], [0], [dnl
-- table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
-- table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
-- table=44, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,45)
-- table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.3 actions=conjunction(),conjunction(),conjunction()
-- table=44, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.4 actions=conjunction(),conjunction(),conjunction()
-- table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=resubmit(,45)
-- table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.2 actions=conjunction(),conjunction()
-- table=44, priority=1003,ip,metadata=0x1,nw_src=10.0.0.42 actions=conjunction()
-- table=44, priority=1003,udp,metadata=0x1 actions=resubmit(,45)
-- table=44, priority=1003,udp6,metadata=0x1 actions=resubmit(,45)
-+ table=46, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,47)
-+ table=46, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,47)
-+ table=46, priority=1003,conj_id=xxx,ip,metadata=0x1 actions=resubmit(,47)
-+ table=46, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.3 actions=conjunction(),conjunction(),conjunction()
-+ table=46, priority=1003,ip,metadata=0x1,nw_dst=10.0.0.4 actions=conjunction(),conjunction(),conjunction()
-+ table=46, priority=1003,ip,metadata=0x1,nw_src=10.0.0.1 actions=resubmit(,47)
-+ table=46, priority=1003,ip,metadata=0x1,nw_src=10.0.0.2 actions=conjunction(),conjunction()
-+ table=46, priority=1003,ip,metadata=0x1,nw_src=10.0.0.42 actions=conjunction()
-+ table=46, priority=1003,udp,metadata=0x1 actions=resubmit(,47)
-+ table=46, priority=1003,udp6,metadata=0x1 actions=resubmit(,47)
- ])
-
- OVN_CLEANUP([hv1])
-@@ -18048,17 +18466,17 @@ check ovn-nbctl acl-add pg1 to-lport 100 'outport == @pg1 && ip4.src == $as2' al
-
- wait_for_ports_up
- check ovn-nbctl --wait=hv sync
--ovs-ofctl dump-flows br-int table=44
--AT_CHECK([test `ovs-ofctl dump-flows br-int table=44 | grep -c conj_id` = 2])
-+ovs-ofctl dump-flows br-int table=46
-+AT_CHECK([test `ovs-ofctl dump-flows br-int table=46 | grep -c conj_id` = 2])
-
- echo -------
- # Add another address in as1, so that the 1st ACL will now generate 2 conjunctions.
- ovn-nbctl set address_set as1 addresses="10.0.0.1,10.0.0.2"
- check ovn-nbctl --wait=hv sync
-
--ovs-ofctl dump-flows br-int table=44
-+ovs-ofctl dump-flows br-int table=46
- # There should be 3 conjunctions in total (2 from 1st ACL + 1 from 2nd ACL)
--AT_CHECK([test `ovs-ofctl dump-flows br-int table=44 | grep -c conj_id` = 3])
-+AT_CHECK([test `ovs-ofctl dump-flows br-int table=46 | grep -c conj_id` = 3])
-
- OVN_CLEANUP([hv1])
- AT_CLEANUP
-@@ -18276,7 +18694,7 @@ AT_SETUP([TTL exceeded])
- AT_KEYWORDS([ttl-exceeded])
- ovn_start
-
--# test_ip_packet INPORT HV ETH_SRC ETH_DST IPV4_SRC IPV4_DST IPV4_ROUTER IP_CHKSUM EXP_IP_CHKSUM EXP_ICMP_CHKSUM
-+# test_ip_packet INPORT HV ETH_SRC ETH_DST IPV4_SRC IPV4_DST IPV4_ROUTER IP_CHKSUM EXP_IP_CHKSUM EXP_ICMP_CHKSUM SHOULD_REPLY
- #
- # Causes a packet to be received on INPORT of the hypervisor HV. The packet is an IPv4 packet with
- # ETH_SRC, ETH_DST, IPV4_SRC, IPV4_DST, IP_CHKSUM as specified and TTL set to 1.
-@@ -18292,6 +18710,7 @@ test_ip_packet() {
- local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ipv4_src=$5 ipv4_dst=$6 ip_router=$7 ip_chksum=$8
- local exp_ip_chksum=$9 exp_icmp_chksum=${10}
- shift 10
-+ local should_reply=$1
-
- local ip_ttl=01
- local packet=${eth_dst}${eth_src}08004500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst}
-@@ -18300,27 +18719,31 @@ test_ip_packet() {
- local icmp_type_code_response=0b00
- local icmp_data=00000000
- local reply_icmp_payload=${icmp_type_code_response}${exp_icmp_chksum}${icmp_data}
-- local reply=${eth_src}${eth_dst}08004500003000004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload}
-- echo $reply$orig_pkt_in_reply >> vif$inport.expected
-+ if test $should_reply == yes; then
-+ local reply=${eth_src}${eth_dst}08004500003000004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload}
-+ echo $reply$orig_pkt_in_reply >> vif$inport.expected
-+ fi
-
- as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
- }
-
--# test_ip6_packet INPORT HV ETH_SRC ETH_DST IPV6_SRC IPV6_DST IPV6_ROUTER EXP_ICMP_CHKSUM
-+# test_ip6_packet INPORT HV ETH_SRC ETH_DST IPV6_SRC IPV6_DST IPV6_ROUTER EXP_ICMP_CHKSUM SHOULD_REPLY
- #
- # Causes a packet to be received on INPORT of the hypervisor HV. The packet is an IPv6
- # packet with ETH_SRC, ETH_DST, IPV6_SRC and IPV6_DST as specified.
- # IPV6_ROUTER and EXP_ICMP_CHKSUM are the source IP and checksum of the icmpv6 ttl exceeded
- # packet sent by OVN logical router
- test_ip6_packet() {
-- local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ipv6_src=$5 ipv6_dst=$6 ipv6_router=$7 exp_icmp_chksum=$8
-+ local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ipv6_src=$5 ipv6_dst=$6 ipv6_router=$7 exp_icmp_chksum=$8 should_reply=$9
- shift 8
-
- local ip6_hdr=6000000000151101${ipv6_src}${ipv6_dst}
- local packet=${eth_dst}${eth_src}86dd${ip6_hdr}dbb8303900155bac6b646f65206676676e6d66720a
-
-- local reply=${eth_src}${eth_dst}86dd6000000000453afe${ipv6_router}${ipv6_src}0300${exp_icmp_chksum}00000000${ip6_hdr}dbb8303900155bac6b646f65206676676e6d66720a
-- echo $reply >> vif$inport.expected
-+ if test $should_reply == yes; then
-+ local reply=${eth_src}${eth_dst}86dd6000000000453afe${ipv6_router}${ipv6_src}0300${exp_icmp_chksum}00000000${ip6_hdr}dbb8303900155bac6b646f65206676676e6d66720a
-+ echo $reply >> vif$inport.expected
-+ fi
-
- as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
- }
-@@ -18343,6 +18766,8 @@ for i in 1 2; do
- options:tx_pcap=hv$i/vif$i-tx.pcap \
- options:rxq_pcap=hv$i/vif$i-rx.pcap \
- ofport-request=$i
-+
-+ ovs-appctl -t ovn-controller vlog/set file:dbg:pinctrl
- done
-
- ovn-nbctl lr-add lr0
-@@ -18358,10 +18783,22 @@ OVN_POPULATE_ARP
- wait_for_ports_up
- ovn-nbctl --wait=hv sync
-
--test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 2 1) $(ip_to_hex 192 168 1 254) 0000 f87c ea96
--test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011 20010db8000200000000000000000011 20010db8000100000000000000000001 1c22
-+test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 2 1) $(ip_to_hex 192 168 1 254) 0000 f87c ea96 yes
-+test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011 20010db8000200000000000000000011 20010db8000100000000000000000001 1c22 yes
-+
-+# Should not send ICMP for multicast
-+test_ip_packet 1 1 000000000001 01005e7f0001 $(ip_to_hex 192 168 1 1) $(ip_to_hex 239 255 0 1) $(ip_to_hex 192 168 1 254) 0000 000000000 no
-+test_ip6_packet 1 1 000000000001 333300000001 20010db8000100000000000000000011 ff020000000000000000000000000001 20010db8000100000000000000000001 0000 no
-+
- OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [vif1.expected])
-
-+# Confirm from debug log that we only see 2 packet-ins (no packet-ins for
-+# multicasts). This is necessary because not seeing ICMP messages doesn't
-+# necessarily mean the packet-in didn't happen. It is possible that packet-in
-+# is processed but the ICMP message got dropped.
-+AT_CHECK([grep -c packet-in hv1/ovn-controller.log], [0], [2
-+])
-+
- OVN_CLEANUP([hv1], [hv2])
- AT_CLEANUP
- ])
-@@ -18656,7 +19093,7 @@ packet="inport==\"sw1-p1\" && eth.src==$sw1_p1_mac && eth.dst==$sw1_ro_mac &&
- udp && udp.src==53 && udp.dst==4369"
-
- # Start by Sending the packet and make sure it makes it there as expected
--as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Expected packet has TTL decreased by 1
- expected="eth.src==$sw2_ro_mac && eth.dst==$sw2_p1_mac &&
-@@ -18670,7 +19107,7 @@ OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
- as hv2 ovs-appctl -t ovn-controller exit
-
- # Now send the packet again. This time, it should not arrive.
--as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
-
-@@ -19552,7 +19989,7 @@ packet="inport==\"sw1-p1\" && eth.src==$sw1_p1_mac && eth.dst==$sw1_ro_mac &&
- udp && udp.src==53 && udp.dst==4369"
-
- # Start by Sending the packet and make sure it makes it there as expected
--as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Expected packet has TTL decreased by 1
- expected="eth.src==$sw2_ro_mac && eth.dst==$sw2_p1_mac &&
-@@ -19566,7 +20003,7 @@ OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
- as hv2 ovs-appctl -t ovn-controller exit --restart
-
- # Now send the packet again. This time, it should still arrive
--as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- cat expected expected > expected2
-
-@@ -19705,7 +20142,7 @@ test_ip_packet_larger() {
- # Set the packet length to 114.
- pkt_len=0072
- packet=${dst_mac}${src_mac}08004500${pkt_len}000000004001c3dd
-- orig_packet_l3=${src_ip}${dst_ip}0304fcfb00000000
-+ orig_packet_l3=${src_ip}${dst_ip}0800f7ff00000000
- orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
- orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
- orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
-@@ -19729,10 +20166,10 @@ test_ip_packet_larger() {
- # Packet to expect at br-phys.
- src_mac="000020201213"
- dst_mac="00000012af11"
-- src_ip=`ip_to_hex 10 0 0 3`
-+ src_ip=`ip_to_hex 172 168 0 100`
- dst_ip=`ip_to_hex 172 168 0 3`
-- expected=${dst_mac}${src_mac}08004500${pkt_len}000000003f01c4dd
-- expected=${expected}${src_ip}${dst_ip}0304fcfb00000000
-+ expected=${dst_mac}${src_mac}08004500${pkt_len}000000003f0121d4
-+ expected=${expected}${src_ip}${dst_ip}0800f7ff00000000
- expected=${expected}000000000000000000000000000000000000
- expected=${expected}000000000000000000000000000000000000
- expected=${expected}000000000000000000000000000000000000
-@@ -19793,7 +20230,7 @@ test_ip_packet_larger_ext() {
- # Set the packet length to 114.
- pkt_len=0072
- packet=${dst_mac}${src_mac}08004500${pkt_len}000000004001${checksum}
-- orig_packet_l3=${src_ip}${dst_ip}0900000000000000
-+ orig_packet_l3=${src_ip}${dst_ip}0800f7ff00000000
- orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
- orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
- orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
-@@ -19810,7 +20247,7 @@ test_ip_packet_larger_ext() {
- dst_ip=`ip_to_hex 172 168 0 4`
- # pkt len should be 146 (28 (icmp packet) + 118 (orig ip + payload))
- reply_pkt_len=008e
-- ip_csum=f39b
-+ ip_csum=$7
- icmp_reply=${src_mac}${dst_mac}08004500${reply_pkt_len}00004000fe01${reply_checksum}
- icmp_reply=${icmp_reply}${src_ip}${dst_ip}0304${ip_csum}0000$(printf "%04x" $mtu)
- icmp_reply=${icmp_reply}4500${pkt_len}000000004001${checksum}
-@@ -19985,10 +20422,10 @@ OVS_WAIT_FOR_OUTPUT([
- ])
-
- AS_BOX([testing ingress traffic mtu 100 - IPv4])
--test_ip_packet_larger_ext 1 000020201213 $(ip_to_hex 172 168 0 100) 20cf 100 22b6
-+test_ip_packet_larger_ext 1 000020201213 $(ip_to_hex 172 168 0 100) 20d3 100 22b6 fc97
-
- AS_BOX([testing ingress traffic mtu 100 - IPv4 FIP])
--test_ip_packet_larger_ext 2 f00000010204 $(ip_to_hex 172 168 0 110) 20c5 100 22ac
-+test_ip_packet_larger_ext 2 f00000010204 $(ip_to_hex 172 168 0 110) 20c5 100 22ac fc9b
-
- AS_BOX([testing ingress traffic mtu 100 - IPv6])
- test_ip6_packet_larger_ext 1 000020201213 20000000000000000000000000000001 100 cc7a
-@@ -20055,10 +20492,10 @@ OVS_WAIT_FOR_OUTPUT([
- ])
-
- AS_BOX([testing ingress traffic mtu 100 for gw router - IPv4])
--test_ip_packet_larger_ext 1 000020201213 $(ip_to_hex 172 168 0 100) 20cf 100 22b6
-+test_ip_packet_larger_ext 1 000020201213 $(ip_to_hex 172 168 0 100) 20d3 100 22b6 fc97
-
- AS_BOX([testing ingress traffic mtu 100 for gw router - IPv6])
--test_ip6_packet_larger_ext 1 000020201213 20000000000000000000000000000001 100 cc7a
-+test_ip6_packet_larger_ext 1 000020201213 20000000000000000000000000000001 100 cc7a fc9b
-
- OVN_CLEANUP([hv1])
- AT_CLEANUP
-@@ -21012,9 +21449,9 @@ check_virtual_offlows_present() {
- lr0_dp_key=$(printf "%x" $(fetch_column Datapath_Binding tunnel_key external_ids:name=lr0))
- lr0_public_dp_key=$(printf "%x" $(fetch_column Port_Binding tunnel_key logical_port=lr0-public))
-
-- AT_CHECK_UNQUOTED([as $hv ovs-ofctl dump-flows br-int table=44 | ofctl_strip_all | grep "priority=2000"], [0], [dnl
-- table=44, priority=2000,ip,metadata=0x$sw0_dp_key actions=resubmit(,45)
-- table=44, priority=2000,ipv6,metadata=0x$sw0_dp_key actions=resubmit(,45)
-+ AT_CHECK_UNQUOTED([as $hv ovs-ofctl dump-flows br-int table=46 | ofctl_strip_all | grep "priority=2000"], [0], [dnl
-+ table=46, priority=2000,ip,metadata=0x$sw0_dp_key actions=resubmit(,47)
-+ table=46, priority=2000,ipv6,metadata=0x$sw0_dp_key actions=resubmit(,47)
- ])
-
- AT_CHECK_UNQUOTED([as $hv ovs-ofctl dump-flows br-int table=11 | ofctl_strip_all | \
-@@ -21025,7 +21462,7 @@ check_virtual_offlows_present() {
-
- check_virtual_offlows_not_present() {
- hv=$1
-- AT_CHECK([as $hv ovs-ofctl dump-flows br-int table=45 | ofctl_strip_all | grep "priority=2000"], [1], [dnl
-+ AT_CHECK([as $hv ovs-ofctl dump-flows br-int table=47 | ofctl_strip_all | grep "priority=2000"], [1], [dnl
- ])
-
- AT_CHECK([as $hv ovs-ofctl dump-flows br-int table=11 | ofctl_strip_all | \
-@@ -21116,7 +21553,7 @@ check_virtual_offlows_not_present hv2
- send_garp 1 1 $eth_src $eth_dst $spa $tpa
-
- OVS_WAIT_UNTIL([test x$(ovn-sbctl --bare --columns chassis find port_binding \
--logical_port=sw0-vir) = x$hv1_ch_uuid], [0], [])
-+logical_port=sw0-vir) = x$hv1_ch_uuid])
-
- AT_CHECK([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \
- logical_port=sw0-vir) = xsw0-p1])
-@@ -21184,7 +21621,7 @@ tpa=$(ip_to_hex 10 0 0 10)
- send_garp 1 2 $eth_src $eth_dst $spa $tpa
-
- OVS_WAIT_UNTIL([test x$(ovn-sbctl --bare --columns chassis find port_binding \
--logical_port=sw0-vir) = x$hv1_ch_uuid], [0], [])
-+logical_port=sw0-vir) = x$hv1_ch_uuid])
-
- OVS_WAIT_UNTIL([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \
- logical_port=sw0-vir) = xsw0-p3])
-@@ -21217,7 +21654,7 @@ tpa=$(ip_to_hex 10 0 0 10)
- send_garp 2 1 $eth_src $eth_dst $spa $tpa
-
- OVS_WAIT_UNTIL([test x$(ovn-sbctl --bare --columns chassis find port_binding \
--logical_port=sw0-vir) = x$hv2_ch_uuid], [0], [])
-+logical_port=sw0-vir) = x$hv2_ch_uuid])
-
- AT_CHECK([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \
- logical_port=sw0-vir) = xsw0-p2])
-@@ -21249,7 +21686,7 @@ tpa=$(ip_to_hex 10 0 0 4)
- send_arp_reply 1 1 $eth_src $eth_dst $spa $tpa
-
- OVS_WAIT_UNTIL([test x$(ovn-sbctl --bare --columns chassis find port_binding \
--logical_port=sw0-vir) = x$hv1_ch_uuid], [0], [])
-+logical_port=sw0-vir) = x$hv1_ch_uuid])
- sleep 1
-
- AT_CHECK([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \
-@@ -21275,7 +21712,7 @@ check_virtual_offlows_not_present hv2
- as hv1 ovs-vsctl del-port hv1-vif1
-
- OVS_WAIT_UNTIL([test x$(ovn-sbctl --bare --columns chassis find port_binding \
--logical_port=sw0-vir) = x], [0], [])
-+logical_port=sw0-vir) = x])
- sleep 1
-
- AT_CHECK([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \
-@@ -21310,7 +21747,7 @@ send_arp_reply 2 1 $eth_src $eth_dst $spa $tpa
- sleep 1
-
- OVS_WAIT_UNTIL([test x$(ovn-sbctl --bare --columns chassis find port_binding \
--logical_port=sw0-vir) = x$hv2_ch_uuid], [0], [])
-+logical_port=sw0-vir) = x$hv2_ch_uuid])
- sleep 1
- AT_CHECK([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \
- logical_port=sw0-vir) = xsw0-p2])
-@@ -21335,7 +21772,7 @@ check_virtual_offlows_not_present hv1
- ovn-nbctl lsp-del sw0-p2
-
- OVS_WAIT_UNTIL([test x$(ovn-sbctl --bare --columns chassis find port_binding \
--logical_port=sw0-vir) = x], [0], [])
-+logical_port=sw0-vir) = x])
- AT_CHECK([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \
- logical_port=sw0-vir) = x])
-
-@@ -21516,7 +21953,7 @@ AT_CAPTURE_FILE([offlows])
- packet0="inport==\"sw0-p11\" && eth.src==00:00:00:00:00:11 && eth.dst==00:00:00:00:00:21 &&
- ip4 && ip.ttl==64 && ip4.src==192.168.1.11 && ip4.dst==192.168.1.100 &&
- tcp && tcp.src==10000 && tcp.dst==80"
--as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet0"
-+OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet0"])
- ovn-nbctl --wait=hv
-
- ovn-sbctl list controller_event > events
-@@ -21545,7 +21982,7 @@ packet1="inport==\"sw1-p0\" && eth.src==00:00:00:00:00:33 && eth.dst==00:00:00:0
- ip4 && ip.ttl==64 && ip4.src==192.168.2.11 && ip4.dst==192.168.2.100 &&
- tcp && tcp.src==10000 && tcp.dst==80"
-
--as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet1"
-+OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet1"])
- ovn-nbctl --wait=hv
- ovn-sbctl list controller_event
- uuid=$(ovn-sbctl list controller_event | awk '/_uuid/{print $3}')
-@@ -21561,7 +21998,7 @@ packet2="inport==\"sw0-p11\" && eth.src==00:00:00:00:00:11 && eth.dst==00:00:00:
- ip6 && ip.ttl==64 && ip6.src==2001::11 && ip6.dst==2001::10 &&
- tcp && tcp.src==10000 && tcp.dst==50051"
-
--as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet2"
-+OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet2"])
- ovn-nbctl --wait=hv
- ovn-sbctl list controller_event
- uuid=$(ovn-sbctl list controller_event | awk '/_uuid/{print $3}')
-@@ -23619,7 +24056,7 @@ m4_define([DVR_N_S_PING],
- OVN_CHECK_PACKETS_REMOVE_BROADCAST([hv4/vif-north-tx.pcap], [vif-north.expected])
-
- # Confirm that packets did not go out via tunnel port.
-- AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep table=38 | grep NXM_NX_TUN_METADATA0 | grep n_packets=0 | wc -l], [0], [[0
-+ AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep table=39 | grep NXM_NX_TUN_METADATA0 | grep n_packets=0 | wc -l], [0], [[0
- ]])
-
- # Confirm that packet went out via localnet port
-@@ -23744,7 +24181,7 @@ send_garp 1 1 $eth_src $eth_dst $spa $tpa
-
- wait_row_count MAC_Binding 1
-
--OVS_WAIT_UNTIL([ovn-sbctl --format=csv --bare --columns logical_port,ip,mac \
-+OVS_WAIT_FOR_OUTPUT([ovn-sbctl --format=csv --bare --columns logical_port,ip,mac \
- list mac_binding], [0], [lr0-sw0
- 10.0.0.30
- 50:54:00:00:00:03
-@@ -23791,7 +24228,7 @@ grep table_id=10 | wc -l`])
-
- check_row_count MAC_Binding 1
-
--OVS_WAIT_UNTIL([ovn-sbctl --format=csv --bare --columns logical_port,ip,mac \
-+OVS_WAIT_FOR_OUTPUT([ovn-sbctl --format=csv --bare --columns logical_port,ip,mac \
- list mac_binding], [0], [lr0-sw0
- 10.0.0.30
- 50:54:00:00:00:13
-@@ -23820,7 +24257,7 @@ OVS_WAIT_UNTIL(
- | wc -l`]
- )
-
--OVS_WAIT_UNTIL([ovn-sbctl --format=csv --bare --columns logical_port,ip,mac \
-+OVS_WAIT_FOR_OUTPUT([ovn-sbctl --format=csv --bare --columns logical_port,ip,mac \
- find mac_binding ip=10.0.0.50], [0], [lr0-sw0
- 10.0.0.50
- 50:54:00:00:00:33
-@@ -24377,7 +24814,7 @@ AT_CAPTURE_FILE([sbflows2])
- OVS_WAIT_FOR_OUTPUT(
- [ovn-sbctl dump-flows > sbflows2
- ovn-sbctl dump-flows lr0 | grep ct_lb_mark | grep priority=120 | sed 's/table=..//'], 0,
-- [ (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80; hash_fields="ip_dst,ip_src,tcp_dst,tcp_src");)
-+ [ (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80; hash_fields="ip_dst,ip_src,tcp_dst,tcp_src");)
- ])
-
- # get the svc monitor mac.
-@@ -24419,8 +24856,7 @@ AT_CHECK(
- AT_CAPTURE_FILE([sbflows4])
- ovn-sbctl dump-flows lr0 > sbflows4
- AT_CHECK([grep lr_in_dnat sbflows4 | grep priority=120 | sed 's/table=..//' | sort], [0], [dnl
-- (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;)
-- (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && is_chassis_resident("cr-lr0-public")), action=(drop;)
-+ (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80 && is_chassis_resident("cr-lr0-public")), action=(drop;)
- ])
-
- # Delete sw0-p1
-@@ -24576,7 +25012,7 @@ AT_CAPTURE_FILE([sbflows2])
- OVS_WAIT_FOR_OUTPUT(
- [ovn-sbctl dump-flows > sbflows2
- ovn-sbctl dump-flows lr0 | grep ct_lb_mark | grep priority=120 | sed 's/table=..//'], 0,
-- [ (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip6 && xxreg0 == 2001::a && tcp && reg9[[16..31]] == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=[[2001::3]]:80,[[2002::3]]:80; hash_fields="ip_dst,ip_src,tcp_dst,tcp_src");)
-+ [ (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip6 && ip6.dst == 2001::a && tcp && tcp.dst == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=[[2001::3]]:80,[[2002::3]]:80; hash_fields="ip_dst,ip_src,tcp_dst,tcp_src");)
- ])
-
- # get the svc monitor mac.
-@@ -24618,8 +25054,7 @@ AT_CHECK(
- AT_CAPTURE_FILE([sbflows4])
- ovn-sbctl dump-flows lr0 > sbflows4
- AT_CHECK([grep lr_in_dnat sbflows4 | grep priority=120 | sed 's/table=..//' | sort], [0], [dnl
-- (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip6 && xxreg0 == 2001::a && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;)
-- (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip6 && xxreg0 == 2001::a && tcp && reg9[[16..31]] == 80 && is_chassis_resident("cr-lr0-public")), action=(drop;)
-+ (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip6 && ip6.dst == 2001::a && tcp && tcp.dst == 80 && is_chassis_resident("cr-lr0-public")), action=(drop;)
- ])
-
- # Delete sw0-p1
-@@ -25447,7 +25882,7 @@ for s_az in $(seq 1 $n_az); do
- udp && udp.src==53 && udp.dst==4369"
- echo "sending: $packet"
- AT_CHECK([ovn_trace --ovs "$packet" > ${s_az}-${d_az}-$i.ovn-trace])
-- AT_CHECK([ovs-appctl -t ovn-controller inject-pkt "$packet"])
-+ OVS_WAIT_UNTIL([ovs-appctl -t ovn-controller inject-pkt "$packet"])
- ovs_inport=$(ovs-vsctl --bare --columns=ofport find Interface external-ids:iface-id="$ovn_inport")
-
- ovs_packet=$(echo $packet | ovstest test-ovn expr-to-packets)
-@@ -26002,7 +26437,7 @@ for i in $(seq 5001 5010); do
- packet="inport==\"lsp11\" && eth.src==f0:00:00:00:01:11 && eth.dst==00:00:00:01:01:01 &&
- ip4 && ip.ttl==64 && ip4.src==192.168.1.11 && ip4.dst==10.0.0.123 &&
- tcp && tcp.src==$i && tcp.dst==80"
-- AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-+ OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- for j in 1 2; do
- # Assume all packets go to lsp2${j}.
-@@ -26121,7 +26556,7 @@ wait_for_ports_up
- # Test 1
- packet="inport==\"lsp11\" && eth.src==f0:00:00:00:01:11 && eth.dst==00:00:00:01:01:01 &&
- ip4 && ip.ttl==64 && ip4.src==192.168.1.11 && ip4.dst==2.2.2.2 && icmp"
--AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-+OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Assume no packets go neither to lsp21 nor to lsp22.
- > expected_lsp21
-@@ -26151,7 +26586,7 @@ done
- # Test 2
- packet="inport==\"lsp11\" && eth.src==f0:00:00:00:01:11 && eth.dst==00:00:00:01:01:01 &&
- ip4 && ip.ttl==64 && ip4.src==192.168.1.11 && ip4.dst==1.1.1.1 && icmp"
--AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-+OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Assume all packets go to lsp22.
- exp_packet="eth.src==00:00:00:01:02:01 && eth.dst==f0:00:00:00:02:22 &&
-@@ -26181,7 +26616,7 @@ done
- # Test 3
- packet="inport==\"lsp21\" && eth.src==f0:00:00:00:02:21 && eth.dst==00:00:00:01:02:01 &&
- ip4 && ip.ttl==64 && ip4.src==192.168.2.21 && ip4.dst==2.2.2.2 && icmp"
--AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-+OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Assume all packets go to lsp21.
- exp_packet="eth.src==00:00:00:01:02:01 && eth.dst==f0:00:00:00:02:21 &&
-@@ -26278,7 +26713,7 @@ wait_for_ports_up
- # test 1
- packet="inport==\"lsp11\" && eth.src==f0:00:00:00:01:11 && eth.dst==00:00:00:01:01:01 &&
- ip4 && ip.ttl==64 && ip4.src==192.168.1.11 && ip4.dst==192.168.2.21 && icmp"
--AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-+OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Assume all packets go to lsp21.
- exp_packet="eth.src==00:00:00:01:02:01 && eth.dst==f0:00:00:00:02:21 && ip4 &&
-@@ -26312,7 +26747,7 @@ ovs-vsctl set interface hv1-vif2 options:tx_pcap=hv1/vif2-tx.pcap
- # test 2
- packet="inport==\"lsp11\" && eth.src==f0:00:00:00:01:11 && eth.dst==00:00:00:01:01:01 &&
- ip4 && ip.ttl==64 && ip4.src==192.168.1.11 && ip4.dst==192.168.2.200 && icmp"
--AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-+OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Assume all packets go to lsp11.
- exp_packet="eth.src==00:00:00:01:01:01 && eth.dst==f0:00:00:00:01:11 && ip4 &&
-@@ -26417,7 +26852,7 @@ for i in $(seq 1 2); do
- packet="inport==\"lsp${i}1\" && eth.src==f0:00:00:00:0${i}:1${i} &&
- eth.dst==00:00:00:01:0${i}:01 && ip4 && ip.ttl==64 &&
- ip4.src==192.168.${i}.${i}1 && ip4.dst==10.0.0.1 && icmp"
-- AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-+ OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Assume all packets go to lsp${di}1.
- exp_packet="eth.src==00:00:00:01:0${di}:01 && eth.dst==f0:00:00:00:0${di}:1${di} &&
-@@ -26530,7 +26965,7 @@ for i in $(seq 1 2); do
- packet="inport==\"lsp${i}1\" && eth.src==f0:00:00:00:0${i}:1${i} &&
- eth.dst==00:00:00:01:0${i}:01 && ip6 && ip.ttl==64 &&
- ip6.src==2001:db8:${i}::${i}1 && ip6.dst==2001:db8:2000::1 && icmp6"
-- AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-+ OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Assume all packets go to lsp${di}1.
- exp_packet="eth.src==00:00:00:01:0${di}:01 && eth.dst==f0:00:00:00:0${di}:1${di} && ip6 &&
-@@ -26650,7 +27085,7 @@ dst_ip=172.16.1.11
- packet="inport==\"lsp11\" && eth.src==$src_mac && eth.dst==$dst_mac &&
- ip4 && ip.ttl==64 && ip4.src==$src_ip && ip4.dst==$dst_ip &&
- udp && udp.src==53 && udp.dst==4369"
--check as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Check if the packet hit the forwarding group policy
- AT_CAPTURE_FILE([offlows2])
-@@ -27173,7 +27608,7 @@ ovn_attach n1 br-phys 192.168.0.1
-
- # Chassis hv1 should add flows for the ls1 datapath in table 8 (ls_in_port_sec_l2).
- dp_key=$(ovn-sbctl --bare --columns tunnel_key list Datapath_Binding ls1)
--OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int | grep -E "table=8.*metadata=0x${dp_key}"], [0], [ignore])
-+OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int | grep -E "table=8.*metadata=0x${dp_key}"])
-
- OVN_CLEANUP([hv1])
- AT_CLEANUP
-@@ -27199,7 +27634,7 @@ ovs-vsctl add-br br-phys
- ovn_attach n1 br-phys 192.168.0.1
-
- # Port_Binding should be released.
--OVS_WAIT_UNTIL([test 0 = $(ovn-sbctl show | grep Port_Binding -c)], [0])
-+OVS_WAIT_UNTIL([test 0 = $(ovn-sbctl show | grep Port_Binding -c)])
-
- OVN_CLEANUP([hv1])
- AT_CLEANUP
-@@ -27332,22 +27767,24 @@ sleep 5
- send_ipv4_pkt() {
- local hv=$1 inport=$2 eth_src=$3 eth_dst=$4
- local ip_src=$5 ip_dst=$6
-- packet=${eth_dst}${eth_src}08004500001c0000000040110000${ip_src}${ip_dst}0035111100080000
-+ local ip_cksum=$7 tcp_cksum=$8
-+ packet=${eth_dst}${eth_src}080045000028000000004006${ip_cksum}${ip_src}${ip_dst}0035111112345678000000005002faf0${tcp_cksum}0000
- tcpdump_hex $packet
- as $hv ovs-appctl netdev-dummy/receive ${inport} ${packet}
- }
-
- send_icmp6_packet() {
-- local hv=$1 inport=$2 eth_src=$3 eth_dst=$4 ipv6_src=$5 ipv6_dst=$6
-+ local hv=$1 inport=$2 eth_src=$3 eth_dst=$4 ipv6_src=$5 ipv6_dst=$6 tcp_cksum=$7
-
-- local ip6_hdr=6000000000083aff${ipv6_src}${ipv6_dst}
-- local packet=${eth_dst}${eth_src}86dd${ip6_hdr}8000dcb662f00001
-+ local ip6_hdr=60000000001406ff${ipv6_src}${ipv6_dst}
-+ local packet=${eth_dst}${eth_src}86dd${ip6_hdr}0035111112345678000000005002faf0${tcp_cksum}0000
-
- as $hv ovs-appctl netdev-dummy/receive ${inport} ${packet}
- }
-
- send_ipv4_pkt hv1 hv1-vif1 505400000003 00000000ff01 \
-- $(ip_to_hex 10 0 0 3) $(ip_to_hex 172 168 0 120)
-+ $(ip_to_hex 10 0 0 3) $(ip_to_hex 172 168 0 120) \
-+ c3ad 83dc
-
- AT_CAPTURE_FILE([offlows2])
- OVS_WAIT_UNTIL([
-@@ -27364,7 +27801,8 @@ AT_CHECK([
-
- # Send the pkt from sw0-port2. Packet should not be marked.
- send_ipv4_pkt hv1 hv1-vif2 505400000004 00000000ff01 \
-- $(ip_to_hex 10 0 0 4) $(ip_to_hex 172 168 0 120)
-+ $(ip_to_hex 10 0 0 4) $(ip_to_hex 172 168 0 120) \
-+ c3ac 83db
-
- AT_CHECK([
- test 1 -eq $(as hv1 ovs-ofctl dump-flows br-phys table=0 | \
-@@ -27398,7 +27836,8 @@ AT_CHECK([
-
- ovn-nbctl set logical_router_policy $pol1 options:pkt_mark=2
- send_ipv4_pkt hv1 hv1-vif1 505400000003 00000000ff01 \
-- $(ip_to_hex 10 0 0 3) $(ip_to_hex 172 168 0 120)
-+ $(ip_to_hex 10 0 0 3) $(ip_to_hex 172 168 0 120) \
-+ c3ad 83dc
-
- OVS_WAIT_UNTIL([
- test 1 -eq $(as hv1 ovs-ofctl dump-flows br-int table=23 | \
-@@ -27431,7 +27870,8 @@ AT_CHECK([
- # Send with src ip 10.0.0.5. The reroute policy should be hit
- # and the packet should be marked with 5.
- send_ipv4_pkt hv1 hv1-vif1 505400000003 00000000ff01 \
-- $(ip_to_hex 10 0 0 5) $(ip_to_hex 172 168 0 120)
-+ $(ip_to_hex 10 0 0 5) $(ip_to_hex 172 168 0 120) \
-+ c3ab 83da
-
- OVS_WAIT_UNTIL([
- test 1 -eq $(as hv1 ovs-ofctl dump-flows br-phys table=0 | \
-@@ -27443,7 +27883,7 @@ OVS_WAIT_UNTIL([
- src_ip6=aef00000000000000000000000000004
- dst_ip6=bef00000000000000000000000000004
-
--send_icmp6_packet hv1 hv1-vif2 505400000004 00000000ff01 ${src_ip6} ${dst_ip6}
-+send_icmp6_packet hv1 hv1-vif2 505400000004 00000000ff01 ${src_ip6} ${dst_ip6} cd16
-
- OVS_WAIT_UNTIL([
- test 1 -eq $(as hv1 ovs-ofctl dump-flows br-phys table=0 | \
-@@ -27463,7 +27903,7 @@ AT_CHECK([
- src_ip6=aef00000000000000000000000000004
- dst_ip6=bef00000000000000000000000000005
-
--send_icmp6_packet hv1 hv1-vif2 505400000004 00000000ff01 ${src_ip6} ${dst_ip6}
-+send_icmp6_packet hv1 hv1-vif2 505400000004 00000000ff01 ${src_ip6} ${dst_ip6} cd15
-
- OVS_WAIT_UNTIL([
- test 1 -eq $(as hv1 ovs-ofctl dump-flows br-phys table=0 | \
-@@ -27970,22 +28410,22 @@ AT_CHECK([test ! -z $p1_zoneid])
- p2_zoneid=$(as hv1 ovs-vsctl get bridge br-int external_ids:ct-zone-sw0-p2 | sed 's/"//g')
- AT_CHECK([test ! -z $p2_zoneid])
-
--AT_CHECK([test $(ovs-ofctl dump-flows br-int table=38,metadata=${sw0_dpkey},\
-+AT_CHECK([test $(ovs-ofctl dump-flows br-int table=40,metadata=${sw0_dpkey},\
- reg15=0x${p1_dpkey} | grep REG13 | wc -l) -eq 1])
-
--AT_CHECK([test $(ovs-ofctl dump-flows br-int table=38,metadata=${sw0_dpkey},\
-+AT_CHECK([test $(ovs-ofctl dump-flows br-int table=40,metadata=${sw0_dpkey},\
- reg15=0x${p1_dpkey} | grep "load:0x${p1_zoneid}->NXM_NX_REG13" | wc -l) -eq 1])
-
--AT_CHECK([test $(ovs-ofctl dump-flows br-int table=38,metadata=${sw1_dpkey},\
-+AT_CHECK([test $(ovs-ofctl dump-flows br-int table=40,metadata=${sw1_dpkey},\
- reg15=0x${p2_dpkey} | grep REG13 | wc -l) -eq 1])
-
--AT_CHECK([test $(ovs-ofctl dump-flows br-int table=38,metadata=${sw1_dpkey},\
-+AT_CHECK([test $(ovs-ofctl dump-flows br-int table=40,metadata=${sw1_dpkey},\
- reg15=0x${p2_dpkey} | grep "load:0x${p2_zoneid}->NXM_NX_REG13" | wc -l) -eq 1])
-
- ovs-vsctl set interface hv1-vif1 external_ids:iface-id=foo
- OVS_WAIT_UNTIL([test x$(ovn-nbctl lsp-get-up sw0-p1) = xdown])
-
--AT_CHECK([test $(ovs-ofctl dump-flows br-int table=38,metadata=${sw0_dpkey},\
-+AT_CHECK([test $(ovs-ofctl dump-flows br-int table=40,metadata=${sw0_dpkey},\
- reg15=0x${p1_dpkey} | grep REG13 | wc -l) -eq 0])
-
- p1_zoneid=$(as hv1 ovs-vsctl get bridge br-int external_ids:ct-zone-sw0-p1 | sed 's/"//g')
-@@ -27997,16 +28437,16 @@ OVS_WAIT_UNTIL([test x$(ovn-nbctl lsp-get-up sw0-p1) = xup])
- p1_zoneid=$(as hv1 ovs-vsctl get bridge br-int external_ids:ct-zone-sw0-p1 | sed 's/"//g')
- AT_CHECK([test ! -z $p1_zoneid])
-
--AT_CHECK([test $(ovs-ofctl dump-flows br-int table=38,metadata=${sw0_dpkey},\
-+AT_CHECK([test $(ovs-ofctl dump-flows br-int table=40,metadata=${sw0_dpkey},\
- reg15=0x${p1_dpkey} | grep REG13 | wc -l) -eq 1])
-
--AT_CHECK([test $(ovs-ofctl dump-flows br-int table=38,metadata=${sw0_dpkey},\
-+AT_CHECK([test $(ovs-ofctl dump-flows br-int table=40,metadata=${sw0_dpkey},\
- reg15=0x${p1_dpkey} | grep "load:0x${p1_zoneid}->NXM_NX_REG13" | wc -l) -eq 1])
-
- ovs-vsctl del-port hv1-vif2
- OVS_WAIT_UNTIL([test x$(ovn-nbctl lsp-get-up sw0-p2) = xdown])
-
--AT_CHECK([test $(ovs-ofctl dump-flows br-int table=38,metadata=${sw0_dpkey},\
-+AT_CHECK([test $(ovs-ofctl dump-flows br-int table=40,metadata=${sw0_dpkey},\
- reg15=0x${p2_dpkey} | grep REG13 | wc -l) -eq 0])
-
- p2_zoneid=$(as hv1 ovs-vsctl get bridge br-int external_ids:ct-zone-sw0-p2 | sed 's/"//g')
-@@ -28014,7 +28454,7 @@ AT_CHECK([test -z $p2_zoneid])
-
- ovn-nbctl lsp-del sw0-p1
-
--OVS_WAIT_UNTIL([test $(ovs-ofctl dump-flows br-int table=38,metadata=${sw0_dpkey},\
-+OVS_WAIT_UNTIL([test $(ovs-ofctl dump-flows br-int table=40,metadata=${sw0_dpkey},\
- reg15=0x${p1_dpkey} | grep REG13 | wc -l) -eq 0])
-
- p1_zoneid=$(as hv1 ovs-vsctl get bridge br-int external_ids:ct-zone-sw0-p1 | sed 's/"//g')
-@@ -28737,7 +29177,7 @@ src_mac="f00000000102"
- dst_mac="000000000101"
- src_ip=`ip_to_hex 10 0 1 2`
- dst_ip=`ip_to_hex 10 0 1 1`
--packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000
-+packet=${dst_mac}${src_mac}08004500001c00000000401164cf${src_ip}${dst_ip}0035111100080000
- as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet
-
- # Even after configuring a router owned IP for SNAT, no packet-ins should
-@@ -28763,7 +29203,7 @@ src_mac="f00000000202"
- dst_mac="000000000201"
- src_ip=`ip_to_hex 10 0 2 2`
- dst_ip=`ip_to_hex 10 0 1 1`
--packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000
-+packet=${dst_mac}${src_mac}08004500001c00000000401163cf${src_ip}${dst_ip}0035111100080000
- as hv1 ovs-appctl netdev-dummy/receive hv1-vif2 $packet
-
- # Still no packet-ins should reach ovn-controller.
-@@ -29548,7 +29988,9 @@ OVS_WAIT_UNTIL([test x$(ovn-nbctl lsp-get-up sw1-p1) = xup])
-
- check ovn-nbctl lb-add lb-ipv4-tcp 88.88.88.88:8080 42.42.42.1:4041 tcp
- check ovn-nbctl lb-add lb-ipv4-udp 88.88.88.88:4040 42.42.42.1:2021 udp
-+check ovn-nbctl lb-add lb-ipv4 88.88.88.89 42.42.42.2
- check ovn-nbctl lb-add lb-ipv6-tcp [[8800::0088]]:8080 [[4200::1]]:4041 tcp
-+check ovn-nbctl lb-add lb-ipv6 8800::0089 4200::2
- check ovn-nbctl --wait=hv lb-add lb-ipv6-udp [[8800::0088]]:4040 [[4200::1]]:2021 udp
-
- AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=68 | grep -v NXST], [1], [dnl
-@@ -29839,6 +30281,119 @@ AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=70 | ofctl_strip_all | grep -
- table=70, priority=100,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=8800::88))
- ])
-
-+check ovn-nbctl --wait=hv ls-lb-add sw0 lb-ipv4
-+OVS_WAIT_UNTIL(
-+ [test $(as hv1 ovs-ofctl dump-flows br-int table=68 | grep -c -v NXST) -eq 7]
-+)
-+
-+OVS_WAIT_UNTIL(
-+ [test $(as hv2 ovs-ofctl dump-flows br-int table=68 | grep -c -v NXST) -eq 7]
-+)
-+
-+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=68 | ofctl_strip_all | grep -v NXST], [0], [dnl
-+ table=68, priority=100,ct_mark=0x2/0x2,ip,reg1=0x58585859,nw_src=42.42.42.2,nw_dst=42.42.42.2 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.89,NXM_OF_IP_PROTO[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+])
-+
-+AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=69 | grep -v NXST], [1], [dnl
-+])
-+
-+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=70 | ofctl_strip_all | grep -v NXST], [0], [dnl
-+ table=70, priority=100,tcp,reg1=0x58585858,reg2=0x1f90/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.88))
-+ table=70, priority=100,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.90))
-+ table=70, priority=100,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=8800::88))
-+ table=70, priority=100,udp,reg1=0x58585858,reg2=0xfc8/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.88))
-+ table=70, priority=100,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=8800::88))
-+ table=70, priority=90,ip,reg1=0x58585859 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.89))
-+])
-+
-+AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=68 | ofctl_strip_all | grep -v NXST], [0], [dnl
-+ table=68, priority=100,ct_mark=0x2/0x2,ip,reg1=0x58585859,nw_src=42.42.42.2,nw_dst=42.42.42.2 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.89,NXM_OF_IP_PROTO[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+])
-+
-+AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=69 | grep -v NXST], [1], [dnl
-+])
-+
-+AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=70 | ofctl_strip_all | grep -v NXST], [0], [dnl
-+ table=70, priority=100,tcp,reg1=0x58585858,reg2=0x1f90/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.88))
-+ table=70, priority=100,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.90))
-+ table=70, priority=100,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=8800::88))
-+ table=70, priority=100,udp,reg1=0x58585858,reg2=0xfc8/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.88))
-+ table=70, priority=100,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=8800::88))
-+ table=70, priority=90,ip,reg1=0x58585859 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.89))
-+])
-+
-+check ovn-nbctl --wait=hv ls-lb-add sw0 lb-ipv6
-+OVS_WAIT_UNTIL(
-+ [test $(as hv1 ovs-ofctl dump-flows br-int table=68 | grep -c -v NXST) -eq 8]
-+)
-+
-+OVS_WAIT_UNTIL(
-+ [test $(as hv2 ovs-ofctl dump-flows br-int table=68 | grep -c -v NXST) -eq 8]
-+)
-+
-+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=68 | ofctl_strip_all | grep -v NXST], [0], [dnl
-+ table=68, priority=100,ct_mark=0x2/0x2,ip,reg1=0x58585859,nw_src=42.42.42.2,nw_dst=42.42.42.2 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.89,NXM_OF_IP_PROTO[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,ipv6,reg4=0x88000000,reg5=0,reg6=0,reg7=0x89,ipv6_src=4200::2,ipv6_dst=4200::2 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::89,NXM_OF_IP_PROTO[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+])
-+
-+AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=69 | grep -v NXST], [1], [dnl
-+])
-+
-+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=70 | ofctl_strip_all | grep -v NXST], [0], [dnl
-+ table=70, priority=100,tcp,reg1=0x58585858,reg2=0x1f90/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.88))
-+ table=70, priority=100,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.90))
-+ table=70, priority=100,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=8800::88))
-+ table=70, priority=100,udp,reg1=0x58585858,reg2=0xfc8/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.88))
-+ table=70, priority=100,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=8800::88))
-+ table=70, priority=90,ip,reg1=0x58585859 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.89))
-+ table=70, priority=90,ipv6,reg4=0x88000000,reg5=0,reg6=0,reg7=0x89 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=8800::89))
-+])
-+
-+AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=68 | ofctl_strip_all | grep -v NXST], [0], [dnl
-+ table=68, priority=100,ct_mark=0x2/0x2,ip,reg1=0x58585859,nw_src=42.42.42.2,nw_dst=42.42.42.2 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.89,NXM_OF_IP_PROTO[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,ipv6,reg4=0x88000000,reg5=0,reg6=0,reg7=0x89,ipv6_src=4200::2,ipv6_dst=4200::2 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::89,NXM_OF_IP_PROTO[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+ table=68, priority=100,ct_mark=0x2/0x2,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]])
-+])
-+
-+AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=69 | grep -v NXST], [1], [dnl
-+])
-+
-+AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=70 | ofctl_strip_all | grep -v NXST], [0], [dnl
-+ table=70, priority=100,tcp,reg1=0x58585858,reg2=0x1f90/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.88))
-+ table=70, priority=100,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.90))
-+ table=70, priority=100,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=8800::88))
-+ table=70, priority=100,udp,reg1=0x58585858,reg2=0xfc8/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.88))
-+ table=70, priority=100,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=8800::88))
-+ table=70, priority=90,ip,reg1=0x58585859 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.89))
-+ table=70, priority=90,ipv6,reg4=0x88000000,reg5=0,reg6=0,reg7=0x89 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=8800::89))
-+])
-+
-+check ovn-nbctl --wait=hv ls-lb-del sw0 lb-ipv4
-+check ovn-nbctl --wait=hv ls-lb-del sw0 lb-ipv6
-+
- # Check backwards compatibility with ovn-northd versions that don't store the
- # original destination tuple.
- #
-@@ -30354,46 +30909,46 @@ AT_CHECK([kill -0 $(cat hv1/ovn-controller.pid)])
- check ovn-nbctl --wait=hv sync
-
- # Check OVS flows are installed properly.
--AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=44 | ofctl_strip_all | \
-+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=46 | ofctl_strip_all | \
- grep "priority=2002" | grep conjunction | \
- sed 's/conjunction([[^)]]*)/conjunction()/g' | \
- sed 's/reg15=0x[[1-9]]/reg15=0xN/g' | sort], [0], [dnl
-- table=44, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x10/0xfff0 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x100/0xff00 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x1000/0xf000 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x2/0xfffe actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x20/0xffe0 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x200/0xfe00 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x2000/0xe000 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x4/0xfffc actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x40/0xffc0 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x400/0xfc00 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x4000/0xc000 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x8/0xfff8 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x80/0xff80 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x800/0xf800 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x8000/0x8000 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=1 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x100/0x100,reg15=0xN,metadata=0x1,nw_src=192.168.47.4 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x100/0x100,reg15=0xN,metadata=0x1,nw_src=192.168.47.4 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x10/0xfff0 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x100/0xff00 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x1000/0xf000 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x2/0xfffe actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x20/0xffe0 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x200/0xfe00 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x2000/0xe000 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x4/0xfffc actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x40/0xffc0 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x400/0xfc00 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x4000/0xc000 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x8/0xfff8 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x80/0xff80 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x800/0xf800 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x8000/0x8000 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=1 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x80/0x80,reg15=0xN,metadata=0x1,nw_src=192.168.47.4 actions=conjunction()
-- table=44, priority=2002,udp,reg0=0x80/0x80,reg15=0xN,metadata=0x1,nw_src=192.168.47.4 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x10/0xfff0 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x100/0xff00 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x1000/0xf000 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x2/0xfffe actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x20/0xffe0 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x200/0xfe00 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x2000/0xe000 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x4/0xfffc actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x40/0xffc0 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x400/0xfc00 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x4000/0xc000 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x8/0xfff8 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x80/0xff80 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x800/0xf800 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x8000/0x8000 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x100/0x100,metadata=0x1,nw_src=192.168.47.4,tp_dst=1 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x100/0x100,reg15=0xN,metadata=0x1,nw_src=192.168.47.4 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x100/0x100,reg15=0xN,metadata=0x1,nw_src=192.168.47.4 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x10/0xfff0 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x100/0xff00 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x1000/0xf000 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x2/0xfffe actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x20/0xffe0 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x200/0xfe00 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x2000/0xe000 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x4/0xfffc actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x40/0xffc0 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x400/0xfc00 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x4000/0xc000 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x8/0xfff8 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x80/0xff80 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x800/0xf800 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=0x8000/0x8000 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x80/0x80,metadata=0x1,nw_src=192.168.47.4,tp_dst=1 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x80/0x80,reg15=0xN,metadata=0x1,nw_src=192.168.47.4 actions=conjunction()
-+ table=46, priority=2002,udp,reg0=0x80/0x80,reg15=0xN,metadata=0x1,nw_src=192.168.47.4 actions=conjunction()
- ])
-
- OVN_CLEANUP([hv1])
-@@ -31568,7 +32123,7 @@ ovs-vsctl add-port br-int lsp0-0 -- set interface lsp0-0 external_ids:iface-id=l
- ovs-vsctl add-port br-int lsp0-1 -- set interface lsp0-1 external_ids:iface-id=lsp0-1
-
- check ovn-nbctl --wait=hv sync
--AT_CHECK([test $(ovs-ofctl dump-flows br-int table=44 | grep conjunction | wc -l) == 22])
-+AT_CHECK([test $(ovs-ofctl dump-flows br-int table=46 | grep conjunction | wc -l) == 22])
-
- # Save the current lflow_run counter
- lflow_run=$(ovn-appctl -t ovn-controller coverage/read-counter lflow_run)
-@@ -31578,7 +32133,7 @@ lflow_run=$(ovn-appctl -t ovn-controller coverage/read-counter lflow_run)
- # 1. Remove half of the ports from pg1. The excepted conjunction flows should be:
- # 2 + 10 = 12
- check ovn-nbctl --wait=hv pg-set-ports pg1 $(for i in 0 1 2 3 4; do for j in 0 1; do echo lsp${i}-${j}; done; done)
--AT_CHECK([test $(ovs-ofctl dump-flows br-int table=44 | grep conjunction | wc -l) == 12])
-+AT_CHECK([test $(ovs-ofctl dump-flows br-int table=46 | grep conjunction | wc -l) == 12])
-
- # 2. Unbind lsp0-0. The there shouldn't be any conjunction flows because the
- # port group const set should have only one member (lsp0-1). And the total
-@@ -31586,25 +32141,25 @@ AT_CHECK([test $(ovs-ofctl dump-flows br-int table=44 | grep conjunction | wc -l
- # 10.
- ovs-vsctl del-port br-int lsp0-0
- check ovn-nbctl --wait=hv sync
--AT_CHECK([test $(ovs-ofctl dump-flows br-int table=44 | grep conjunction | wc -l) == 0])
--AT_CHECK([test $(ovs-ofctl dump-flows br-int table=44 | grep 192.168 | wc -l) == 10])
-+AT_CHECK([test $(ovs-ofctl dump-flows br-int table=46 | grep conjunction | wc -l) == 0])
-+AT_CHECK([test $(ovs-ofctl dump-flows br-int table=46 | grep 192.168 | wc -l) == 10])
-
- # 3. Rebind lsp0-0. The expected conjunction flows are back to 12.
- ovs-vsctl add-port br-int lsp0-0 -- set interface lsp0-0 external_ids:iface-id=lsp0-0
- check ovn-nbctl --wait=hv sync
--AT_CHECK([test $(ovs-ofctl dump-flows br-int table=44 | grep conjunction | wc -l) == 12])
-+AT_CHECK([test $(ovs-ofctl dump-flows br-int table=46 | grep conjunction | wc -l) == 12])
-
- # 4. Bind a lsp (lsp9-0) that doesn't belong to pg1, should not see any change.
- ovs-vsctl add-port br-int lsp9-0 -- set interface lsp9-0 external_ids:iface-id=lsp9-0
- check ovn-nbctl --wait=hv sync
--AT_CHECK([test $(ovs-ofctl dump-flows br-int table=44 | grep conjunction | wc -l) == 12])
-+AT_CHECK([test $(ovs-ofctl dump-flows br-int table=46 | grep conjunction | wc -l) == 12])
-
- # 5. Bind another 2 lsps (lsp1-0 lsp1-1) that belong to pg1 and on a different
- # LS (ls1), should see conjunction flows doubled (12 x 2 = 24)
- ovs-vsctl add-port br-int lsp1-0 -- set interface lsp1-0 external_ids:iface-id=lsp1-0
- ovs-vsctl add-port br-int lsp1-1 -- set interface lsp1-1 external_ids:iface-id=lsp1-1
- check ovn-nbctl --wait=hv sync
--AT_CHECK([test $(ovs-ofctl dump-flows br-int table=44 | grep conjunction | wc -l) == 24])
-+AT_CHECK([test $(ovs-ofctl dump-flows br-int table=46 | grep conjunction | wc -l) == 24])
-
- # 6. Simulate a SB port-group "del and add" notification to ovn-controller in the
- # same IDL iteration. ovn-controller should still program the same flows. In
-@@ -31629,7 +32184,7 @@ for i in $(seq 1 10); do
- check ovn-nbctl --wait=hv sync
-
- # Finally check flow count is the same as before.
-- AT_CHECK([test $(ovs-ofctl dump-flows br-int table=44 | grep conjunction | wc -l) == 24])
-+ AT_CHECK([test $(ovs-ofctl dump-flows br-int table=46 | grep conjunction | wc -l) == 24])
- done
-
- # Make sure all the above was performed with I-P (no recompute)
-@@ -31743,7 +32298,7 @@ packet="inport==\"sw1-lp1\" && eth.src==00:00:04:01:02:03 &&
- ip4.src==10.0.0.100 && ip4.dst==20.0.0.200 &&
- udp && udp.src==53 && udp.dst==4369"
-
--as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Check if packet hit the drop rule
- AT_CHECK([ovs-ofctl dump-flows br-int | grep "nw_dst=20.0.0.0/24" | \
-@@ -31770,7 +32325,7 @@ packet="inport==\"sw1-lp1\" && eth.src==00:00:04:01:02:03 &&
- ip4.src==10.0.0.100 && ip4.dst==20.0.0.200 &&
- udp && udp.src==53 && udp.dst==4369"
-
--as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"])
-
- # Check if packet hit the drop rule
- AT_CHECK([ovs-ofctl dump-flows br-int "nw_src=10.0.0.0/24" | \
-@@ -31857,7 +32412,7 @@ packet="inport==\"ls1-lp1\" && eth.src==$ls1_p1_mac && eth.dst==$bcast_mac &&
- arp.op==1 && arp.sha==$ls1_p1_mac && arp.spa==$ls1_p1_ip &&
- arp.tha==$bcast_mac && arp.tpa==$proxy_ip1"
-
--as hv1 ovn-appctl -t ovn-controller inject-pkt "$packet"
-+OVS_WAIT_UNTIL([as hv1 ovn-appctl -t ovn-controller inject-pkt "$packet"])
-
- as hv1 ovs-ofctl dump-flows br-int| grep 169.254.239.254 | grep priority=50 > debug1
- AT_CAPTURE_FILE([debug1])
-@@ -31916,8 +32471,8 @@ check ovn-nbctl acl-add lsw0 to-lport 1002 'outport == "lp2" && ip4.src == 10.0.
-
- # The first ACL should be programmed, but the second one shouldn't.
- check ovn-nbctl --wait=hv sync
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10.0.0.111], [0], [ignore])
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10.0.0.122], [1], [ignore])
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep 10.0.0.111], [0], [ignore])
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep 10.0.0.122], [1], [ignore])
-
- # Now create the lport lp2.
- check ovn-nbctl lsp-add lsw0 lp2 \
-@@ -31925,12 +32480,12 @@ check ovn-nbctl lsp-add lsw0 lp2 \
-
- check ovn-nbctl --wait=hv sync
- # Now the second ACL should be programmed.
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10.0.0.122], [0], [ignore])
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep 10.0.0.122], [0], [ignore])
-
- # Remove the lport lp2 again, the OVS flow for the second ACL should be
- # removed.
- check ovn-nbctl --wait=hv lsp-del lp2
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10.0.0.122], [1], [ignore])
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep 10.0.0.122], [1], [ignore])
-
- # Test similar scenario but when the referenced lport is not bound locally.
-
-@@ -31944,8 +32499,8 @@ check ovn-nbctl acl-add lsw0 to-lport 1002 'inport == "lp4" && ip4.dst == 10.0.0
-
- # The ACL for lp3 should be programmed, but the one for lp4 shouldn't.
- check ovn-nbctl --wait=hv sync
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10.0.0.133], [0], [ignore])
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10.0.0.144], [1], [ignore])
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep 10.0.0.133], [0], [ignore])
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep 10.0.0.144], [1], [ignore])
-
- # Now create the lport lp4.
- check ovn-nbctl lsp-add lsw0 lp4 \
-@@ -31953,7 +32508,7 @@ check ovn-nbctl lsp-add lsw0 lp4 \
-
- # Now the ACL for lp4 should be programmed.
- check ovn-nbctl --wait=hv sync
--AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep 10.0.0.144], [0], [ignore])
-+AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep 10.0.0.144], [0], [ignore])
-
- OVN_CLEANUP([hv1])
- AT_CLEANUP
-@@ -32108,7 +32663,6 @@ ovn-nbctl lrp-set-gateway-chassis DR-S3 hv4
-
- ovn-nbctl --wait=sb sync
- OVN_POPULATE_ARP
--
- vif_to_ls () {
- case ${1} in dnl (
- vif?[[11]]) echo ls ;; dnl (
-@@ -32222,6 +32776,9 @@ echo "Send Dummy ARP"
- sip=`ip_to_hex 172 16 1 10`
- tip=`ip_to_hex 172 16 1 50`
- test_arp vif-north1 f0f000000011 $sip $tip
-+OVS_WAIT_UNTIL(
-+ [test 1 = `as hv1 ovs-ofctl dump-flows br-int table=67 | grep dl_src=f0:f0:00:00:00:11 | wc -l`]
-+)
-
- echo "Send traffic North to South"
- sip=`ip_to_hex 172 16 1 10`
-@@ -32242,6 +32799,9 @@ echo "Send Dummy ARP"
- sip=`ip_to_hex 10 0 0 10`
- tip=`ip_to_hex 10 0 0 50`
- test_arp vif-north2 f0f000000022 $sip $tip
-+OVS_WAIT_UNTIL(
-+ [test 1 = `as hv1 ovs-ofctl dump-flows br-int table=67 | grep dl_src=f0:f0:00:00:00:22 | wc -l`]
-+)
-
- echo "Send traffic South to North2"
- sip=`ip_to_hex 20 0 0 10`
-@@ -32255,6 +32815,9 @@ echo "Send Dummy ARP"
- sip=`ip_to_hex 192 168 0 10`
- tip=`ip_to_hex 192 168 0 50`
- test_arp vif-north3 f0f000000033 $sip $tip
-+OVS_WAIT_UNTIL(
-+ [test 1 = `as hv1 ovs-ofctl dump-flows br-int table=67 | grep dl_src=f0:f0:00:00:00:33 | wc -l`]
-+)
-
- echo "Send traffic South to North3"
- sip=`ip_to_hex 20 0 0 10`
-@@ -33384,7 +33947,7 @@ check ovn-nbctl --wait=hv sync
- # Use constants so that if tables or registers change, this test can
- # be updated easily.
- DNAT_TABLE=15
--SNAT_TABLE=43
-+SNAT_TABLE=45
- DNAT_ZONE_REG="NXM_NX_REG11[[0..15]]"
- SNAT_ZONE_REG="NXM_NX_REG12[[0..15]]"
-
-@@ -33929,6 +34492,7 @@ m4_define([MULTIPLE_OVS_INT],
- ovs-ofctl dump-flows br-int | grep $cookie |
- sed -e 's/duration=[[0-9.]]*s, //g' |
- sed -e 's/idle_age=[[0-9]]*, //g' |
-+ sed -e 's/hard_age=[[0-9]]*, //g' |
- sed -e 's/n_packets=[[0-9]]*, //g' |
- sed -e 's/n_bytes=[[0-9]]*, //g'
- }
-@@ -34926,7 +35490,8 @@ check ovs-vsctl add-port br-int p1 -- set interface p1 external_ids:iface-id=lsp
- wait_for_ports_up
- ovn-nbctl --wait=hv sync
-
--check ovn-nbctl lb-add lb1 "192.168.0.10" "192.168.10.10,192.168.10.20"
-+check ovn-nbctl lb-add lb1 "192.168.0.10" "192.168.10.10,192.168.10.20" \
-+ -- set load_balancer lb1 options:ct_flush="true"
- check ovn-nbctl ls-lb-add sw lb1
-
- # Remove a single backend
-@@ -34949,7 +35514,8 @@ AT_CHECK([grep -q "Flushing CT for 5-tuple: vip=192.168.0.10:0, backend=192.168.
- AT_CHECK([grep -q "Flushing CT for 5-tuple: vip=192.168.0.10:0, backend=192.168.10.30:0, protocol=0" hv1/ovn-controller.log], [0])
-
- # Check flush for LB with port and protocol
--check ovn-nbctl lb-add lb1 "192.168.30.10:80" "192.168.40.10:8080,192.168.40.20:8090" udp
-+check ovn-nbctl lb-add lb1 "192.168.30.10:80" "192.168.40.10:8080,192.168.40.20:8090" udp \
-+ -- set load_balancer lb1 options:ct_flush="true"
- check ovn-nbctl ls-lb-add sw lb1
- check ovn-nbctl lb-del lb1
- check ovn-nbctl --wait=hv sync
-@@ -34958,7 +35524,8 @@ AT_CHECK([grep -q "Flushing CT for 5-tuple: vip=192.168.30.10:80, backend=192.16
- AT_CHECK([grep -q "Flushing CT for 5-tuple: vip=192.168.30.10:80, backend=192.168.40.20:8090, protocol=17" hv1/ovn-controller.log], [0])
-
- # Check recompute when LB is no longer local
--check ovn-nbctl lb-add lb1 "192.168.50.10:80" "192.168.60.10:8080"
-+check ovn-nbctl lb-add lb1 "192.168.50.10:80" "192.168.60.10:8080" \
-+ -- set load_balancer lb1 options:ct_flush="true"
- check ovn-nbctl ls-lb-add sw lb1
- check ovs-vsctl remove interface p1 external_ids iface-id
- check ovn-appctl inc-engine/recompute
-@@ -34968,6 +35535,193 @@ AT_CHECK([grep -q "Flushing CT for 5-tuple: vip=192.168.50.10:80, backend=192.16
-
- AT_CHECK([test "$(grep -c "Flushing CT for 5-tuple" hv1/ovn-controller.log)" = "6"], [0])
-
-+# Check if CT flush is disabled by default
-+check ovn-nbctl lb-del lb1
-+check ovn-nbctl lb-add lb1 "192.168.70.10:80" "192.168.80.10:8080,192.168.90.10:8080"
-+check ovn-nbctl ls-lb-add sw lb1
-+check ovs-vsctl set interface p1 external_ids:iface-id=lsp1
-+check ovn-nbctl --wait=hv sync
-+
-+AT_CHECK([test "$(grep -c "Flushing CT for 5-tuple" hv1/ovn-controller.log)" = "6"], [0])
-+
-+# Remove one backend
-+check ovn-nbctl --wait=hv set load_balancer lb1 vips='"192.168.70.10:80"="192.168.80.10:8080"'
-+
-+AT_CHECK([grep -q "Flushing CT for 5-tuple: vip=192.168.70.10:80, backend=192.168.90.10:8080, protocol=6" hv1/ovn-controller.log], [1])
-+AT_CHECK([test "$(grep -c "Flushing CT for 5-tuple" hv1/ovn-controller.log)" = "6"], [0])
-+
-+check ovn-nbctl --wait=hv lb-del lb1
-+AT_CHECK([grep -q "Flushing CT for 5-tuple: vip=192.168.70.10:80, backend=192.168.80.10:8080, protocol=6" hv1/ovn-controller.log], [1])
-+AT_CHECK([test "$(grep -c "Flushing CT for 5-tuple" hv1/ovn-controller.log)" = "6"], [0])
-+
-+OVN_CLEANUP([hv1])
-+AT_CLEANUP
-+])
-+
-+OVN_FOR_EACH_NORTHD([
-+AT_SETUP([Re-create encap tunnels during integration bridge migration])
-+ovn_start
-+net_add n1
-+
-+sim_add hv1
-+as hv1
-+ovs-vsctl add-br br-phys
-+ovn_attach n1 br-phys 192.168.0.1
-+
-+sim_add hv2
-+as hv2
-+ovs-vsctl add-br br-phys
-+ovn_attach n1 br-phys 192.168.0.2
-+
-+check ovn-nbctl --wait=hv sync
-+
-+check_tunnel_port() {
-+ local hv=$1
-+ local br=$2
-+ local id=$3
-+
-+ as $hv
-+ OVS_WAIT_UNTIL([
-+ test "$(ovs-vsctl --format=table --no-headings find port external_ids:ovn-chassis-id="$id" | wc -l)" = "1"
-+ ])
-+ local tunnel_id=$(ovs-vsctl --bare --columns _uuid find port external_ids:ovn-chassis-id="$id")
-+ AT_CHECK([ovs-vsctl --bare --columns ports find bridge name="$br" | grep -q "$tunnel_id"])
-+}
-+
-+# Check that both chassis have tunnel
-+check_tunnel_port hv1 br-int hv2@192.168.0.2
-+check_tunnel_port hv2 br-int hv1@192.168.0.1
-+
-+# Stop ovn-controller on hv1
-+check as hv1 ovn-appctl -t ovn-controller exit --restart
-+
-+# The tunnel should remain intact
-+check_tunnel_port hv1 br-int hv2@192.168.0.2
-+
-+# Change the bridge to br-int1 on hv1
-+as hv1
-+check ovs-vsctl add-br br-int1
-+check ovs-vsctl set open . external_ids:ovn-bridge="br-int1"
-+start_daemon ovn-controller --verbose="encaps:dbg"
-+check ovn-nbctl --wait=hv sync
-+
-+# Check that the tunnel was created on br-int1 instead
-+check_tunnel_port hv1 br-int1 hv2@192.168.0.2
-+check grep -q "Clearing old tunnel port \"ovn-hv2-0\" (hv2@192.168.0.2) from bridge \"br-int\"" hv1/ovn-controller.log
-+
-+# Change the bridge to br-int1 on hv2
-+as hv2
-+check ovn-appctl vlog/set encaps:dbg
-+check ovs-vsctl add-br br-int1
-+check ovs-vsctl set open . external_ids:ovn-bridge="br-int1"
-+check ovn-nbctl --wait=hv sync
-+
-+
-+# Check that the tunnel was created on br-int1 instead
-+check_tunnel_port hv2 br-int1 hv1@192.168.0.1
-+check grep -q "Clearing old tunnel port \"ovn-hv1-0\" (hv1@192.168.0.1) from bridge \"br-int\"" hv2/ovn-controller.log
-+
-+# Stop ovn-controller on hv1
-+check as hv1 ovn-appctl -t ovn-controller exit --restart
-+
-+# The tunnel should remain intact
-+check_tunnel_port hv1 br-int1 hv2@192.168.0.2
-+prev_id=$(ovs-vsctl --bare --columns _uuid find port external_ids:ovn-chassis-id="hv2@192.168.0.2")
-+
-+# Start the controller again
-+start_daemon ovn-controller --verbose="encaps:dbg"
-+check ovn-nbctl --wait=hv sync
-+check_tunnel_port hv1 br-int1 hv2@192.168.0.2
-+current_id=$(ovs-vsctl --bare --columns _uuid find port external_ids:ovn-chassis-id="hv2@192.168.0.2")
-+
-+# The tunnel should be the same after restart
-+check test "$current_id" = "$prev_id"
-+
-+OVN_CLEANUP([hv1],[hv2])
-+AT_CLEANUP
-+])
-+
-+# NOTE: This test case runs two ovn-controllers inside the same sandbox (hv1).
-+# Each controller uses a unique chassis name - hv1 and hv2 - and manage
-+# different bridges with different ports.
-+OVN_FOR_EACH_NORTHD([
-+AT_SETUP([Encaps tunnel cleanup does not interfere with multiple controller on the same host])
-+ovn_start
-+net_add n1
-+
-+sim_add hv1
-+as hv1
-+ovs-vsctl add-br br-phys-1
-+ovn_attach n1 br-phys-1 192.168.0.1 24
-+
-+
-+# now start the second virtual controller
-+ovs-vsctl add-br br-phys-2
-+
-+
-+# the file is read once at startup so it's safe to write it
-+# here after the first ovn-controller has started
-+echo hv2 > ${OVN_SYSCONFDIR}/system-id-override
-+
-+# for some reason SSL ovsdb configuration overrides CLI, so
-+# delete ssl config from ovsdb to give CLI arguments priority
-+ovs-vsctl del-ssl
-+
-+start_virtual_controller n1 br-phys-2 br-int-2 192.168.0.2 24 geneve,vxlan hv2 \
-+ --pidfile=${OVS_RUNDIR}/ovn-controller-2.pid \
-+ --log-file=${OVS_RUNDIR}/ovn-controller-2.log \
-+ -p $PKIDIR/testpki-hv2-privkey.pem \
-+ -c $PKIDIR/testpki-hv2-cert.pem \
-+ -C $PKIDIR/testpki-cacert.pem
-+pidfile="$OVS_RUNDIR"/ovn-controller-2.pid
-+on_exit "test -e \"$pidfile\" && kill \`cat \"$pidfile\"\`"
-+
-+ovn-nbctl --wait=hv sync
-+
-+check_tunnel_port() {
-+ local hv=$1
-+ local br=$2
-+ local id=$3
-+
-+ as $hv
-+ OVS_WAIT_UNTIL([
-+ test "$(ovs-vsctl --format=table --no-headings find port external_ids:ovn-chassis-id="$id" | wc -l)" = "1"
-+ ])
-+ local tunnel_id=$(ovs-vsctl --bare --columns _uuid find port external_ids:ovn-chassis-id="$id")
-+ AT_CHECK([ovs-vsctl --bare --columns ports find bridge name="$br" | grep -q "$tunnel_id"])
-+}
-+
-+check_tunnel_port hv1 br-int hv2@192.168.0.2
-+check_tunnel_port hv1 br-int-2 hv1@192.168.0.1
-+prev_id1=$(ovs-vsctl --bare --columns _uuid find port external_ids:ovn-chassis-id="hv1@192.168.0.1")
-+prev_id2=$(ovs-vsctl --bare --columns _uuid find port external_ids:ovn-chassis-id="hv2@192.168.0.2")
-+
-+# The hv2 is running we can remove the override file
-+rm -f ${OVN_SYSCONFDIR}/system-id-override
-+
-+check ovn-appctl -t ovn-controller exit --restart
-+
-+# for some reason SSL ovsdb configuration overrides CLI, so
-+# delete ssl config from ovsdb to give CLI arguments priority
-+ovs-vsctl del-ssl
-+
-+start_daemon ovn-controller --verbose="encaps:dbg" \
-+ -p $PKIDIR/testpki-hv1-privkey.pem \
-+ -c $PKIDIR/testpki-hv1-cert.pem \
-+ -C $PKIDIR/testpki-cacert.pem
-+
-+check ovn-nbctl --wait=hv sync
-+
-+check_tunnel_port hv1 br-int hv2@192.168.0.2
-+check_tunnel_port hv1 br-int-2 hv1@192.168.0.1
-+current_id1=$(ovs-vsctl --bare --columns _uuid find port external_ids:ovn-chassis-id="hv1@192.168.0.1")
-+current_id2=$(ovs-vsctl --bare --columns _uuid find port external_ids:ovn-chassis-id="hv2@192.168.0.2")
-+
-+# Check that restart of hv1 ovn-controller did not interfere with hv2
-+AT_CHECK([grep -q "Clearing old tunnel port \"ovn0-hv1-0\" (hv1@192.168.0.1) from bridge \"br-int-2\"" hv1/ovn-controller.log], [1])
-+check test "$current_id1" = "$prev_id1"
-+check test "$current_id2" = "$prev_id2"
-+
- OVN_CLEANUP([hv1])
- AT_CLEANUP
- ])
-diff --git a/tests/ovs-macros.at b/tests/ovs-macros.at
-index 36b58b5ae..cc5f6e3b1 100644
---- a/tests/ovs-macros.at
-+++ b/tests/ovs-macros.at
-@@ -256,6 +256,13 @@ ovs_wait () {
- ovs_wait_failed
- AT_FAIL_IF([:])
- }
-+
-+check_ovs_wait_until_args() {
-+ AT_FAIL_IF([test $1 -ge 3])
-+ dnl The second argument should not be a number (confused with AT_CHECK ?).
-+ AT_FAIL_IF([test $1 -eq 2 && test "$2" -eq "$2" 2>/dev/null])
-+}
-+
- OVS_END_SHELL_HELPERS
- m4_define([OVS_WAIT], [dnl
- ovs_wait_cond () {
-@@ -276,7 +283,8 @@ dnl zero code within reasonable time limit, then
- dnl the test fails. In that case, runs IF-FAILED
- dnl before aborting.
- m4_define([OVS_WAIT_UNTIL],
-- [OVS_WAIT([$1], [$2], [AT_LINE], [until $1])])
-+ [check_ovs_wait_until_args "$#" "$2"
-+ OVS_WAIT([$1], [$2], [AT_LINE], [until $1])])
-
- dnl OVS_WAIT_FOR_OUTPUT(COMMAND, EXIT-STATUS, STDOUT, STDERR)
- dnl OVS_WAIT_FOR_OUTPUT_UNQUOTED(COMMAND, EXIT-STATUS, STDOUT, STDERR)
-diff --git a/tests/system-common-macros.at b/tests/system-common-macros.at
-index d65f359a6..b8c5ae9ad 100644
---- a/tests/system-common-macros.at
-+++ b/tests/system-common-macros.at
-@@ -44,43 +44,8 @@ m4_define([NS_CHECK_EXEC],
- # appropriate type, and allows additional arguments to be passed.
- m4_define([ADD_BR], [ovs-vsctl _ADD_BR([$1]) -- $2])
-
--# ADD_INT([port], [namespace], [ovs-br], [ip_addr] [ip6_addr])
--#
--# Add an internal port to 'ovs-br', then shift it into 'namespace' and
--# configure it with 'ip_addr' (specified in CIDR notation).
--# Optionally add an ipv6 address
--m4_define([ADD_INT],
-- [ AT_CHECK([ovs-vsctl add-port $3 $1 -- set int $1 type=internal])
-- AT_CHECK([ip link set $1 netns $2])
-- NS_CHECK_EXEC([$2], [ip addr add $4 dev $1])
-- NS_CHECK_EXEC([$2], [ip link set dev $1 up])
-- if test -n "$5"; then
-- NS_CHECK_EXEC([$2], [ip -6 addr add $5 dev $1])
-- fi
-- ]
--)
--
--# NS_ADD_INT([port], [namespace], [ovs-br], [ip_addr] [mac_addr] [ip6_addr] [default_gw] [default_ipv6_gw])
--# Create a namespace
--# Add an internal port to 'ovs-br', then shift it into 'namespace'.
--# Configure it with 'ip_addr' (specified in CIDR notation) and ip6_addr.
--# Set mac_addr
--# Add default gw for ipv4 and ipv6
--m4_define([NS_ADD_INT],
-- [ AT_CHECK([ovs-vsctl add-port $3 $1 -- set int $1 type=internal external_ids:iface-id=$1])
-- ADD_NAMESPACES($2)
-- AT_CHECK([ip link set $1 netns $2])
-- NS_CHECK_EXEC([$2], [ip link set $1 address $5])
-- NS_CHECK_EXEC([$2], [ip link set dev $1 up])
-- NS_CHECK_EXEC([$2], [ip addr add $4 dev $1])
-- NS_CHECK_EXEC([$2], [ip addr add $6 dev $1])
-- NS_CHECK_EXEC([$2], [ip route add default via $7 dev $1])
-- NS_CHECK_EXEC([$2], [ip -6 route add default via $8 dev $1])
-- ]
--)
--
- # ADD_VETH([port], [namespace], [ovs-br], [ip_addr] [mac_addr], [gateway],
--# [ip_addr_flags])
-+# [ip_addr_flags] [ip6_addr] [gateway6])
- #
- # Add a pair of veth ports. 'port' will be added to name space 'namespace',
- # and "ovs-'port'" will be added to ovs bridge 'ovs-br'.
-@@ -108,6 +73,12 @@ m4_define([ADD_VETH],
- if test -n "$6"; then
- NS_CHECK_EXEC([$2], [ip route add default via $6])
- fi
-+ if test -n "$8"; then
-+ NS_CHECK_EXEC([$2], [ip addr add $8 dev $1])
-+ fi
-+ if test -n "$9"; then
-+ NS_CHECK_EXEC([$2], [ip route add default via $9])
-+ fi
- on_exit "ip link del ovs-$1"
- ]
- )
-@@ -263,7 +234,7 @@ m4_define([STRIP_MONITOR_CSUM], [grep "csum:" | sed 's/csum:.*/csum: /'])
- # and limit the output to the rows containing 'ip-addr'.
- #
- m4_define([FORMAT_CT],
-- [[grep -F "dst=$1" | sed -e 's/port=[0-9]*/port=/g' -e 's/id=[0-9]*/id=/g' -e 's/state=[0-9_A-Z]*/state=/g' | sort | uniq]])
-+ [[grep -F "dst=$1," | sed -e 's/port=[0-9]*/port=/g' -e 's/id=[0-9]*/id=/g' -e 's/state=[0-9_A-Z]*/state=/g' | sort | uniq]])
-
- # NETNS_DAEMONIZE([namespace], [command], [pidfile])
- #
-diff --git a/tests/system-ovn-kmod.at b/tests/system-ovn-kmod.at
-index dd4996041..a1aee3313 100644
---- a/tests/system-ovn-kmod.at
-+++ b/tests/system-ovn-kmod.at
-@@ -172,7 +172,7 @@ ovn-nbctl set load_balancer $uuid vips:'"30.0.0.2:8000"'='"192.168.1.2:12345,192
-
- ovn-nbctl list load_balancer
- ovn-sbctl dump-flows R2
--OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-flows br-int table=41 | \
-+OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-flows br-int table=43 | \
- grep 'nat(src=20.0.0.2)'])
-
- dnl Test load-balancing that includes L4 ports in NAT.
-@@ -215,3 +215,139 @@ as
- OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
- /connection dropped.*/d"])
- AT_CLEANUP
-+
-+OVN_FOR_EACH_NORTHD([
-+AT_SETUP([LB correctly de-fragments traffic])
-+AT_KEYWORDS([ovnlb])
-+
-+CHECK_CONNTRACK()
-+CHECK_CONNTRACK_NAT()
-+AT_SKIP_IF([test $HAVE_SCAPY = no])
-+
-+ovn_start
-+OVS_TRAFFIC_VSWITCHD_START()
-+ADD_BR([br-int])
-+ADD_BR([br-ext])
-+
-+# Logical network:
-+# 2 logical switches "public" (192.168.1.0/24) and "internal" (172.16.1.0/24)
-+# connected to a router lr.
-+# internal has a server.
-+# client is connected through localnet.
-+#
-+# Load balancer for udp 192.168.1.20:4242 172.16.1.2 4242.
-+
-+check ovs-ofctl add-flow br-ext action=normal
-+# Set external-ids in br-int needed for ovn-controller
-+check ovs-vsctl \
-+ -- set Open_vSwitch . external-ids:system-id=hv1 \
-+ -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
-+ -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
-+ -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
-+ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true \
-+ -- set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext
-+
-+
-+# Start ovn-controller
-+start_daemon ovn-controller
-+
-+check ovn-nbctl lr-add lr
-+check ovn-nbctl ls-add internal
-+check ovn-nbctl ls-add public
-+
-+check ovn-nbctl lrp-add lr lr-pub 00:00:01:01:02:03 192.168.1.1/24
-+check ovn-nbctl lsp-add public pub-lr -- set Logical_Switch_Port pub-lr \
-+ type=router options:router-port=lr-pub addresses=\"00:00:01:01:02:03\"
-+
-+check ovn-nbctl lrp-add lr lr-internal 00:00:01:01:02:04 172.16.1.1/24
-+check ovn-nbctl lsp-add internal internal-lr -- set Logical_Switch_Port internal-lr \
-+ type=router options:router-port=lr-internal addresses=\"00:00:01:01:02:04\"
-+
-+ovn-nbctl lsp-add public ln_port \
-+ -- lsp-set-addresses ln_port unknown \
-+ -- lsp-set-type ln_port localnet \
-+ -- lsp-set-options ln_port network_name=phynet
-+
-+ADD_NAMESPACES(client)
-+ADD_VETH(client, client, br-ext, "192.168.1.2/24", "f0:00:00:01:02:03", \
-+ "192.168.1.1")
-+
-+ADD_NAMESPACES(server)
-+ADD_VETH(server, server, br-int, "172.16.1.2/24", "f0:00:0f:01:02:03", \
-+ "172.16.1.1")
-+check ovn-nbctl lsp-add internal server \
-+-- lsp-set-addresses server "f0:00:0f:01:02:03 172.16.1.2"
-+
-+# Config OVN load-balancer with a VIP.
-+check ovn-nbctl lb-add lb1 192.168.1.20:4242 172.16.1.2:4242 udp
-+check ovn-nbctl lr-lb-add lr lb1
-+check ovn-nbctl set logical_router lr options:chassis=hv1
-+check ovn-nbctl set logical_router_port lr-internal options:gateway_mtu=800
-+
-+ovn-nbctl --wait=hv sync
-+
-+NETNS_DAEMONIZE([server], [nc -l -u 172.16.1.2 4242 > /dev/null], [server.pid])
-+
-+# Collect ICMP packets on client side
-+NETNS_DAEMONIZE([client], [tcpdump -l -U -i client -vnne \
-+icmp > client.pcap 2>client_err], [tcpdump0.pid])
-+OVS_WAIT_UNTIL([grep "listening" client_err])
-+
-+# Collect UDP packets on server side
-+NETNS_DAEMONIZE([server], [tcpdump -l -U -i server -vnne \
-+'udp and ip[[6:2]] > 0 and not ip[[6]] = 64' > server.pcap 2>server_err], [tcpdump1.pid])
-+OVS_WAIT_UNTIL([grep "listening" server_err])
-+
-+check ip netns exec client python3 << EOF
-+import os
-+import socket
-+import sys
-+import time
-+
-+FILE="client.pcap"
-+
-+
-+def contains_string(file, str):
-+ file = open(file, "r")
-+ for line in file.readlines():
-+ if str in line:
-+ return True
-+ return False
-+
-+
-+def need_frag_received():
-+ for _ in range(20):
-+ if os.path.getsize(FILE) and contains_string(FILE, "need to frag"):
-+ return True
-+ time.sleep(0.5)
-+ return False
-+
-+
-+sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-+sock.sendto(b"x" * 1000, ("192.168.1.20", 4242))
-+if need_frag_received():
-+ sock.sendto(b"x" * 1000, ("192.168.1.20", 4242))
-+else:
-+ print("Missing need frag")
-+ sys.exit(1)
-+EOF
-+
-+OVS_WAIT_UNTIL([test "$(cat server.pcap | wc -l)" = "4"])
-+
-+
-+OVS_APP_EXIT_AND_WAIT([ovn-controller])
-+
-+as ovn-sb
-+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
-+
-+as ovn-nb
-+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
-+
-+as northd
-+OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE])
-+
-+as
-+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
-+/connection dropped.*/d"])
-+AT_CLEANUP
-+])
-diff --git a/tests/system-ovn.at b/tests/system-ovn.at
-index 84a459d6a..0b6e9f602 100644
---- a/tests/system-ovn.at
-+++ b/tests/system-ovn.at
-@@ -1569,7 +1569,6 @@ bar3_ct=$(ovs-appctl dpctl/dump-conntrack | grep 30.0.0.2 | grep 172.16.1.4 -c)
- AT_CHECK([test $(ovs-appctl dpctl/dump-conntrack | grep 30.0.0.2 | grep 172.16.1 -c) -ne 0])
-
- if [[ "$bar1_ct" == "20" ]]; then
-- AT_CHECK([test $bar1_ct -eq 20])
- AT_CHECK([test $bar2_ct -eq 0])
- AT_CHECK([test $bar3_ct -eq 0])
- else
-@@ -1577,17 +1576,15 @@ else
- fi
-
- if [[ "$bar2_ct" == "20" ]]; then
-- AT_CHECK([test $bar1_ct -eq 20])
-- AT_CHECK([test $bar2_ct -eq 0])
-+ AT_CHECK([test $bar1_ct -eq 0])
- AT_CHECK([test $bar3_ct -eq 0])
- else
- AT_CHECK([test $bar2_ct -eq 0])
- fi
-
- if [[ "$bar3_ct" == "20" ]]; then
-- AT_CHECK([test $bar1_ct -eq 20])
-+ AT_CHECK([test $bar1_ct -eq 0])
- AT_CHECK([test $bar2_ct -eq 0])
-- AT_CHECK([test $bar3_ct -eq 0])
- else
- AT_CHECK([test $bar3_ct -eq 0])
- fi
-@@ -2246,7 +2243,7 @@ ovn-nbctl set load_balancer $uuid vips:'"30.0.0.2:8000"'='"192.168.1.2:80,192.16
-
- ovn-nbctl list load_balancer
- ovn-sbctl dump-flows R2
--OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-flows br-int table=43 | \
-+OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-flows br-int table=45 | \
- grep 'nat(src=20.0.0.2)'])
-
- check ovs-appctl dpctl/flush-conntrack
-@@ -2285,7 +2282,7 @@ ovn-nbctl set load_balancer $uuid vips:'"30.0.0.2:8000"'='"192.168.1.2:80,192.16
-
- ovn-nbctl list load_balancer
- ovn-sbctl dump-flows R2
--OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-flows br-int table=43 | \
-+OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-flows br-int table=45 | \
- grep 'nat(src=20.0.0.2)'])
-
- rm -f wget*.log
-@@ -4850,9 +4847,9 @@ NS_CHECK_EXEC([lsp], [tcpdump -l -nn -c 3 -i lsp ${filter} > lsp.pcap 2>tcpdump_
- OVS_WAIT_UNTIL([grep "listening" tcpdump_err])
-
- # Generate IPv4 UDP hairpin traffic.
--NS_CHECK_EXEC([lsp], [echo a | nc -u 88.88.88.88 4040 &], [0])
--NS_CHECK_EXEC([lsp], [echo a | nc -u 88.88.88.89 4040 &], [0])
--NS_CHECK_EXEC([lsp], [echo a | nc -u 88.88.88.90 2021 &], [0])
-+NS_CHECK_EXEC([lsp], [echo a | nc -u 88.88.88.88 4040], [ignore], [ignore], [ignore])
-+NS_CHECK_EXEC([lsp], [echo a | nc -u 88.88.88.89 4040], [ignore], [ignore], [ignore])
-+NS_CHECK_EXEC([lsp], [echo a | nc -u 88.88.88.90 2021], [ignore], [ignore], [ignore])
-
- # Check hairpin traffic.
- OVS_WAIT_UNTIL([
-@@ -4949,9 +4946,9 @@ NS_CHECK_EXEC([lsp], [tcpdump -l -nn -c 3 -i lsp $filter > lsp.pcap 2>tcpdump_er
- OVS_WAIT_UNTIL([grep "listening" tcpdump_err])
-
- # Generate IPv6 UDP hairpin traffic.
--NS_CHECK_EXEC([lsp], [echo a | nc -u 8800::0088 4040 &], [0])
--NS_CHECK_EXEC([lsp], [echo a | nc -u 8800::0089 4040 &], [0])
--NS_CHECK_EXEC([lsp], [echo a | nc -u 8800::0090 2021 &], [0])
-+NS_CHECK_EXEC([lsp], [echo a | nc -u 8800::0088 4040], [ignore], [ignore], [ignore])
-+NS_CHECK_EXEC([lsp], [echo a | nc -u 8800::0089 4040], [ignore], [ignore], [ignore])
-+NS_CHECK_EXEC([lsp], [echo a | nc -u 8800::0090 2021], [ignore], [ignore], [ignore])
-
- # Check hairpin traffic.
- OVS_WAIT_UNTIL([
-@@ -5084,7 +5081,7 @@ OVS_WAIT_UNTIL([
- ])
-
- OVS_WAIT_UNTIL([
-- n_pkt=$(ovs-ofctl dump-flows br-int table=44 | grep -v n_packets=0 | \
-+ n_pkt=$(ovs-ofctl dump-flows br-int table=46 | grep -v n_packets=0 | \
- grep controller | grep tp_dst=84 -c)
- test $n_pkt -eq 1
- ])
-@@ -5334,7 +5331,7 @@ OVS_WAIT_UNTIL([
- ])
-
- OVS_WAIT_UNTIL([
-- n_pkt=$(ovs-ofctl dump-flows br-int table=44 | grep -v n_packets=0 | \
-+ n_pkt=$(ovs-ofctl dump-flows br-int table=46 | grep -v n_packets=0 | \
- grep controller | grep tp_dst=84 -c)
- test $n_pkt -eq 1
- ])
-@@ -7190,7 +7187,7 @@ NS_EXEC([sw01], [tcpdump -l -n -i sw01 icmp -Q in > reject.pcap &])
- check ovn-nbctl --may-exist meter-add acl-meter drop 10 pktps 0
- ip netns exec sw01 scapy -H <<-EOF
- p = IP(src="192.168.1.2", dst="192.168.1.1") / UDP(dport = 12345) / Raw(b"X"*64)
--send (p, iface='sw01', loop = 0, verbose = 0, count = 100)
-+send (p, iface='sw01', loop = 0, verbose = 0, count = 40)
- EOF
-
- # 10pps
-@@ -8482,11 +8479,18 @@ check ovn-nbctl lsp-set-addresses ln unknown
- check ovn-nbctl lr-nat-add lr1 snat 172.16.1.10 192.168.1.0/24
- check ovn-nbctl lr-nat-add lr1 snat 1711::10 2001::/64
-
--NS_ADD_INT(ls1p1, ls1p1, br-int, "192.168.1.1/24", "00:00:00:01:01:01", "2001::1/64", "192.168.1.254", "2001::a" )
--NS_ADD_INT(ls1p2, ls1p2, br-int, "192.168.1.2/24", "00:00:00:01:01:02", "2001::2/64", "192.168.1.254", "2001::a" )
-+ADD_NAMESPACES(ls1p1)
-+ADD_VETH(ls1p1, ls1p1, br-int, "192.168.1.1/24", "00:00:00:01:01:01", \
-+ "192.168.1.254", , "2001::1/64", "2001::a")
-+
-+ADD_NAMESPACES(ls1p2)
-+ADD_VETH(ls1p2, ls1p2, br-int, "192.168.1.2/24", "00:00:00:01:01:02", \
-+ "192.168.1.254", , "2001::2/64", "2001::a")
-
- ADD_NAMESPACES(ext1)
--ADD_INT(ext1, ext1, br0, 172.16.1.1/24, 1711::1/64)
-+ADD_VETH(ext1, ext1, br0, "172.16.1.1/24", "00:ee:00:01:01:01", \
-+ "172.16.1.254", , "1711::1/64", "1711::a")
-+
- check ovn-nbctl --wait=hv sync
- wait_for_ports_up
- OVS_WAIT_UNTIL([test "$(ip netns exec ls1p1 ip a | grep 2001::1 | grep tentative)" = ""])
-@@ -8548,25 +8552,17 @@ wait_igmp_flows_installed()
- }
-
- ADD_NAMESPACES(vm1)
--ADD_INT([vm1], [vm1], [br-int], [42.42.42.1/24])
--NS_CHECK_EXEC([vm1], [ip link set vm1 address 00:00:00:00:00:01], [0])
--NS_CHECK_EXEC([vm1], [ip route add default via 42.42.42.5], [0])
--check ovs-vsctl set Interface vm1 external_ids:iface-id=vm1
-+ADD_VETH(vm1, vm1, br-int, "42.42.42.1/24", "00:00:00:00:00:01", \
-+ "42.42.42.5")
-
- ADD_NAMESPACES(vm2)
--ADD_INT([vm2], [vm2], [br-int], [42.42.42.2/24])
--NS_CHECK_EXEC([vm2], [ip link set vm2 address 00:00:00:00:00:02], [0])
--NS_CHECK_EXEC([vm2], [ip link set lo up], [0])
--check ovs-vsctl set Interface vm2 external_ids:iface-id=vm2
-+ADD_VETH(vm2, vm2, br-int, "42.42.42.2/24", "00:00:00:00:00:02")
-
- ADD_NAMESPACES(vm3)
- NETNS_DAEMONIZE([vm3], [tcpdump -n -i any -nnleX > vm3.pcap 2>/dev/null], [tcpdump3.pid])
-
--ADD_INT([vm3], [vm3], [br-int], [42.42.42.3/24])
--NS_CHECK_EXEC([vm3], [ip link set vm3 address 00:00:00:00:00:03], [0])
--NS_CHECK_EXEC([vm3], [ip link set lo up], [0])
--NS_CHECK_EXEC([vm3], [ip route add default via 42.42.42.5], [0])
--check ovs-vsctl set Interface vm3 external_ids:iface-id=vm3
-+ADD_VETH(vm3, vm3, br-int, "42.42.42.3/24", "00:00:00:00:00:03", \
-+ "42.42.42.5")
-
- NS_CHECK_EXEC([vm2], [sysctl -w net.ipv4.igmp_max_memberships=100], [ignore], [ignore])
- NS_CHECK_EXEC([vm3], [sysctl -w net.ipv4.igmp_max_memberships=100], [ignore], [ignore])
-@@ -9639,7 +9635,7 @@ start_daemon ovn-controller
- # |
- # VM2 ----+
- #
--# Two templated load balancer applied on LS1 and GW-Router with
-+# Four templated load balancer applied on LS1 and GW-Router with
- # VM1 as backend. The VIPs should be accessible from both VM2 and VM3.
-
- check ovn-nbctl \
-@@ -9667,7 +9663,7 @@ check ovn-nbctl \
- # VIP=66.66.66.66:777 backends=42.42.42.2:4343 proto=udp
-
- AT_CHECK([ovn-nbctl -- create chassis_template_var chassis="hv1" \
-- variables="{vip=66.66.66.66,vport1=666,backends1=\"42.42.42.2:4242\",vport2=777,backends2=\"42.42.42.2:4343\"}"],
-+ variables="{vip=66.66.66.66,vport1=666,backends1=\"42.42.42.2:4242\",vport2=777,backends2=\"42.42.42.2:4343\",vport3=888,vport4=999}"],
- [0], [ignore])
-
- check ovn-nbctl --template lb-add lb-test-tcp "^vip:^vport1" "^backends1" tcp \
-@@ -9678,6 +9674,18 @@ check ovn-nbctl --template lb-add lb-test-udp "^vip:^vport2" "^backends2" udp \
- -- ls-lb-add ls1 lb-test-udp \
- -- lr-lb-add rtr lb-test-udp
-
-+# Add a TCP template LB with explicit backends that eventually expands to:
-+# VIP=66.66.66.66:888 backends=42.42.42.2:4242 proto=tcp
-+# And a UDP template LB that eventually expands to:
-+# VIP=66.66.66.66:999 backends=42.42.42.2:4343 proto=udp
-+check ovn-nbctl --template lb-add lb-test-tcp2 "^vip:^vport3" "42.42.42.2:4242" tcp ipv4 \
-+ -- ls-lb-add ls1 lb-test-tcp2 \
-+ -- lr-lb-add rtr lb-test-tcp2
-+
-+check ovn-nbctl --template lb-add lb-test-udp2 "^vip:^vport4" "42.42.42.2:4343" udp ipv4 \
-+ -- ls-lb-add ls1 lb-test-udp2 \
-+ -- lr-lb-add rtr lb-test-udp2
-+
- ADD_NAMESPACES(vm1)
- ADD_VETH(vm1, vm1, br-int, "42.42.42.2/24", "00:00:00:00:00:01", "42.42.42.1")
-
-@@ -9698,13 +9706,15 @@ name: 'backends2' value: '42.42.42.2:4343'
- name: 'vip' value: '66.66.66.66'
- name: 'vport1' value: '666'
- name: 'vport2' value: '777'
-+name: 'vport3' value: '888'
-+name: 'vport4' value: '999'
- ])
-
- # Start IPv4 TCP server on vm1.
- NETNS_DAEMONIZE([vm1], [nc -k -l 42.42.42.2 4242], [nc-vm1.pid])
-
- NETNS_DAEMONIZE([vm1],
-- [tcpdump -n -i vm1 -nnleX -c3 udp and dst 42.42.42.2 and dst port 4343 > vm1.pcap 2>/dev/null],
-+ [tcpdump -n -i vm1 -nnleX -c6 udp and dst 42.42.42.2 and dst port 4343 > vm1.pcap 2>/dev/null],
- [tcpdump1.pid])
-
- # Make sure connecting to the VIP works (hairpin, via ls and via lr).
-@@ -9712,13 +9722,21 @@ NS_CHECK_EXEC([vm1], [nc 66.66.66.66 666 -z], [0], [ignore], [ignore])
- NS_CHECK_EXEC([vm2], [nc 66.66.66.66 666 -z], [0], [ignore], [ignore])
- NS_CHECK_EXEC([vm3], [nc 66.66.66.66 666 -z], [0], [ignore], [ignore])
-
--NS_CHECK_EXEC([vm1], [echo a | nc -u 66.66.66.66 777 &], [0])
--NS_CHECK_EXEC([vm2], [echo a | nc -u 66.66.66.66 777 &], [0])
--NS_CHECK_EXEC([vm3], [echo a | nc -u 66.66.66.66 777 &], [0])
-+NS_CHECK_EXEC([vm1], [echo a | nc -u 66.66.66.66 777], [ignore], [ignore], [ignore])
-+NS_CHECK_EXEC([vm2], [echo a | nc -u 66.66.66.66 777], [ignore], [ignore], [ignore])
-+NS_CHECK_EXEC([vm3], [echo a | nc -u 66.66.66.66 777], [ignore], [ignore], [ignore])
-+
-+NS_CHECK_EXEC([vm1], [nc 66.66.66.66 888 -z], [0], [ignore], [ignore])
-+NS_CHECK_EXEC([vm2], [nc 66.66.66.66 888 -z], [0], [ignore], [ignore])
-+NS_CHECK_EXEC([vm3], [nc 66.66.66.66 888 -z], [0], [ignore], [ignore])
-+
-+NS_CHECK_EXEC([vm1], [echo a | nc -u 66.66.66.66 999], [ignore], [ignore], [ignore])
-+NS_CHECK_EXEC([vm2], [echo a | nc -u 66.66.66.66 999], [ignore], [ignore], [ignore])
-+NS_CHECK_EXEC([vm3], [echo a | nc -u 66.66.66.66 999], [ignore], [ignore], [ignore])
-
- OVS_WAIT_UNTIL([
- requests=`grep "UDP" -c vm1.pcap`
-- test "${requests}" -ge "3"
-+ test "${requests}" -ge "6"
- ])
-
- AT_CLEANUP
-@@ -9753,7 +9771,7 @@ start_daemon ovn-controller
- # |
- # VM2 ----+
- #
--# Two templated load balancer applied on LS1 and GW-Router with
-+# Four templated load balancer applied on LS1 and GW-Router with
- # VM1 as backend. The VIPs should be accessible from both VM2 and VM3.
-
- check ovn-nbctl \
-@@ -9781,7 +9799,7 @@ check ovn-nbctl \
- # VIP=[6666::1]:777 backends=[4242::2]:4343 proto=udp
-
- AT_CHECK([ovn-nbctl -- create chassis_template_var chassis="hv1" \
-- variables="{vip=\"6666::1\",vport1=666,backends1=\"[[4242::2]]:4242\",vport2=777,backends2=\"[[4242::2]]:4343\"}"],
-+ variables="{vip=\"6666::1\",vport1=666,backends1=\"[[4242::2]]:4242\",vport2=777,backends2=\"[[4242::2]]:4343\",vport3=888,vport4=999}"],
- [0], [ignore])
-
- check ovn-nbctl --template lb-add lb-test-tcp "^vip:^vport1" "^backends1" tcp ipv6 \
-@@ -9792,6 +9810,18 @@ check ovn-nbctl --template lb-add lb-test-udp "^vip:^vport2" "^backends2" udp ip
- -- ls-lb-add ls1 lb-test-udp \
- -- lr-lb-add rtr lb-test-udp
-
-+# Add a TCP template LB with explicit backends that eventually expands to:
-+# VIP=[6666::1]:888 backends=[4242::2]:4242 proto=tcp
-+# And a UDP template LB that eventually expands to:
-+# VIP=[6666::1]:999 backends=[4242::2]:4343 proto=udp
-+check ovn-nbctl --template lb-add lb-test-tcp2 "^vip:^vport3" "[[4242::2]]:4242" tcp ipv6 \
-+ -- ls-lb-add ls1 lb-test-tcp2 \
-+ -- lr-lb-add rtr lb-test-tcp2
-+
-+check ovn-nbctl --template lb-add lb-test-udp2 "^vip:^vport4" "[[4242::2]]:4343" udp ipv6 \
-+ -- ls-lb-add ls1 lb-test-udp2 \
-+ -- lr-lb-add rtr lb-test-udp2
-+
- ADD_NAMESPACES(vm1)
- ADD_VETH(vm1, vm1, br-int, "4242::2/64", "00:00:00:00:00:01", "4242::1")
- OVS_WAIT_UNTIL([test "$(ip netns exec vm1 ip a | grep 4242::2 | grep tentative)" = ""])
-@@ -9815,13 +9845,15 @@ name: 'backends2' value: '[[4242::2]]:4343'
- name: 'vip' value: '6666::1'
- name: 'vport1' value: '666'
- name: 'vport2' value: '777'
-+name: 'vport3' value: '888'
-+name: 'vport4' value: '999'
- ])
-
- # Start IPv6 TCP server on vm1.
- NETNS_DAEMONIZE([vm1], [nc -k -l 4242::2 4242], [nc-vm1.pid])
-
- NETNS_DAEMONIZE([vm1],
-- [tcpdump -n -i vm1 -nnleX -c3 udp and dst 4242::2 and dst port 4343 > vm1.pcap 2>/dev/null],
-+ [tcpdump -n -i vm1 -nnleX -c6 udp and dst 4242::2 and dst port 4343 > vm1.pcap 2>/dev/null],
- [tcpdump1.pid])
-
- # Make sure connecting to the VIP works (hairpin, via ls and via lr).
-@@ -9829,13 +9861,21 @@ NS_CHECK_EXEC([vm1], [nc 6666::1 666 -z], [0], [ignore], [ignore])
- NS_CHECK_EXEC([vm2], [nc 6666::1 666 -z], [0], [ignore], [ignore])
- NS_CHECK_EXEC([vm3], [nc 6666::1 666 -z], [0], [ignore], [ignore])
-
--NS_CHECK_EXEC([vm1], [echo a | nc -u 6666::1 777 &], [0])
--NS_CHECK_EXEC([vm2], [echo a | nc -u 6666::1 777 &], [0])
--NS_CHECK_EXEC([vm3], [echo a | nc -u 6666::1 777 &], [0])
-+NS_CHECK_EXEC([vm1], [echo a | nc -u 6666::1 777], [ignore], [ignore], [ignore])
-+NS_CHECK_EXEC([vm2], [echo a | nc -u 6666::1 777], [ignore], [ignore], [ignore])
-+NS_CHECK_EXEC([vm3], [echo a | nc -u 6666::1 777], [ignore], [ignore], [ignore])
-+
-+NS_CHECK_EXEC([vm1], [nc 6666::1 888 -z], [0], [ignore], [ignore])
-+NS_CHECK_EXEC([vm2], [nc 6666::1 888 -z], [0], [ignore], [ignore])
-+NS_CHECK_EXEC([vm3], [nc 6666::1 888 -z], [0], [ignore], [ignore])
-+
-+NS_CHECK_EXEC([vm1], [echo a | nc -u 6666::1 999], [ignore], [ignore], [ignore])
-+NS_CHECK_EXEC([vm2], [echo a | nc -u 6666::1 999], [ignore], [ignore], [ignore])
-+NS_CHECK_EXEC([vm3], [echo a | nc -u 6666::1 999], [ignore], [ignore], [ignore])
-
- OVS_WAIT_UNTIL([
- requests=`grep "UDP" -c vm1.pcap`
-- test "${requests}" -ge "3"
-+ test "${requests}" -ge "6"
- ])
-
- AT_CLEANUP
-@@ -10587,11 +10627,13 @@ check ovn-nbctl lsp-add bar bar3 \
- -- lsp-set-addresses bar3 "f0:00:0f:01:02:05 172.16.1.4"
-
- # Config OVN load-balancer with a VIP.
--check ovn-nbctl lb-add lb1 30.0.0.1 "172.16.1.2,172.16.1.3,172.16.1.4"
-+check ovn-nbctl lb-add lb1 30.0.0.1 "172.16.1.2,172.16.1.3,172.16.1.4" \
-+ -- set load_balancer lb1 options:ct_flush="true"
- check ovn-nbctl ls-lb-add foo lb1
-
- # Create another load-balancer with another VIP.
- lb2_uuid=`ovn-nbctl create load_balancer name=lb2 vips:30.0.0.3="172.16.1.2,172.16.1.3,172.16.1.4"`
-+check ovn-nbctl set load_balancer lb2 options:ct_flush="true"
- check ovn-nbctl ls-lb-add foo lb2
-
- # Config OVN load-balancer with another VIP (this time with ports).
-@@ -10607,16 +10649,18 @@ OVS_START_L7([bar1], [http])
- OVS_START_L7([bar2], [http])
- OVS_START_L7([bar3], [http])
-
--OVS_WAIT_FOR_OUTPUT([
-- for i in `seq 1 20`; do
-- ip netns exec foo1 wget 30.0.0.1 -t 5 -T 1 --retry-connrefused -v -o wget$i.log;
-- done
-- ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl
-+m4_define([LB1_CT_ENTRIES], [dnl
- tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=172.16.1.2,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=)
- tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=172.16.1.3,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=)
- tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=172.16.1.4,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=)
- ])
-
-+OVS_WAIT_FOR_OUTPUT([
-+ for i in `seq 1 20`; do
-+ ip netns exec foo1 wget 30.0.0.1 -t 5 -T 1 --retry-connrefused -v -o wget$i.log;
-+ done
-+ ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | sed -e 's/zone=[[0-9]]*/zone=/'], [0], [LB1_CT_ENTRIES])
-+
- OVS_WAIT_FOR_OUTPUT([
- for i in `seq 1 20`; do
- ip netns exec foo1 wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log;
-@@ -10690,6 +10734,535 @@ check ovn-nbctl lb-del lb2
-
- OVS_WAIT_UNTIL([test "$(ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.3) | wc -l)" = "0"])
-
-+# Check that LB has CT flush disabled by default
-+check ovn-nbctl lb-add lb1 30.0.0.1 "172.16.1.2,172.16.1.3,172.16.1.4"
-+check ovn-nbctl ls-lb-add foo lb1
-+
-+OVS_WAIT_FOR_OUTPUT([
-+ for i in `seq 1 20`; do
-+ ip netns exec foo1 wget 30.0.0.1 -t 5 -T 1 --retry-connrefused -v -o wget$i.log;
-+ done
-+ ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | sed -e 's/zone=[[0-9]]*/zone=/'], [0], [LB1_CT_ENTRIES])
-+
-+# Remove one backend
-+check ovn-nbctl --wait=hv set load_balancer lb1 vips='"30.0.0.1"="172.16.1.2,172.16.1.3"'
-+
-+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | sed -e 's/zone=[[0-9]]*/zone=/'], [0], [LB1_CT_ENTRIES])
-+
-+# Remove whole LB
-+check ovn-nbctl --wait=hv lb-del lb1
-+
-+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | sed -e 's/zone=[[0-9]]*/zone=/'], [0], [LB1_CT_ENTRIES])
-+
-+OVS_APP_EXIT_AND_WAIT([ovn-controller])
-+
-+as ovn-sb
-+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
-+
-+as ovn-nb
-+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
-+
-+as northd
-+OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE])
-+
-+as
-+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
-+/connection dropped.*/d"])
-+AT_CLEANUP
-+])
-+
-+OVN_FOR_EACH_NORTHD([
-+AT_SETUP([ACL and committing to conntrack])
-+AT_KEYWORDS([acl])
-+
-+CHECK_CONNTRACK()
-+CHECK_CONNTRACK_NAT()
-+ovn_start
-+OVS_TRAFFIC_VSWITCHD_START()
-+ADD_BR([br-int])
-+# Set external-ids in br-int needed for ovn-controller
-+ovs-vsctl \
-+ -- set Open_vSwitch . external-ids:system-id=hv1 \
-+ -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
-+ -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
-+ -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
-+ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
-+
-+start_daemon ovn-controller
-+
-+check ovn-nbctl lr-add r1
-+check ovn-nbctl lrp-add r1 r1_s1 00:de:ad:fe:00:01 173.0.1.1/24
-+check ovn-nbctl lrp-add r1 r1_s2 00:de:ad:fe:00:02 173.0.2.1/24
-+
-+check ovn-nbctl ls-add s1
-+check ovn-nbctl lsp-add s1 s1_r1
-+check ovn-nbctl lsp-set-type s1_r1 router
-+check ovn-nbctl lsp-set-addresses s1_r1 router
-+check ovn-nbctl lsp-set-options s1_r1 router-port=r1_s1
-+
-+check ovn-nbctl ls-add s2
-+check ovn-nbctl lsp-add s2 s2_r1
-+check ovn-nbctl lsp-set-type s2_r1 router
-+check ovn-nbctl lsp-set-addresses s2_r1 router
-+check ovn-nbctl lsp-set-options s2_r1 router-port=r1_s2
-+
-+check ovn-nbctl lsp-add s1 vm1
-+check ovn-nbctl lsp-set-addresses vm1 "00:de:ad:01:00:01 173.0.1.2"
-+
-+check ovn-nbctl lsp-add s2 vm2
-+check ovn-nbctl lsp-set-addresses vm2 "00:de:ad:01:00:02 173.0.2.2"
-+
-+check ovn-nbctl lsp-add s2 vm3
-+check ovn-nbctl lsp-set-addresses vm3 "00:de:ad:01:00:03 173.0.2.3"
-+
-+check ovn-nbctl lb-add lb1 30.0.0.1:80 173.0.2.2:80 udp
-+check ovn-nbctl lb-add lb2 20.0.0.1:80 173.0.1.2:80 udp
-+check ovn-nbctl lb-add lb1 30.0.0.1 173.0.2.2
-+check ovn-nbctl lb-add lb2 173.0.2.250 173.0.1.3
-+check ovn-nbctl ls-lb-add s1 lb1
-+check ovn-nbctl ls-lb-add s2 lb2
-+
-+ADD_NAMESPACES(vm1)
-+ADD_VETH(vm1, vm1, br-int, "173.0.1.2/24", "00:de:ad:01:00:01", \
-+ "173.0.1.1")
-+ADD_NAMESPACES(vm2)
-+ADD_VETH(vm2, vm2, br-int, "173.0.2.2/24", "00:de:ad:01:00:02", \
-+ "173.0.2.1")
-+ADD_NAMESPACES(vm3)
-+ADD_VETH(vm3, vm3, br-int, "173.0.2.250/24", "00:de:ad:01:00:03", \
-+ "173.0.2.1")
-+
-+check ovn-nbctl acl-add s1 from-lport 1001 "ip" allow
-+check ovn-nbctl acl-add s1 to-lport 1002 "ip" allow
-+check ovn-nbctl acl-add s2 from-lport 1003 "ip" allow
-+check ovn-nbctl acl-add s2 to-lport 1004 "ip" allow
-+check ovn-nbctl --wait=hv sync
-+AS_BOX([initial ping])
-+# Send ping in background. Same ping, same flow throughout the test
-+on_exit 'kill $(pidof ping)'
-+NS_EXEC([vm1], [ping -c 10000 -i 0.1 30.0.0.1 > icmp.txt &])
-+
-+# Check for conntrack entries
-+OVS_WAIT_FOR_OUTPUT([
-+ ovs-appctl dpctl/dump-conntrack | FORMAT_CT(173.0.1.2) | \
-+ sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl
-+icmp,orig=(src=173.0.1.2,dst=173.0.2.2,id=,type=8,code=0),reply=(src=173.0.2.2,dst=173.0.1.2,id=,type=0,code=0),zone=
-+icmp,orig=(src=173.0.1.2,dst=30.0.0.1,id=,type=8,code=0),reply=(src=173.0.2.2,dst=173.0.1.2,id=,type=0,code=0),zone=,mark=2
-+])
-+
-+# Now check for multiple ct_commits
-+ovs-appctl dpctl/dump-flows > dp_flows
-+zone_id=$(ovn-appctl -t ovn-controller ct-zone-list | grep vm1 | cut -d ' ' -f2)
-+AT_CHECK([test 1 = `cat dp_flows | grep "commit,zone=$zone_id" | wc -l`])
-+
-+check ovn-nbctl acl-del s1 from-lport 1001 "ip"
-+check ovn-nbctl acl-del s1 to-lport 1002 "ip"
-+check ovn-nbctl acl-del s2 from-lport 1003 "ip"
-+check ovn-nbctl acl-del s2 to-lport 1004 "ip"
-+
-+AS_BOX([acl drop echo request])
-+check ovn-nbctl --log --severity=alert --name=drop-flow-s1 acl-add s1 to-lport 2001 icmp4 drop
-+# acl-drop to-lport s1 apply to traffic from s1 to vm1 and s1 to r1.
-+check ovn-nbctl --wait=hv sync
-+
-+# Check that traffic is blocked
-+# Wait for some packets to hit the rule to avoid potential race conditions. Then count packets.
-+OVS_WAIT_UNTIL([test `cat ovn-controller.log | grep acl_log | grep -c drop-flow-s1` -gt "0"])
-+total_icmp_pkts=$(cat icmp.txt | grep ttl | wc -l)
-+
-+# Wait some time and check whether packets went through. In the worse race condition, the sleep is too short
-+# and this test will still succeed.
-+sleep 1
-+OVS_WAIT_UNTIL([
-+ total_icmp1_pkts=$(cat icmp.txt | grep ttl | wc -l)
-+ test "${total_icmp1_pkts}" -eq "${total_icmp_pkts}"
-+])
-+
-+AS_BOX([acl allow-related echo request])
-+check ovn-nbctl acl-add s1 to-lport 2002 "icmp4 && ip4.src == 173.0.1.2" allow-related
-+# This rule has higher priority than to-lport 2001 icmp4 drop.
-+# So traffic from s1 (w/ src=173.0.1.2) to r1 should be accepted
-+# (return) traffic from s1 to vm1 should be accepted as return traffic
-+check ovn-nbctl --wait=hv sync
-+OVS_WAIT_UNTIL([
-+ total_icmp1_pkts=$(cat icmp.txt | grep ttl | wc -l)
-+ test "${total_icmp1_pkts}" -gt "${total_icmp_pkts}"
-+])
-+
-+# Check we did not break handling acl-drop for existing flows
-+AS_BOX([acl drop echo request in s2])
-+check ovn-nbctl acl-del s1 to-lport 2001 icmp4
-+check ovn-nbctl --log --severity=alert --name=drop-flow-s2 acl-add s2 to-lport 2001 icmp4 drop
-+check ovn-nbctl --wait=hv sync
-+
-+OVS_WAIT_UNTIL([test `cat ovn-controller.log | grep acl_log | grep -c drop-flow-s2` -gt "0"])
-+
-+OVS_WAIT_FOR_OUTPUT([
-+ ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | \
-+ sed -e 's/zone=[[0-9]]*/zone=/' | \
-+ sed -e 's/mark=[[0-9]]*/mark=/'], [0], [dnl
-+icmp,orig=(src=173.0.1.2,dst=30.0.0.1,id=,type=8,code=0),reply=(src=173.0.2.2,dst=173.0.1.2,id=,type=0,code=0),zone=,mark=
-+])
-+total_icmp_pkts=$(cat icmp.txt | grep ttl | wc -l)
-+
-+# Allow ping again
-+AS_BOX([acl allow echo request in s2])
-+check ovn-nbctl acl-add s2 to-lport 2005 icmp4 allow
-+check ovn-nbctl --wait=hv sync
-+OVS_WAIT_FOR_OUTPUT([
-+ ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | \
-+ sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl
-+icmp,orig=(src=173.0.1.2,dst=30.0.0.1,id=,type=8,code=0),reply=(src=173.0.2.2,dst=173.0.1.2,id=,type=0,code=0),zone=,mark=2
-+])
-+OVS_WAIT_UNTIL([
-+ total_icmp1_pkts=$(cat icmp.txt | grep ttl | wc -l)
-+ test "${total_icmp1_pkts}" -gt "${total_icmp_pkts}"
-+])
-+
-+OVS_APP_EXIT_AND_WAIT([ovn-controller])
-+
-+as ovn-sb
-+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
-+
-+as ovn-nb
-+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
-+
-+as northd
-+OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE])
-+
-+as
-+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
-+/connection dropped.*/d"])
-+AT_CLEANUP
-+])
-+
-+# This tests port->up/down and ovn-installed after adding and removing Ports and Interfaces.
-+# 3 Conditions x 3 tests:
-+# - 3 Conditions:
-+# - In normal conditions
-+# - Remove interface while starting and stopping SB and Controller
-+# - Remove and add back interface while starting and stopping SB and Controller
-+# - 3 tests:
-+# - Add/Remove Logical Port
-+# - Add/Remove iface-id
-+# - Add/Remove Interface
-+# Each tests/conditions checks for
-+# - Port_binding->chassis
-+# - Port up or down
-+# - ovn-installed
-+OVN_FOR_EACH_NORTHD([
-+AT_SETUP([ovn-install on slow ovsdb])
-+AT_KEYWORDS([ovn-install])
-+
-+OVS_TRAFFIC_VSWITCHD_START()
-+# Restart ovsdb-server, this time with tcp
-+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
-+start_daemon ovsdb-server --remote=punix:"$OVS_RUNDIR"/db.sock --remote=ptcp:0:127.0.0.1
-+
-+ovn_start
-+ADD_BR([br-int])
-+
-+# Set external-ids in br-int needed for ovn-controller
-+ovs-vsctl \
-+ -- set Open_vSwitch . external-ids:system-id=hv1 \
-+ -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
-+ -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
-+ -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
-+ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
-+
-+# Start ovn-controller
-+PARSE_LISTENING_PORT([$ovs_base/ovsdb-server.log], [TCP_PORT])
-+start_daemon ovn-controller tcp:127.0.0.1:$TCP_PORT
-+
-+check ovn-nbctl ls-add ls1
-+check ovn-nbctl set Logical_Switch ls1 other_config:subnet=10.1.0.0/16
-+
-+check ovn-nbctl --wait=hv sync
-+
-+add_logical_ports() {
-+ echo Adding logical ports
-+ check ovn-nbctl lsp-add ls1 lsp1
-+ check ovn-nbctl lsp-add ls1 lsp2
-+}
-+
-+remove_logical_ports() {
-+ echo Removing logical ports
-+ check ovn-nbctl lsp-del lsp1
-+ check ovn-nbctl lsp-del lsp2
-+}
-+
-+add_ovs_interface() {
-+ echo Adding interface $1 $2
-+ ovs-vsctl --no-wait -- add-port br-int $1 \
-+ -- set Interface $1 external_ids:iface-id=$2 \
-+ -- set Interface $1 type=internal
-+}
-+add_ovs_interfaces() {
-+ add_ovs_interface vif1 lsp1
-+ add_ovs_interface vif2 lsp2
-+}
-+remove_ovs_interface() {
-+ echo Removing interface $1
-+ check ovs-vsctl --no-wait -- del-port $1
-+}
-+remove_ovs_interfaces() {
-+ remove_ovs_interface vif1
-+ remove_ovs_interface vif2
-+}
-+add_iface_ids() {
-+ echo Adding iface-id vif1 lsp1
-+ ovs-vsctl --no-wait -- set Interface vif1 external_ids:iface-id=lsp1
-+ echo Adding iface-id vif2 lsp2
-+ ovs-vsctl --no-wait -- set Interface vif2 external_ids:iface-id=lsp2
-+}
-+remove_iface_id() {
-+ echo Removing iface-id $1
-+ check ovs-vsctl remove Interface $1 external_ids iface-id
-+}
-+remove_iface_ids() {
-+ remove_iface_id vif1
-+ remove_iface_id vif2
-+}
-+wait_for_local_bindings() {
-+ OVS_WAIT_UNTIL(
-+ [test `ovs-appctl -t ovn-controller debug/dump-local-bindings | grep interface | wc -l` -eq 2],
-+ [kill -CONT $(cat ovn-sb/ovsdb-server.pid)]
-+ )
-+}
-+sleep_sb() {
-+ echo SB going to sleep
-+ AT_CHECK([kill -STOP $(cat ovn-sb/ovsdb-server.pid)])
-+}
-+wake_up_sb() {
-+ echo SB waking up
-+ AT_CHECK([kill -CONT $(cat ovn-sb/ovsdb-server.pid)])
-+}
-+sleep_controller() {
-+ echo Controller going to sleep
-+ ovn-appctl debug/pause
-+ OVS_WAIT_UNTIL([test x$(ovn-appctl -t ovn-controller debug/status) = "xpaused"])
-+}
-+
-+stop_ovsdb_controller_updates() {
-+ TCP_PORT=$1
-+ echo Stopping updates from ovn-controller to ovsdb using port $TCP_PORT
-+ on_exit 'iptables -C INPUT -p tcp --destination-port $TCP_PORT -j DROP 2>/dev/null && iptables -D INPUT -p tcp --destination-port $TCP_PORT -j DROP'
-+ iptables -A INPUT -p tcp --destination-port $TCP_PORT -j DROP
-+}
-+restart_ovsdb_controller_updates() {
-+ TCP_PORT=$1
-+ echo Restarting updates from ovn-controller to ovsdb
-+ iptables -D INPUT -p tcp --destination-port $TCP_PORT -j DROP
-+}
-+wake_up_controller() {
-+ echo Controller waking up
-+ ovn-appctl debug/resume
-+}
-+ensure_controller_run() {
-+# We want to make sure controller could run at least one full loop.
-+# We can't use wait=hv as sb might be sleeping.
-+# Use 2 ovn-appctl to guarentee that ovn-controller run the full loop, and not just the unixctl handling
-+ OVS_WAIT_UNTIL([test x$(ovn-appctl -t ovn-controller debug/status) = "xrunning"])
-+ OVS_WAIT_UNTIL([test x$(ovn-appctl -t ovn-controller debug/status) = "xrunning"])
-+}
-+sleep_ovsdb() {
-+ echo OVSDB going to sleep
-+ AT_CHECK([kill -STOP $(cat ovsdb-server.pid)])
-+}
-+wake_up_ovsdb() {
-+ echo OVSDB waking up
-+ AT_CHECK([kill -CONT $(cat ovsdb-server.pid)])
-+}
-+check_ovn_installed() {
-+ OVS_WAIT_UNTIL([test `ovs-vsctl get Interface vif1 external_ids:ovn-installed` = '"true"'])
-+ OVS_WAIT_UNTIL([test `ovs-vsctl get Interface vif2 external_ids:ovn-installed` = '"true"'])
-+}
-+check_ovn_uninstalled() {
-+ OVS_WAIT_UNTIL([test x`ovs-vsctl get Interface vif2 external_ids:ovn-installed` = x])
-+ OVS_WAIT_UNTIL([test x`ovs-vsctl get Interface vif1 external_ids:ovn-installed` = x])
-+}
-+check_ports_up() {
-+ OVS_WAIT_UNTIL([test `ovn-sbctl get Port_Binding lsp1 up` = 'true'])
-+ OVS_WAIT_UNTIL([test `ovn-sbctl get Port_Binding lsp2 up` = 'true'])
-+}
-+check_ports_down() {
-+ OVS_WAIT_UNTIL([test `ovn-sbctl get Port_Binding lsp1 up` = 'false'])
-+ OVS_WAIT_UNTIL([test `ovn-sbctl get Port_Binding lsp2 up` = 'false'])
-+}
-+
-+check_ports_bound() {
-+ ch=$(fetch_column Chassis _uuid name=hv1)
-+ wait_row_count Port_Binding 1 logical_port=lsp1 chassis=$ch
-+ wait_row_count Port_Binding 1 logical_port=lsp2 chassis=$ch
-+}
-+check_ports_unbound() {
-+ wait_column "" Port_Binding chassis logical_port=lsp1
-+ wait_column "" Port_Binding chassis logical_port=lsp2
-+}
-+add_logical_ports
-+add_ovs_interfaces
-+wait_for_local_bindings
-+wait_for_ports_up
-+check ovn-nbctl --wait=hv sync
-+############################################################
-+########## Remove interface while removing iface-id ########
-+############################################################
-+AS_BOX(["Remove interface while removing iface-id"])
-+stop_ovsdb_controller_updates $TCP_PORT
-+remove_iface_id vif1
-+ensure_controller_run
-+# OVSDB should be seen as ro now
-+remove_iface_id vif2
-+ensure_controller_run
-+# Controller delaying ovn-install removal for vif2 as ovsdb ro
-+sleep_controller
-+restart_ovsdb_controller_updates $TCP_PORT
-+remove_ovs_interface vif2
-+# vif2, for which we want to remove ovn-install, is deleted
-+wake_up_controller
-+check_ovn_uninstalled
-+check_ports_down
-+check_ports_unbound
-+add_ovs_interface vif2 lsp2
-+add_iface_ids
-+check_ovn_installed
-+check_ports_up
-+check_ports_bound
-+############################################################
-+################### Add/Remove iface-id ####################
-+############################################################
-+AS_BOX(["iface-id removal and added back (no sleeping sb or controller)"])
-+remove_iface_ids
-+check_ovn_uninstalled
-+check_ports_down
-+check_ports_unbound
-+add_iface_ids
-+check_ovn_installed
-+check_ports_up
-+check_ports_bound
-+
-+AS_BOX(["iface-id removal"])
-+sleep_sb
-+remove_iface_ids
-+ensure_controller_run
-+sleep_controller
-+wake_up_sb
-+wake_up_controller
-+check_ovn_uninstalled
-+check_ports_down
-+check_ports_unbound
-+add_iface_ids
-+check ovn-nbctl --wait=hv sync
-+
-+AS_BOX(["iface-id removal 2"])
-+# Block IDL from ovn-controller to OVSDB
-+stop_ovsdb_controller_updates $TCP_PORT
-+remove_iface_id vif2
-+ensure_controller_run
-+
-+# OVSDB should now be seen as read-only by ovn-controller
-+remove_iface_id vif1
-+ensure_controller_run
-+
-+# Restart connection from ovn-controller to OVSDB
-+restart_ovsdb_controller_updates $TCP_PORT
-+check_ovn_uninstalled
-+check_ports_down
-+check_ports_unbound
-+
-+add_iface_ids
-+check ovn-nbctl --wait=hv sync
-+
-+AS_BOX(["iface-id removal and added back"])
-+sleep_sb
-+remove_iface_ids
-+ensure_controller_run
-+sleep_controller
-+add_iface_ids
-+wake_up_sb
-+wake_up_controller
-+check_ovn_installed
-+check_ports_up
-+check_ports_bound
-+############################################################
-+###################### Add/Remove Interface ################
-+############################################################
-+AS_BOX(["Interface removal and added back (no sleeping sb or controller)"])
-+remove_ovs_interfaces
-+check_ovn_uninstalled
-+check_ports_down
-+check_ports_unbound
-+add_ovs_interfaces
-+check_ovn_installed
-+check_ports_up
-+check_ports_bound
-+check ovn-nbctl --wait=hv sync
-+
-+AS_BOX(["Interface removal"])
-+sleep_sb
-+remove_ovs_interfaces
-+ensure_controller_run
-+sleep_controller
-+wake_up_sb
-+wake_up_controller
-+check_ovn_uninstalled
-+check_ports_down
-+check_ports_unbound
-+add_ovs_interfaces
-+check ovn-nbctl --wait=hv sync
-+
-+AS_BOX(["Interface removal and added back"])
-+sleep_sb
-+remove_ovs_interfaces
-+ensure_controller_run
-+sleep_controller
-+add_ovs_interfaces
-+wake_up_sb
-+wake_up_controller
-+check_ovn_installed
-+check_ports_up
-+check_ports_bound
-+check ovn-nbctl --wait=hv sync
-+############################################################
-+###################### Add/Remove Logical Port #############
-+############################################################
-+AS_BOX(["Logical port removal and added back (no sleeping sb or controller)"])
-+remove_logical_ports
-+check_ovn_uninstalled
-+check_ports_unbound
-+sleep_ovsdb
-+add_logical_ports
-+ensure_controller_run
-+wake_up_ovsdb
-+check_ovn_installed
-+check_ports_up
-+check_ports_bound
-+check ovn-nbctl --wait=hv sync
-+
-+AS_BOX(["Logical port removal"])
-+sleep_sb
-+remove_logical_ports
-+ensure_controller_run
-+sleep_controller
-+wake_up_sb
-+wake_up_controller
-+check_ovn_uninstalled
-+check_ports_unbound
-+add_logical_ports
-+check ovn-nbctl --wait=hv sync
-+
-+AS_BOX(["Logical port removal and added back"])
-+sleep_sb
-+remove_logical_ports
-+ensure_controller_run
-+sleep_controller
-+add_logical_ports
-+wake_up_sb
-+wake_up_controller
-+check_ovn_installed
-+check_ports_up
-+check_ports_bound
-+
- OVS_APP_EXIT_AND_WAIT([ovn-controller])
-
- as ovn-sb
-@@ -10706,3 +11279,338 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
- /connection dropped.*/d"])
- AT_CLEANUP
- ])
-+
-+OVN_FOR_EACH_NORTHD([
-+AT_SETUP([ovn mirroring])
-+AT_KEYWORDS([mirror])
-+AT_SKIP_IF([test $HAVE_TCPDUMP = no])
-+
-+CHECK_CONNTRACK()
-+CHECK_CONNTRACK_NAT()
-+ovn_start
-+OVS_TRAFFIC_VSWITCHD_START()
-+ADD_BR([br-int])
-+ADD_BR([br-mirror])
-+
-+# Set external-ids in br-int needed for ovn-controller
-+ovs-vsctl \
-+ -- set Open_vSwitch . external-ids:system-id=hv1 \
-+ -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
-+ -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
-+ -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
-+ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
-+
-+# Start ovn-controller
-+start_daemon ovn-controller
-+
-+ovs-ofctl add-flow br-mirror action=normal
-+
-+ovn-nbctl create Logical_Router name=R1 options:chassis=hv1
-+
-+ovn-nbctl ls-add foo
-+ovn-nbctl ls-add bar
-+
-+# Connect foo to R1
-+ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 192.168.1.1/24 2001::1/64
-+ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
-+ type=router options:router-port=foo addresses=\"00:00:01:01:02:03\"
-+
-+# Connect bar to R1
-+ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 192.168.2.1/24 2002::1/64
-+ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \
-+ type=router options:router-port=bar addresses=\"00:00:01:01:02:04\"
-+
-+# Logical port 'foo1' in switch 'foo'.
-+ADD_NAMESPACES(foo1)
-+ADD_VETH(foo1, foo1, br-int, "2001::2/64", "f0:00:00:01:02:03", \
-+ "2001::1", "nodad", "192.168.1.2/24", "192.168.1.1")
-+ovn-nbctl lsp-add foo foo1 \
-+-- lsp-set-addresses foo1 "f0:00:00:01:02:03 192.168.1.2 2001::2"
-+
-+# Logical port 'bar1' in switch 'bar'.
-+ADD_NAMESPACES(bar1)
-+ADD_VETH(bar1, bar1, br-int, "2002::2/64", "f0:00:00:01:02:05", \
-+ "2002::1", "nodad", "192.168.2.2/24", "192.168.2.1")
-+ovn-nbctl lsp-add bar bar1 \
-+-- lsp-set-addresses bar1 "f0:00:00:01:02:05 192.168.2.2 2002::2"
-+
-+ovn-nbctl mirror-add mirror0 gre 1 to-lport 172.16.0.100
-+ovn-nbctl lsp-attach-mirror bar1 mirror0
-+
-+OVN_POPULATE_ARP
-+check ovn-nbctl --wait=hv sync
-+
-+ADD_NAMESPACES(mirror)
-+ADD_VETH(mirror, mirror, br-mirror, "2003::b/64", "f0:00:00:01:07:06", \
-+ "2003::1", "nodad", "172.16.0.100/24", "172.16.0.1")
-+AT_CHECK([ip addr add 172.16.0.101/24 dev br-mirror])
-+AT_CHECK([ip addr add 2003::a/64 dev br-mirror nodad])
-+AT_CHECK([ip link set dev br-mirror up])
-+
-+NS_CHECK_EXEC([mirror], [tcpdump -l -c 3 -neei mirror proto GRE > gre_mirror4.pcap 2>gre_mirror4_error &])
-+OVS_WAIT_UNTIL([grep "listening" gre_mirror4_error])
-+
-+NS_CHECK_EXEC([foo1], [ping -q -c 3 -i 0.3 -w 2 192.168.2.2 | FORMAT_PING], \
-+[0], [dnl
-+3 packets transmitted, 3 received, 0% packet loss, time 0ms
-+])
-+OVS_WAIT_UNTIL([
-+ n_packets=$(grep "GRE" -c gre_mirror4.pcap)
-+ test "${n_packets}" = "3"
-+])
-+
-+killall tcpdump
-+
-+ovn-nbctl mirror-del mirror0
-+ovn-nbctl mirror-add mirror1 gre 2 to-lport 2003::b
-+
-+ovn-nbctl --wait=hv lsp-attach-mirror bar1 mirror1
-+
-+NS_CHECK_EXEC([mirror], [tcpdump -l -c 3 -neei mirror proto GRE > gre_mirror6.pcap 2>gre_mirror6_error &])
-+OVS_WAIT_UNTIL([grep "listening" gre_mirror6_error])
-+
-+NS_CHECK_EXEC([foo1], [ping6 -q -c 3 -i 0.3 -w 2 2002::2 | FORMAT_PING], \
-+[0], [dnl
-+3 packets transmitted, 3 received, 0% packet loss, time 0ms
-+])
-+
-+OVS_WAIT_UNTIL([
-+ n_packets=$(grep "GRE" -c gre_mirror6.pcap)
-+ test "${n_packets}" = "3"
-+])
-+
-+killall tcpdump
-+
-+ovn-nbctl mirror-del mirror1
-+ovn-nbctl mirror-add mirror2 erspan 3 to-lport 172.16.0.100
-+ovn-nbctl --wait=hv lsp-attach-mirror bar1 mirror2
-+
-+NS_CHECK_EXEC([mirror], [tcpdump -l -c 3 -neei mirror ip[[22:2]]=0x88be > erspan_mirror4.pcap 2>erspan_mirror4_error &])
-+OVS_WAIT_UNTIL([grep "listening" erspan_mirror4_error])
-+
-+NS_CHECK_EXEC([foo1], [ping -q -c 3 -i 0.3 -w 2 192.168.2.2 | FORMAT_PING], \
-+[0], [dnl
-+3 packets transmitted, 3 received, 0% packet loss, time 0ms
-+])
-+OVS_WAIT_UNTIL([
-+ n_packets=$(grep "gre-proto-0x88be" -c erspan_mirror4.pcap)
-+ test "${n_packets}" = "3"
-+])
-+
-+killall tcpdump
-+
-+ovn-nbctl mirror-del mirror2
-+ovn-nbctl mirror-add mirror3 erspan 4 to-lport 2003::b
-+ovn-nbctl --wait=hv lsp-attach-mirror bar1 mirror3
-+
-+NS_CHECK_EXEC([mirror], [tcpdump -l -c 3 -neei mirror ip6[[42:2]]=0x88be > erspan_mirror6.pcap 2>erspan_mirror6_error &])
-+OVS_WAIT_UNTIL([grep "listening" erspan_mirror6_error])
-+
-+NS_CHECK_EXEC([foo1], [ping6 -q -c 3 -i 0.3 -w 2 2002::2 | FORMAT_PING], \
-+[0], [dnl
-+3 packets transmitted, 3 received, 0% packet loss, time 0ms
-+])
-+OVS_WAIT_UNTIL([
-+ n_packets=$(grep "gre-proto-0x88be" -c erspan_mirror6.pcap)
-+ test "${n_packets}" = "3"
-+])
-+
-+killall tcpdump
-+
-+uuid=$(fetch_column nb:mirror _uuid name="mirror3")
-+ovn-nbctl --wait=hv set mirror $uuid type=gre
-+
-+NS_CHECK_EXEC([mirror], [tcpdump -c 3 -l -neei mirror proto GRE > gre_mirror6.pcap 2>gre_mirror6_error &])
-+OVS_WAIT_UNTIL([grep "listening" gre_mirror6_error])
-+
-+NS_CHECK_EXEC([foo1], [ping6 -q -c 3 -i 0.3 -w 2 2002::2 | FORMAT_PING], \
-+[0], [dnl
-+3 packets transmitted, 3 received, 0% packet loss, time 0ms
-+])
-+
-+OVS_WAIT_UNTIL([
-+ n_packets=$(grep "GRE" -c gre_mirror6.pcap)
-+ test "${n_packets}" = "3"
-+])
-+
-+killall tcpdump
-+
-+OVS_APP_EXIT_AND_WAIT([ovn-controller])
-+
-+as ovn-sb
-+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
-+
-+as ovn-nb
-+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
-+
-+as northd
-+OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE])
-+
-+as
-+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
-+/connection dropped.*/d"])
-+AT_CLEANUP
-+])
-+
-+OVN_FOR_EACH_NORTHD([
-+AT_SETUP([load balancer with localnet port])
-+CHECK_CONNTRACK()
-+CHECK_CONNTRACK_NAT()
-+ovn_start
-+OVS_TRAFFIC_VSWITCHD_START()
-+ADD_BR([br-int])
-+ADD_BR([br-phys], [set Bridge br-phys fail-mode=standalone])
-+
-+# Set external-ids in br-int needed for ovn-controller
-+ovs-vsctl \
-+ -- set Open_vSwitch . external-ids:system-id=hv1 \
-+ -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
-+ -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
-+ -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
-+ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
-+
-+start_daemon ovn-controller
-+
-+check ovn-nbctl lr-add ro
-+check ovn-nbctl lrp-add ro ro-sw 00:00:00:00:00:01 192.168.0.1/24
-+check ovn-nbctl lrp-add ro ro-pub 00:00:00:00:01:01 10.0.0.1/24
-+
-+check ovn-nbctl ls-add sw
-+check ovn-nbctl lsp-add sw sw-vm1 \
-+ -- lsp-set-addresses sw-vm1 "00:00:00:00:00:02 192.168.0.2"
-+check ovn-nbctl lsp-add sw sw-ro \
-+ -- lsp-set-type sw-ro router \
-+ -- lsp-set-addresses sw-ro router \
-+ -- lsp-set-options sw-ro router-port=ro-sw
-+
-+check ovn-nbctl ls-add pub
-+check ovn-nbctl lsp-add pub sw-ln \
-+ -- lsp-set-type sw-ln localnet \
-+ -- lsp-set-addresses sw-ln unknown \
-+ -- lsp-set-options sw-ln network_name=phys
-+check ovn-nbctl lsp-add pub pub-ro \
-+ -- lsp-set-type pub-ro router \
-+ -- lsp-set-addresses pub-ro router \
-+ -- lsp-set-options pub-ro router-port=ro-pub
-+
-+check ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
-+
-+ADD_NAMESPACES(sw-vm1)
-+ADD_VETH(sw-vm1, sw-vm1, br-int, "192.168.0.2/24", "00:00:00:00:00:02", \
-+ "192.168.0.1")
-+
-+ADD_NAMESPACES(ln)
-+ADD_VETH(ln, ln, br-phys, "10.0.0.2/24", "00:00:00:00:01:02", \
-+ "10.0.0.1")
-+
-+# We have the basic network set up. Now let's add a load balancer
-+# on the "pub" logical switch.
-+
-+check ovn-nbctl lb-add ln-lb 172.16.0.1:80 192.168.0.2:80 tcp
-+check ovn-nbctl ls-lb-add pub ln-lb
-+check ovn-nbctl --wait=hv sync
-+
-+# Add a route so that the localnet port can reach the load balancer
-+# VIP.
-+NS_CHECK_EXEC([ln], [ip route add 172.16.0.1 via 10.0.0.1])
-+NS_CHECK_EXEC([ln], [ip route add 192.168.0.0/24 via 10.0.0.1])
-+
-+OVS_START_L7([sw-vm1], [http])
-+
-+NS_CHECK_EXEC([ln], [wget 172.16.0.1 -t 5 -T 1 --retry-connrefused -v -o wget.log])
-+
-+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.0.1) | \
-+sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl
-+tcp,orig=(src=10.0.0.2,dst=172.16.0.1,sport=,dport=),reply=(src=192.168.0.2,dst=10.0.0.2,sport=,dport=),zone=,mark=2,protoinfo=(state=)
-+])
-+
-+OVS_APP_EXIT_AND_WAIT([ovn-controller])
-+
-+as ovn-sb
-+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
-+
-+as ovn-nb
-+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
-+
-+as northd
-+OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE])
-+
-+as
-+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
-+/connection dropped.*/d"])
-+
-+AT_CLEANUP
-+])
-+
-+OVN_FOR_EACH_NORTHD([
-+AT_SETUP([Traffic to router port via LLA])
-+ovn_start
-+OVS_TRAFFIC_VSWITCHD_START()
-+ADD_BR([br-int])
-+ADD_BR([br-phys], [set Bridge br-phys fail-mode=standalone])
-+
-+# Set external-ids in br-int needed for ovn-controller
-+ovs-vsctl \
-+ -- set Open_vSwitch . external-ids:system-id=hv1 \
-+ -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
-+ -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
-+ -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
-+ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
-+
-+start_daemon ovn-controller
-+
-+check ovn-nbctl lr-add lr0
-+check ovn-nbctl lrp-add lr0 lr0-ls0 00:00:00:00:00:01 fd00::1/64
-+
-+check ovn-nbctl ls-add ls0
-+check ovn-nbctl lsp-add ls0 vif0 \
-+ -- lsp-set-addresses vif0 "00:00:00:00:00:02 fd00::2"
-+check ovn-nbctl lsp-add ls0 ls0-lr0 \
-+ -- lsp-set-type ls0-lr0 router \
-+ -- lsp-set-addresses ls0-lr0 router \
-+ -- lsp-set-options ls0-lr0 router-port=lr0-ls0
-+
-+ADD_NAMESPACES(vif0)
-+ADD_VETH(vif0, vif0, br-int, "fd00::2/64", "00:00:00:00:00:02", "fd00::1")
-+OVS_WAIT_UNTIL([test "$(ip netns exec vif0 ip a | grep fe80:: | grep tentative)" = ""])
-+
-+check ovn-nbctl set logical_router lr0 options:always_learn_from_arp_request=false
-+
-+OVN_POPULATE_ARP
-+wait_for_ports_up
-+check ovn-nbctl --wait=sb sync
-+
-+NS_CHECK_EXEC([vif0], [ping -q -c 3 -i 0.3 -w 2 fe80::200:ff:fe00:1 | FORMAT_PING], \
-+[0], [dnl
-+3 packets transmitted, 3 received, 0% packet loss, time 0ms
-+])
-+
-+check_row_count mac_binding 1 mac=\"00:00:00:00:00:02\"
-+ovn-sbctl --all destroy mac_binding
-+
-+ovn-nbctl --wait=hv set logical_router lr0 options:always_learn_from_arp_request=true
-+
-+NS_CHECK_EXEC([vif0], [ping -q -c 3 -i 0.3 -w 2 fe80::200:ff:fe00:1 | FORMAT_PING], \
-+[0], [dnl
-+3 packets transmitted, 3 received, 0% packet loss, time 0ms
-+])
-+
-+check_row_count mac_binding 1 mac=\"00:00:00:00:00:02\"
-+
-+OVS_APP_EXIT_AND_WAIT([ovn-controller])
-+
-+as ovn-sb
-+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
-+
-+as ovn-nb
-+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
-+
-+as northd
-+OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE])
-+
-+as
-+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
-+/connection dropped.*/d"])
-+
-+AT_CLEANUP
-+])
-diff --git a/utilities/containers/py-requirements.txt b/utilities/containers/py-requirements.txt
-index d7bd21e0d..0d90765c9 100644
---- a/utilities/containers/py-requirements.txt
-+++ b/utilities/containers/py-requirements.txt
-@@ -1,5 +1,6 @@
- flake8
- hacking>=3.0
-+scapy
- sphinx
- setuptools
- pyelftools
-diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c
-index 45572fd30..9399f9462 100644
---- a/utilities/ovn-nbctl.c
-+++ b/utilities/ovn-nbctl.c
-@@ -3033,7 +3033,7 @@ nbctl_lb_add(struct ctl_context *ctx)
- }
-
- ovn_lb_vip_format(&lb_vip_parsed, &lb_vip_normalized, template);
-- ovn_lb_vip_backends_format(&lb_vip_parsed, &lb_ips_new, template);
-+ ovn_lb_vip_backends_format(&lb_vip_parsed, &lb_ips_new);
- ovn_lb_vip_destroy(&lb_vip_parsed);
-
- const struct nbrec_load_balancer *lb = NULL;
-@@ -4204,8 +4204,7 @@ print_routing_policy(const struct nbrec_logical_router_policy *policy,
- policy->match, policy->action);
- for (int i = 0; i < policy->n_nexthops; i++) {
- char *next_hop = normalize_prefix_str(policy->nexthops[i]);
-- char *fmt = i ? ", %s" : " %25s";
-- ds_put_format(s, fmt, next_hop);
-+ ds_put_format(s, i ? ", %s" : " %25s", next_hop ? next_hop : "");
- free(next_hop);
- }
- } else {
-@@ -6586,18 +6585,17 @@ print_route(const struct nbrec_logical_router_static_route *route,
- {
-
- char *prefix = normalize_prefix_str(route->ip_prefix);
-- char *next_hop = "";
-+ char *next_hop = NULL;
-
- if (!strcmp(route->nexthop, "discard")) {
- next_hop = xasprintf("discard");
- } else if (route->nexthop[0]) {
- next_hop = normalize_prefix_str(route->nexthop);
- }
-- ds_put_format(s, "%25s %25s", prefix, next_hop);
-+ ds_put_format(s, "%25s %25s", prefix ? prefix : "",
-+ next_hop ? next_hop : "");
- free(prefix);
-- if (next_hop[0]) {
-- free(next_hop);
-- }
-+ free(next_hop);
-
- if (route->policy) {
- ds_put_format(s, " %s", route->policy);
diff --git a/SOURCES/ovn23.06.patch b/SOURCES/ovn23.06.patch
new file mode 100644
index 0000000..ccd46e5
--- /dev/null
+++ b/SOURCES/ovn23.06.patch
@@ -0,0 +1,669 @@
+diff --git a/NEWS b/NEWS
+index ef000ef7b..0056bb175 100644
+--- a/NEWS
++++ b/NEWS
+@@ -1,3 +1,6 @@
++OVN v23.06.2 - xx xxx xxxx
++--------------------------
++
+ OVN v23.06.1 - 29 Aug 2023
+ --------------------------
+ - Bug fixes
+diff --git a/configure.ac b/configure.ac
+index fc4ba024a..3ed093ebe 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -13,7 +13,7 @@
+ # limitations under the License.
+
+ AC_PREREQ(2.63)
+-AC_INIT(ovn, 23.06.1, bugs@openvswitch.org)
++AC_INIT(ovn, 23.06.2, bugs@openvswitch.org)
+ AC_CONFIG_MACRO_DIR([m4])
+ AC_CONFIG_AUX_DIR([build-aux])
+ AC_CONFIG_HEADERS([config.h])
+diff --git a/controller/lflow.c b/controller/lflow.c
+index 22faaf013..718b4a27a 100644
+--- a/controller/lflow.c
++++ b/controller/lflow.c
+@@ -2513,10 +2513,10 @@ build_in_port_sec_default_flows(const struct sbrec_port_binding *pb,
+ * investigation.
+ *
+ * Eg. If there are below OF rules in the same table
+- * (1) priority=90,icmp6,reg14=0x1,metadata=0x1,nw_ttl=225,icmp_type=135,
++ * (1) priority=90,icmp6,reg14=0x1,metadata=0x1,nw_ttl=255,icmp_type=135,
+ * icmp_code=0,nd_sll=fa:16:3e:94:05:98
+ * actions=load:0->NXM_NX_REG10[12]
+- * (2) priority=80,icmp6,reg14=0x1,metadata=0x1,nw_ttl=225,icmp_type=135,
++ * (2) priority=80,icmp6,reg14=0x1,metadata=0x1,nw_ttl=255,icmp_type=135,
+ * icmp_code=0 actions=load:1->NXM_NX_REG10[12]
+ *
+ * An IPv6 NS packet with nd_sll = fa:16:3e:94:05:98 is matching on the
+@@ -2801,7 +2801,7 @@ build_in_port_sec_nd_flows(const struct sbrec_port_binding *pb,
+ reset_match_for_port_sec_flows(pb, MFF_LOG_INPORT, m);
+ match_set_dl_type(m, htons(ETH_TYPE_IPV6));
+ match_set_nw_proto(m, IPPROTO_ICMPV6);
+- match_set_nw_ttl(m, 225);
++ match_set_nw_ttl(m, 255);
+ match_set_icmp_type(m, 135);
+ match_set_icmp_code(m, 0);
+
+diff --git a/controller/ofctrl.c b/controller/ofctrl.c
+index 64a444ff6..a1676a788 100644
+--- a/controller/ofctrl.c
++++ b/controller/ofctrl.c
+@@ -16,6 +16,7 @@
+ #include
+ #include "bitmap.h"
+ #include "byte-order.h"
++#include "coverage.h"
+ #include "dirs.h"
+ #include "dp-packet.h"
+ #include "flow.h"
+@@ -55,6 +56,8 @@
+
+ VLOG_DEFINE_THIS_MODULE(ofctrl);
+
++COVERAGE_DEFINE(ofctrl_msg_too_long);
++
+ /* An OpenFlow flow. */
+ struct ovn_flow {
+ /* Key. */
+@@ -1273,6 +1276,37 @@ ofctrl_add_flow_metered(struct ovn_desired_flow_table *desired_flows,
+ meter_id, as_info, true);
+ }
+
++struct ofpact_ref {
++ struct hmap_node hmap_node;
++ struct ofpact *ofpact;
++};
++
++static struct ofpact_ref *
++ofpact_ref_find(const struct hmap *refs, const struct ofpact *ofpact)
++{
++ uint32_t hash = hash_bytes(ofpact, ofpact->len, 0);
++
++ struct ofpact_ref *ref;
++ HMAP_FOR_EACH_WITH_HASH (ref, hmap_node, hash, refs) {
++ if (ofpacts_equal(ref->ofpact, ref->ofpact->len,
++ ofpact, ofpact->len)) {
++ return ref;
++ }
++ }
++
++ return NULL;
++}
++
++static void
++ofpact_refs_destroy(struct hmap *refs)
++{
++ struct ofpact_ref *ref;
++ HMAP_FOR_EACH_POP (ref, hmap_node, refs) {
++ free(ref);
++ }
++ hmap_destroy(refs);
++}
++
+ /* Either add a new flow, or append actions on an existing flow. If the
+ * flow existed, a new link will also be created between the new sb_uuid
+ * and the existing flow. */
+@@ -1292,6 +1326,21 @@ ofctrl_add_or_append_flow(struct ovn_desired_flow_table *desired_flows,
+ meter_id);
+ existing = desired_flow_lookup_conjunctive(desired_flows, &f->flow);
+ if (existing) {
++ struct hmap existing_conj = HMAP_INITIALIZER(&existing_conj);
++
++ struct ofpact *ofpact;
++ OFPACT_FOR_EACH (ofpact, existing->flow.ofpacts,
++ existing->flow.ofpacts_len) {
++ if (ofpact->type != OFPACT_CONJUNCTION) {
++ continue;
++ }
++
++ struct ofpact_ref *ref = xmalloc(sizeof *ref);
++ ref->ofpact = ofpact;
++ uint32_t hash = hash_bytes(ofpact, ofpact->len, 0);
++ hmap_insert(&existing_conj, &ref->hmap_node, hash);
++ }
++
+ /* There's already a flow with this particular match and action
+ * 'conjunction'. Append the action to that flow rather than
+ * adding a new flow.
+@@ -1301,7 +1350,15 @@ ofctrl_add_or_append_flow(struct ovn_desired_flow_table *desired_flows,
+ ofpbuf_use_stub(&compound, compound_stub, sizeof(compound_stub));
+ ofpbuf_put(&compound, existing->flow.ofpacts,
+ existing->flow.ofpacts_len);
+- ofpbuf_put(&compound, f->flow.ofpacts, f->flow.ofpacts_len);
++
++ OFPACT_FOR_EACH (ofpact, f->flow.ofpacts, f->flow.ofpacts_len) {
++ if (ofpact->type != OFPACT_CONJUNCTION ||
++ !ofpact_ref_find(&existing_conj, ofpact)) {
++ ofpbuf_put(&compound, ofpact, OFPACT_ALIGN(ofpact->len));
++ }
++ }
++
++ ofpact_refs_destroy(&existing_conj);
+
+ mem_stats.desired_flow_usage -= desired_flow_size(existing);
+ free(existing->flow.ofpacts);
+@@ -1769,6 +1826,18 @@ ovn_flow_log(const struct ovn_flow *f, const char *action)
+ }
+ }
+
++static void
++ovn_flow_log_size_err(const struct ovn_flow *f)
++{
++ COVERAGE_INC(ofctrl_msg_too_long);
++
++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
++
++ char *s = ovn_flow_to_string(f);
++ VLOG_ERR_RL(&rl, "The FLOW_MOD message is too big: %s", s);
++ free(s);
++}
++
+ static void
+ ovn_flow_uninit(struct ovn_flow *f)
+ {
+@@ -1888,15 +1957,27 @@ encode_bundle_add(struct ofpbuf *msg, struct ofputil_bundle_ctrl_msg *bc)
+ return ofputil_encode_bundle_add(OFP15_VERSION, &bam);
+ }
+
+-static void
++static bool
+ add_flow_mod(struct ofputil_flow_mod *fm,
+ struct ofputil_bundle_ctrl_msg *bc,
+ struct ovs_list *msgs)
+ {
+ struct ofpbuf *msg = encode_flow_mod(fm);
+ struct ofpbuf *bundle_msg = encode_bundle_add(msg, bc);
++
++ uint32_t flow_mod_len = msg->size;
++ uint32_t bundle_len = bundle_msg->size;
++
+ ofpbuf_delete(msg);
++
++ if (flow_mod_len > UINT16_MAX || bundle_len > UINT16_MAX) {
++ ofpbuf_delete(bundle_msg);
++
++ return false;
++ }
++
+ ovs_list_push_back(msgs, &bundle_msg->list_node);
++ return true;
+ }
+
+ /* group_table. */
+@@ -2235,7 +2316,10 @@ installed_flow_add(struct ovn_flow *d,
+ .new_cookie = htonll(d->cookie),
+ .command = OFPFC_ADD,
+ };
+- add_flow_mod(&fm, bc, msgs);
++
++ if (!add_flow_mod(&fm, bc, msgs)) {
++ ovn_flow_log_size_err(d);
++ }
+ }
+
+ static void
+@@ -2259,7 +2343,7 @@ installed_flow_mod(struct ovn_flow *i, struct ovn_flow *d,
+ /* Use OFPFC_ADD so that cookie can be updated. */
+ fm.command = OFPFC_ADD;
+ }
+- add_flow_mod(&fm, bc, msgs);
++ bool result = add_flow_mod(&fm, bc, msgs);
+
+ /* Replace 'i''s actions and cookie by 'd''s. */
+ mem_stats.installed_flow_usage -= i->ofpacts_len - d->ofpacts_len;
+@@ -2267,6 +2351,10 @@ installed_flow_mod(struct ovn_flow *i, struct ovn_flow *d,
+ i->ofpacts = xmemdup(d->ofpacts, d->ofpacts_len);
+ i->ofpacts_len = d->ofpacts_len;
+ i->cookie = d->cookie;
++
++ if (!result) {
++ ovn_flow_log_size_err(i);
++ }
+ }
+
+ static void
+@@ -2280,7 +2368,10 @@ installed_flow_del(struct ovn_flow *i,
+ .table_id = i->table_id,
+ .command = OFPFC_DELETE_STRICT,
+ };
+- add_flow_mod(&fm, bc, msgs);
++
++ if (!add_flow_mod(&fm, bc, msgs)) {
++ ovn_flow_log_size_err(i);
++ }
+ }
+
+ static void
+diff --git a/debian/changelog b/debian/changelog
+index e1d505a7e..e147d113c 100644
+--- a/debian/changelog
++++ b/debian/changelog
+@@ -1,3 +1,9 @@
++OVN (23.06.2-1) unstable; urgency=low
++ [ OVN team ]
++ * New upstream version
++
++ -- OVN team Tue, 29 Aug 2023 11:28:59 -0400
++
+ OVN (23.06.1-1) unstable; urgency=low
+ [ OVN team ]
+ * New upstream version
+diff --git a/northd/northd.c b/northd/northd.c
+index af871e260..3d6449c88 100644
+--- a/northd/northd.c
++++ b/northd/northd.c
+@@ -259,7 +259,6 @@ enum ovn_stage {
+ #define REGBIT_LOOKUP_NEIGHBOR_RESULT "reg9[2]"
+ #define REGBIT_LOOKUP_NEIGHBOR_IP_RESULT "reg9[3]"
+ #define REGBIT_DST_NAT_IP_LOCAL "reg9[4]"
+-#define REGBIT_KNOWN_ECMP_NH "reg9[5]"
+ #define REGBIT_KNOWN_LB_SESSION "reg9[6]"
+
+ /* Register to store the eth address associated to a router port for packets
+@@ -367,8 +366,7 @@ enum ovn_stage {
+ * | | EGRESS_LOOPBACK/ | G | UNUSED |
+ * | R9 | PKT_LARGER/ | 4 | |
+ * | | LOOKUP_NEIGHBOR_RESULT/ | | |
+- * | | SKIP_LOOKUP_NEIGHBOR/ | | |
+- * | | KNOWN_ECMP_NH} | | |
++ * | | SKIP_LOOKUP_NEIGHBOR} | | |
+ * | | | | |
+ * | | REG_ORIG_TP_DPORT_ROUTER | | |
+ * | | | | |
+@@ -10326,15 +10324,13 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows,
+ cidr);
+ free(cidr);
+ ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DEFRAG, 100,
+- ds_cstr(&base_match),
+- REGBIT_KNOWN_ECMP_NH" = chk_ecmp_nh_mac(); ct_next;",
+- &st_route->header_);
++ ds_cstr(&base_match), "ct_next;",
++ &st_route->header_);
+
+ /* And packets that go out over an ECMP route need conntrack */
+ ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DEFRAG, 100,
+- ds_cstr(route_match),
+- REGBIT_KNOWN_ECMP_NH" = chk_ecmp_nh(); ct_next;",
+- &st_route->header_);
++ ds_cstr(route_match), "ct_next;",
++ &st_route->header_);
+
+ /* Save src eth and inport in ct_label for packets that arrive over
+ * an ECMP route.
+@@ -10347,9 +10343,8 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows,
+ ds_put_format(&actions,
+ "ct_commit { ct_label.ecmp_reply_eth = eth.src; "
+ " %s = %" PRId64 ";}; "
+- "commit_ecmp_nh(ipv6 = %s, proto = tcp); next;",
+- ct_ecmp_reply_port_match, out_port->sb->tunnel_key,
+- IN6_IS_ADDR_V4MAPPED(&route->prefix) ? "false" : "true");
++ "next;",
++ ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
+ ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
+ ds_cstr(&match), ds_cstr(&actions),
+ &st_route->header_);
+@@ -10360,9 +10355,8 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows,
+ ds_put_format(&actions,
+ "ct_commit { ct_label.ecmp_reply_eth = eth.src; "
+ " %s = %" PRId64 ";}; "
+- "commit_ecmp_nh(ipv6 = %s, proto = udp); next;",
+- ct_ecmp_reply_port_match, out_port->sb->tunnel_key,
+- IN6_IS_ADDR_V4MAPPED(&route->prefix) ? "false" : "true");
++ "next;",
++ ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
+ ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
+ ds_cstr(&match), ds_cstr(&actions),
+ &st_route->header_);
+@@ -10373,53 +10367,49 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows,
+ ds_put_format(&actions,
+ "ct_commit { ct_label.ecmp_reply_eth = eth.src; "
+ " %s = %" PRId64 ";}; "
+- "commit_ecmp_nh(ipv6 = %s, proto = sctp); next;",
+- ct_ecmp_reply_port_match, out_port->sb->tunnel_key,
+- IN6_IS_ADDR_V4MAPPED(&route->prefix) ? "false" : "true");
++ "next;",
++ ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
+ ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
+ ds_cstr(&match), ds_cstr(&actions),
+ &st_route->header_);
+
+ ds_clear(&match);
+ ds_put_format(&match,
+- "%s && (!ct.rpl && ct.est) && tcp && "REGBIT_KNOWN_ECMP_NH" == 0",
++ "%s && (!ct.rpl && ct.est) && tcp",
+ ds_cstr(&base_match));
+ ds_clear(&actions);
+ ds_put_format(&actions,
+ "ct_commit { ct_label.ecmp_reply_eth = eth.src; "
+ " %s = %" PRId64 ";}; "
+- "commit_ecmp_nh(ipv6 = %s, proto = tcp); next;",
+- ct_ecmp_reply_port_match, out_port->sb->tunnel_key,
+- IN6_IS_ADDR_V4MAPPED(&route->prefix) ? "false" : "true");
++ "next;",
++ ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
+ ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
+ ds_cstr(&match), ds_cstr(&actions),
+ &st_route->header_);
+
+ ds_clear(&match);
+ ds_put_format(&match,
+- "%s && (!ct.rpl && ct.est) && udp && "REGBIT_KNOWN_ECMP_NH" == 0",
++ "%s && (!ct.rpl && ct.est) && udp",
+ ds_cstr(&base_match));
+ ds_clear(&actions);
+ ds_put_format(&actions,
+ "ct_commit { ct_label.ecmp_reply_eth = eth.src; "
+ " %s = %" PRId64 ";}; "
+- "commit_ecmp_nh(ipv6 = %s, proto = udp); next;",
+- ct_ecmp_reply_port_match, out_port->sb->tunnel_key,
+- IN6_IS_ADDR_V4MAPPED(&route->prefix) ? "false" : "true");
++ "next;",
++ ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
+ ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
+ ds_cstr(&match), ds_cstr(&actions),
+ &st_route->header_);
+ ds_clear(&match);
+ ds_put_format(&match,
+- "%s && (!ct.rpl && ct.est) && sctp && "REGBIT_KNOWN_ECMP_NH" == 0",
++ "%s && (!ct.rpl && ct.est) && sctp",
+ ds_cstr(&base_match));
+ ds_clear(&actions);
+ ds_put_format(&actions,
+ "ct_commit { ct_label.ecmp_reply_eth = eth.src; "
+ " %s = %" PRId64 ";}; "
+- "commit_ecmp_nh(ipv6 = %s, proto = sctp); next;",
+- ct_ecmp_reply_port_match, out_port->sb->tunnel_key,
+- IN6_IS_ADDR_V4MAPPED(&route->prefix) ? "false" : "true");
++ "next;",
++ ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
+ ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100,
+ ds_cstr(&match), ds_cstr(&actions),
+ &st_route->header_);
+@@ -10428,7 +10418,7 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows,
+ * for where to route the packet.
+ */
+ ds_put_format(&ecmp_reply,
+- "ct.rpl && "REGBIT_KNOWN_ECMP_NH" == 1 && %s == %"PRId64,
++ "ct.rpl && %s == %"PRId64,
+ ct_ecmp_reply_port_match, out_port->sb->tunnel_key);
+ ds_clear(&match);
+ ds_put_format(&match, "%s && %s", ds_cstr(&ecmp_reply),
+@@ -10853,6 +10843,10 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
+ {
+ bool ipv4 = lb_vip->address_family == AF_INET;
+ const char *ip_match = ipv4 ? "ip4" : "ip6";
++ char *aff_action[LROUTER_NAT_LB_FLOW_MAX] = {
++ [LROUTER_NAT_LB_FLOW_SKIP_SNAT] = "flags.skip_snat_for_lb = 1; ",
++ [LROUTER_NAT_LB_FLOW_FORCE_SNAT] = "flags.force_snat_for_lb = 1; ",
++ };
+
+ int prio = 110;
+
+@@ -10925,15 +10919,13 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
+ ctx.new_action[LROUTER_NAT_LB_FLOW_SKIP_SNAT] = ds_cstr(&skip_snat_act);
+ ctx.new_action[LROUTER_NAT_LB_FLOW_FORCE_SNAT] = ds_cstr(&force_snat_act);
+
+- enum {
+- LROUTER_NAT_LB_AFF = LROUTER_NAT_LB_FLOW_MAX,
+- LROUTER_NAT_LB_AFF_FORCE_SNAT = LROUTER_NAT_LB_FLOW_MAX + 1,
+- };
+- unsigned long *dp_bitmap[LROUTER_NAT_LB_FLOW_MAX + 2];
++ unsigned long *gw_dp_bitmap[LROUTER_NAT_LB_FLOW_MAX];
++ unsigned long *aff_dp_bitmap[LROUTER_NAT_LB_FLOW_MAX];
+
+ size_t bitmap_len = ods_size(lr_datapaths);
+- for (size_t i = 0; i < LROUTER_NAT_LB_FLOW_MAX + 2; i++) {
+- dp_bitmap[i] = bitmap_allocate(bitmap_len);
++ for (size_t i = 0; i < LROUTER_NAT_LB_FLOW_MAX; i++) {
++ gw_dp_bitmap[i] = bitmap_allocate(bitmap_len);
++ aff_dp_bitmap[i] = bitmap_allocate(bitmap_len);
+ }
+
+ /* Group gw router since we do not have datapath dependency in
+@@ -10954,18 +10946,13 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
+ }
+
+ if (!od->n_l3dgw_ports) {
+- bitmap_set1(dp_bitmap[type], index);
++ bitmap_set1(gw_dp_bitmap[type], index);
+ } else {
+ build_distr_lrouter_nat_flows_for_lb(&ctx, type, od);
+ }
+
+ if (lb->affinity_timeout) {
+- if (!lport_addresses_is_empty(&od->lb_force_snat_addrs) ||
+- od->lb_force_snat_router_ip) {
+- bitmap_set1(dp_bitmap[LROUTER_NAT_LB_AFF_FORCE_SNAT], index);
+- } else {
+- bitmap_set1(dp_bitmap[LROUTER_NAT_LB_AFF], index);
+- }
++ bitmap_set1(aff_dp_bitmap[type], index);
+ }
+
+ if (sset_contains(&od->external_ips, lb_vip->vip_str)) {
+@@ -10988,33 +10975,20 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
+
+ for (size_t type = 0; type < LROUTER_NAT_LB_FLOW_MAX; type++) {
+ build_gw_lrouter_nat_flows_for_lb(&ctx, type, lr_datapaths,
+- dp_bitmap[type]);
++ gw_dp_bitmap[type]);
++ build_lb_affinity_lr_flows(lflows, lb, lb_vip, ds_cstr(match),
++ aff_action[type], aff_dp_bitmap[type],
++ lr_datapaths);
+ }
+
+- /* LB affinity flows for datapaths where CMS has specified
+- * force_snat_for_lb floag option.
+- */
+- build_lb_affinity_lr_flows(lflows, lb, lb_vip, ds_cstr(match),
+- "flags.force_snat_for_lb = 1; ",
+- dp_bitmap[LROUTER_NAT_LB_AFF_FORCE_SNAT],
+- lr_datapaths);
+-
+- /* LB affinity flows for datapaths where CMS has specified
+- * skip_snat_for_lb floag option or regular datapaths.
+- */
+- char *lb_aff_action =
+- lb->skip_snat ? "flags.skip_snat_for_lb = 1; " : NULL;
+- build_lb_affinity_lr_flows(lflows, lb, lb_vip, ds_cstr(match),
+- lb_aff_action, dp_bitmap[LROUTER_NAT_LB_AFF],
+- lr_datapaths);
+-
+ ds_destroy(&unsnat_match);
+ ds_destroy(&undnat_match);
+ ds_destroy(&skip_snat_act);
+ ds_destroy(&force_snat_act);
+
+- for (size_t i = 0; i < LROUTER_NAT_LB_FLOW_MAX + 2; i++) {
+- bitmap_free(dp_bitmap[i]);
++ for (size_t i = 0; i < LROUTER_NAT_LB_FLOW_MAX; i++) {
++ bitmap_free(gw_dp_bitmap[i]);
++ bitmap_free(aff_dp_bitmap[i]);
+ }
+ }
+
+@@ -11761,7 +11735,13 @@ build_gateway_get_l2_hdr_size(struct ovn_port *op)
+ struct ovn_port *localnet_port = peer->od->localnet_ports[i];
+ const struct nbrec_logical_switch_port *nbsp = localnet_port->nbsp;
+
+- if (nbsp && nbsp->n_tag_request > 0) {
++ if (!nbsp || !nbsp->tag_request) {
++ continue;
++ }
++
++ if (nbsp->tag_request[0] ||
++ (nbsp->parent_name && nbsp->parent_name[0])) {
++ /* Valid tag. */
+ return VLAN_ETH_HEADER_LEN;
+ }
+ }
+diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
+index 35c79cd69..60cb947c4 100644
+--- a/tests/ovn-northd.at
++++ b/tests/ovn-northd.at
+@@ -6193,6 +6193,23 @@ AT_CHECK([grep "lr_in_admission" lr0flows | grep -e "check_pkt_larger" | sort],
+ table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
+ ])
+
++# tag 0 requires a parent port
++check ovn-nbctl --wait=sb set Logical_Switch_Port ext-port tag_request=0
++
++ovn-sbctl dump-flows lr0 > lr0flows
++AT_CHECK([grep "lr_in_admission" lr0flows | grep -e "check_pkt_larger" | sort], [0], [dnl
++ table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
++ table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
++])
++
++check ovn-nbctl --wait=sb set Logical_Switch_Port ext-port parent_name=ext-parent-port
++
++ovn-sbctl dump-flows lr0 > lr0flows
++AT_CHECK([grep "lr_in_admission" lr0flows | grep -e "check_pkt_larger" | sort], [0], [dnl
++ table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
++ table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;)
++])
++
+ AT_CLEANUP
+ ])
+
+@@ -6236,24 +6253,16 @@ AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed 's/192\.168\.0\..0/192.
+ table=??(lr_in_ip_routing_ecmp), priority=150 , match=(reg8[[0..15]] == 0), action=(next;)
+ ])
+
+-AT_CHECK([grep -e "lr_in_ecmp_stateful".*commit_ecmp_nh lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl
+- table=??(lr_in_ecmp_stateful), priority=100 , match=(inport == "lr0-public" && ip4.src == 1.0.0.1 && (!ct.rpl && ct.est) && sctp && reg9[[5]] == 0), action=(ct_commit { ct_label.ecmp_reply_eth = eth.src; ct_label.ecmp_reply_port = 1;}; commit_ecmp_nh(ipv6 = false, proto = sctp); next;)
+- table=??(lr_in_ecmp_stateful), priority=100 , match=(inport == "lr0-public" && ip4.src == 1.0.0.1 && (!ct.rpl && ct.est) && tcp && reg9[[5]] == 0), action=(ct_commit { ct_label.ecmp_reply_eth = eth.src; ct_label.ecmp_reply_port = 1;}; commit_ecmp_nh(ipv6 = false, proto = tcp); next;)
+- table=??(lr_in_ecmp_stateful), priority=100 , match=(inport == "lr0-public" && ip4.src == 1.0.0.1 && (!ct.rpl && ct.est) && udp && reg9[[5]] == 0), action=(ct_commit { ct_label.ecmp_reply_eth = eth.src; ct_label.ecmp_reply_port = 1;}; commit_ecmp_nh(ipv6 = false, proto = udp); next;)
+- table=??(lr_in_ecmp_stateful), priority=100 , match=(inport == "lr0-public" && ip4.src == 1.0.0.1 && (ct.new && !ct.est) && sctp), action=(ct_commit { ct_label.ecmp_reply_eth = eth.src; ct_label.ecmp_reply_port = 1;}; commit_ecmp_nh(ipv6 = false, proto = sctp); next;)
+- table=??(lr_in_ecmp_stateful), priority=100 , match=(inport == "lr0-public" && ip4.src == 1.0.0.1 && (ct.new && !ct.est) && tcp), action=(ct_commit { ct_label.ecmp_reply_eth = eth.src; ct_label.ecmp_reply_port = 1;}; commit_ecmp_nh(ipv6 = false, proto = tcp); next;)
+- table=??(lr_in_ecmp_stateful), priority=100 , match=(inport == "lr0-public" && ip4.src == 1.0.0.1 && (ct.new && !ct.est) && udp), action=(ct_commit { ct_label.ecmp_reply_eth = eth.src; ct_label.ecmp_reply_port = 1;}; commit_ecmp_nh(ipv6 = false, proto = udp); next;)
+-])
+-
+-AT_CHECK([grep -e "lr_in_defrag".*chk_ecmp_nh* lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl
+- table=??(lr_in_defrag ), priority=100 , match=(inport == "lr0-public" && ip4.src == 1.0.0.1), action=(reg9[[5]] = chk_ecmp_nh_mac(); ct_next;)
+- table=??(lr_in_defrag ), priority=100 , match=(reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(reg9[[5]] = chk_ecmp_nh(); ct_next;)
++AT_CHECK([grep -e "lr_in_defrag" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl
++ table=??(lr_in_defrag ), priority=0 , match=(1), action=(next;)
++ table=??(lr_in_defrag ), priority=100 , match=(inport == "lr0-public" && ip4.src == 1.0.0.1), action=(ct_next;)
++ table=??(lr_in_defrag ), priority=100 , match=(reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ct_next;)
+ ])
+
+ dnl The chassis was created with other_config:ct-no-masked-label=false, the flows
+ dnl should be using ct_label.ecmp_reply_port.
+ 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 && reg9[[5]] == 1 && ct_label.ecmp_reply_port == 1), action=(push(xxreg1); xxreg1 = ct_label; eth.dst = xxreg1[[32..79]]; pop(xxreg1); next;)
++ table=??(lr_in_arp_resolve ), priority=200 , match=(ct.rpl && ct_label.ecmp_reply_port == 1), action=(push(xxreg1); xxreg1 = ct_label; eth.dst = xxreg1[[32..79]]; pop(xxreg1); next;)
+ ])
+
+ dnl Simulate an ovn-controller upgrade to a version that supports
+@@ -6263,7 +6272,7 @@ check ovn-sbctl set chassis ch1 other_config:ct-no-masked-label=true
+ check ovn-nbctl --wait=sb sync
+ ovn-sbctl dump-flows lr0 > lr0flows
+ 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 && reg9[[5]] == 1 && ct_mark.ecmp_reply_port == 1), action=(push(xxreg1); xxreg1 = ct_label; eth.dst = xxreg1[[32..79]]; pop(xxreg1); next;)
++ table=??(lr_in_arp_resolve ), priority=200 , match=(ct.rpl && ct_mark.ecmp_reply_port == 1), action=(push(xxreg1); xxreg1 = ct_label; eth.dst = xxreg1[[32..79]]; pop(xxreg1); next;)
+ ])
+
+ # add ecmp route with wrong nexthop
+@@ -8807,6 +8816,26 @@ AT_CHECK([grep "lr_in_dnat " R1flows_force_snat | sed 's/table=../table=??/' | s
+ table=??(lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
+ ])
+
++AS_BOX([Test LR flows - lb_force_snat_ip="172.16.0.1" + skip_snat=true])
++check ovn-nbctl --wait=sb set logical_router R1 options:lb_force_snat_ip="172.16.0.1"
++check ovn-nbctl --wait=sb set load_balancer lb0 options:skip_snat=true
++
++ovn-sbctl dump-flows R1 > R1flows_force_skip_snat
++AT_CAPTURE_FILE([R1flows_force_skip_snat])
++
++AT_CHECK([grep "lr_in_dnat " R1flows_force_skip_snat | sed 's/table=../table=??/' | sort], [0], [dnl
++ table=??(lr_in_dnat ), priority=0 , match=(1), action=(next;)
++ table=??(lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; skip_snat);)
++ table=??(lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; skip_snat);)
++ table=??(lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; skip_snat);)
++ table=??(lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;)
++ table=??(lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;)
++ table=??(lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;)
++ table=??(lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;)
++ table=??(lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;)
++ table=??(lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;)
++])
++
+ AT_CLEANUP
+ ])
+
+diff --git a/tests/ovn.at b/tests/ovn.at
+index 48dbc3347..acda8514e 100644
+--- a/tests/ovn.at
++++ b/tests/ovn.at
+@@ -34023,10 +34023,10 @@ echo " table=74, priority=80,arp,reg14=0x$sw0p1_key,metadata=0x1 actions=load:0x
+ table=74, priority=80,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=255,icmp_type=135 actions=load:0->NXM_NX_REG10[[12]]
+ table=74, priority=80,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=255,icmp_type=136 actions=load:0x1->NXM_NX_REG10[[12]]
+ table=74, priority=90,arp,reg14=0x$sw0p1_key,metadata=0x1,dl_src=00:00:00:00:00:03,arp_sha=00:00:00:00:00:03 actions=load:0->NXM_NX_REG10[[12]]
+- table=74, priority=90,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=225,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:00 actions=load:0->NXM_NX_REG10[[12]]
+- table=74, priority=90,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=225,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:03 actions=load:0->NXM_NX_REG10[[12]]
+- table=74, priority=90,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=225,icmp_type=136,icmp_code=0,nd_tll=00:00:00:00:00:00 actions=load:0->NXM_NX_REG10[[12]]
+- table=74, priority=90,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=225,icmp_type=136,icmp_code=0,nd_tll=00:00:00:00:00:03 actions=load:0->NXM_NX_REG10[[12]]" > hv1_t74_flows.expected
++ table=74, priority=90,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=255,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:00 actions=load:0->NXM_NX_REG10[[12]]
++ table=74, priority=90,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=255,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:03 actions=load:0->NXM_NX_REG10[[12]]
++ table=74, priority=90,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=255,icmp_type=136,icmp_code=0,nd_tll=00:00:00:00:00:00 actions=load:0->NXM_NX_REG10[[12]]
++ table=74, priority=90,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=255,icmp_type=136,icmp_code=0,nd_tll=00:00:00:00:00:03 actions=load:0->NXM_NX_REG10[[12]]" > hv1_t74_flows.expected
+
+ check_port_sec_offlows hv1 74
+
+@@ -34060,12 +34060,12 @@ echo " table=74, priority=80,arp,reg14=0x$sw0p1_key,metadata=0x1 actions=load:0x
+ table=74, priority=80,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=255,icmp_type=136 actions=load:0x1->NXM_NX_REG10[[12]]
+ table=74, priority=90,arp,reg14=0x$sw0p1_key,metadata=0x1,dl_src=00:00:00:00:00:03,arp_spa=10.0.0.3,arp_sha=00:00:00:00:00:03 actions=load:0->NXM_NX_REG10[[12]]
+ table=74, priority=90,arp,reg14=0x$sw0p1_key,metadata=0x1,dl_src=00:00:00:00:00:13,arp_spa=10.0.0.13,arp_sha=00:00:00:00:00:13 actions=load:0->NXM_NX_REG10[[12]]
+- table=74, priority=90,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=225,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:00 actions=load:0->NXM_NX_REG10[[12]]
+- table=74, priority=90,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=225,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:03 actions=load:0->NXM_NX_REG10[[12]]
+- table=74, priority=90,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=225,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:13 actions=load:0->NXM_NX_REG10[[12]]
+- table=74, priority=90,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=225,icmp_type=136,icmp_code=0,nd_tll=00:00:00:00:00:00 actions=load:0->NXM_NX_REG10[[12]]
+- table=74, priority=90,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=225,icmp_type=136,icmp_code=0,nd_tll=00:00:00:00:00:03 actions=load:0->NXM_NX_REG10[[12]]
+- table=74, priority=90,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=225,icmp_type=136,icmp_code=0,nd_tll=00:00:00:00:00:13 actions=load:0->NXM_NX_REG10[[12]]" > hv1_t74_flows.expected
++ table=74, priority=90,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=255,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:00 actions=load:0->NXM_NX_REG10[[12]]
++ table=74, priority=90,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=255,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:03 actions=load:0->NXM_NX_REG10[[12]]
++ table=74, priority=90,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=255,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:13 actions=load:0->NXM_NX_REG10[[12]]
++ table=74, priority=90,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=255,icmp_type=136,icmp_code=0,nd_tll=00:00:00:00:00:00 actions=load:0->NXM_NX_REG10[[12]]
++ table=74, priority=90,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=255,icmp_type=136,icmp_code=0,nd_tll=00:00:00:00:00:03 actions=load:0->NXM_NX_REG10[[12]]
++ table=74, priority=90,icmp6,reg14=0x$sw0p1_key,metadata=0x1,nw_ttl=255,icmp_type=136,icmp_code=0,nd_tll=00:00:00:00:00:13 actions=load:0->NXM_NX_REG10[[12]]" > hv1_t74_flows.expected
+
+ check_port_sec_offlows hv1 74
+
+@@ -34144,13 +34144,13 @@ echo " table=74, priority=80,arp,reg14=0x$sw0p2_key,metadata=0x1 actions=load:0x
+ table=74, priority=90,icmp6,reg14=0x$sw0p2_key,metadata=0x1,dl_src=00:00:00:00:00:04,icmp_type=136,icmp_code=0,nd_target=2000::/64,nd_tll=00:00:00:00:00:04 actions=load:0->NXM_NX_REG10[[12]]
+ table=74, priority=90,icmp6,reg14=0x$sw0p2_key,metadata=0x1,dl_src=00:00:00:00:00:13,icmp_type=136,icmp_code=0,nd_target=aef0::4,nd_tll=00:00:00:00:00:00 actions=load:0->NXM_NX_REG10[[12]]
+ table=74, priority=90,icmp6,reg14=0x$sw0p2_key,metadata=0x1,dl_src=00:00:00:00:00:13,icmp_type=136,icmp_code=0,nd_target=aef0::4,nd_tll=00:00:00:00:00:13 actions=load:0->NXM_NX_REG10[[12]]
+- table=74, priority=90,icmp6,reg14=0x$sw0p2_key,metadata=0x1,nw_ttl=225,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:00 actions=load:0->NXM_NX_REG10[[12]]
+- table=74, priority=90,icmp6,reg14=0x$sw0p2_key,metadata=0x1,nw_ttl=225,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:04 actions=load:0->NXM_NX_REG10[[12]]
+- table=74, priority=90,icmp6,reg14=0x$sw0p2_key,metadata=0x1,nw_ttl=225,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:13 actions=load:0->NXM_NX_REG10[[12]]
+- table=74, priority=90,icmp6,reg14=0x$sw0p2_key,metadata=0x1,nw_ttl=225,icmp_type=136,icmp_code=0,nd_target=fe80::200:ff:fe00:13,nd_tll=00:00:00:00:00:00 actions=load:0->NXM_NX_REG10[[12]]
+- table=74, priority=90,icmp6,reg14=0x$sw0p2_key,metadata=0x1,nw_ttl=225,icmp_type=136,icmp_code=0,nd_target=fe80::200:ff:fe00:13,nd_tll=00:00:00:00:00:13 actions=load:0->NXM_NX_REG10[[12]]
+- table=74, priority=90,icmp6,reg14=0x$sw0p2_key,metadata=0x1,nw_ttl=225,icmp_type=136,icmp_code=0,nd_target=fe80::200:ff:fe00:4,nd_tll=00:00:00:00:00:00 actions=load:0->NXM_NX_REG10[[12]]
+- table=74, priority=90,icmp6,reg14=0x$sw0p2_key,metadata=0x1,nw_ttl=225,icmp_type=136,icmp_code=0,nd_target=fe80::200:ff:fe00:4,nd_tll=00:00:00:00:00:04 actions=load:0->NXM_NX_REG10[[12]]" > hv2_t74_flows.expected
++ table=74, priority=90,icmp6,reg14=0x$sw0p2_key,metadata=0x1,nw_ttl=255,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:00 actions=load:0->NXM_NX_REG10[[12]]
++ table=74, priority=90,icmp6,reg14=0x$sw0p2_key,metadata=0x1,nw_ttl=255,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:04 actions=load:0->NXM_NX_REG10[[12]]
++ table=74, priority=90,icmp6,reg14=0x$sw0p2_key,metadata=0x1,nw_ttl=255,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:13 actions=load:0->NXM_NX_REG10[[12]]
++ table=74, priority=90,icmp6,reg14=0x$sw0p2_key,metadata=0x1,nw_ttl=255,icmp_type=136,icmp_code=0,nd_target=fe80::200:ff:fe00:13,nd_tll=00:00:00:00:00:00 actions=load:0->NXM_NX_REG10[[12]]
++ table=74, priority=90,icmp6,reg14=0x$sw0p2_key,metadata=0x1,nw_ttl=255,icmp_type=136,icmp_code=0,nd_target=fe80::200:ff:fe00:13,nd_tll=00:00:00:00:00:13 actions=load:0->NXM_NX_REG10[[12]]
++ table=74, priority=90,icmp6,reg14=0x$sw0p2_key,metadata=0x1,nw_ttl=255,icmp_type=136,icmp_code=0,nd_target=fe80::200:ff:fe00:4,nd_tll=00:00:00:00:00:00 actions=load:0->NXM_NX_REG10[[12]]
++ table=74, priority=90,icmp6,reg14=0x$sw0p2_key,metadata=0x1,nw_ttl=255,icmp_type=136,icmp_code=0,nd_target=fe80::200:ff:fe00:4,nd_tll=00:00:00:00:00:04 actions=load:0->NXM_NX_REG10[[12]]" > hv2_t74_flows.expected
+
+ check_port_sec_offlows hv2 74
+
+diff --git a/utilities/checkpatch.py b/utilities/checkpatch.py
+index da3224bbc..5467d604d 100755
+--- a/utilities/checkpatch.py
++++ b/utilities/checkpatch.py
+@@ -196,7 +196,7 @@ skip_signoff_check = False
+ #
+ # Python isn't checked as flake8 performs these checks during build.
+ line_length_blacklist = re.compile(
+- r'\.(am|at|etc|in|m4|mk|patch|py)$|^debian/.*$')
++ r'\.(am|at|etc|in|m4|mk|patch|py|yml)$|^debian/.*$')
+
+ # Don't enforce a requirement that leading whitespace be all spaces on
+ # files that include these characters in their name, since these kinds
diff --git a/SPECS/ovn23.03.spec b/SPECS/ovn23.03.spec
deleted file mode 100644
index de8ca26..0000000
--- a/SPECS/ovn23.03.spec
+++ /dev/null
@@ -1,790 +0,0 @@
-# Copyright (C) 2009, 2010, 2013, 2014 Nicira Networks, Inc.
-#
-# Copying and distribution of this file, with or without modification,
-# are permitted in any medium without royalty provided the copyright
-# notice and this notice are preserved. This file is offered as-is,
-# without warranty of any kind.
-#
-# If tests have to be skipped while building, specify the '--without check'
-# option. For example:
-# rpmbuild -bb --without check rhel/openvswitch-fedora.spec
-
-# This defines the base package name's version.
-
-%define pkgver 2.13
-%define pkgname ovn23.03
-
-# If libcap-ng isn't available and there is no need for running OVS
-# as regular user, specify the '--without libcapng'
-%bcond_without libcapng
-
-# Enable PIE, bz#955181
-%global _hardened_build 1
-
-# RHEL-7 doesn't define _rundir macro yet
-# Fedora 15 onwards uses /run as _rundir
-%if 0%{!?_rundir:1}
-%define _rundir /run
-%endif
-
-# Build python2 (that provides python) and python3 subpackages on Fedora
-# Build only python3 (that provides python) subpackage on RHEL8
-# Build only python subpackage on RHEL7
-%if 0%{?rhel} > 7 || 0%{?fedora}
-# On RHEL8 Sphinx is included in buildroot
-%global external_sphinx 1
-%else
-# Don't use external sphinx (RHV doesn't have optional repositories enabled)
-%global external_sphinx 0
-%endif
-
-# We would see rpmlinit error - E: hardcoded-library-path in '% {_prefix}/lib'.
-# But there is no solution to fix this. Using {_lib} macro will solve the
-# rpmlink error, but will install the files in /usr/lib64/.
-# OVN pacemaker ocf script file is copied in /usr/lib/ocf/resource.d/ovn/
-# and we are not sure if pacemaker looks into this path to find the
-# OVN resource agent script.
-%global ovnlibdir %{_prefix}/lib
-
-Name: %{pkgname}
-Summary: Open Virtual Network support
-Group: System Environment/Daemons
-URL: http://www.ovn.org/
-Version: 23.03.0
-Release: 69%{?commit0:.%{date}git%{shortcommit0}}%{?dist}
-Provides: openvswitch%{pkgver}-ovn-common = %{?epoch:%{epoch}:}%{version}-%{release}
-Obsoletes: openvswitch%{pkgver}-ovn-common < 2.11.0-1
-
-# Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the
-# lib/sflow*.[ch] files are SISSL
-License: ASL 2.0 and LGPLv2+ and SISSL
-
-# Always pull an upstream release, since this is what we rebase to.
-Source: https://github.com/ovn-org/ovn/archive/v%{version}.tar.gz#/ovn-%{version}.tar.gz
-
-%define ovscommit 8986d4d5564401eeef3dea828b51fe8bae2cc8aa
-%define ovsshortcommit 8986d4d
-
-Source10: https://github.com/openvswitch/ovs/archive/%{ovscommit}.tar.gz#/openvswitch-%{ovsshortcommit}.tar.gz
-%define ovsdir ovs-%{ovscommit}
-
-%define docutilsver 0.12
-%define pygmentsver 1.4
-%define sphinxver 1.1.3
-Source100: https://pypi.io/packages/source/d/docutils/docutils-%{docutilsver}.tar.gz
-Source101: https://pypi.io/packages/source/P/Pygments/Pygments-%{pygmentsver}.tar.gz
-Source102: https://pypi.io/packages/source/S/Sphinx/Sphinx-%{sphinxver}.tar.gz
-
-Source500: configlib.sh
-Source501: gen_config_group.sh
-Source502: set_config.sh
-
-# Important: source503 is used as the actual copy file
-# @TODO: this causes a warning - fix it?
-Source504: arm64-armv8a-linuxapp-gcc-config
-Source505: ppc_64-power8-linuxapp-gcc-config
-Source506: x86_64-native-linuxapp-gcc-config
-
-Patch: %{pkgname}.patch
-
-# FIXME Sphinx is used to generate some manpages, unfortunately, on RHEL, it's
-# in the -optional repository and so we can't require it directly since RHV
-# doesn't have the -optional repository enabled and so TPS fails
-%if %{external_sphinx}
-BuildRequires: python3-sphinx
-%else
-# Sphinx dependencies
-BuildRequires: python-devel
-BuildRequires: python-setuptools
-#BuildRequires: python2-docutils
-BuildRequires: python-jinja2
-BuildRequires: python-nose
-#BuildRequires: python2-pygments
-# docutils dependencies
-BuildRequires: python-imaging
-# pygments dependencies
-BuildRequires: python-nose
-%endif
-
-BuildRequires: gcc gcc-c++ make
-BuildRequires: autoconf automake libtool
-BuildRequires: systemd-units openssl openssl-devel
-BuildRequires: python3-devel python3-setuptools
-BuildRequires: desktop-file-utils
-BuildRequires: groff-base graphviz
-BuildRequires: unbound-devel
-
-# make check dependencies
-BuildRequires: procps-ng
-%if 0%{?rhel} == 8 || 0%{?fedora}
-BuildRequires: python3-pyOpenSSL
-%endif
-BuildRequires: tcpdump
-
-%if %{with libcapng}
-BuildRequires: libcap-ng libcap-ng-devel
-%endif
-
-Requires: hostname openssl iproute module-init-tools
-
-Requires(post): systemd-units
-Requires(preun): systemd-units
-Requires(postun): systemd-units
-
-# to skip running checks, pass --without check
-%bcond_without check
-
-%description
-OVN, the Open Virtual Network, is a system to support virtual network
-abstraction. OVN complements the existing capabilities of OVS to add
-native support for virtual network abstractions, such as virtual L2 and L3
-overlays and security groups.
-
-%package central
-Summary: Open Virtual Network support
-License: ASL 2.0
-Requires: %{pkgname}
-Requires: firewalld-filesystem
-Provides: openvswitch%{pkgver}-ovn-central = %{?epoch:%{epoch}:}%{version}-%{release}
-Obsoletes: openvswitch%{pkgver}-ovn-central < 2.11.0-1
-
-%description central
-OVN DB servers and ovn-northd running on a central node.
-
-%package host
-Summary: Open Virtual Network support
-License: ASL 2.0
-Requires: %{pkgname}
-Requires: firewalld-filesystem
-Provides: openvswitch%{pkgver}-ovn-host = %{?epoch:%{epoch}:}%{version}-%{release}
-Obsoletes: openvswitch%{pkgver}-ovn-host < 2.11.0-1
-
-%description host
-OVN controller running on each host.
-
-%package vtep
-Summary: Open Virtual Network support
-License: ASL 2.0
-Requires: %{pkgname}
-Provides: openvswitch%{pkgver}-ovn-vtep = %{?epoch:%{epoch}:}%{version}-%{release}
-Obsoletes: openvswitch%{pkgver}-ovn-vtep < 2.11.0-1
-
-%description vtep
-OVN vtep controller
-
-%prep
-%autosetup -n ovn-%{version} -a 10 -p 1
-
-%build
-%if 0%{?commit0:1}
-# fix the snapshot unreleased version to be the released one.
-sed -i.old -e "s/^AC_INIT(openvswitch,.*,/AC_INIT(openvswitch, %{version},/" configure.ac
-%endif
-./boot.sh
-
-# OVN source code is now separate.
-# Build openvswitch first.
-# XXX Current openvswitch2.13 doesn't
-# use "2.13.0" for version. It's a commit hash
-pushd %{ovsdir}
-./boot.sh
-%configure \
-%if %{with libcapng}
- --enable-libcapng \
-%else
- --disable-libcapng \
-%endif
- --enable-ssl \
- --with-pkidir=%{_sharedstatedir}/openvswitch/pki
-
-make %{?_smp_mflags}
-popd
-
-# Build OVN.
-# XXX OVS version needs to be updated when ovs2.13 is updated.
-%configure \
- --with-ovs-source=$PWD/%{ovsdir} \
-%if %{with libcapng}
- --enable-libcapng \
-%else
- --disable-libcapng \
-%endif
- --enable-ssl \
- --with-pkidir=%{_sharedstatedir}/openvswitch/pki
-
-make %{?_smp_mflags}
-
-%install
-%make_install
-install -p -D -m 0644 \
- rhel/usr_share_ovn_scripts_systemd_sysconfig.template \
- $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/ovn
-
-for service in ovn-controller ovn-controller-vtep ovn-northd; do
- install -p -D -m 0644 \
- rhel/usr_lib_systemd_system_${service}.service \
- $RPM_BUILD_ROOT%{_unitdir}/${service}.service
-done
-
-install -d -m 0755 $RPM_BUILD_ROOT/%{_sharedstatedir}/ovn
-
-install -d $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/
-install -p -m 0644 rhel/usr_lib_firewalld_services_ovn-central-firewall-service.xml \
- $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/ovn-central-firewall-service.xml
-install -p -m 0644 rhel/usr_lib_firewalld_services_ovn-host-firewall-service.xml \
- $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/ovn-host-firewall-service.xml
-
-install -d -m 0755 $RPM_BUILD_ROOT%{ovnlibdir}/ocf/resource.d/ovn
-ln -s %{_datadir}/ovn/scripts/ovndb-servers.ocf \
- $RPM_BUILD_ROOT%{ovnlibdir}/ocf/resource.d/ovn/ovndb-servers
-
-install -p -D -m 0644 rhel/etc_logrotate.d_ovn \
- $RPM_BUILD_ROOT/%{_sysconfdir}/logrotate.d/ovn
-
-# remove unneeded files.
-rm -f $RPM_BUILD_ROOT%{_bindir}/ovs*
-rm -f $RPM_BUILD_ROOT%{_bindir}/vtep-ctl
-rm -f $RPM_BUILD_ROOT%{_sbindir}/ovs*
-rm -f $RPM_BUILD_ROOT%{_mandir}/man1/ovs*
-rm -f $RPM_BUILD_ROOT%{_mandir}/man5/ovs*
-rm -f $RPM_BUILD_ROOT%{_mandir}/man5/vtep*
-rm -f $RPM_BUILD_ROOT%{_mandir}/man7/ovs*
-rm -f $RPM_BUILD_ROOT%{_mandir}/man8/ovs*
-rm -f $RPM_BUILD_ROOT%{_mandir}/man8/vtep*
-rm -rf $RPM_BUILD_ROOT%{_datadir}/ovn/python
-rm -f $RPM_BUILD_ROOT%{_datadir}/ovn/scripts/ovs*
-rm -rf $RPM_BUILD_ROOT%{_datadir}/ovn/bugtool-plugins
-rm -f $RPM_BUILD_ROOT%{_libdir}/*.a
-rm -f $RPM_BUILD_ROOT%{_libdir}/*.la
-rm -f $RPM_BUILD_ROOT%{_libdir}/pkgconfig/*.pc
-rm -f $RPM_BUILD_ROOT%{_includedir}/ovn/*
-rm -f $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d/ovs-appctl-bashcomp.bash
-rm -f $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d/ovs-vsctl-bashcomp.bash
-rm -rf $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/openvswitch
-rm -f $RPM_BUILD_ROOT%{_datadir}/ovn/scripts/ovn-bugtool*
-rm -f $RPM_BUILD_ROOT/%{_bindir}/ovn-docker-overlay-driver \
- $RPM_BUILD_ROOT/%{_bindir}/ovn-docker-underlay-driver
-
-%check
-%if %{with check}
- touch resolv.conf
- export OVS_RESOLV_CONF=$(pwd)/resolv.conf
- if ! make check TESTSUITEFLAGS='%{_smp_mflags}'; then
- cat tests/testsuite.log
- if ! make check TESTSUITEFLAGS='--recheck'; then
- cat tests/testsuite.log
- # Presently a test case - "2796: ovn -- ovn-controller incremental processing"
- # is failing on aarch64 arch. Let's not exit for this arch
- # until we figure out why it is failing.
- # Test case 93: ovn.at:12105 ovn -- ACLs on Port Groups is failing
- # repeatedly on s390x. This needs to be investigated.
- %ifnarch aarch64
- %ifnarch ppc64le
- %ifnarch s390x
- exit 1
- %endif
- %endif
- %endif
- fi
- fi
-%endif
-
-%clean
-rm -rf $RPM_BUILD_ROOT
-
-%pre central
-if [ $1 -eq 1 ] ; then
- # Package install.
- /bin/systemctl status ovn-northd.service >/dev/null
- ovn_status=$?
- rpm -ql openvswitch-ovn-central > /dev/null
- if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then
- # ovn-northd service is running which means old openvswitch-ovn-central
- # is already installed and it will be cleaned up. So start ovn-northd
- # service when posttrans central is called.
- touch %{_localstatedir}/lib/rpm-state/ovn-northd
- fi
-fi
-
-%pre host
-if [ $1 -eq 1 ] ; then
- # Package install.
- /bin/systemctl status ovn-controller.service >/dev/null
- ovn_status=$?
- rpm -ql openvswitch-ovn-host > /dev/null
- if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then
- # ovn-controller service is running which means old
- # openvswitch-ovn-host is installed and it will be cleaned up. So
- # start ovn-controller service when posttrans host is called.
- touch %{_localstatedir}/lib/rpm-state/ovn-controller
- fi
-fi
-
-%pre vtep
-if [ $1 -eq 1 ] ; then
- # Package install.
- /bin/systemctl status ovn-controller-vtep.service >/dev/null
- ovn_status=$?
- rpm -ql openvswitch-ovn-vtep > /dev/null
- if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then
- # ovn-controller-vtep service is running which means old
- # openvswitch-ovn-vtep is installed and it will be cleaned up. So
- # start ovn-controller-vtep service when posttrans host is called.
- touch %{_localstatedir}/lib/rpm-state/ovn-controller-vtep
- fi
-fi
-
-%preun central
-%if 0%{?systemd_preun:1}
- %systemd_preun ovn-northd.service
-%else
- if [ $1 -eq 0 ] ; then
- # Package removal, not upgrade
- /bin/systemctl --no-reload disable ovn-northd.service >/dev/null 2>&1 || :
- /bin/systemctl stop ovn-northd.service >/dev/null 2>&1 || :
- fi
-%endif
-
-%preun host
-%if 0%{?systemd_preun:1}
- %systemd_preun ovn-controller.service
-%else
- if [ $1 -eq 0 ] ; then
- # Package removal, not upgrade
- /bin/systemctl --no-reload disable ovn-controller.service >/dev/null 2>&1 || :
- /bin/systemctl stop ovn-controller.service >/dev/null 2>&1 || :
- fi
-%endif
-
-%preun vtep
-%if 0%{?systemd_preun:1}
- %systemd_preun ovn-controller-vtep.service
-%else
- if [ $1 -eq 0 ] ; then
- # Package removal, not upgrade
- /bin/systemctl --no-reload disable ovn-controller-vtep.service >/dev/null 2>&1 || :
- /bin/systemctl stop ovn-controller-vtep.service >/dev/null 2>&1 || :
- fi
-%endif
-
-%post
-%if %{with libcapng}
-if [ $1 -eq 1 ]; then
- sed -i 's:^#OVN_USER_ID=:OVN_USER_ID=:' %{_sysconfdir}/sysconfig/ovn
- sed -i 's:\(.*su\).*:\1 openvswitch openvswitch:' %{_sysconfdir}/logrotate.d/ovn
-fi
-%endif
-
-%post central
-%if 0%{?systemd_post:1}
- %systemd_post ovn-northd.service
-%else
- # Package install, not upgrade
- if [ $1 -eq 1 ]; then
- /bin/systemctl daemon-reload >dev/null || :
- fi
-%endif
-
-%post host
-%if 0%{?systemd_post:1}
- %systemd_post ovn-controller.service
-%else
- # Package install, not upgrade
- if [ $1 -eq 1 ]; then
- /bin/systemctl daemon-reload >dev/null || :
- fi
-%endif
-
-%post vtep
-%if 0%{?systemd_post:1}
- %systemd_post ovn-controller-vtep.service
-%else
- # Package install, not upgrade
- if [ $1 -eq 1 ]; then
- /bin/systemctl daemon-reload >dev/null || :
- fi
-%endif
-
-%postun
-
-%postun central
-%if 0%{?systemd_postun_with_restart:1}
- %systemd_postun_with_restart ovn-northd.service
-%else
- /bin/systemctl daemon-reload >/dev/null 2>&1 || :
- if [ "$1" -ge "1" ] ; then
- # Package upgrade, not uninstall
- /bin/systemctl try-restart ovn-northd.service >/dev/null 2>&1 || :
- fi
-%endif
-
-%postun host
-%if 0%{?systemd_postun_with_restart:1}
- %systemd_postun_with_restart ovn-controller.service
-%else
- /bin/systemctl daemon-reload >/dev/null 2>&1 || :
- if [ "$1" -ge "1" ] ; then
- # Package upgrade, not uninstall
- /bin/systemctl try-restart ovn-controller.service >/dev/null 2>&1 || :
- fi
-%endif
-
-%postun vtep
-%if 0%{?systemd_postun_with_restart:1}
- %systemd_postun_with_restart ovn-controller-vtep.service
-%else
- /bin/systemctl daemon-reload >/dev/null 2>&1 || :
- if [ "$1" -ge "1" ] ; then
- # Package upgrade, not uninstall
- /bin/systemctl try-restart ovn-controller-vtep.service >/dev/null 2>&1 || :
- fi
-%endif
-
-%posttrans central
-if [ $1 -eq 1 ]; then
- # Package install, not upgrade
- if [ -e %{_localstatedir}/lib/rpm-state/ovn-northd ]; then
- rm %{_localstatedir}/lib/rpm-state/ovn-northd
- /bin/systemctl start ovn-northd.service >/dev/null 2>&1 || :
- fi
-fi
-
-
-%posttrans host
-if [ $1 -eq 1 ]; then
- # Package install, not upgrade
- if [ -e %{_localstatedir}/lib/rpm-state/ovn-controller ]; then
- rm %{_localstatedir}/lib/rpm-state/ovn-controller
- /bin/systemctl start ovn-controller.service >/dev/null 2>&1 || :
- fi
-fi
-
-%posttrans vtep
-if [ $1 -eq 1 ]; then
- # Package install, not upgrade
- if [ -e %{_localstatedir}/lib/rpm-state/ovn-controller-vtep ]; then
- rm %{_localstatedir}/lib/rpm-state/ovn-controller-vtep
- /bin/systemctl start ovn-controller-vtep.service >/dev/null 2>&1 || :
- fi
-fi
-
-%files
-%{_bindir}/ovn-nbctl
-%{_bindir}/ovn-sbctl
-%{_bindir}/ovn-trace
-%{_bindir}/ovn-detrace
-%{_bindir}/ovn_detrace.py
-%{_bindir}/ovn-appctl
-%{_bindir}/ovn-ic-nbctl
-%{_bindir}/ovn-ic-sbctl
-%dir %{_datadir}/ovn/
-%dir %{_datadir}/ovn/scripts/
-%{_datadir}/ovn/scripts/ovn-ctl
-%{_datadir}/ovn/scripts/ovn-lib
-%{_datadir}/ovn/scripts/ovndb-servers.ocf
-%{_mandir}/man8/ovn-ctl.8*
-%{_mandir}/man8/ovn-appctl.8*
-%{_mandir}/man8/ovn-nbctl.8*
-%{_mandir}/man8/ovn-ic-nbctl.8*
-%{_mandir}/man8/ovn-trace.8*
-%{_mandir}/man1/ovn-detrace.1*
-%{_mandir}/man7/ovn-architecture.7*
-%{_mandir}/man8/ovn-sbctl.8*
-%{_mandir}/man8/ovn-ic-sbctl.8*
-%{_mandir}/man5/ovn-nb.5*
-%{_mandir}/man5/ovn-ic-nb.5*
-%{_mandir}/man5/ovn-sb.5*
-%{_mandir}/man5/ovn-ic-sb.5*
-%dir %{ovnlibdir}/ocf/resource.d/ovn/
-%{ovnlibdir}/ocf/resource.d/ovn/ovndb-servers
-%config(noreplace) %verify(not md5 size mtime) %{_sysconfdir}/logrotate.d/ovn
-%config(noreplace) %verify(not md5 size mtime) %{_sysconfdir}/sysconfig/ovn
-
-%files central
-%{_bindir}/ovn-northd
-%{_bindir}/ovn-ic
-%{_mandir}/man8/ovn-northd.8*
-%{_mandir}/man8/ovn-ic.8*
-%{_datadir}/ovn/ovn-nb.ovsschema
-%{_datadir}/ovn/ovn-ic-nb.ovsschema
-%{_datadir}/ovn/ovn-sb.ovsschema
-%{_datadir}/ovn/ovn-ic-sb.ovsschema
-%{_unitdir}/ovn-northd.service
-%{ovnlibdir}/firewalld/services/ovn-central-firewall-service.xml
-
-%files host
-%{_bindir}/ovn-controller
-%{_mandir}/man8/ovn-controller.8*
-%{_unitdir}/ovn-controller.service
-%{ovnlibdir}/firewalld/services/ovn-host-firewall-service.xml
-
-%files vtep
-%{_bindir}/ovn-controller-vtep
-%{_mandir}/man8/ovn-controller-vtep.8*
-%{_unitdir}/ovn-controller-vtep.service
-
-%changelog
-* Fri Jun 09 2023 Igor Zhukov - 23.03.0-69
-- call ovsrcu_exit() before exit in ovn-northd and ovn-controller to make valgrind happy
-[Upstream: a3aba935cda359db5d9c99e8ea9ba688e4f888bc]
-
-* Thu Jun 08 2023 Dumitru Ceara - 23.03.0-68
-- controller: Turn OFTABLE_OUTPUT_INIT into an alias.
-[Upstream: 8c274866a29534c6ecb80f0242798edbb078bfda]
-
-* Thu Jun 08 2023 Ihar Hrachyshka - 23.03.0-67
-- Implement MTU Path Discovery for multichassis ports
-[Upstream: 44e07200a8f04b70bbcba20d2b5346aa840b4f40]
-
-* Thu Jun 08 2023 Ihar Hrachyshka - 23.03.0-66
-- Add new egress tables to accommodate for too-big packets handling
-[Upstream: 44d6692e28478e4e971de09045f42cc5c3000540]
-
-* Thu Jun 08 2023 Ihar Hrachyshka - 23.03.0-65
-- if-status: track interfaces for additional chassis
-[Upstream: 57f15c6d78b4fbcd9ead81328e06a714b75942f0]
-
-* Thu Jun 08 2023 Ihar Hrachyshka - 23.03.0-64
-- Track interface MTU in if-status-mgr
-[Upstream: e6f097fe148deb3f60c2e2fc57e80f91986f248e]
-
-* Thu Jun 08 2023 Ihar Hrachyshka - 23.03.0-63
-- Track ip version of tunnel in chassis_tunnel struct
-[Upstream: c8fccfa720b7d8e176be05bfd37fd6e74764ee3d]
-
-* Thu Jun 08 2023 Ales Musil - 23.03.0-62
-- northd: Add logical flow to skip GARP with LLA (#2211240)
-[Upstream: dc0b0b55d93cb2516f1759b65f198485597d4575]
-
-* Thu Jun 08 2023 Vladislav Odintsov - 23.03.0-61
-- northd: match only on supported protocols to handle_svc_check (#1913162)
-[Upstream: 822861db016d9360d6a88a486d5db8d5936e66fa]
-
-* Thu Jun 08 2023 Xavier Simonart - 23.03.0-60
-- tests: Fixed "nested containers" test
-[Upstream: f914cf2cab4b4a872d246961c6521cd8a48f2bd3]
-
-* Thu Jun 08 2023 Xavier Simonart - 23.03.0-59
-- tests: fix flaky Multiple OVS interfaces bound to same logical ports
-[Upstream: 8f29930c22687c3247a784e1e2fe4a6dc0fdd86c]
-
-* Thu Jun 08 2023 Ales Musil - 23.03.0-58
-- system-tests: Prevent flakiness in ovn mirroring
-[Upstream: 352041d0fa66772d86980f46c63e023c40286723]
-
-* Thu Jun 08 2023 Ales Musil - 23.03.0-57
-- northd: Fix address set incremental processing (#2196885)
-[Upstream: e8baef1c0fc671fe4e2d3af63de979e22a0c899d]
-
-* Tue May 30 2023 Brian Haley - 23.03.0-56
-- controller: Ignore DNS queries with RRs
-[Upstream: 529ea698f5d1d2b7083210318cfc0a64b701ca62]
-
-* Tue May 30 2023 Ales Musil - 23.03.0-55
-- ci: ovn-kubernetes: Align the timeouts with u/s ovnk
-[Upstream: ecc0a06af3bb47fe49ee897896af35a0efe33486]
-
-* Tue May 30 2023 Dumitru Ceara - 23.03.0-54
-- controller: Handle OpenFlow errors. (#2134880)
-[Upstream: 158463b94f5b6c37a37d9755ba9d5ef7473d35d3]
-
-* Tue May 30 2023 Vladislav Odintsov - 23.03.0-53
-- controller: fix typo in comments
-[Upstream: f24e9bf7b4b5822e0d37a4382fe49607c132a3ee]
-
-* Tue May 30 2023 Vladislav Odintsov - 23.03.0-52
-- northd: build vtep hairpin lflows only for lswitches with vtep lports
-[Upstream: 222f74acea04c9ae46bb3767ff256f8249ee7ab8]
-
-* Tue May 30 2023 Vladislav Odintsov - 23.03.0-51
-- northd: fix ls_in_hairpin l3dgw flow generation
-[Upstream: e4f8547be8774c085ef212fbed3e5e76e77d661c]
-
-* Fri May 26 2023 Han Zhou - 23.03.0-50
-- ovn-controller.c: Fix assertion failure during address set update.
-[Upstream: 777786f38a61041898891ccbb3f139b0552e5794]
-
-* Fri May 19 2023 Mark Michelson - 23.03.0-49
-- Pass localnet traffic through CT when a LB is configured. (#2164652)
-[Upstream: 2449608303464d62ff5b1a89e20e476248d1e82b]
-
-* Fri May 19 2023 Mark Michelson - 23.03.0-48
-- tests: Use stricter IP match for FORMAT_CT.
-[Upstream: a1d8ebd306021844646629c42bd638203399c568]
-
-* Wed May 17 2023 Ales Musil - 23.03.0-47
-- tests: Fix flakiness of policy based routing on slower systems
-[Upstream: bb22fe9c4591dc96d98bf2c2c3f629efb5721757]
-
-* Wed May 17 2023 Vladislav Odintsov - 23.03.0-46
-- ovn-controller docs: fix typo in ovn-monitor-all description
-[Upstream: 0ba1609d6426cd779f48cb5a97e63c0a7811dc03]
-
-* Wed May 10 2023 Ales Musil - 23.03.0-45
-- system-tests: Replace use of ADD_INT with ADD_VETH
-[Upstream: c2f36b530613728100b1dbdf7f967c4a87053155]
-
-* Wed May 10 2023 Lorenzo Bianconi - 23.03.0-44
-- controller: fix possible unaligned accesses in DHCPv6 code
-[Upstream: 080cbcd95d3d065524272f5f1d0bed11df35a9d4]
-
-* Tue May 09 2023 Lorenzo Bianconi - 23.03.0-43
-- mirror: fix ovn mirror support with IPv6 (#2168119)
-[Upstream: 5255303229f4da0c1478656597c774510ceda4e9]
-
-* Mon May 08 2023 Xavier Simonart - 23.03.0-42
-- ovn-controller: fixed port not always set down when unbinding interface (#2150905)
-[Upstream: 39930c0254bc8758b5722e0f2c3a7fdc43256888]
-
-* Mon May 08 2023 Xavier Simonart - 23.03.0-41
-- ovn-controller: fixed ovn-installed not always properly added or removed.
-[Upstream: 395eac485b871ef75bb0b5f29b09ebd1cb877ca8]
-
-* Mon May 08 2023 Wei Li - 23.03.0-40
-- documentation: packets that arrive from other chassis resubmit to table 38
-[Upstream: 4ad402df2870c44234945b462345bfcb0c95b6f6]
-
-* Mon May 08 2023 Tao Liu - 23.03.0-39
-- northd: fix use-after-free after lrp destroyed
-[Upstream: fd0111e59c6a78acf70dd47e10e724210c2e94ea]
-
-* Mon May 08 2023 Ihar Hrachyshka - 23.03.0-38
-- docs: document that vxlan is supported for encap type
-[Upstream: 31bc347255a9206b29dc3f9af14c8af75ea9600e]
-
-* Mon May 08 2023 Xavier Simonart - 23.03.0-37
-- tests: Fixed flaky lr multiple gw ports
-[Upstream: 94dea8bb6bba439de673fa4fa72e3fa3f8c44593]
-
-* Mon May 08 2023 Xavier Simonart - 23.03.0-36
-- Fix test "load-balancing"
-[Upstream: bfdfb9a0565b2f21f59120b360db1aa59b24f96d]
-
-* Fri May 05 2023 Dumitru Ceara - 23.03.0-35
-- tests: Retry inject-pkt in case ovn-controller is still busy.
-[Upstream: d6cad0cc05f752a83f72c82881a76642301125b9]
-
-* Tue May 02 2023 wangchuanlei - 23.03.0-34
-- pinctrl: fix restart of controller when bfd min_tx is too low.
-[Upstream: 77d0ff0dace95ce6c8453c2b95f65d18892133b6]
-
-* Tue May 02 2023 Ales Musil - 23.03.0-33
-- ovn-nbctl: Fix unhandled NULL return from normalize_prefix_str
-[Upstream: 86ceec393a9b776990bb24625bf9ca13ce9dfe05]
-
-* Mon May 01 2023 Xavier Simonart - 23.03.0-32
-- tests: decrease risk of flaky failures of ovn -- CoPP system test
-[Upstream: b81229835436b63a593e0e6a55bb639309101592]
-
-* Mon May 01 2023 Xavier Simonart - 23.03.0-31
-- tests: check arguments count of OVS_WAIT_UNTIL
-[Upstream: 352c584c403ce914b59e3c3c95028949ec3ede05]
-
-* Mon May 01 2023 Xavier Simonart - 23.03.0-30
-- tests: Fixed wrong usage of OVS_WAIT_UNTIL
-[Upstream: b88d8bbba3ba59ee0a3c2d3fb62cab748e1b59dc]
-
-* Mon May 01 2023 Xavier Simonart - 23.03.0-29
-- tests: Fixed "1 LR with HA distributed router gateway port"
-[Upstream: 1758332a51766231e74479302ee8efdfc07bf33c]
-
-* Fri Apr 21 2023 Mark Michelson - 23.03.0-28
-- tests: Skip "daemon ssl files change" when SSL is disabled.
-[Upstream: 3d231640d852bc4c7b49d17de80ba747bebe8817]
-
-* Wed Apr 19 2023 Ihar Hrachyshka - 23.03.0-27
-- Omit ACLs for nd || nd_ra || nd_rs || mldv1 || mldv2 (#2149731)
-[Upstream: 6e6cc27bdb9735a6461b53771b3969a2ca230cab]
-
-* Wed Apr 19 2023 Ihar Hrachyshka - 23.03.0-26
-- tests: define fmt_pkt function to construct packets with scapy
-[Upstream: b797e5dbd955ee61d503bb38dade490957bce563]
-
-* Wed Apr 19 2023 Ales Musil - 23.03.0-25
-- controller: Prevent race in tunnel cleanup
-[Upstream: 40befbb1d508db48f894cb190637ee33cccf0977]
-
-* Thu Apr 13 2023 Han Zhou - 23.03.0-24
-- northd.c: Avoid sending ICMP time exceeded for multicast packets.
-[Upstream: a38a5df4a49ddf678d6a50de39b613b8f0305e26]
-
-* Thu Apr 13 2023 Han Zhou - 23.03.0-23
-- northd.c: TTL discard flow should support for both ipv4 and ipv6.
-[Upstream: d42d070bd2598b72c13d2a67209d368acc8128b8]
-
-* Tue Apr 11 2023 Ales Musil - 23.03.0-22
-- northd: Update the is_stateless helper for router nat
-[Upstream: 99b42566998c9e9b952cdfe3f8435e8bd79eca43]
-
-* Tue Apr 11 2023 Eelco Chaudron - 23.03.0-21
-- ci: Add arping package to run floating IP tests.
-[Upstream: 825164cd4164e9c9bf5c66ebe00e147f1e2ac1fd]
-
-* Tue Apr 11 2023 Ales Musil - 23.03.0-20
-- controller: Clear tunnels from old integration bridge (#2173635)
-[Upstream: 8481abcc04fee5e0ecd881e599be178625ad1522]
-
-* Tue Apr 11 2023 Lorenzo Bianconi - 23.03.0-19
-- northd: revert ct.inv drop flows
-[Upstream: 04d7552479736bd2da84dd5d2be146fa4a51e3e6]
-
-* Thu Apr 06 2023 Lorenzo Bianconi - 23.03.0-18
-- northd: take into account qos_min_rate in port_has_qos_params
-[Upstream: 0bbcfb52f0248d839e413acaf2b116bb7b1c4db6]
-
-* Thu Mar 30 2023 Ales Musil - 23.03.0-17
-- system-tests: Reduce flakiness of netcat UDP clients
-[Upstream: 6c2d80c5bb6a2cd7c353b796a7d46b3962a06c9f]
-
-* Tue Mar 28 2023 Dumitru Ceara - 23.03.0-16
-- Revert "DOWNSTREAM: Forcefully disable backend conntrack flushing."
-[Upstream: 8c98303437610a32faff8c0e7d8eff419b40619e]
-
-* Tue Mar 28 2023 Xavier Simonart - 23.03.0-15
-- northd: prevents sending packet to conntrack for router ports (#2062431)
-[Upstream: 2bab96e899b5da5ae0c3b24bd04ece93d1339824]
-
-* Tue Mar 28 2023 Dumitru Ceara - 23.03.0-14
-- lb: Allow IPv6 template LBs to use explicit backends.
-[Upstream: d01fdfdb2c97222cf326c8ab5579f670ded6e3cb]
-
-* Tue Mar 28 2023 Lorenzo Bianconi - 23.03.0-13
-- controller: lflow: do not use tcp as default IP protocol for ct_snat_to_vip action (#2157846)
-[Upstream: 6a16c741e5a10a817ca8251898f48bf9eeb971f5]
-
-* Tue Mar 28 2023 Ales Musil - 23.03.0-12
-- northd: Drop packets for LBs with no backends (#2177173)
-[Upstream: 77384b7fe3f7d3260fd2f94a3bd75b8ca79f56ae]
-
-* Mon Mar 27 2023 Ales Musil - 23.03.0-11
-- northd: Use generic ct.est flows for LR LBs (#2172048 2170885)
-[Upstream: 81eaa98bbb608bda320abfa0122ba073de6597d7]
-
-* Thu Mar 23 2023 Lorenzo Bianconi - 23.03.0-10
-- northd: drop ct.inv packets in post snat and lb_aff_learn stages (#2160685)
-[Upstream: 0af110c400cc29bb037172cdfd674794716771df]
-
-* Mon Mar 20 2023 Ales Musil - 23.03.0-9
-- controller: Add config option per LB to enable/disable CT flush (#2178962)
-[Upstream: 89fc85fa7f2b00f404ec5aef4ce8f2236474fbab]
-
-* Thu Mar 16 2023 Dumitru Ceara - 23.03.0-8
-- DOWNSTREAM: Forcefully disable backend conntrack flushing. (#2178962)
-[Upstream: b7522be8bf28534cc422234e8d9484b9ef4220d9]
-
-* Thu Mar 16 2023 Dumitru Ceara - 23.03.0-7
-- northd: Ignore remote chassis when computing the supported feature set.
-[Upstream: 80b7e48a877abd337eb54b9bb9c7b4280aa9ff74]
-
-* Wed Mar 08 2023 Ilya Maximets - 23.03.0-6
-- controller: Use ofctrl_add_flow for CT SNAT hairpin flows.
-[Upstream: 888215e2164b476462f12d206a3d734958ef79e2]
-
-* Wed Mar 08 2023 Vladislav Odintsov - 23.03.0-5
-- rhel: pass options to stop daemon command in systemd units
-[Upstream: ed7095613abf3d36cbcf347e1238b84e6843eaf1]
-
-* Fri Mar 03 2023 Mark Michelson - 23.03.0-4
-- Prepare for 23.03.1.
-[Upstream: e98ea52f12de2a7d6a9a7547b6b0a493a78f0fed]
-
diff --git a/SPECS/ovn23.06.spec b/SPECS/ovn23.06.spec
new file mode 100644
index 0000000..9a9a793
--- /dev/null
+++ b/SPECS/ovn23.06.spec
@@ -0,0 +1,560 @@
+# Copyright (C) 2009, 2010, 2013, 2014 Nicira Networks, Inc.
+#
+# Copying and distribution of this file, with or without modification,
+# are permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved. This file is offered as-is,
+# without warranty of any kind.
+#
+# If tests have to be skipped while building, specify the '--without check'
+# option. For example:
+# rpmbuild -bb --without check rhel/openvswitch-fedora.spec
+
+# This defines the base package name's version.
+
+%define pkgver 2.13
+%define pkgname ovn23.06
+
+# If libcap-ng isn't available and there is no need for running OVS
+# as regular user, specify the '--without libcapng'
+%bcond_without libcapng
+
+# Enable PIE, bz#955181
+%global _hardened_build 1
+
+# RHEL-7 doesn't define _rundir macro yet
+# Fedora 15 onwards uses /run as _rundir
+%if 0%{!?_rundir:1}
+%define _rundir /run
+%endif
+
+# Build python2 (that provides python) and python3 subpackages on Fedora
+# Build only python3 (that provides python) subpackage on RHEL8
+# Build only python subpackage on RHEL7
+%if 0%{?rhel} > 7 || 0%{?fedora}
+# On RHEL8 Sphinx is included in buildroot
+%global external_sphinx 1
+%else
+# Don't use external sphinx (RHV doesn't have optional repositories enabled)
+%global external_sphinx 0
+%endif
+
+# We would see rpmlinit error - E: hardcoded-library-path in '% {_prefix}/lib'.
+# But there is no solution to fix this. Using {_lib} macro will solve the
+# rpmlink error, but will install the files in /usr/lib64/.
+# OVN pacemaker ocf script file is copied in /usr/lib/ocf/resource.d/ovn/
+# and we are not sure if pacemaker looks into this path to find the
+# OVN resource agent script.
+%global ovnlibdir %{_prefix}/lib
+
+Name: %{pkgname}
+Summary: Open Virtual Network support
+Group: System Environment/Daemons
+URL: http://www.ovn.org/
+Version: 23.06.1
+Release: 11%{?commit0:.%{date}git%{shortcommit0}}%{?dist}
+Provides: openvswitch%{pkgver}-ovn-common = %{?epoch:%{epoch}:}%{version}-%{release}
+Obsoletes: openvswitch%{pkgver}-ovn-common < 2.11.0-1
+
+# Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the
+# lib/sflow*.[ch] files are SISSL
+License: ASL 2.0 and LGPLv2+ and SISSL
+
+%define ovncommit a20f880efdba9dcf19c1df77b31a3b8b9dffa345
+
+# Always pull an upstream release, since this is what we rebase to.
+Source: https://github.com/ovn-org/ovn/archive/%{ovncommit}.tar.gz#/ovn-%{version}.tar.gz
+
+%define ovscommit 0187eadfce4505d502e57c0e688b830f0a1ec728
+%define ovsshortcommit 0187ead
+
+Source10: https://github.com/openvswitch/ovs/archive/%{ovscommit}.tar.gz#/openvswitch-%{ovsshortcommit}.tar.gz
+%define ovsdir ovs-%{ovscommit}
+
+%define docutilsver 0.12
+%define pygmentsver 1.4
+%define sphinxver 1.1.3
+Source100: https://pypi.io/packages/source/d/docutils/docutils-%{docutilsver}.tar.gz
+Source101: https://pypi.io/packages/source/P/Pygments/Pygments-%{pygmentsver}.tar.gz
+Source102: https://pypi.io/packages/source/S/Sphinx/Sphinx-%{sphinxver}.tar.gz
+
+Source500: configlib.sh
+Source501: gen_config_group.sh
+Source502: set_config.sh
+
+# Important: source503 is used as the actual copy file
+# @TODO: this causes a warning - fix it?
+Source504: arm64-armv8a-linuxapp-gcc-config
+Source505: ppc_64-power8-linuxapp-gcc-config
+Source506: x86_64-native-linuxapp-gcc-config
+
+Patch: %{pkgname}.patch
+
+# FIXME Sphinx is used to generate some manpages, unfortunately, on RHEL, it's
+# in the -optional repository and so we can't require it directly since RHV
+# doesn't have the -optional repository enabled and so TPS fails
+%if %{external_sphinx}
+BuildRequires: python3-sphinx
+%else
+# Sphinx dependencies
+BuildRequires: python-devel
+BuildRequires: python-setuptools
+#BuildRequires: python2-docutils
+BuildRequires: python-jinja2
+BuildRequires: python-nose
+#BuildRequires: python2-pygments
+# docutils dependencies
+BuildRequires: python-imaging
+# pygments dependencies
+BuildRequires: python-nose
+%endif
+
+BuildRequires: gcc gcc-c++ make
+BuildRequires: autoconf automake libtool
+BuildRequires: systemd-units openssl openssl-devel
+BuildRequires: python3-devel python3-setuptools
+BuildRequires: desktop-file-utils
+BuildRequires: groff-base graphviz
+BuildRequires: unbound-devel
+
+# make check dependencies
+BuildRequires: procps-ng
+%if 0%{?rhel} == 8 || 0%{?fedora}
+BuildRequires: python3-pyOpenSSL
+%endif
+BuildRequires: tcpdump
+
+%if %{with libcapng}
+BuildRequires: libcap-ng libcap-ng-devel
+%endif
+
+Requires: hostname openssl iproute module-init-tools
+
+Requires(post): systemd-units
+Requires(preun): systemd-units
+Requires(postun): systemd-units
+
+# to skip running checks, pass --without check
+%bcond_without check
+
+%description
+OVN, the Open Virtual Network, is a system to support virtual network
+abstraction. OVN complements the existing capabilities of OVS to add
+native support for virtual network abstractions, such as virtual L2 and L3
+overlays and security groups.
+
+%package central
+Summary: Open Virtual Network support
+License: ASL 2.0
+Requires: %{pkgname}
+Requires: firewalld-filesystem
+Provides: openvswitch%{pkgver}-ovn-central = %{?epoch:%{epoch}:}%{version}-%{release}
+Obsoletes: openvswitch%{pkgver}-ovn-central < 2.11.0-1
+
+%description central
+OVN DB servers and ovn-northd running on a central node.
+
+%package host
+Summary: Open Virtual Network support
+License: ASL 2.0
+Requires: %{pkgname}
+Requires: firewalld-filesystem
+Provides: openvswitch%{pkgver}-ovn-host = %{?epoch:%{epoch}:}%{version}-%{release}
+Obsoletes: openvswitch%{pkgver}-ovn-host < 2.11.0-1
+
+%description host
+OVN controller running on each host.
+
+%package vtep
+Summary: Open Virtual Network support
+License: ASL 2.0
+Requires: %{pkgname}
+Provides: openvswitch%{pkgver}-ovn-vtep = %{?epoch:%{epoch}:}%{version}-%{release}
+Obsoletes: openvswitch%{pkgver}-ovn-vtep < 2.11.0-1
+
+%description vtep
+OVN vtep controller
+
+%prep
+%autosetup -n ovn-%{ovncommit} -a 10 -p 1
+
+%build
+%if 0%{?commit0:1}
+# fix the snapshot unreleased version to be the released one.
+sed -i.old -e "s/^AC_INIT(openvswitch,.*,/AC_INIT(openvswitch, %{version},/" configure.ac
+%endif
+./boot.sh
+
+# OVN source code is now separate.
+# Build openvswitch first.
+# XXX Current openvswitch2.13 doesn't
+# use "2.13.0" for version. It's a commit hash
+pushd %{ovsdir}
+./boot.sh
+%configure \
+%if %{with libcapng}
+ --enable-libcapng \
+%else
+ --disable-libcapng \
+%endif
+ --enable-ssl \
+ --with-pkidir=%{_sharedstatedir}/openvswitch/pki
+
+make %{?_smp_mflags}
+popd
+
+# Build OVN.
+# XXX OVS version needs to be updated when ovs2.13 is updated.
+%configure \
+ --with-ovs-source=$PWD/%{ovsdir} \
+%if %{with libcapng}
+ --enable-libcapng \
+%else
+ --disable-libcapng \
+%endif
+ --enable-ssl \
+ --with-pkidir=%{_sharedstatedir}/openvswitch/pki
+
+make %{?_smp_mflags}
+
+%install
+%make_install
+install -p -D -m 0644 \
+ rhel/usr_share_ovn_scripts_systemd_sysconfig.template \
+ $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/ovn
+
+for service in ovn-controller ovn-controller-vtep ovn-northd; do
+ install -p -D -m 0644 \
+ rhel/usr_lib_systemd_system_${service}.service \
+ $RPM_BUILD_ROOT%{_unitdir}/${service}.service
+done
+
+install -d -m 0755 $RPM_BUILD_ROOT/%{_sharedstatedir}/ovn
+
+install -d $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/
+install -p -m 0644 rhel/usr_lib_firewalld_services_ovn-central-firewall-service.xml \
+ $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/ovn-central-firewall-service.xml
+install -p -m 0644 rhel/usr_lib_firewalld_services_ovn-host-firewall-service.xml \
+ $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/ovn-host-firewall-service.xml
+
+install -d -m 0755 $RPM_BUILD_ROOT%{ovnlibdir}/ocf/resource.d/ovn
+ln -s %{_datadir}/ovn/scripts/ovndb-servers.ocf \
+ $RPM_BUILD_ROOT%{ovnlibdir}/ocf/resource.d/ovn/ovndb-servers
+
+install -p -D -m 0644 rhel/etc_logrotate.d_ovn \
+ $RPM_BUILD_ROOT/%{_sysconfdir}/logrotate.d/ovn
+
+# remove unneeded files.
+rm -f $RPM_BUILD_ROOT%{_bindir}/ovs*
+rm -f $RPM_BUILD_ROOT%{_bindir}/vtep-ctl
+rm -f $RPM_BUILD_ROOT%{_sbindir}/ovs*
+rm -f $RPM_BUILD_ROOT%{_mandir}/man1/ovs*
+rm -f $RPM_BUILD_ROOT%{_mandir}/man5/ovs*
+rm -f $RPM_BUILD_ROOT%{_mandir}/man5/vtep*
+rm -f $RPM_BUILD_ROOT%{_mandir}/man7/ovs*
+rm -f $RPM_BUILD_ROOT%{_mandir}/man8/ovs*
+rm -f $RPM_BUILD_ROOT%{_mandir}/man8/vtep*
+rm -rf $RPM_BUILD_ROOT%{_datadir}/ovn/python
+rm -f $RPM_BUILD_ROOT%{_datadir}/ovn/scripts/ovs*
+rm -rf $RPM_BUILD_ROOT%{_datadir}/ovn/bugtool-plugins
+rm -f $RPM_BUILD_ROOT%{_libdir}/*.a
+rm -f $RPM_BUILD_ROOT%{_libdir}/*.la
+rm -f $RPM_BUILD_ROOT%{_libdir}/pkgconfig/*.pc
+rm -f $RPM_BUILD_ROOT%{_includedir}/ovn/*
+rm -f $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d/ovs-appctl-bashcomp.bash
+rm -f $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d/ovs-vsctl-bashcomp.bash
+rm -rf $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/openvswitch
+rm -f $RPM_BUILD_ROOT%{_datadir}/ovn/scripts/ovn-bugtool*
+rm -f $RPM_BUILD_ROOT/%{_bindir}/ovn-docker-overlay-driver \
+ $RPM_BUILD_ROOT/%{_bindir}/ovn-docker-underlay-driver
+
+%check
+%if %{with check}
+ touch resolv.conf
+ export OVS_RESOLV_CONF=$(pwd)/resolv.conf
+ if ! make check TESTSUITEFLAGS='%{_smp_mflags}'; then
+ cat tests/testsuite.log
+ if ! make check TESTSUITEFLAGS='--recheck'; then
+ cat tests/testsuite.log
+ # Presently a test case - "2796: ovn -- ovn-controller incremental processing"
+ # is failing on aarch64 arch. Let's not exit for this arch
+ # until we figure out why it is failing.
+ # Test case 93: ovn.at:12105 ovn -- ACLs on Port Groups is failing
+ # repeatedly on s390x. This needs to be investigated.
+ %ifnarch aarch64
+ %ifnarch ppc64le
+ %ifnarch s390x
+ exit 1
+ %endif
+ %endif
+ %endif
+ fi
+ fi
+%endif
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%pre central
+if [ $1 -eq 1 ] ; then
+ # Package install.
+ /bin/systemctl status ovn-northd.service >/dev/null
+ ovn_status=$?
+ rpm -ql openvswitch-ovn-central > /dev/null
+ if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then
+ # ovn-northd service is running which means old openvswitch-ovn-central
+ # is already installed and it will be cleaned up. So start ovn-northd
+ # service when posttrans central is called.
+ touch %{_localstatedir}/lib/rpm-state/ovn-northd
+ fi
+fi
+
+%pre host
+if [ $1 -eq 1 ] ; then
+ # Package install.
+ /bin/systemctl status ovn-controller.service >/dev/null
+ ovn_status=$?
+ rpm -ql openvswitch-ovn-host > /dev/null
+ if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then
+ # ovn-controller service is running which means old
+ # openvswitch-ovn-host is installed and it will be cleaned up. So
+ # start ovn-controller service when posttrans host is called.
+ touch %{_localstatedir}/lib/rpm-state/ovn-controller
+ fi
+fi
+
+%pre vtep
+if [ $1 -eq 1 ] ; then
+ # Package install.
+ /bin/systemctl status ovn-controller-vtep.service >/dev/null
+ ovn_status=$?
+ rpm -ql openvswitch-ovn-vtep > /dev/null
+ if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then
+ # ovn-controller-vtep service is running which means old
+ # openvswitch-ovn-vtep is installed and it will be cleaned up. So
+ # start ovn-controller-vtep service when posttrans host is called.
+ touch %{_localstatedir}/lib/rpm-state/ovn-controller-vtep
+ fi
+fi
+
+%preun central
+%if 0%{?systemd_preun:1}
+ %systemd_preun ovn-northd.service
+%else
+ if [ $1 -eq 0 ] ; then
+ # Package removal, not upgrade
+ /bin/systemctl --no-reload disable ovn-northd.service >/dev/null 2>&1 || :
+ /bin/systemctl stop ovn-northd.service >/dev/null 2>&1 || :
+ fi
+%endif
+
+%preun host
+%if 0%{?systemd_preun:1}
+ %systemd_preun ovn-controller.service
+%else
+ if [ $1 -eq 0 ] ; then
+ # Package removal, not upgrade
+ /bin/systemctl --no-reload disable ovn-controller.service >/dev/null 2>&1 || :
+ /bin/systemctl stop ovn-controller.service >/dev/null 2>&1 || :
+ fi
+%endif
+
+%preun vtep
+%if 0%{?systemd_preun:1}
+ %systemd_preun ovn-controller-vtep.service
+%else
+ if [ $1 -eq 0 ] ; then
+ # Package removal, not upgrade
+ /bin/systemctl --no-reload disable ovn-controller-vtep.service >/dev/null 2>&1 || :
+ /bin/systemctl stop ovn-controller-vtep.service >/dev/null 2>&1 || :
+ fi
+%endif
+
+%post
+%if %{with libcapng}
+if [ $1 -eq 1 ]; then
+ sed -i 's:^#OVN_USER_ID=:OVN_USER_ID=:' %{_sysconfdir}/sysconfig/ovn
+ sed -i 's:\(.*su\).*:\1 openvswitch openvswitch:' %{_sysconfdir}/logrotate.d/ovn
+fi
+%endif
+
+%post central
+%if 0%{?systemd_post:1}
+ %systemd_post ovn-northd.service
+%else
+ # Package install, not upgrade
+ if [ $1 -eq 1 ]; then
+ /bin/systemctl daemon-reload >dev/null || :
+ fi
+%endif
+
+%post host
+%if 0%{?systemd_post:1}
+ %systemd_post ovn-controller.service
+%else
+ # Package install, not upgrade
+ if [ $1 -eq 1 ]; then
+ /bin/systemctl daemon-reload >dev/null || :
+ fi
+%endif
+
+%post vtep
+%if 0%{?systemd_post:1}
+ %systemd_post ovn-controller-vtep.service
+%else
+ # Package install, not upgrade
+ if [ $1 -eq 1 ]; then
+ /bin/systemctl daemon-reload >dev/null || :
+ fi
+%endif
+
+%postun
+
+%postun central
+%if 0%{?systemd_postun_with_restart:1}
+ %systemd_postun_with_restart ovn-northd.service
+%else
+ /bin/systemctl daemon-reload >/dev/null 2>&1 || :
+ if [ "$1" -ge "1" ] ; then
+ # Package upgrade, not uninstall
+ /bin/systemctl try-restart ovn-northd.service >/dev/null 2>&1 || :
+ fi
+%endif
+
+%postun host
+%if 0%{?systemd_postun_with_restart:1}
+ %systemd_postun_with_restart ovn-controller.service
+%else
+ /bin/systemctl daemon-reload >/dev/null 2>&1 || :
+ if [ "$1" -ge "1" ] ; then
+ # Package upgrade, not uninstall
+ /bin/systemctl try-restart ovn-controller.service >/dev/null 2>&1 || :
+ fi
+%endif
+
+%postun vtep
+%if 0%{?systemd_postun_with_restart:1}
+ %systemd_postun_with_restart ovn-controller-vtep.service
+%else
+ /bin/systemctl daemon-reload >/dev/null 2>&1 || :
+ if [ "$1" -ge "1" ] ; then
+ # Package upgrade, not uninstall
+ /bin/systemctl try-restart ovn-controller-vtep.service >/dev/null 2>&1 || :
+ fi
+%endif
+
+%posttrans central
+if [ $1 -eq 1 ]; then
+ # Package install, not upgrade
+ if [ -e %{_localstatedir}/lib/rpm-state/ovn-northd ]; then
+ rm %{_localstatedir}/lib/rpm-state/ovn-northd
+ /bin/systemctl start ovn-northd.service >/dev/null 2>&1 || :
+ fi
+fi
+
+
+%posttrans host
+if [ $1 -eq 1 ]; then
+ # Package install, not upgrade
+ if [ -e %{_localstatedir}/lib/rpm-state/ovn-controller ]; then
+ rm %{_localstatedir}/lib/rpm-state/ovn-controller
+ /bin/systemctl start ovn-controller.service >/dev/null 2>&1 || :
+ fi
+fi
+
+%posttrans vtep
+if [ $1 -eq 1 ]; then
+ # Package install, not upgrade
+ if [ -e %{_localstatedir}/lib/rpm-state/ovn-controller-vtep ]; then
+ rm %{_localstatedir}/lib/rpm-state/ovn-controller-vtep
+ /bin/systemctl start ovn-controller-vtep.service >/dev/null 2>&1 || :
+ fi
+fi
+
+%files
+%{_bindir}/ovn-nbctl
+%{_bindir}/ovn-sbctl
+%{_bindir}/ovn-trace
+%{_bindir}/ovn-detrace
+%{_bindir}/ovn_detrace.py
+%{_bindir}/ovn-appctl
+%{_bindir}/ovn-ic-nbctl
+%{_bindir}/ovn-ic-sbctl
+%dir %{_datadir}/ovn/
+%dir %{_datadir}/ovn/scripts/
+%{_datadir}/ovn/scripts/ovn-ctl
+%{_datadir}/ovn/scripts/ovn-lib
+%{_datadir}/ovn/scripts/ovndb-servers.ocf
+%{_mandir}/man8/ovn-ctl.8*
+%{_mandir}/man8/ovn-appctl.8*
+%{_mandir}/man8/ovn-nbctl.8*
+%{_mandir}/man8/ovn-ic-nbctl.8*
+%{_mandir}/man8/ovn-trace.8*
+%{_mandir}/man1/ovn-detrace.1*
+%{_mandir}/man7/ovn-architecture.7*
+%{_mandir}/man8/ovn-sbctl.8*
+%{_mandir}/man8/ovn-ic-sbctl.8*
+%{_mandir}/man5/ovn-nb.5*
+%{_mandir}/man5/ovn-ic-nb.5*
+%{_mandir}/man5/ovn-sb.5*
+%{_mandir}/man5/ovn-ic-sb.5*
+%dir %{ovnlibdir}/ocf/resource.d/ovn/
+%{ovnlibdir}/ocf/resource.d/ovn/ovndb-servers
+%config(noreplace) %verify(not md5 size mtime) %{_sysconfdir}/logrotate.d/ovn
+%config(noreplace) %verify(not md5 size mtime) %{_sysconfdir}/sysconfig/ovn
+
+%files central
+%{_bindir}/ovn-northd
+%{_bindir}/ovn-ic
+%{_mandir}/man8/ovn-northd.8*
+%{_mandir}/man8/ovn-ic.8*
+%{_datadir}/ovn/ovn-nb.ovsschema
+%{_datadir}/ovn/ovn-ic-nb.ovsschema
+%{_datadir}/ovn/ovn-sb.ovsschema
+%{_datadir}/ovn/ovn-ic-sb.ovsschema
+%{_unitdir}/ovn-northd.service
+%{ovnlibdir}/firewalld/services/ovn-central-firewall-service.xml
+
+%files host
+%{_bindir}/ovn-controller
+%{_mandir}/man8/ovn-controller.8*
+%{_unitdir}/ovn-controller.service
+%{ovnlibdir}/firewalld/services/ovn-host-firewall-service.xml
+
+%files vtep
+%{_bindir}/ovn-controller-vtep
+%{_mandir}/man8/ovn-controller-vtep.8*
+%{_unitdir}/ovn-controller-vtep.service
+
+%changelog
+* Thu Sep 14 2023 Lorenzo Bianconi - 23.06.1-11
+- northd: check if parent_name is set for tag_request 0
+[Upstream: c869db90e2b18515caad8ad95555d989d3379e3f]
+
+* Thu Sep 14 2023 Ales Musil - 23.06.1-10
+- ofctrl: Prevent conjunction duplication (#2175928)
+[Upstream: 4281178a8882d0194ce8edf35018227ab20fa80e]
+
+* Thu Sep 14 2023 Ales Musil - 23.06.1-9
+- ofctrl: Do not try to program long flows (#1955167)
+[Upstream: f18bbbbc1ec0110cde8146ea4e2b34b1ec488ba7]
+
+* Mon Sep 11 2023 Dumitru Ceara - 23.06.1-8
+- northd: Always ct commit ECMP symmetric traffic in the original direction.
+[Upstream: 6de90ba4c43e1798a63167fd7f790126cf240e9c]
+
+* Wed Sep 06 2023 Ihar Hrachyshka - 23.06.1-7
+- Use correct nw_ttl=255 to match against legit NAs
+[Upstream: 059d1337af1be97b8f89fcf65e2ba6c9ae217d76]
+
+* Wed Sep 06 2023 Dumitru Ceara - 23.06.1-6
+- checkpatch: Ignore yml files when checking line lengths.
+[Upstream: 18b9ca0630c537b142d6ac849a6a2092d4f5bc0f]
+
+* Wed Aug 30 2023 Ales Musil - 23.06.1-5
+- northd: Make sure that skip_snat=true is evaluated before force_snat (#2224260)
+[Upstream: 04cf3fd8c2de752ac6ca538f6570547a69dcaac3]
+
+* Tue Aug 29 2023 Mark Michelson - 23.06.1-4
+- Prepare for 23.06.2.
+[Upstream: c215b5237d46e7aa3b7e095f1e955db5b646e4eb]
+