diff --git a/SOURCES/ovn23.03.patch b/SOURCES/ovn23.03.patch index c66abc6..9478c3b 100644 --- a/SOURCES/ovn23.03.patch +++ b/SOURCES/ovn23.03.patch @@ -1,3 +1,26 @@ +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 @@ -13,10 +36,10 @@ index 0f8d9d193..edf4fb2fd 100644 ARCH: ${{ matrix.cfg.arch }} CC: ${{ matrix.cfg.compiler }} diff --git a/NEWS b/NEWS -index 5e8aed06d..60c460a05 100644 +index 5e8aed06d..d7ba71ef5 100644 --- a/NEWS +++ b/NEWS -@@ -1,3 +1,11 @@ +@@ -1,3 +1,17 @@ +OVN v23.03.1 - xx xxx xxxx +-------------------------- + - CT entries are not flushed by default anymore whenever a load balancer @@ -24,6 +47,12 @@ index 5e8aed06d..60c460a05 100644 + 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 -------------------------- @@ -42,10 +71,21 @@ index b51d0f01e..0ba9e8d7e 100644 AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_HEADERS([config.h]) diff --git a/controller/binding.c b/controller/binding.c -index 5df62baef..bd810f669 100644 +index 5df62baef..8fce6fc3f 100644 --- a/controller/binding.c +++ b/controller/binding.c -@@ -746,6 +746,19 @@ local_binding_get_lport_ofport(const struct shash *local_bindings, +@@ -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; } @@ -65,7 +105,7 @@ index 5df62baef..bd810f669 100644 bool local_binding_is_up(struct shash *local_bindings, const char *pb_name, const struct sbrec_chassis *chassis_rec) -@@ -783,6 +796,7 @@ local_binding_is_down(struct shash *local_bindings, const char *pb_name, +@@ -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); @@ -73,7 +113,7 @@ index 5df62baef..bd810f669 100644 } } -@@ -834,6 +848,38 @@ local_binding_set_up(struct shash *local_bindings, const char *pb_name, +@@ -834,6 +852,38 @@ local_binding_set_up(struct shash *local_bindings, const char *pb_name, } } @@ -112,7 +152,7 @@ index 5df62baef..bd810f669 100644 void local_binding_set_down(struct shash *local_bindings, const char *pb_name, const struct sbrec_chassis *chassis_rec, -@@ -853,7 +899,6 @@ local_binding_set_down(struct shash *local_bindings, const char *pb_name, +@@ -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)) { @@ -120,7 +160,45 @@ index 5df62baef..bd810f669 100644 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); -@@ -1239,7 +1284,9 @@ claim_lport(const struct sbrec_port_binding *pb, +@@ -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 { @@ -129,9 +207,35 @@ index 5df62baef..bd810f669 100644 + !smap_get_bool(&iface_rec->external_ids, + OVN_INSTALLED_EXT_ID, false)) { if_status_mgr_claim_iface(if_mgr, pb, chassis_rec, - sb_readonly); +- sb_readonly); ++ iface_rec, sb_readonly, ++ can_bind); } -@@ -1464,9 +1511,11 @@ consider_vif_lport_(const struct sbrec_port_binding *pb, + } + } + } 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, @@ -145,7 +249,25 @@ index 5df62baef..bd810f669 100644 } } -@@ -2288,6 +2337,11 @@ consider_iface_release(const struct ovsrec_interface *iface_rec, +@@ -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; } } @@ -157,7 +279,7 @@ index 5df62baef..bd810f669 100644 } else if (lbinding && b_lport && b_lport->type == LP_LOCALPORT) { /* lbinding is associated with a localport. Remove it from the -@@ -2558,6 +2612,7 @@ handle_deleted_lport(const struct sbrec_port_binding *pb, +@@ -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); @@ -165,7 +287,7 @@ index 5df62baef..bd810f669 100644 return; } -@@ -2581,6 +2636,7 @@ handle_deleted_lport(const struct sbrec_port_binding *pb, +@@ -2581,6 +2648,7 @@ handle_deleted_lport(const struct sbrec_port_binding *pb, remove_pb_from_local_datapath(pb, b_ctx_out, ld); } @@ -173,7 +295,7 @@ index 5df62baef..bd810f669 100644 } } -@@ -2627,6 +2683,11 @@ handle_deleted_vif_lport(const struct sbrec_port_binding *pb, +@@ -2627,6 +2695,11 @@ handle_deleted_vif_lport(const struct sbrec_port_binding *pb, } handle_deleted_lport(pb, b_ctx_in, b_ctx_out); @@ -185,7 +307,7 @@ index 5df62baef..bd810f669 100644 return true; } -@@ -3314,6 +3375,24 @@ binding_lport_delete(struct shash *binding_lports, +@@ -3314,6 +3387,24 @@ binding_lport_delete(struct shash *binding_lports, binding_lport_destroy(b_lport); } @@ -210,7 +332,7 @@ index 5df62baef..bd810f669 100644 static void binding_lport_set_up(struct binding_lport *b_lport, bool sb_readonly) { -@@ -3331,6 +3410,7 @@ binding_lport_set_down(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; } @@ -219,7 +341,7 @@ index 5df62baef..bd810f669 100644 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..5b73c6a4b 100644 +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, @@ -237,10 +359,15 @@ index 6c3a98b02..5b73c6a4b 100644 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, -@@ -195,6 +203,14 @@ void set_pb_chassis_in_sbrec(const struct sbrec_port_binding *pb, +@@ -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 *); + @@ -248,10 +375,9 @@ index 6c3a98b02..5b73c6a4b 100644 + 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 { - LP_UNKNOWN, diff --git a/controller/encaps.c b/controller/encaps.c index 2662eaf98..b69d72584 100644 --- a/controller/encaps.c @@ -363,10 +489,25 @@ index 867c6f28c..3e58b3c82 100644 + #endif /* controller/encaps.h */ diff --git a/controller/if-status.c b/controller/if-status.c -index d1c14ac30..8503e5daa 100644 +index d1c14ac30..2b2eb1679 100644 --- a/controller/if-status.c +++ b/controller/if-status.c -@@ -54,44 +54,54 @@ VLOG_DEFINE_THIS_MODULE(if_status); +@@ -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 { @@ -450,7 +591,7 @@ index d1c14ac30..8503e5daa 100644 * | | +----------------------+ | | | * | | | V ^ | | | * | | | | | handle_claims() | | | -@@ -109,38 +119,63 @@ static const char *if_state_names[] = { +@@ -109,43 +121,69 @@ static const char *if_state_names[] = { * | | | - remove ovn-installed from ovsdb | | | * | | | mgr_update() | | | * | +----------------------+ - sbrec_update_chassis if needed | | | @@ -538,7 +679,13 @@ index d1c14ac30..8503e5daa 100644 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 -@@ -155,6 +190,9 @@ struct if_status_mgr { + * 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; @@ -548,10 +695,17 @@ index d1c14ac30..8503e5daa 100644 /* All local interfaces, stored per state. */ struct hmapx ifaces_per_state[OIF_MAX]; -@@ -170,15 +208,20 @@ struct if_status_mgr { - static struct ovs_iface *ovs_iface_create(struct if_status_mgr *, - const char *iface_id, - enum if_state ); +@@ -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 *); @@ -569,7 +723,7 @@ index d1c14ac30..8503e5daa 100644 struct if_status_mgr * if_status_mgr_create(void) { -@@ -189,6 +232,7 @@ 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); @@ -577,7 +731,7 @@ index d1c14ac30..8503e5daa 100644 return mgr; } -@@ -202,6 +246,11 @@ if_status_mgr_clear(struct if_status_mgr *mgr) +@@ -202,6 +250,11 @@ if_status_mgr_clear(struct if_status_mgr *mgr) } ovs_assert(shash_is_empty(&mgr->ifaces)); @@ -589,7 +743,7 @@ index d1c14ac30..8503e5daa 100644 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 +261,7 @@ if_status_mgr_destroy(struct if_status_mgr *mgr) +@@ -212,6 +265,7 @@ if_status_mgr_destroy(struct if_status_mgr *mgr) { if_status_mgr_clear(mgr); shash_destroy(&mgr->ifaces); @@ -597,15 +751,32 @@ index d1c14ac30..8503e5daa 100644 for (size_t i = 0; i < ARRAY_SIZE(mgr->ifaces_per_state); i++) { hmapx_destroy(&mgr->ifaces_per_state[i]); } -@@ -231,6 +281,7 @@ if_status_mgr_claim_iface(struct if_status_mgr *mgr, - iface = ovs_iface_create(mgr, iface_id, OIF_CLAIMED); +@@ -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); +- 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); ++ } } -@@ -238,11 +289,13 @@ if_status_mgr_claim_iface(struct if_status_mgr *mgr, + switch (iface->state) { case OIF_CLAIMED: case OIF_INSTALL_FLOWS: @@ -619,7 +790,7 @@ index d1c14ac30..8503e5daa 100644 ovs_iface_set_state(mgr, iface, OIF_CLAIMED); break; case OIF_MAX: -@@ -271,9 +324,10 @@ if_status_mgr_release_iface(struct if_status_mgr *mgr, const char *iface_id) +@@ -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: @@ -633,7 +804,7 @@ index d1c14ac30..8503e5daa 100644 case OIF_MARK_UP: case OIF_INSTALLED: /* Properly mark interfaces "down" if their flows were already -@@ -282,6 +336,7 @@ if_status_mgr_release_iface(struct if_status_mgr *mgr, const char *iface_id) +@@ -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: @@ -641,7 +812,7 @@ index d1c14ac30..8503e5daa 100644 /* Nothing to do here. */ break; case OIF_MAX: -@@ -302,9 +357,10 @@ if_status_mgr_delete_iface(struct if_status_mgr *mgr, const char *iface_id) +@@ -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: @@ -655,7 +826,7 @@ index d1c14ac30..8503e5daa 100644 case OIF_MARK_UP: case OIF_INSTALLED: /* Properly mark interfaces "down" if their flows were already -@@ -313,6 +369,7 @@ if_status_mgr_delete_iface(struct if_status_mgr *mgr, const char *iface_id) +@@ -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: @@ -663,7 +834,7 @@ index d1c14ac30..8503e5daa 100644 /* Nothing to do here. */ break; case OIF_MAX: -@@ -346,12 +403,34 @@ if_status_handle_claims(struct if_status_mgr *mgr, +@@ -346,12 +412,34 @@ if_status_handle_claims(struct if_status_mgr *mgr, return rc; } @@ -698,7 +869,7 @@ index d1c14ac30..8503e5daa 100644 if (!binding_data) { return; } -@@ -359,6 +438,17 @@ if_status_mgr_update(struct if_status_mgr *mgr, +@@ -359,6 +447,17 @@ if_status_mgr_update(struct if_status_mgr *mgr, struct shash *bindings = &binding_data->bindings; struct hmapx_node *node; @@ -716,7 +887,7 @@ index d1c14ac30..8503e5daa 100644 /* 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 +480,10 @@ if_status_mgr_update(struct if_status_mgr *mgr, +@@ -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; @@ -727,7 +898,7 @@ index d1c14ac30..8503e5daa 100644 if (!sb_readonly) { local_binding_set_pb(bindings, iface->id, chassis_rec, NULL, false); -@@ -437,6 +531,21 @@ if_status_mgr_update(struct if_status_mgr *mgr, +@@ -437,6 +540,21 @@ if_status_mgr_update(struct if_status_mgr *mgr, } } @@ -749,7 +920,7 @@ index d1c14ac30..8503e5daa 100644 /* 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 +559,23 @@ if_status_mgr_update(struct if_status_mgr *mgr, +@@ -450,10 +568,23 @@ if_status_mgr_update(struct if_status_mgr *mgr, } } @@ -773,7 +944,7 @@ index d1c14ac30..8503e5daa 100644 bool sb_readonly, bool ovs_readonly) { struct ofctrl_acked_seqnos *acked_seqnos = -@@ -471,12 +593,25 @@ if_status_mgr_run(struct if_status_mgr *mgr, +@@ -471,12 +602,25 @@ if_status_mgr_run(struct if_status_mgr *mgr, iface->install_seqno)) { continue; } @@ -800,7 +971,7 @@ index d1c14ac30..8503e5daa 100644 sb_readonly, ovs_readonly); } -@@ -492,6 +627,18 @@ ovs_iface_account_mem(const char *iface_id, bool erase) +@@ -492,8 +636,46 @@ ovs_iface_account_mem(const char *iface_id, bool erase) } } @@ -816,10 +987,42 @@ index d1c14ac30..8503e5daa 100644 + } +} + ++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) -@@ -506,6 +653,16 @@ ovs_iface_create(struct if_status_mgr *mgr, const char *iface_id, + { + 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; } @@ -836,7 +1039,7 @@ index d1c14ac30..8503e5daa 100644 static void ovs_iface_destroy(struct if_status_mgr *mgr, struct ovs_iface *iface) { -@@ -521,6 +678,23 @@ 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); } @@ -860,7 +1063,7 @@ index d1c14ac30..8503e5daa 100644 static void ovs_iface_set_state(struct if_status_mgr *mgr, struct ovs_iface *iface, enum if_state state) -@@ -539,6 +713,7 @@ static void +@@ -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, @@ -868,7 +1071,7 @@ index d1c14ac30..8503e5daa 100644 bool sb_readonly, bool ovs_readonly) { if (!binding_data) { -@@ -558,7 +733,17 @@ if_status_mgr_update_bindings(struct if_status_mgr *mgr, +@@ -558,7 +769,17 @@ if_status_mgr_update_bindings(struct if_status_mgr *mgr, sb_readonly, ovs_readonly); } @@ -888,18 +1091,29 @@ index d1c14ac30..8503e5daa 100644 * module. */ diff --git a/controller/if-status.h b/controller/if-status.h -index 5bd187a25..8ba80acd9 100644 +index 5bd187a25..15624bcfa 100644 --- a/controller/if-status.h +++ b/controller/if-status.h -@@ -17,6 +17,7 @@ +@@ -17,8 +17,10 @@ #define IF_STATUS_H 1 #include "openvswitch/shash.h" +#include "lib/vswitch-idl.h" #include "binding.h" - -@@ -35,9 +36,13 @@ void if_status_mgr_delete_iface(struct if_status_mgr *, const char *iface_id); ++#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, @@ -913,19 +1127,41 @@ index 5bd187a25..8ba80acd9 100644 bool sb_readonly, bool ovs_readonly); void if_status_mgr_get_memory_usage(struct if_status_mgr *mgr, struct simap *usage); -@@ -48,5 +53,8 @@ bool if_status_handle_claims(struct if_status_mgr *mgr, +@@ -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..0b071138d 100644 +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 @@ -997,6 +1233,100 @@ index 6a98b19e1..0b071138d 100644 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 @@ -1069,6 +1399,75 @@ index 665736966..0e5885e9b 100644 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 @@ -1112,10 +1511,18 @@ index ab52e2d34..f61f43008 100644 diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c -index 2d18bbfca..44a4518b9 100644 +index 2d18bbfca..ead789fb9 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c -@@ -712,7 +712,7 @@ get_snat_ct_zone(const struct sbrec_datapath_binding *dp) +@@ -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 @@ -1124,7 +1531,7 @@ index 2d18bbfca..44a4518b9 100644 const struct hmap *local_datapaths, struct simap *ct_zones, unsigned long *ct_zone_bitmap, struct shash *pending_ct_zones) -@@ -725,9 +725,9 @@ update_ct_zones(const struct shash *binding_lports, +@@ -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); @@ -1137,7 +1544,72 @@ index 2d18bbfca..44a4518b9 100644 } /* Local patched datapath (gateway routers) need zones assigned. */ -@@ -2010,7 +2010,11 @@ addr_sets_update(const struct sbrec_address_set_table *address_set_table, +@@ -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); @@ -1150,7 +1622,7 @@ index 2d18bbfca..44a4518b9 100644 struct expr_constant_set *cs_old = shash_find_data(addr_sets, as->name); if (!cs_old) { -@@ -2381,7 +2385,7 @@ en_ct_zones_run(struct engine_node *node, void *data) +@@ -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); @@ -1159,7 +1631,7 @@ index 2d18bbfca..44a4518b9 100644 &ct_zones_data->current, ct_zones_data->bitmap, &ct_zones_data->pending); -@@ -2471,8 +2475,10 @@ ct_zones_runtime_data_handler(struct engine_node *node, void *data) +@@ -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, "") @@ -1172,7 +1644,7 @@ index 2d18bbfca..44a4518b9 100644 continue; } -@@ -2697,7 +2703,8 @@ static void +@@ -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) { @@ -1182,7 +1654,7 @@ index 2d18bbfca..44a4518b9 100644 return; } -@@ -2716,7 +2723,8 @@ static void +@@ -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) { @@ -1192,7 +1664,143 @@ index 2d18bbfca..44a4518b9 100644 return; } -@@ -5071,7 +5079,8 @@ main(int argc, char *argv[]) +@@ -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, @@ -1202,7 +1810,7 @@ index 2d18bbfca..44a4518b9 100644 stopwatch_start(CONTROLLER_LOOP_STOPWATCH_NAME, time_msec()); -@@ -5225,6 +5234,11 @@ main(int argc, char *argv[]) +@@ -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, @@ -1214,7 +1822,7 @@ index 2d18bbfca..44a4518b9 100644 !ovnsb_idl_txn); stopwatch_stop(IF_STATUS_MGR_UPDATE_STOPWATCH_NAME, time_msec()); -@@ -5254,11 +5268,12 @@ main(int argc, char *argv[]) +@@ -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, @@ -1228,7 +1836,7 @@ index 2d18bbfca..44a4518b9 100644 } if (!engine_has_run()) { -@@ -5449,6 +5464,7 @@ loop_done: +@@ -5449,6 +5592,7 @@ loop_done: binding_destroy(); patch_destroy(); mirror_destroy(); @@ -1236,10 +1844,651 @@ index 2d18bbfca..44a4518b9 100644 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..761783562 100644 +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) { @@ -1263,7 +2512,21 @@ index 795847729..761783562 100644 case DHCPV6_OPT_SERVER_ID_CODE: { /* The Server Identifier option carries a DUID -@@ -7190,7 +7190,9 @@ bfd_monitor_send_msg(struct rconn *swconn, long long int *bfd_time) +@@ -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); @@ -1288,10 +2551,42 @@ index 11a07dd38..02a9953ba 100644 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..2b566c85e 100644 +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) @@ -1479,6 +2774,324 @@ index 2b20bc380..d718ed39a 100644 /* 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 @@ -1532,10 +3145,19 @@ index d23993a55..fd025c92b 100644 + ds_destroy(&ds); +} diff --git a/northd/northd.c b/northd/northd.c -index 7ad4cdfad..045282fac 100644 +index 7ad4cdfad..66f14e9dd 100644 --- a/northd/northd.c +++ b/northd/northd.c -@@ -432,6 +432,13 @@ build_chassis_features(const struct northd_input *input_data, +@@ -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) { @@ -1549,7 +3171,7 @@ index 7ad4cdfad..045282fac 100644 bool ct_no_masked_label = smap_get_bool(&chassis->other_config, OVN_FEATURE_CT_NO_MASKED_LABEL, -@@ -552,7 +559,7 @@ free_chassis_queueid(struct hmap *set, const struct uuid *uuid, +@@ -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) { @@ -1558,7 +3180,7 @@ index 7ad4cdfad..045282fac 100644 smap_get(opts, "qos_burst")); } -@@ -1641,6 +1648,10 @@ ovn_port_destroy(struct hmap *ports, struct ovn_port *port) +@@ -1641,6 +1650,10 @@ ovn_port_destroy(struct hmap *ports, struct ovn_port *port) * use it. */ hmap_remove(ports, &port->key_node); @@ -1569,7 +3191,7 @@ index 7ad4cdfad..045282fac 100644 for (int i = 0; i < port->n_lsp_addrs; i++) { destroy_lport_addresses(&port->lsp_addrs[i]); } -@@ -3881,7 +3892,7 @@ build_lb_vip_actions(struct ovn_lb_vip *lb_vip, +@@ -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; @@ -1578,7 +3200,7 @@ index 7ad4cdfad..045282fac 100644 if (lb_vip_nb->lb_health_check) { ds_put_format(action, "%s(backends=", ct_lb_action); -@@ -5779,20 +5790,24 @@ skip_port_from_conntrack(struct ovn_datapath *od, struct ovn_port *op, +@@ -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. */ @@ -1613,7 +3235,7 @@ index 7ad4cdfad..045282fac 100644 } static void -@@ -5867,7 +5882,8 @@ build_pre_acls(struct ovn_datapath *od, const struct hmap *port_groups, +@@ -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], @@ -1623,7 +3245,7 @@ index 7ad4cdfad..045282fac 100644 110, lflows); } -@@ -6036,10 +6052,17 @@ build_pre_lb(struct ovn_datapath *od, const struct shash *meter_groups, +@@ -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); } @@ -1645,7 +3267,7 @@ index 7ad4cdfad..045282fac 100644 } /* Do not sent statless flows via conntrack */ -@@ -6700,6 +6723,8 @@ build_port_group_lswitches(struct northd_input *input_data, +@@ -6700,6 +6725,8 @@ build_port_group_lswitches(struct northd_input *input_data, } } @@ -1654,7 +3276,7 @@ index 7ad4cdfad..045282fac 100644 static void build_acls(struct ovn_datapath *od, const struct chassis_features *features, struct hmap *lflows, const struct hmap *port_groups, -@@ -6847,20 +6872,26 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, +@@ -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); @@ -1689,7 +3311,7 @@ index 7ad4cdfad..045282fac 100644 /* 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 +7120,9 @@ build_lb_rules_pre_stateful(struct hmap *lflows, struct ovn_northd_lb *lb, +@@ -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) @@ -1700,7 +3322,7 @@ index 7ad4cdfad..045282fac 100644 * * - load balancing: * table=lr_in_dnat, priority=150 -@@ -7130,16 +7163,11 @@ build_lb_affinity_lr_flows(struct hmap *lflows, struct ovn_northd_lb *lb, +@@ -7130,16 +7165,11 @@ build_lb_affinity_lr_flows(struct hmap *lflows, struct ovn_northd_lb *lb, return; } @@ -1718,7 +3340,7 @@ index 7ad4cdfad..045282fac 100644 bool ipv6 = !IN6_IS_ADDR_V4MAPPED(&lb_vip->vip); const char *ip_match = ipv6 ? "ip6" : "ip4"; -@@ -7155,6 +7183,20 @@ build_lb_affinity_lr_flows(struct hmap *lflows, struct ovn_northd_lb *lb, +@@ -7155,6 +7185,20 @@ build_lb_affinity_lr_flows(struct hmap *lflows, struct ovn_northd_lb *lb, ct_flag = "; force_snat"; } @@ -1739,7 +3361,7 @@ index 7ad4cdfad..045282fac 100644 /* 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 +7294,7 @@ build_lb_affinity_lr_flows(struct hmap *lflows, struct ovn_northd_lb *lb, +@@ -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); @@ -1747,6 +3369,73 @@ index 7ad4cdfad..045282fac 100644 } /* 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 { @@ -1966,7 +3655,33 @@ index 7ad4cdfad..045282fac 100644 } /* Handles the match criteria and actions in logical flow -@@ -12814,8 +12808,7 @@ build_gateway_redirect_flows_for_lrouter( +@@ -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]; @@ -1976,7 +3691,7 @@ index 7ad4cdfad..045282fac 100644 (!nat->nb->allowed_ext_ips && !nat->nb->exempted_ext_ips)) { continue; } -@@ -13038,9 +13031,27 @@ build_misc_local_traffic_drop_flows_for_lrouter( +@@ -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()); @@ -2005,7 +3720,7 @@ index 7ad4cdfad..045282fac 100644 /* Pass other traffic not already handled to the next table for * routing. */ -@@ -13224,7 +13235,7 @@ build_ipv6_input_flows_for_lrouter_port( +@@ -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, @@ -2014,7 +3729,7 @@ index 7ad4cdfad..045282fac 100644 copp_meter_get(COPP_ICMP6_ERR, op->od->nbr->copp, meter_groups), &op->nbrp->header_); -@@ -13352,7 +13363,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, +@@ -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, @@ -2023,7 +3738,7 @@ index 7ad4cdfad..045282fac 100644 copp_meter_get(COPP_ICMP4_ERR, op->od->nbr->copp, meter_groups), &op->nbrp->header_); -@@ -13597,13 +13608,13 @@ build_lrouter_in_unsnat_flow(struct hmap *lflows, struct ovn_datapath *od, +@@ -13597,13 +13627,13 @@ build_lrouter_in_unsnat_flow(struct hmap *lflows, struct ovn_datapath *od, return; } @@ -2039,7 +3754,7 @@ index 7ad4cdfad..045282fac 100644 ds_put_format(actions, "next;"); } else { ds_put_cstr(actions, "ct_snat;"); -@@ -13628,7 +13639,7 @@ build_lrouter_in_unsnat_flow(struct hmap *lflows, struct ovn_datapath *od, +@@ -13628,7 +13658,7 @@ build_lrouter_in_unsnat_flow(struct hmap *lflows, struct ovn_datapath *od, l3dgw_port->cr_port->json_key); } @@ -2048,7 +3763,7 @@ index 7ad4cdfad..045282fac 100644 ds_put_format(actions, "next;"); } else { ds_put_cstr(actions, "ct_snat_in_czone;"); -@@ -13670,7 +13681,7 @@ build_lrouter_in_dnat_flow(struct hmap *lflows, struct ovn_datapath *od, +@@ -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")) { @@ -2057,7 +3772,7 @@ index 7ad4cdfad..045282fac 100644 if (od->is_gw_router) { /* Packet when it goes from the initiator to destination. -@@ -13692,7 +13703,7 @@ build_lrouter_in_dnat_flow(struct hmap *lflows, struct ovn_datapath *od, +@@ -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; "); } @@ -2066,7 +3781,7 @@ index 7ad4cdfad..045282fac 100644 ds_put_format(actions, "flags.loopback = 1; " "ip%s.dst=%s; next;", is_v6 ? "6" : "4", nat->logical_ip); -@@ -13782,8 +13793,7 @@ build_lrouter_out_undnat_flow(struct hmap *lflows, struct ovn_datapath *od, +@@ -13782,8 +13812,7 @@ build_lrouter_out_undnat_flow(struct hmap *lflows, struct ovn_datapath *od, ETH_ADDR_ARGS(mac)); } @@ -2076,7 +3791,7 @@ index 7ad4cdfad..045282fac 100644 ds_put_format(actions, "next;"); } else { ds_put_format(actions, -@@ -13839,7 +13849,7 @@ build_lrouter_out_snat_flow(struct hmap *lflows, struct ovn_datapath *od, +@@ -13839,7 +13868,7 @@ build_lrouter_out_snat_flow(struct hmap *lflows, struct ovn_datapath *od, return; } @@ -2085,7 +3800,7 @@ index 7ad4cdfad..045282fac 100644 if (od->is_gw_router) { ds_clear(match); ds_put_format(match, "ip && ip%s.src == %s", -@@ -13905,7 +13915,7 @@ build_lrouter_out_snat_flow(struct hmap *lflows, struct ovn_datapath *od, +@@ -13905,7 +13934,7 @@ build_lrouter_out_snat_flow(struct hmap *lflows, struct ovn_datapath *od, ETH_ADDR_ARGS(mac)); } @@ -2094,7 +3809,7 @@ index 7ad4cdfad..045282fac 100644 ds_put_format(actions, "ip%s.src=%s; next;", is_v6 ? "6" : "4", nat->external_ip); } else { -@@ -14217,10 +14227,10 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, +@@ -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;"); @@ -2109,7 +3824,7 @@ index 7ad4cdfad..045282fac 100644 * * Allow traffic that is related to an existing conntrack entry. * At the same time apply NAT for this traffic. -@@ -14231,16 +14241,10 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, +@@ -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); @@ -2126,7 +3841,7 @@ index 7ad4cdfad..045282fac 100644 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 +14255,34 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, +@@ -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); @@ -2163,7 +3878,7 @@ index 7ad4cdfad..045282fac 100644 } /* If the router has load balancer or DNAT rules, re-circulate every packet -@@ -14267,6 +14295,9 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, +@@ -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)) { @@ -2174,7 +3889,7 @@ index 7ad4cdfad..045282fac 100644 "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..e16d7d080 100644 +index 2eab2c4ae..5b3559d45 100644 --- a/northd/ovn-northd.8.xml +++ b/northd/ovn-northd.8.xml @@ -748,6 +748,12 @@ @@ -2203,7 +3918,46 @@ index 2eab2c4ae..e16d7d080 100644
-@@ -2056,6 +2056,16 @@ output; +@@ -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.
+
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.
+
-@@ -2098,6 +2108,12 @@ output;
+@@ -2098,6 +2112,12 @@ output;
to-lport
ACLs.
In addition, the following flows are added.
-@@ -3066,10 +3082,18 @@ nd.tll = external_mac; +@@ -3066,10 +3086,18 @@ nd.tll = external_mac; broadcast address. By definition this traffic should not be forwarded.@@ -2294,7 +4048,7 @@ index 2eab2c4ae..e16d7d080 100644
-@@ -3349,10 +3354,11 @@ icmp6 {
+@@ -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 &&
@@ -2309,7 +4063,7 @@ index 2eab2c4ae..e16d7d080 100644
reg9[6] == 1 && ct.new &&
@@ -2321,7 +4075,7 @@ index 2eab2c4ae..e16d7d080 100644
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 +3415,25 @@ icmp6 {
+@@ -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
@@ -2385,7 +4139,7 @@ index 2eab2c4ae..e16d7d080 100644
OVN_Northbound
database that includes just an IP address
VIP to match on, a priority-110 flow that matches on
@@ -2433,7 +4187,7 @@ index 2eab2c4ae..e16d7d080 100644
-@@ -3529,7 +3478,20 @@ icmp6 {
+@@ -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
@@ -2455,7 +4209,7 @@ index 2eab2c4ae..e16d7d080 100644
flags.loopback = 1; ct_dnat;
.
-@@ -4998,7 +4965,19 @@ nd_ns {
+@@ -4998,7 +4969,19 @@ nd_ns {
For distributed logical routers where one of the logical router -@@ -5070,7 +5049,7 @@ clone { +@@ -5070,7 +5053,7 @@ clone { @@ -2497,10 +4251,42 @@ index 2eab2c4ae..e16d7d080 100644
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..86c6258e0 100644 +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 (seeTunnel
@@ -2510,6 +4296,210 @@ index cb1064f71..86c6258e0 100644
+@@ -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
@@ -2572,7 +4562,7 @@ index d281f861c..6c4c6621c 100644
[Install]
WantedBy=multi-user.target
diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at
-index bbe142ae3..27fc44232 100644
+index bbe142ae3..dd7eda516 100644
--- a/tests/ovn-controller.at
+++ b/tests/ovn-controller.at
@@ -493,7 +493,8 @@ check ovn-nbctl --wait=hv sync
@@ -2616,6 +4606,579 @@ index bbe142ae3..27fc44232 100644
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
@@ -2643,7 +5206,7 @@ index bbe142ae3..27fc44232 100644
+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=44 | grep -c "priority=1100"], [0], [1
++AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], [1
+])
+
+# pause ovn-northd
@@ -2659,13 +5222,13 @@ index bbe142ae3..27fc44232 100644
+# 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=44 | grep -c "priority=1100")
++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=44 | grep -c "priority=1100") = "$(($i + 1))"])
++ OVS_WAIT_UNTIL([test $(as hv1 ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100") = "$(($i + 1))"])
+done
+
+OVN_CLEANUP([hv1])
@@ -2772,7 +5335,7 @@ index 2fffe1850..478a32f5a 100644
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..846f10e88 100644
+index 3fa02d2b3..93854dfdc 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -2486,6 +2486,7 @@ check ovn-nbctl --wait=sb \
@@ -2796,7 +5359,31 @@ index 3fa02d2b3..846f10e88 100644
table=8 (ls_in_acl ), priority=65535, match=(1), action=(next;)
])
-@@ -3757,18 +3761,18 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
+@@ -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;)
@@ -2822,7 +5409,7 @@ index 3fa02d2b3..846f10e88 100644
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 +3792,18 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
+@@ -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;)
@@ -2848,7 +5435,7 @@ index 3fa02d2b3..846f10e88 100644
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 +3817,7 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [
+@@ -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;)
@@ -2856,7 +5443,7 @@ index 3fa02d2b3..846f10e88 100644
table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;)
])
-@@ -3838,18 +3843,18 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
+@@ -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;)
@@ -2882,7 +5469,7 @@ index 3fa02d2b3..846f10e88 100644
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 +3869,7 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [
+@@ -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;)
@@ -2890,7 +5477,7 @@ index 3fa02d2b3..846f10e88 100644
table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;)
])
-@@ -3902,18 +3908,18 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
+@@ -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;)
@@ -2916,7 +5503,7 @@ index 3fa02d2b3..846f10e88 100644
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 +3935,7 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [
+@@ -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;)
@@ -2924,7 +5511,7 @@ index 3fa02d2b3..846f10e88 100644
table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;)
])
-@@ -3953,14 +3960,13 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
+@@ -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;)
@@ -2943,7 +5530,7 @@ index 3fa02d2b3..846f10e88 100644
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 +3976,7 @@ AT_CHECK([grep "lr_out_snat" lr0flows | grep skip_snat_for_lb | sed 's/table=./t
+@@ -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;)
@@ -2951,7 +5538,7 @@ index 3fa02d2b3..846f10e88 100644
table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;)
])
-@@ -4111,6 +4118,7 @@ check ovn-nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0
+@@ -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() {
@@ -2959,7 +5546,7 @@ index 3fa02d2b3..846f10e88 100644
ovn-sbctl dump-flows sw0 > sw0flows
AT_CAPTURE_FILE([sw0flows])
-@@ -4144,12 +4152,12 @@ check_stateful_flows() {
+@@ -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;)
])
@@ -2975,7 +5562,7 @@ index 3fa02d2b3..846f10e88 100644
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 +4177,13 @@ check_stateful_flows() {
+@@ -4169,13 +4174,13 @@ check_stateful_flows() {
])
}
@@ -2991,7 +5578,7 @@ index 3fa02d2b3..846f10e88 100644
# Remove load balancers from sw0
check ovn-nbctl ls-lb-del sw0 lb0
-@@ -4231,6 +4239,15 @@ AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl
+@@ -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;)
])
@@ -3007,7 +5594,88 @@ index 3fa02d2b3..846f10e88 100644
AT_CLEANUP
])
-@@ -5211,25 +5228,23 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
+@@ -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;)
@@ -3044,7 +5712,7 @@ index 3fa02d2b3..846f10e88 100644
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 +5299,23 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
+@@ -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;)
@@ -3081,7 +5749,7 @@ index 3fa02d2b3..846f10e88 100644
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 +5327,7 @@ AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sor
+@@ -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;)
@@ -3089,7 +5757,7 @@ index 3fa02d2b3..846f10e88 100644
table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;)
])
-@@ -5349,25 +5363,23 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
+@@ -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;)
@@ -3126,7 +5794,7 @@ index 3fa02d2b3..846f10e88 100644
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 +5391,7 @@ AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sor
+@@ -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;)
@@ -3134,7 +5802,7 @@ index 3fa02d2b3..846f10e88 100644
table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;)
])
-@@ -5416,28 +5429,25 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
+@@ -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;)
@@ -3176,7 +5844,7 @@ index 3fa02d2b3..846f10e88 100644
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 +5459,7 @@ AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sor
+@@ -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;)
@@ -3184,7 +5852,7 @@ index 3fa02d2b3..846f10e88 100644
table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;)
])
-@@ -5496,31 +5507,27 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
+@@ -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;)
@@ -3231,7 +5899,7 @@ index 3fa02d2b3..846f10e88 100644
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 +5539,7 @@ AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sor
+@@ -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;)
@@ -3239,7 +5907,7 @@ index 3fa02d2b3..846f10e88 100644
table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;)
])
-@@ -5572,18 +5580,17 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
+@@ -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;)
@@ -3264,7 +5932,7 @@ index 3fa02d2b3..846f10e88 100644
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 +5601,7 @@ AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sor
+@@ -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;)
@@ -3272,7 +5940,7 @@ index 3fa02d2b3..846f10e88 100644
table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;)
])
-@@ -5634,9 +5642,11 @@ ovn-sbctl set service_monitor $sm_vip2 status=offline
+@@ -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;)
@@ -3286,7 +5954,7 @@ index 3fa02d2b3..846f10e88 100644
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 +5656,11 @@ check ovn-nbctl --wait=sb set load_balancer lb5 options:skip_snat=true
+@@ -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;)
@@ -3300,7 +5968,7 @@ index 3fa02d2b3..846f10e88 100644
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 +5672,58 @@ check ovn-nbctl --wait=sb set logical_router lr0 options:lb_force_snat_ip="route
+@@ -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;)
@@ -3361,7 +6029,7 @@ index 3fa02d2b3..846f10e88 100644
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 +6753,12 @@ dnl Flows to skip TTL == {0, 1} check for IGMP and MLD packets.
+@@ -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;)
@@ -3379,7 +6047,7 @@ index 3fa02d2b3..846f10e88 100644
])
dnl Flows to "route" (statically forward) without decrementing TTL for
-@@ -6755,6 +6817,7 @@ AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0],
+@@ -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;)
@@ -3387,7 +6055,7 @@ index 3fa02d2b3..846f10e88 100644
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 +6872,7 @@ AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0],
+@@ -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 */)
@@ -3395,7 +6063,7 @@ index 3fa02d2b3..846f10e88 100644
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 +6927,7 @@ AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0],
+@@ -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 */)
@@ -3403,7 +6071,7 @@ index 3fa02d2b3..846f10e88 100644
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 +7219,14 @@ flow="inport == \"lsp1\" && eth.src == 00:00:00:00:00:01 && eth.dst == 00:00:00:
+@@ -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
@@ -3418,7 +6086,7 @@ index 3fa02d2b3..846f10e88 100644
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 +7241,14 @@ output("lsp2");
+@@ -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
@@ -3433,7 +6101,7 @@ index 3fa02d2b3..846f10e88 100644
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 +7263,14 @@ output("lsp2");
+@@ -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
@@ -3448,7 +6116,7 @@ index 3fa02d2b3..846f10e88 100644
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 +7292,15 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/
+@@ -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;)
@@ -3464,7 +6132,7 @@ index 3fa02d2b3..846f10e88 100644
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 +7317,15 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/
+@@ -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;)
@@ -3480,7 +6148,7 @@ index 3fa02d2b3..846f10e88 100644
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 +7342,15 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/
+@@ -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;)
@@ -3496,7 +6164,7 @@ index 3fa02d2b3..846f10e88 100644
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 +7375,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/
+@@ -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;)
@@ -3504,7 +6172,7 @@ index 3fa02d2b3..846f10e88 100644
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 +7427,16 @@ check ovn-nbctl --wait=sb remove NB_Global . options default_acl_drop
+@@ -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;)
@@ -3521,7 +6189,7 @@ index 3fa02d2b3..846f10e88 100644
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 +7452,16 @@ check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=false
+@@ -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;)
@@ -3538,7 +6206,7 @@ index 3fa02d2b3..846f10e88 100644
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 +7477,16 @@ check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=true
+@@ -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;)
@@ -3555,7 +6223,7 @@ index 3fa02d2b3..846f10e88 100644
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 +7511,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/
+@@ -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;)
@@ -3563,7 +6231,7 @@ index 3fa02d2b3..846f10e88 100644
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 +7563,16 @@ check ovn-nbctl --wait=sb remove NB_Global . options default_acl_drop
+@@ -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;)
@@ -3580,7 +6248,7 @@ index 3fa02d2b3..846f10e88 100644
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 +7588,16 @@ check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=false
+@@ -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;)
@@ -3597,7 +6265,7 @@ index 3fa02d2b3..846f10e88 100644
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 +7613,16 @@ check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=true
+@@ -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;)
@@ -3614,7 +6282,7 @@ index 3fa02d2b3..846f10e88 100644
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 +7645,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/
+@@ -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;)
@@ -3622,7 +6290,61 @@ index 3fa02d2b3..846f10e88 100644
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;)
-@@ -7886,8 +7990,10 @@ check ovn-nbctl \
+@@ -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
@@ -3635,7 +6357,7 @@ index 3fa02d2b3..846f10e88 100644
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 +8004,10 @@ AS_BOX([Chassis registered that doesn't support ct_lb_mark - use ct_lb and ct_la
+@@ -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
@@ -3648,7 +6370,7 @@ index 3fa02d2b3..846f10e88 100644
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 +8018,10 @@ AS_BOX([Chassis upgrades and supports ct_lb_mark - use ct_lb_mark and ct_mark.na
+@@ -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
@@ -3661,7 +6383,7 @@ index 3fa02d2b3..846f10e88 100644
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 +8354,17 @@ AT_CAPTURE_FILE([R1flows])
+@@ -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;)
@@ -3682,7 +6404,7 @@ index 3fa02d2b3..846f10e88 100644
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 +8382,13 @@ AT_CAPTURE_FILE([R1flows_skip_snat])
+@@ -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;)
@@ -3698,7 +6420,7 @@ index 3fa02d2b3..846f10e88 100644
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 +8403,13 @@ AT_CAPTURE_FILE([R1flows_force_snat])
+@@ -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;)
@@ -3714,7 +6436,31 @@ index 3fa02d2b3..846f10e88 100644
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;)
])
-@@ -8569,12 +8685,13 @@ ovn-sbctl dump-flows | DUMP_FLOWS_SORTED > lflows0
+@@ -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;)
@@ -3732,7 +6478,7 @@ index 3fa02d2b3..846f10e88 100644
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 +8705,7 @@ AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows0 | grep "priority=65532"],
+@@ -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;)
@@ -3740,7 +6486,7 @@ index 3fa02d2b3..846f10e88 100644
table=?(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
])
-@@ -8599,10 +8717,12 @@ ovn-sbctl dump-flows | DUMP_FLOWS_SORTED > lflows1
+@@ -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;)
@@ -3756,7 +6502,7 @@ index 3fa02d2b3..846f10e88 100644
])
AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows1 | grep "priority=65532"], [0], [dnl
-@@ -8614,6 +8734,7 @@ AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows1 | grep "priority=65532"],
+@@ -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;)
@@ -3764,7 +6510,7 @@ index 3fa02d2b3..846f10e88 100644
table=?(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;)
])
-@@ -8625,12 +8746,13 @@ ovn-sbctl dump-flows | DUMP_FLOWS_SORTED > lflows2
+@@ -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;)
@@ -3782,7 +6528,7 @@ index 3fa02d2b3..846f10e88 100644
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 +8766,104 @@ AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows2 | grep "priority=65532"],
+@@ -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;)
@@ -3888,10 +6634,189 @@ index 3fa02d2b3..846f10e88 100644
+AT_CLEANUP
+])
diff --git a/tests/ovn.at b/tests/ovn.at
-index 55de7c85b..3515a1e3c 100644
+index 55de7c85b..ed91d32d0 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
-@@ -5753,7 +5753,7 @@ check ovn-nbctl --wait=hv sync
+@@ -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"
@@ -3900,7 +6825,7 @@ index 55de7c85b..3515a1e3c 100644
echo "---------NB dump-----"
-@@ -5803,7 +5803,7 @@ packet="inport==\"ls1-lp1\" && eth.src==$ls1_lp1_mac && eth.dst==$rp_ls1_mac &&
+@@ -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"
@@ -3909,7 +6834,7 @@ index 55de7c85b..3515a1e3c 100644
# The 2nd packet sent shound not be received.
OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
-@@ -7741,7 +7741,6 @@ ls3_p1_mac=00:00:00:01:02:05
+@@ -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
@@ -3917,7 +6842,7 @@ index 55de7c85b..3515a1e3c 100644
AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | grep "192.168.1.0" | wc -l], [0], [dnl
1
])
-@@ -7751,15 +7750,12 @@ packet="inport==\"ls1-lp1\" && eth.src==$ls1_p1_mac && eth.dst==$ls1_ro_mac &&
+@@ -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"
@@ -3936,7 +6861,7 @@ index 55de7c85b..3515a1e3c 100644
# Expected to drop the packet.
$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" pbr-hv/vif2-tx.pcap > vif2.packets
-@@ -7770,7 +7766,7 @@ AT_FAIL_IF([test "$rcvd_packet" != ""])
+@@ -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
@@ -3945,7 +6870,7 @@ index 55de7c85b..3515a1e3c 100644
2
])
-@@ -7778,15 +7774,12 @@ AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | grep "192.168.1.0" | wc -l]
+@@ -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"
@@ -3965,7 +6890,7 @@ index 55de7c85b..3515a1e3c 100644
# Expected packet has TTL decreased by 1
expected="eth.src==$ls2_ro_mac && eth.dst==$ls2_p1_mac &&
-@@ -7802,7 +7795,7 @@ check ovn-nbctl --wait=hv lr-policy-add R1 30 "ip4.src==192.168.1.0/24 && ip4.ds
+@@ -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" | \
@@ -3974,7 +6899,7 @@ index 55de7c85b..3515a1e3c 100644
1
])
-@@ -7810,21 +7803,12 @@ AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | \
+@@ -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"
@@ -4000,7 +6925,7 @@ index 55de7c85b..3515a1e3c 100644
echo "packet hit reroute policy"
# Expected packet has TTL decreased by 1
-@@ -7927,9 +7911,7 @@ ls3_p1_mac=00:00:00:01:02:05
+@@ -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
@@ -4011,7 +6936,7 @@ index 55de7c85b..3515a1e3c 100644
1
])
-@@ -7938,15 +7920,12 @@ packet="inport==\"ls1-lp1\" && eth.src==$ls1_p1_mac && eth.dst==$ls1_ro_mac &&
+@@ -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"
@@ -4030,7 +6955,7 @@ index 55de7c85b..3515a1e3c 100644
# Expected to drop the packet.
$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" pbr-hv/vif2-tx.pcap > vif2.packets
-@@ -7956,9 +7935,7 @@ AT_FAIL_IF([test -s 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
@@ -4041,7 +6966,7 @@ index 55de7c85b..3515a1e3c 100644
2
])
-@@ -7966,16 +7943,12 @@ AT_CHECK([grep lr_in_policy sbflows2 | grep "2001" | wc -l], [0], [dnl
+@@ -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"
@@ -4062,7 +6987,7 @@ index 55de7c85b..3515a1e3c 100644
# Expected packet has TTL decreased by 1
expected="eth.src==$ls2_ro_mac && eth.dst==$ls2_p1_mac &&
-@@ -7989,11 +7962,9 @@ OVN_CHECK_PACKETS([pbr-hv/vif2-tx.pcap], [expected])
+@@ -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
@@ -4076,7 +7001,7 @@ index 55de7c85b..3515a1e3c 100644
1
])
-@@ -8001,19 +7972,12 @@ AT_CHECK([grep lr_in_policy sbflows4 | \
+@@ -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"
@@ -4100,7 +7025,7 @@ index 55de7c85b..3515a1e3c 100644
# Expected packet has TTL decreased by 1
expected="eth.src==$ls3_ro_mac && eth.dst==$ls3_p1_mac &&
-@@ -9531,73 +9495,73 @@ AT_CAPTURE_FILE([sbflows])
+@@ -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"
@@ -4184,9 +7109,86 @@ index 55de7c85b..3515a1e3c 100644
-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) ])
+ 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")
+ ])
-@@ -12254,7 +12218,7 @@ nexthop_mac="f00000010204"
+ 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"
@@ -4195,7 +7197,7 @@ index 55de7c85b..3515a1e3c 100644
AS_BOX([Wait for GARPs announcing gw IP to arrive])
OVS_WAIT_UNTIL([
-@@ -12265,15 +12229,12 @@ grep actions=mod_dl_dst:f0:00:00:01:02:04 | wc -l` -eq 1
+@@ -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
@@ -4213,7 +7215,18 @@ index 55de7c85b..3515a1e3c 100644
echo $expected > hv3-vif1.expected
check as hv1 ovs-appctl dpctl/del-flows
-@@ -12304,7 +12265,7 @@ cat hv1-br-ex_n2.expected > expout
+@@ -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])
@@ -4222,20 +7235,30 @@ index 55de7c85b..3515a1e3c 100644
cat hv3-vif1.expected > expout
AT_CHECK([sort hv3-vif1], [0], [expout])
-@@ -13268,30 +13229,27 @@ as hv2 ovs-ofctl dump-flows br-int table=37
+@@ -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=37 | \
++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=37 | \
++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
])
@@ -4265,25 +7288,25 @@ index 55de7c85b..3515a1e3c 100644
# 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 +13272,13 @@ wait_for_ports_up
+@@ -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=37 | \
++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=37 | \
++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 +13330,11 @@ AT_CHECK([ovs-vsctl --bare --columns bfd find Interface name=ovn-hv1-0],[0],
+@@ -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
@@ -4299,7 +7322,7 @@ index 55de7c85b..3515a1e3c 100644
]])
# disconnect GW2 from the network, GW1 should take over
-@@ -13386,12 +13344,12 @@ as main ovs-vsctl del-port n1 $port
+@@ -13386,12 +13366,12 @@ as main ovs-vsctl del-port n1 $port
bfd_dump
@@ -4317,14 +7340,14 @@ index 55de7c85b..3515a1e3c 100644
]])
# check that the chassis redirect port has been reclaimed by the gw1 chassis
-@@ -13470,45 +13428,16 @@ ovn-nbctl set Logical_Router_Port outside ha_chassis_group=$hagrp1_uuid
+@@ -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=37 | \
++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
])
@@ -4332,7 +7355,7 @@ index 55de7c85b..3515a1e3c 100644
-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=37 | \
++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
])
@@ -4369,19 +7392,19 @@ index 55de7c85b..3515a1e3c 100644
# Re add the ovs ports.
for i in 1 2; do
as hv$i
-@@ -13519,6 +13448,34 @@ for i in 1 2; do
+@@ -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=37 | \
++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=37 | \
++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
+])
@@ -4404,20 +7427,20 @@ index 55de7c85b..3515a1e3c 100644
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 +13484,18 @@ wait_column "$exp_ref_ch_list" HA_Chassis_Group ref_chassis
+@@ -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=37 | \
++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=37 | \
++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
])
@@ -4439,7 +7462,7 @@ index 55de7c85b..3515a1e3c 100644
# check BFD enablement on tunnel ports from gw1 #########
as gw1
-@@ -13588,11 +13534,11 @@ AT_CHECK([ovs-vsctl --bare --columns bfd find Interface name=ovn-hv1-0],[0],
+@@ -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
@@ -4455,7 +7478,7 @@ index 55de7c85b..3515a1e3c 100644
]])
# disconnect GW2 from the network, GW1 should take over
-@@ -13603,11 +13549,11 @@ as main ovs-vsctl del-port n1 $port
+@@ -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
@@ -4471,7 +7494,7 @@ index 55de7c85b..3515a1e3c 100644
]])
# check that the chassis redirect port has been reclaimed by the gw1 chassis
-@@ -13889,6 +13835,133 @@ OVN_CLEANUP([gw1],[gw2],[hv1])
+@@ -13889,6 +13857,133 @@ OVN_CLEANUP([gw1],[gw2],[hv1])
AT_CLEANUP
])
@@ -4605,7 +7628,390 @@ index 55de7c85b..3515a1e3c 100644
OVN_FOR_EACH_NORTHD([
AT_SETUP([IPv6 Neighbor Solicitation for unknown MAC])
AT_KEYWORDS([ovn-nd_ns for unknown mac])
-@@ -17210,7 +17283,7 @@ test_icmp() {
+@@ -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`
@@ -4614,7 +8020,165 @@ index 55de7c85b..3515a1e3c 100644
in_ls=`vif_to_ls $inport`
in_lrp=`vif_to_lrp $inport`
for outport; do
-@@ -18276,7 +18349,7 @@ AT_SETUP([TTL exceeded])
+@@ -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
@@ -4623,7 +8187,7 @@ index 55de7c85b..3515a1e3c 100644
#
# 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 +18365,7 @@ test_ip_packet() {
+@@ -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
@@ -4631,7 +8195,7 @@ index 55de7c85b..3515a1e3c 100644
local ip_ttl=01
local packet=${eth_dst}${eth_src}08004500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst}
-@@ -18300,27 +18374,31 @@ test_ip_packet() {
+@@ -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}
@@ -4669,7 +8233,7 @@ index 55de7c85b..3515a1e3c 100644
as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet
}
-@@ -18343,6 +18421,8 @@ for i in 1 2; do
+@@ -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
@@ -4678,7 +8242,7 @@ index 55de7c85b..3515a1e3c 100644
done
ovn-nbctl lr-add lr0
-@@ -18358,10 +18438,22 @@ OVN_POPULATE_ARP
+@@ -18358,10 +18783,22 @@ OVN_POPULATE_ARP
wait_for_ports_up
ovn-nbctl --wait=hv sync
@@ -4703,7 +8267,7 @@ index 55de7c85b..3515a1e3c 100644
OVN_CLEANUP([hv1], [hv2])
AT_CLEANUP
])
-@@ -18656,7 +18748,7 @@ packet="inport==\"sw1-p1\" && eth.src==$sw1_p1_mac && eth.dst==$sw1_ro_mac &&
+@@ -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
@@ -4712,7 +8276,7 @@ index 55de7c85b..3515a1e3c 100644
# Expected packet has TTL decreased by 1
expected="eth.src==$sw2_ro_mac && eth.dst==$sw2_p1_mac &&
-@@ -18670,7 +18762,7 @@ OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
+@@ -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.
@@ -4721,7 +8285,7 @@ index 55de7c85b..3515a1e3c 100644
OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
-@@ -19552,7 +19644,7 @@ packet="inport==\"sw1-p1\" && eth.src==$sw1_p1_mac && eth.dst==$sw1_ro_mac &&
+@@ -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
@@ -4730,7 +8294,7 @@ index 55de7c85b..3515a1e3c 100644
# Expected packet has TTL decreased by 1
expected="eth.src==$sw2_ro_mac && eth.dst==$sw2_p1_mac &&
-@@ -19566,7 +19658,7 @@ OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected])
+@@ -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
@@ -4739,7 +8303,7 @@ index 55de7c85b..3515a1e3c 100644
cat expected expected > expected2
-@@ -19705,7 +19797,7 @@ test_ip_packet_larger() {
+@@ -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
@@ -4748,7 +8312,7 @@ index 55de7c85b..3515a1e3c 100644
orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
-@@ -19729,10 +19821,10 @@ test_ip_packet_larger() {
+@@ -19729,10 +20166,10 @@ test_ip_packet_larger() {
# Packet to expect at br-phys.
src_mac="000020201213"
dst_mac="00000012af11"
@@ -4762,7 +8326,7 @@ index 55de7c85b..3515a1e3c 100644
expected=${expected}000000000000000000000000000000000000
expected=${expected}000000000000000000000000000000000000
expected=${expected}000000000000000000000000000000000000
-@@ -19793,7 +19885,7 @@ test_ip_packet_larger_ext() {
+@@ -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}
@@ -4771,7 +8335,7 @@ index 55de7c85b..3515a1e3c 100644
orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000
-@@ -19810,7 +19902,7 @@ test_ip_packet_larger_ext() {
+@@ -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
@@ -4780,7 +8344,7 @@ index 55de7c85b..3515a1e3c 100644
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 +20077,10 @@ OVS_WAIT_FOR_OUTPUT([
+@@ -19985,10 +20422,10 @@ OVS_WAIT_FOR_OUTPUT([
])
AS_BOX([testing ingress traffic mtu 100 - IPv4])
@@ -4793,7 +8357,7 @@ index 55de7c85b..3515a1e3c 100644
AS_BOX([testing ingress traffic mtu 100 - IPv6])
test_ip6_packet_larger_ext 1 000020201213 20000000000000000000000000000001 100 cc7a
-@@ -20055,10 +20147,10 @@ OVS_WAIT_FOR_OUTPUT([
+@@ -20055,10 +20492,10 @@ OVS_WAIT_FOR_OUTPUT([
])
AS_BOX([testing ingress traffic mtu 100 for gw router - IPv4])
@@ -4806,7 +8370,29 @@ index 55de7c85b..3515a1e3c 100644
OVN_CLEANUP([hv1])
AT_CLEANUP
-@@ -21116,7 +21208,7 @@ check_virtual_offlows_not_present hv2
+@@ -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 \
@@ -4815,7 +8401,7 @@ index 55de7c85b..3515a1e3c 100644
AT_CHECK([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \
logical_port=sw0-vir) = xsw0-p1])
-@@ -21184,7 +21276,7 @@ tpa=$(ip_to_hex 10 0 0 10)
+@@ -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 \
@@ -4824,7 +8410,7 @@ index 55de7c85b..3515a1e3c 100644
OVS_WAIT_UNTIL([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \
logical_port=sw0-vir) = xsw0-p3])
-@@ -21217,7 +21309,7 @@ tpa=$(ip_to_hex 10 0 0 10)
+@@ -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 \
@@ -4833,7 +8419,7 @@ index 55de7c85b..3515a1e3c 100644
AT_CHECK([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \
logical_port=sw0-vir) = xsw0-p2])
-@@ -21249,7 +21341,7 @@ tpa=$(ip_to_hex 10 0 0 4)
+@@ -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 \
@@ -4842,7 +8428,7 @@ index 55de7c85b..3515a1e3c 100644
sleep 1
AT_CHECK([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \
-@@ -21275,7 +21367,7 @@ check_virtual_offlows_not_present hv2
+@@ -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 \
@@ -4851,7 +8437,7 @@ index 55de7c85b..3515a1e3c 100644
sleep 1
AT_CHECK([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \
-@@ -21310,7 +21402,7 @@ send_arp_reply 2 1 $eth_src $eth_dst $spa $tpa
+@@ -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 \
@@ -4860,7 +8446,7 @@ index 55de7c85b..3515a1e3c 100644
sleep 1
AT_CHECK([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \
logical_port=sw0-vir) = xsw0-p2])
-@@ -21335,7 +21427,7 @@ check_virtual_offlows_not_present hv1
+@@ -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 \
@@ -4869,7 +8455,7 @@ index 55de7c85b..3515a1e3c 100644
AT_CHECK([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \
logical_port=sw0-vir) = x])
-@@ -21516,7 +21608,7 @@ AT_CAPTURE_FILE([offlows])
+@@ -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"
@@ -4878,7 +8464,7 @@ index 55de7c85b..3515a1e3c 100644
ovn-nbctl --wait=hv
ovn-sbctl list controller_event > events
-@@ -21545,7 +21637,7 @@ packet1="inport==\"sw1-p0\" && eth.src==00:00:00:00:00:33 && eth.dst==00:00:00:0
+@@ -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"
@@ -4887,7 +8473,7 @@ index 55de7c85b..3515a1e3c 100644
ovn-nbctl --wait=hv
ovn-sbctl list controller_event
uuid=$(ovn-sbctl list controller_event | awk '/_uuid/{print $3}')
-@@ -21561,7 +21653,7 @@ packet2="inport==\"sw0-p11\" && eth.src==00:00:00:00:00:11 && eth.dst==00:00:00:
+@@ -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"
@@ -4896,7 +8482,16 @@ index 55de7c85b..3515a1e3c 100644
ovn-nbctl --wait=hv
ovn-sbctl list controller_event
uuid=$(ovn-sbctl list controller_event | awk '/_uuid/{print $3}')
-@@ -23744,7 +23836,7 @@ send_garp 1 1 $eth_src $eth_dst $spa $tpa
+@@ -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
@@ -4905,7 +8500,7 @@ index 55de7c85b..3515a1e3c 100644
list mac_binding], [0], [lr0-sw0
10.0.0.30
50:54:00:00:00:03
-@@ -23791,7 +23883,7 @@ grep table_id=10 | wc -l`])
+@@ -23791,7 +24228,7 @@ grep table_id=10 | wc -l`])
check_row_count MAC_Binding 1
@@ -4914,7 +8509,7 @@ index 55de7c85b..3515a1e3c 100644
list mac_binding], [0], [lr0-sw0
10.0.0.30
50:54:00:00:00:13
-@@ -23820,7 +23912,7 @@ OVS_WAIT_UNTIL(
+@@ -23820,7 +24257,7 @@ OVS_WAIT_UNTIL(
| wc -l`]
)
@@ -4923,7 +8518,7 @@ index 55de7c85b..3515a1e3c 100644
find mac_binding ip=10.0.0.50], [0], [lr0-sw0
10.0.0.50
50:54:00:00:00:33
-@@ -24377,7 +24469,7 @@ AT_CAPTURE_FILE([sbflows2])
+@@ -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,
@@ -4932,7 +8527,7 @@ index 55de7c85b..3515a1e3c 100644
])
# get the svc monitor mac.
-@@ -24419,8 +24511,7 @@ AT_CHECK(
+@@ -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
@@ -4942,7 +8537,7 @@ index 55de7c85b..3515a1e3c 100644
])
# Delete sw0-p1
-@@ -24576,7 +24667,7 @@ AT_CAPTURE_FILE([sbflows2])
+@@ -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,
@@ -4951,7 +8546,7 @@ index 55de7c85b..3515a1e3c 100644
])
# get the svc monitor mac.
-@@ -24618,8 +24709,7 @@ AT_CHECK(
+@@ -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
@@ -4961,7 +8556,7 @@ index 55de7c85b..3515a1e3c 100644
])
# Delete sw0-p1
-@@ -25447,7 +25537,7 @@ for s_az in $(seq 1 $n_az); do
+@@ -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])
@@ -4970,7 +8565,7 @@ index 55de7c85b..3515a1e3c 100644
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 +26092,7 @@ for i in $(seq 5001 5010); do
+@@ -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"
@@ -4979,7 +8574,7 @@ index 55de7c85b..3515a1e3c 100644
for j in 1 2; do
# Assume all packets go to lsp2${j}.
-@@ -26121,7 +26211,7 @@ wait_for_ports_up
+@@ -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"
@@ -4988,7 +8583,7 @@ index 55de7c85b..3515a1e3c 100644
# Assume no packets go neither to lsp21 nor to lsp22.
> expected_lsp21
-@@ -26151,7 +26241,7 @@ done
+@@ -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"
@@ -4997,7 +8592,7 @@ index 55de7c85b..3515a1e3c 100644
# 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 +26271,7 @@ done
+@@ -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"
@@ -5006,7 +8601,7 @@ index 55de7c85b..3515a1e3c 100644
# 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 +26368,7 @@ wait_for_ports_up
+@@ -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"
@@ -5015,7 +8610,7 @@ index 55de7c85b..3515a1e3c 100644
# 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 +26402,7 @@ ovs-vsctl set interface hv1-vif2 options:tx_pcap=hv1/vif2-tx.pcap
+@@ -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"
@@ -5024,7 +8619,7 @@ index 55de7c85b..3515a1e3c 100644
# 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 +26507,7 @@ for i in $(seq 1 2); do
+@@ -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"
@@ -5033,7 +8628,7 @@ index 55de7c85b..3515a1e3c 100644
# 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 +26620,7 @@ for i in $(seq 1 2); do
+@@ -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"
@@ -5042,7 +8637,7 @@ index 55de7c85b..3515a1e3c 100644
# 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 +26740,7 @@ dst_ip=172.16.1.11
+@@ -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"
@@ -5051,7 +8646,7 @@ index 55de7c85b..3515a1e3c 100644
# Check if the packet hit the forwarding group policy
AT_CAPTURE_FILE([offlows2])
-@@ -27173,7 +27263,7 @@ ovn_attach n1 br-phys 192.168.0.1
+@@ -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)
@@ -5060,7 +8655,7 @@ index 55de7c85b..3515a1e3c 100644
OVN_CLEANUP([hv1])
AT_CLEANUP
-@@ -27199,7 +27289,7 @@ ovs-vsctl add-br br-phys
+@@ -27199,7 +27634,7 @@ ovs-vsctl add-br br-phys
ovn_attach n1 br-phys 192.168.0.1
# Port_Binding should be released.
@@ -5069,7 +8664,7 @@ index 55de7c85b..3515a1e3c 100644
OVN_CLEANUP([hv1])
AT_CLEANUP
-@@ -27332,22 +27422,24 @@ sleep 5
+@@ -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
@@ -5099,7 +8694,7 @@ index 55de7c85b..3515a1e3c 100644
AT_CAPTURE_FILE([offlows2])
OVS_WAIT_UNTIL([
-@@ -27364,7 +27456,8 @@ AT_CHECK([
+@@ -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 \
@@ -5109,7 +8704,7 @@ index 55de7c85b..3515a1e3c 100644
AT_CHECK([
test 1 -eq $(as hv1 ovs-ofctl dump-flows br-phys table=0 | \
-@@ -27398,7 +27491,8 @@ AT_CHECK([
+@@ -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 \
@@ -5119,7 +8714,7 @@ index 55de7c85b..3515a1e3c 100644
OVS_WAIT_UNTIL([
test 1 -eq $(as hv1 ovs-ofctl dump-flows br-int table=23 | \
-@@ -27431,7 +27525,8 @@ AT_CHECK([
+@@ -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 \
@@ -5129,7 +8724,7 @@ index 55de7c85b..3515a1e3c 100644
OVS_WAIT_UNTIL([
test 1 -eq $(as hv1 ovs-ofctl dump-flows br-phys table=0 | \
-@@ -27443,7 +27538,7 @@ OVS_WAIT_UNTIL([
+@@ -27443,7 +27883,7 @@ OVS_WAIT_UNTIL([
src_ip6=aef00000000000000000000000000004
dst_ip6=bef00000000000000000000000000004
@@ -5138,7 +8733,7 @@ index 55de7c85b..3515a1e3c 100644
OVS_WAIT_UNTIL([
test 1 -eq $(as hv1 ovs-ofctl dump-flows br-phys table=0 | \
-@@ -27463,7 +27558,7 @@ AT_CHECK([
+@@ -27463,7 +27903,7 @@ AT_CHECK([
src_ip6=aef00000000000000000000000000004
dst_ip6=bef00000000000000000000000000005
@@ -5147,7 +8742,64 @@ index 55de7c85b..3515a1e3c 100644
OVS_WAIT_UNTIL([
test 1 -eq $(as hv1 ovs-ofctl dump-flows br-phys table=0 | \
-@@ -28737,7 +28832,7 @@ src_mac="f00000000102"
+@@ -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`
@@ -5156,7 +8808,7 @@ index 55de7c85b..3515a1e3c 100644
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 +28858,7 @@ src_mac="f00000000202"
+@@ -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`
@@ -5165,7 +8817,7 @@ index 55de7c85b..3515a1e3c 100644
as hv1 ovs-appctl netdev-dummy/receive hv1-vif2 $packet
# Still no packet-ins should reach ovn-controller.
-@@ -29548,7 +29643,9 @@ OVS_WAIT_UNTIL([test x$(ovn-nbctl lsp-get-up sw1-p1) = xup])
+@@ -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
@@ -5175,7 +8827,7 @@ index 55de7c85b..3515a1e3c 100644
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 +29936,119 @@ AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=70 | ofctl_strip_all | grep -
+@@ -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))
])
@@ -5295,7 +8947,149 @@ index 55de7c85b..3515a1e3c 100644
# Check backwards compatibility with ovn-northd versions that don't store the
# original destination tuple.
#
-@@ -31743,7 +31953,7 @@ packet="inport==\"sw1-lp1\" && eth.src==00:00:04:01:02:03 &&
+@@ -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"
@@ -5304,7 +9098,7 @@ index 55de7c85b..3515a1e3c 100644
# 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 +31980,7 @@ packet="inport==\"sw1-lp1\" && eth.src==00:00:04:01:02:03 &&
+@@ -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"
@@ -5313,7 +9107,7 @@ index 55de7c85b..3515a1e3c 100644
# Check if packet hit the drop rule
AT_CHECK([ovs-ofctl dump-flows br-int "nw_src=10.0.0.0/24" | \
-@@ -31857,7 +32067,7 @@ packet="inport==\"ls1-lp1\" && eth.src==$ls1_p1_mac && eth.dst==$bcast_mac &&
+@@ -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"
@@ -5322,7 +9116,53 @@ index 55de7c85b..3515a1e3c 100644
as hv1 ovs-ofctl dump-flows br-int| grep 169.254.239.254 | grep priority=50 > debug1
AT_CAPTURE_FILE([debug1])
-@@ -32108,7 +32318,6 @@ ovn-nbctl lrp-set-gateway-chassis DR-S3 hv4
+@@ -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
@@ -5330,7 +9170,7 @@ index 55de7c85b..3515a1e3c 100644
vif_to_ls () {
case ${1} in dnl (
vif?[[11]]) echo ls ;; dnl (
-@@ -32222,6 +32431,9 @@ echo "Send Dummy ARP"
+@@ -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
@@ -5340,7 +9180,7 @@ index 55de7c85b..3515a1e3c 100644
echo "Send traffic North to South"
sip=`ip_to_hex 172 16 1 10`
-@@ -32242,6 +32454,9 @@ echo "Send Dummy ARP"
+@@ -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
@@ -5350,7 +9190,7 @@ index 55de7c85b..3515a1e3c 100644
echo "Send traffic South to North2"
sip=`ip_to_hex 20 0 0 10`
-@@ -32255,6 +32470,9 @@ echo "Send Dummy ARP"
+@@ -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
@@ -5360,7 +9200,24 @@ index 55de7c85b..3515a1e3c 100644
echo "Send traffic South to North3"
sip=`ip_to_hex 20 0 0 10`
-@@ -34926,7 +35144,8 @@ check ovs-vsctl add-port br-int p1 -- set interface p1 external_ids:iface-id=lsp
+@@ -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
@@ -5370,7 +9227,7 @@ index 55de7c85b..3515a1e3c 100644
check ovn-nbctl ls-lb-add sw lb1
# Remove a single backend
-@@ -34949,7 +35168,8 @@ AT_CHECK([grep -q "Flushing CT for 5-tuple: vip=192.168.0.10:0, backend=192.168.
+@@ -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
@@ -5380,7 +9237,7 @@ index 55de7c85b..3515a1e3c 100644
check ovn-nbctl ls-lb-add sw lb1
check ovn-nbctl lb-del lb1
check ovn-nbctl --wait=hv sync
-@@ -34958,7 +35178,8 @@ AT_CHECK([grep -q "Flushing CT for 5-tuple: vip=192.168.30.10:80, backend=192.16
+@@ -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
@@ -5390,7 +9247,7 @@ index 55de7c85b..3515a1e3c 100644
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 +35189,193 @@ AT_CHECK([grep -q "Flushing CT for 5-tuple: vip=192.168.50.10:80, backend=192.16
+@@ -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])
@@ -5684,9 +9541,18 @@ index d65f359a6..b8c5ae9ad 100644
# NETNS_DAEMONIZE([namespace], [command], [pidfile])
#
diff --git a/tests/system-ovn-kmod.at b/tests/system-ovn-kmod.at
-index dd4996041..3c3e5bc61 100644
+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"])
@@ -5828,7 +9694,7 @@ index dd4996041..3c3e5bc61 100644
+AT_CLEANUP
+])
diff --git a/tests/system-ovn.at b/tests/system-ovn.at
-index 84a459d6a..40f808515 100644
+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)
@@ -5859,6 +9725,24 @@ index 84a459d6a..40f808515 100644
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])
@@ -5885,6 +9769,24 @@ index 84a459d6a..40f808515 100644
# 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
@@ -6146,7 +10048,7 @@ index 84a459d6a..40f808515 100644
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,191 @@ check ovn-nbctl lb-del lb2
+@@ -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"])
@@ -6335,13 +10237,22 @@ index 84a459d6a..40f808515 100644
+ test "${total_icmp1_pkts}" -gt "${total_icmp_pkts}"
+])
+
- OVS_APP_EXIT_AND_WAIT([ovn-controller])
-
- as ovn-sb
-@@ -10706,3 +10935,605 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
- /connection dropped.*/d"])
- AT_CLEANUP
- ])
++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:
@@ -6670,22 +10581,13 @@ index 84a459d6a..40f808515 100644
+check_ports_up
+check_ports_bound
+
-+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
-+])
+ 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])
@@ -6744,6 +10646,9 @@ index 84a459d6a..40f808515 100644
+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")
@@ -6767,7 +10672,8 @@ index 84a459d6a..40f808515 100644
+
+ovn-nbctl mirror-del mirror0
+ovn-nbctl mirror-add mirror1 gre 2 to-lport 2003::b
-+ovn-nbctl lsp-attach-mirror bar1 mirror1
++
++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])
@@ -6786,7 +10692,7 @@ index 84a459d6a..40f808515 100644
+
+ovn-nbctl mirror-del mirror1
+ovn-nbctl mirror-add mirror2 erspan 3 to-lport 172.16.0.100
-+ovn-nbctl lsp-attach-mirror bar1 mirror2
++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])
@@ -6804,7 +10710,7 @@ index 84a459d6a..40f808515 100644
+
+ovn-nbctl mirror-del mirror2
+ovn-nbctl mirror-add mirror3 erspan 4 to-lport 2003::b
-+ovn-nbctl lsp-attach-mirror bar1 mirror3
++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])
@@ -6821,7 +10727,7 @@ index 84a459d6a..40f808515 100644
+killall tcpdump
+
+uuid=$(fetch_column nb:mirror _uuid name="mirror3")
-+ovn-nbctl set mirror $uuid type=gre
++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])
@@ -6944,6 +10850,79 @@ index 84a459d6a..40f808515 100644
+
+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
diff --git a/SPECS/ovn23.03.spec b/SPECS/ovn23.03.spec
index e3ac702..de8ca26 100644
--- a/SPECS/ovn23.03.spec
+++ b/SPECS/ovn23.03.spec
@@ -51,7 +51,7 @@ Summary: Open Virtual Network support
Group: System Environment/Daemons
URL: http://www.ovn.org/
Version: 23.03.0
-Release: 50%{?commit0:.%{date}git%{shortcommit0}}%{?dist}
+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
@@ -524,6 +524,82 @@ fi
%{_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]