diff --git a/.ovn.metadata b/.ovn.metadata index 4bcfed1..3c2a0bd 100644 --- a/.ovn.metadata +++ b/.ovn.metadata @@ -1,5 +1,5 @@ 002450621b33c5690060345b0aac25bc2426d675 SOURCES/docutils-0.12.tar.gz -838279b54706cbb447491f422d829569c1c90b73 SOURCES/openvswitch-498cedc.tar.gz +3141cf2ef8fc5066ae4d7f128e105a293c81549a SOURCES/openvswitch-45ecaa9.tar.gz 347346dae160f28d6e56b1dee8fa8b701a50748e SOURCES/ovn-21.12.0.tar.gz d34f96421a86004aa5d26ecf975edefd09f948b1 SOURCES/Pygments-1.4.tar.gz 6beb30f18ffac3de7689b7fd63e9a8a7d9c8df3a SOURCES/Sphinx-1.1.3.tar.gz diff --git a/SOURCES/ovn-2021.patch b/SOURCES/ovn-2021.patch index 9f922c1..d1ba099 100644 --- a/SOURCES/ovn-2021.patch +++ b/SOURCES/ovn-2021.patch @@ -15,7 +15,7 @@ index 37e8d4250..e0c528479 100755 +pip3 install --disable-pip-version-check --user \ + flake8 'hacking>=3.0' sphinx setuptools pyelftools pyOpenSSL diff --git a/.ci/ovn-kubernetes/Dockerfile b/.ci/ovn-kubernetes/Dockerfile -index 9cfc32f62..495ffc8be 100644 +index 9cfc32f62..2439c61f7 100644 --- a/.ci/ovn-kubernetes/Dockerfile +++ b/.ci/ovn-kubernetes/Dockerfile @@ -1,4 +1,5 @@ @@ -24,7 +24,7 @@ index 9cfc32f62..495ffc8be 100644 FROM fedora:33 AS ovnbuilder -@@ -38,11 +39,21 @@ RUN rm rpm/rpmbuild/RPMS/x86_64/*docker* +@@ -38,18 +39,28 @@ RUN rm rpm/rpmbuild/RPMS/x86_64/*docker* # Build ovn-kubernetes FROM golang:1.16 as ovnkubebuilder ARG OVNKUBE_COMMIT @@ -47,6 +47,14 @@ index 9cfc32f62..495ffc8be 100644 # Build the final image FROM fedora:33 + + # install needed dependencies + RUN INSTALL_PKGS=" \ +- iptables iproute iputils hostname unbound-libs kubernetes-client kmod" && \ ++ iptables iproute iputils hostname unbound-libs kubernetes-client kmod socat" && \ + dnf install --best --refresh -y --setopt=tsflags=nodocs $INSTALL_PKGS && \ + dnf clean all && rm -rf /var/cache/dnf/* + diff --git a/.github/workflows/ovn-kubernetes.yml b/.github/workflows/ovn-kubernetes.yml index 60c585a24..c05bbd3f9 100644 --- a/.github/workflows/ovn-kubernetes.yml @@ -109,14 +117,20 @@ index 064725f68..40f36d815 100644 Terry Wilson twilson@redhat.com Tetsuo NAKAGAWA nakagawa@mxc.nes.nec.co.jp diff --git a/NEWS b/NEWS -index 75f26ddb7..3b3104c2f 100644 +index 75f26ddb7..31e08b015 100644 --- a/NEWS +++ b/NEWS -@@ -1,3 +1,12 @@ -+OVN v21.12.2 - xx xxx xxxx +@@ -1,3 +1,18 @@ ++OVN v21.12.3 - xx xxx xxxx ++-------------------------- ++ ++OVN v21.12.2 - 03 Jun 2022 +-------------------------- ++ - Bug fixes + - When configured to log packets matching ACLs, log the direction (logical + pipeline) too. ++ - Replaced the usage of masked ct_label by ct_mark in most cases to work ++ better with hardware-offloading. + +OVN v21.12.1 - 11 Mar 2022 +-------------------------- @@ -126,7 +140,7 @@ index 75f26ddb7..3b3104c2f 100644 -------------------------- - Set ignore_lsp_down to true as default, so that ARP responder flows are diff --git a/configure.ac b/configure.ac -index 48b4662f0..c4bf08db7 100644 +index 48b4662f0..f37afb7bb 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ @@ -134,7 +148,7 @@ index 48b4662f0..c4bf08db7 100644 AC_PREREQ(2.63) -AC_INIT(ovn, 21.12.0, bugs@openvswitch.org) -+AC_INIT(ovn, 21.12.2, bugs@openvswitch.org) ++AC_INIT(ovn, 21.12.3, bugs@openvswitch.org) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_HEADERS([config.h]) @@ -182,7 +196,7 @@ index 288772dc4..9fbfc0337 100644 if (gw_node) { VLOG_WARN("Chassis for VTEP physical switch (%s) disappears, " diff --git a/controller/binding.c b/controller/binding.c -index 4d62b0858..1259e6b3b 100644 +index 4d62b0858..c40751465 100644 --- a/controller/binding.c +++ b/controller/binding.c @@ -481,6 +481,16 @@ remove_related_lport(const struct sbrec_port_binding *pb, @@ -202,7 +216,34 @@ index 4d62b0858..1259e6b3b 100644 static void update_active_pb_ras_pd(const struct sbrec_port_binding *pb, struct hmap *local_datapaths, -@@ -2251,6 +2261,9 @@ binding_handle_port_binding_changes(struct binding_ctx_in *b_ctx_in, +@@ -898,7 +908,9 @@ claimed_lport_set_up(const struct sbrec_port_binding *pb, + if (!notify_up) { + bool up = true; + if (!parent_pb || (parent_pb->n_up && parent_pb->up[0])) { +- sbrec_port_binding_set_up(pb, &up, 1); ++ if (pb->n_up) { ++ sbrec_port_binding_set_up(pb, &up, 1); ++ } + } + return; + } +@@ -2049,6 +2061,15 @@ handle_deleted_lport(const struct sbrec_port_binding *pb, + return; + } + ++ /* ++ * Remove localport that was part of local datapath that is not ++ * considered to be local anymore. ++ */ ++ if (!ld && !strcmp(pb->type, "localport") && ++ sset_find(&b_ctx_out->related_lports->lport_names, pb->logical_port)) { ++ remove_related_lport(pb, b_ctx_out); ++ } ++ + /* If the binding is not local, if 'pb' is a L3 gateway port, we should + * remove its peer, if that one is local. + */ +@@ -2251,6 +2272,9 @@ binding_handle_port_binding_changes(struct binding_ctx_in *b_ctx_in, continue; } @@ -212,6 +253,31 @@ index 4d62b0858..1259e6b3b 100644 enum en_lport_type lport_type = get_lport_type(pb); struct binding_lport *b_lport = +diff --git a/controller/chassis.c b/controller/chassis.c +index 8a1559653..92850fcc1 100644 +--- a/controller/chassis.c ++++ b/controller/chassis.c +@@ -350,6 +350,7 @@ chassis_build_other_config(const struct ovs_chassis_cfg *ovs_cfg, + smap_replace(config, "is-interconn", + ovs_cfg->is_interconn ? "true" : "false"); + smap_replace(config, OVN_FEATURE_PORT_UP_NOTIF, "true"); ++ smap_replace(config, OVN_FEATURE_CT_NO_MASKED_LABEL, "true"); + } + + /* +@@ -455,6 +456,12 @@ chassis_other_config_changed(const struct ovs_chassis_cfg *ovs_cfg, + return true; + } + ++ if (!smap_get_bool(&chassis_rec->other_config, ++ OVN_FEATURE_CT_NO_MASKED_LABEL, ++ false)) { ++ return true; ++ } ++ + return false; + } + diff --git a/controller/lflow-conj-ids.c b/controller/lflow-conj-ids.c index bfe63862a..6d3601237 100644 --- a/controller/lflow-conj-ids.c @@ -571,10 +637,42 @@ index 6da0a612c..b53e570f2 100644 #endif /* controller/lflow-conj-ids.h */ diff --git a/controller/lflow.c b/controller/lflow.c -index 933e2f3cc..489347dae 100644 +index 933e2f3cc..7abd24c42 100644 --- a/controller/lflow.c +++ b/controller/lflow.c -@@ -852,6 +852,7 @@ consider_logical_flow__(const struct sbrec_logical_flow *lflow, +@@ -580,6 +580,23 @@ lflow_parse_ctrl_meter(const struct sbrec_logical_flow *lflow, + } + } + ++static int ++get_common_nat_zone(const struct sbrec_datapath_binding *dp) ++{ ++ /* Normally, the common NAT zone defaults to the DNAT zone. However, ++ * if the "snat-ct-zone" is set on the datapath, the user is ++ * expecting an explicit CT zone to be used for SNAT. If we default ++ * to the DNAT zone, then it means SNAT will not use the configured ++ * value. The way we get around this is to use the SNAT zone as the ++ * common zone if "snat-ct-zone" is set. ++ */ ++ if (smap_get(&dp->external_ids, "snat-ct-zone")) { ++ return MFF_LOG_SNAT_ZONE; ++ } else { ++ return MFF_LOG_DNAT_ZONE; ++ } ++} ++ + static void + add_matches_to_flow_table(const struct sbrec_logical_flow *lflow, + const struct sbrec_datapath_binding *dp, +@@ -629,6 +646,7 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow, + .fdb_ptable = OFTABLE_GET_FDB, + .fdb_lookup_ptable = OFTABLE_LOOKUP_FDB, + .ctrl_meter_id = ctrl_meter_id, ++ .common_nat_ct_zone = get_common_nat_zone(dp), + }; + ovnacts_encode(ovnacts->data, ovnacts->size, &ep, &ofpacts); + +@@ -852,6 +870,7 @@ consider_logical_flow__(const struct sbrec_logical_flow *lflow, && lcv->n_conjs && !lflow_conj_ids_alloc_specified(l_ctx_out->conj_ids, &lflow->header_.uuid, @@ -582,7 +680,7 @@ index 933e2f3cc..489347dae 100644 lcv->conj_id_ofs, lcv->n_conjs)) { /* This should happen very rarely. */ VLOG_DBG("lflow "UUID_FMT" match cached with conjunctions, but the" -@@ -915,6 +916,7 @@ consider_logical_flow__(const struct sbrec_logical_flow *lflow, +@@ -915,6 +934,7 @@ consider_logical_flow__(const struct sbrec_logical_flow *lflow, if (n_conjs) { start_conj_id = lflow_conj_ids_alloc(l_ctx_out->conj_ids, &lflow->header_.uuid, @@ -590,8 +688,154 @@ index 933e2f3cc..489347dae 100644 n_conjs); if (!start_conj_id) { VLOG_ERR("32-bit conjunction ids exhausted!"); +@@ -1302,6 +1322,7 @@ add_lb_vip_hairpin_flows(struct ovn_controller_lb *lb, + struct ovn_lb_vip *lb_vip, + struct ovn_lb_backend *lb_backend, + uint8_t lb_proto, ++ bool use_ct_mark, + struct ovn_desired_flow_table *flow_table) + { + uint64_t stub[1024 / 8]; +@@ -1392,15 +1413,30 @@ add_lb_vip_hairpin_flows(struct ovn_controller_lb *lb, + * - packets must have ip.src == ip.dst at this point. + * - the destination protocol and port must be of a valid backend that + * has the same IP as ip.dst. ++ * ++ * During upgrades logical flows might still use the old way of storing ++ * ct.natted in ct_label. For backwards compatibility, only use ct_mark ++ * if ovn-northd notified ovn-controller to do that. + */ +- ovs_u128 lb_ct_label = { +- .u64.lo = OVN_CT_NATTED, +- }; +- match_set_ct_label_masked(&hairpin_match, lb_ct_label, lb_ct_label); ++ if (use_ct_mark) { ++ uint32_t lb_ct_mark = OVN_CT_NATTED; ++ match_set_ct_mark_masked(&hairpin_match, lb_ct_mark, lb_ct_mark); ++ ++ ofctrl_add_flow(flow_table, OFTABLE_CHK_LB_HAIRPIN, 100, ++ lb->slb->header_.uuid.parts[0], &hairpin_match, ++ &ofpacts, &lb->slb->header_.uuid); ++ } else { ++ match_set_ct_mark_masked(&hairpin_match, 0, 0); ++ ovs_u128 lb_ct_label = { ++ .u64.lo = OVN_CT_NATTED, ++ }; ++ match_set_ct_label_masked(&hairpin_match, lb_ct_label, lb_ct_label); ++ ++ ofctrl_add_flow(flow_table, OFTABLE_CHK_LB_HAIRPIN, 100, ++ lb->slb->header_.uuid.parts[0], &hairpin_match, ++ &ofpacts, &lb->slb->header_.uuid); ++ } + +- ofctrl_add_flow(flow_table, OFTABLE_CHK_LB_HAIRPIN, 100, +- lb->slb->header_.uuid.parts[0], &hairpin_match, +- &ofpacts, &lb->slb->header_.uuid); + ofpbuf_uninit(&ofpacts); + } + +@@ -1673,6 +1709,7 @@ add_lb_ct_snat_hairpin_flows(struct ovn_controller_lb *lb, + static void + consider_lb_hairpin_flows(const struct sbrec_load_balancer *sbrec_lb, + const struct hmap *local_datapaths, ++ bool use_ct_mark, + struct ovn_desired_flow_table *flow_table, + struct simap *ids) + { +@@ -1712,7 +1749,7 @@ consider_lb_hairpin_flows(const struct sbrec_load_balancer *sbrec_lb, + struct ovn_lb_backend *lb_backend = &lb_vip->backends[j]; + + add_lb_vip_hairpin_flows(lb, lb_vip, lb_backend, lb_proto, +- flow_table); ++ use_ct_mark, flow_table); + } + } + +@@ -1725,7 +1762,7 @@ consider_lb_hairpin_flows(const struct sbrec_load_balancer *sbrec_lb, + * backends to handle the load balanced hairpin traffic. */ + static void + add_lb_hairpin_flows(const struct sbrec_load_balancer_table *lb_table, +- const struct hmap *local_datapaths, ++ const struct hmap *local_datapaths, bool use_ct_mark, + struct ovn_desired_flow_table *flow_table, + struct simap *ids, + struct id_pool *pool) +@@ -1748,7 +1785,8 @@ add_lb_hairpin_flows(const struct sbrec_load_balancer_table *lb_table, + ovs_assert(id_pool_alloc_id(pool, &id)); + simap_put(ids, lb->name, id); + } +- consider_lb_hairpin_flows(lb, local_datapaths, flow_table, ids); ++ consider_lb_hairpin_flows(lb, local_datapaths, use_ct_mark, ++ flow_table, ids); + } + } + +@@ -1854,6 +1892,7 @@ lflow_run(struct lflow_ctx_in *l_ctx_in, struct lflow_ctx_out *l_ctx_out) + l_ctx_in->mac_binding_table, l_ctx_in->local_datapaths, + l_ctx_out->flow_table); + add_lb_hairpin_flows(l_ctx_in->lb_table, l_ctx_in->local_datapaths, ++ l_ctx_in->lb_hairpin_use_ct_mark, + l_ctx_out->flow_table, + l_ctx_out->hairpin_lb_ids, + l_ctx_out->hairpin_id_pool); +@@ -1967,6 +2006,18 @@ lflow_add_flows_for_datapath(const struct sbrec_datapath_binding *dp, + } + sbrec_fdb_index_destroy_row(fdb_index_row); + ++ struct sbrec_mac_binding *mb_index_row = sbrec_mac_binding_index_init_row( ++ l_ctx_in->sbrec_mac_binding_by_datapath); ++ sbrec_mac_binding_index_set_datapath(mb_index_row, dp); ++ const struct sbrec_mac_binding *mb; ++ SBREC_MAC_BINDING_FOR_EACH_EQUAL ( ++ mb, mb_index_row, l_ctx_in->sbrec_mac_binding_by_datapath) { ++ consider_neighbor_flow(l_ctx_in->sbrec_port_binding_by_name, ++ l_ctx_in->local_datapaths, ++ mb, l_ctx_out->flow_table); ++ } ++ sbrec_mac_binding_index_destroy_row(mb_index_row); ++ + dhcp_opts_destroy(&dhcp_opts); + dhcp_opts_destroy(&dhcpv6_opts); + nd_ra_opts_destroy(&nd_ra_opts); +@@ -1976,6 +2027,7 @@ lflow_add_flows_for_datapath(const struct sbrec_datapath_binding *dp, + * associated. */ + for (size_t i = 0; i < n_dp_lbs; i++) { + consider_lb_hairpin_flows(dp_lbs[i], l_ctx_in->local_datapaths, ++ l_ctx_in->lb_hairpin_use_ct_mark, + l_ctx_out->flow_table, + l_ctx_out->hairpin_lb_ids); + } +@@ -2089,6 +2141,7 @@ lflow_handle_changed_lbs(struct lflow_ctx_in *l_ctx_in, + VLOG_DBG("Add load balancer hairpin flows for "UUID_FMT, + UUID_ARGS(&lb->header_.uuid)); + consider_lb_hairpin_flows(lb, l_ctx_in->local_datapaths, ++ l_ctx_in->lb_hairpin_use_ct_mark, + l_ctx_out->flow_table, + l_ctx_out->hairpin_lb_ids); + } +diff --git a/controller/lflow.h b/controller/lflow.h +index 489dd70fb..569eecedc 100644 +--- a/controller/lflow.h ++++ b/controller/lflow.h +@@ -133,6 +133,8 @@ struct lflow_ctx_in { + struct ovsdb_idl_index *sbrec_logical_flow_by_logical_dp_group; + struct ovsdb_idl_index *sbrec_port_binding_by_name; + struct ovsdb_idl_index *sbrec_fdb_by_dp_key; ++ struct ovsdb_idl_index *sbrec_mac_binding_by_datapath; ++ struct ovsdb_idl_index *sbrec_static_mac_binding_by_datapath; + const struct sbrec_port_binding_table *port_binding_table; + const struct sbrec_dhcp_options_table *dhcp_options_table; + const struct sbrec_dhcpv6_options_table *dhcpv6_options_table; +@@ -150,6 +152,7 @@ struct lflow_ctx_in { + const struct sset *active_tunnels; + const struct sset *related_lport_ids; + const struct hmap *chassis_tunnels; ++ bool lb_hairpin_use_ct_mark; + }; + + struct lflow_ctx_out { diff --git a/controller/ofctrl.c b/controller/ofctrl.c -index 08fcfed8b..8d958faf1 100644 +index 08fcfed8b..c0a04ec50 100644 --- a/controller/ofctrl.c +++ b/controller/ofctrl.c @@ -335,6 +335,22 @@ static struct ovn_extend_table *groups; @@ -641,7 +885,21 @@ index 08fcfed8b..8d958faf1 100644 } uint64_t -@@ -1802,26 +1821,14 @@ add_meter_string(struct ovn_extend_table_info *m_desired, +@@ -899,7 +918,12 @@ link_installed_to_desired(struct installed_flow *i, struct desired_flow *d) + break; + } + } +- ovs_list_insert(&f->installed_ref_list_node, &d->installed_ref_list_node); ++ if (!f) { ++ ovs_list_insert(&i->desired_refs, &d->installed_ref_list_node); ++ } else { ++ ovs_list_insert(&f->installed_ref_list_node, ++ &d->installed_ref_list_node); ++ } + d->installed_flow = i; + return installed_flow_get_active(i) == d; + } +@@ -1802,26 +1826,14 @@ add_meter_string(struct ovn_extend_table_info *m_desired, } static void @@ -673,7 +931,7 @@ index 08fcfed8b..8d958faf1 100644 mm.meter.flags = OFPMF13_STATS; if (!strcmp(sb_meter->unit, "pktps")) { -@@ -1854,6 +1861,152 @@ add_meter(struct ovn_extend_table_info *m_desired, +@@ -1854,6 +1866,152 @@ add_meter(struct ovn_extend_table_info *m_desired, free(mm.meter.bands); } @@ -826,7 +1084,7 @@ index 08fcfed8b..8d958faf1 100644 static void installed_flow_add(struct ovn_flow *d, struct ofputil_bundle_ctrl_msg *bc, -@@ -1994,7 +2147,20 @@ deleted_flow_lookup(struct hmap *deleted_flows, struct ovn_flow *target) +@@ -1994,7 +2152,20 @@ deleted_flow_lookup(struct hmap *deleted_flows, struct ovn_flow *target) && f->cookie == target->cookie && ofpacts_equal(f->ofpacts, f->ofpacts_len, target->ofpacts, target->ofpacts_len)) { @@ -848,7 +1106,7 @@ index 08fcfed8b..8d958faf1 100644 } } return NULL; -@@ -2023,10 +2189,6 @@ merge_tracked_flows(struct ovn_desired_flow_table *flow_table) +@@ -2023,10 +2194,6 @@ merge_tracked_flows(struct ovn_desired_flow_table *flow_table) continue; } @@ -859,7 +1117,7 @@ index 08fcfed8b..8d958faf1 100644 if (!f->installed_flow) { /* f is not installed yet. */ replace_installed_to_desired(del_f->installed_flow, del_f, f); -@@ -2232,13 +2394,19 @@ ofctrl_put(struct ovn_desired_flow_table *lflow_table, +@@ -2232,13 +2399,19 @@ ofctrl_put(struct ovn_desired_flow_table *lflow_table, /* Iterate through all the desired meters. If there are new ones, * add them to the switch. */ struct ovn_extend_table_info *m_desired; @@ -885,7 +1143,7 @@ index 08fcfed8b..8d958faf1 100644 } } -@@ -2328,12 +2496,14 @@ ofctrl_put(struct ovn_desired_flow_table *lflow_table, +@@ -2328,12 +2501,14 @@ ofctrl_put(struct ovn_desired_flow_table *lflow_table, struct ovn_extend_table_info *m_installed, *next_meter; EXTEND_TABLE_FOR_EACH_INSTALLED (m_installed, next_meter, meters) { /* Delete the meter. */ @@ -907,10 +1165,52 @@ index 08fcfed8b..8d958faf1 100644 } diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c -index 5069aedfc..f85af9353 100644 +index 5069aedfc..f5d749a2f 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c -@@ -962,7 +962,8 @@ ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl) +@@ -131,6 +131,9 @@ static const char *ssl_ca_cert_file; + #define DEFAULT_LFLOW_CACHE_WMARK_PERC 50 + #define DEFAULT_LFLOW_CACHE_TRIM_TO_MS 30000 + ++/* SB Global options defaults. */ ++#define DEFAULT_SB_GLOBAL_LB_HAIRPIN_USE_CT_MARK false ++ + struct controller_engine_ctx { + struct lflow_cache *lflow_cache; + struct if_status_mgr *if_mgr; +@@ -813,13 +816,18 @@ restore_ct_zones(const struct ovsrec_bridge_table *bridge_table, + } + + const char *user = node->key + 8; +- int zone = atoi(node->value); ++ if (!user[0]) { ++ continue; ++ } + +- if (user[0] && zone) { +- VLOG_DBG("restoring ct zone %"PRId32" for '%s'", zone, user); +- bitmap_set1(ct_zone_bitmap, zone); +- simap_put(ct_zones, user, zone); ++ unsigned int zone; ++ if (!str_to_uint(node->value, 10, &zone)) { ++ continue; + } ++ ++ VLOG_DBG("restoring ct zone %"PRId32" for '%s'", zone, user); ++ bitmap_set1(ct_zone_bitmap, zone); ++ simap_put(ct_zones, user, zone); + } + } + +@@ -948,6 +956,7 @@ ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl) + } + + #define SB_NODES \ ++ SB_NODE(sb_global, "sb_global") \ + SB_NODE(chassis, "chassis") \ + SB_NODE(encap, "encap") \ + SB_NODE(address_set, "address_set") \ +@@ -962,7 +971,8 @@ ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl) SB_NODE(dhcpv6_options, "dhcpv6_options") \ SB_NODE(dns, "dns") \ SB_NODE(load_balancer, "load_balancer") \ @@ -920,7 +1220,109 @@ index 5069aedfc..f85af9353 100644 enum sb_engine_node { #define SB_NODE(NAME, NAME_STR) SB_##NAME, -@@ -2713,6 +2714,26 @@ lflow_output_sb_fdb_handler(struct engine_node *node, void *data) +@@ -2155,6 +2165,63 @@ non_vif_data_ovs_iface_handler(struct engine_node *node, void *data OVS_UNUSED) + return local_nonvif_data_handle_ovs_iface_changes(iface_table); + } + ++struct ed_type_northd_options { ++ bool lb_hairpin_use_ct_mark; ++}; ++ ++ ++static void * ++en_northd_options_init(struct engine_node *node OVS_UNUSED, ++ struct engine_arg *arg OVS_UNUSED) ++{ ++ struct ed_type_northd_options *n_opts = xzalloc(sizeof *n_opts); ++ return n_opts; ++} ++ ++static void ++en_northd_options_cleanup(void *data OVS_UNUSED) ++{ ++} ++ ++static void ++en_northd_options_run(struct engine_node *node, void *data) ++{ ++ struct ed_type_northd_options *n_opts = data; ++ const struct sbrec_sb_global_table *sb_global_table = ++ EN_OVSDB_GET(engine_get_input("SB_sb_global", node)); ++ const struct sbrec_sb_global *sb_global = ++ sbrec_sb_global_table_first(sb_global_table); ++ ++ n_opts->lb_hairpin_use_ct_mark = ++ sb_global ++ ? smap_get_bool(&sb_global->options, "lb_hairpin_use_ct_mark", ++ DEFAULT_SB_GLOBAL_LB_HAIRPIN_USE_CT_MARK) ++ : DEFAULT_SB_GLOBAL_LB_HAIRPIN_USE_CT_MARK; ++ engine_set_node_state(node, EN_UPDATED); ++} ++ ++static bool ++en_northd_options_sb_sb_global_handler(struct engine_node *node, void *data) ++{ ++ struct ed_type_northd_options *n_opts = data; ++ const struct sbrec_sb_global_table *sb_global_table = ++ EN_OVSDB_GET(engine_get_input("SB_sb_global", node)); ++ const struct sbrec_sb_global *sb_global = ++ sbrec_sb_global_table_first(sb_global_table); ++ ++ bool lb_hairpin_use_ct_mark = ++ sb_global ++ ? smap_get_bool(&sb_global->options, "lb_hairpin_use_ct_mark", ++ DEFAULT_SB_GLOBAL_LB_HAIRPIN_USE_CT_MARK) ++ : DEFAULT_SB_GLOBAL_LB_HAIRPIN_USE_CT_MARK; ++ ++ if (lb_hairpin_use_ct_mark != n_opts->lb_hairpin_use_ct_mark) { ++ n_opts->lb_hairpin_use_ct_mark = lb_hairpin_use_ct_mark; ++ engine_set_node_state(node, EN_UPDATED); ++ } ++ return true; ++} ++ + struct lflow_output_persistent_data { + struct lflow_cache *lflow_cache; + }; +@@ -2217,6 +2284,11 @@ init_lflow_ctx(struct engine_node *node, + engine_get_input("SB_fdb", node), + "dp_key"); + ++ struct ovsdb_idl_index *sbrec_mac_binding_by_datapath = ++ engine_ovsdb_node_get_index( ++ engine_get_input("SB_mac_binding", node), ++ "datapath"); ++ + struct sbrec_port_binding_table *port_binding_table = + (struct sbrec_port_binding_table *)EN_OVSDB_GET( + engine_get_input("SB_port_binding", node)); +@@ -2277,6 +2349,9 @@ init_lflow_ctx(struct engine_node *node, + engine_get_input_data("port_groups", node); + struct shash *port_groups = &pg_data->port_groups_cs_local; + ++ struct ed_type_northd_options *n_opts = ++ engine_get_input_data("northd_options", node); ++ + l_ctx_in->sbrec_multicast_group_by_name_datapath = + sbrec_mc_group_by_name_dp; + l_ctx_in->sbrec_logical_flow_by_logical_datapath = +@@ -2285,6 +2360,7 @@ init_lflow_ctx(struct engine_node *node, + sbrec_logical_flow_by_dp_group; + l_ctx_in->sbrec_port_binding_by_name = sbrec_port_binding_by_name; + l_ctx_in->sbrec_fdb_by_dp_key = sbrec_fdb_by_dp_key; ++ l_ctx_in->sbrec_mac_binding_by_datapath = sbrec_mac_binding_by_datapath; + l_ctx_in->port_binding_table = port_binding_table; + l_ctx_in->dhcp_options_table = dhcp_table; + l_ctx_in->dhcpv6_options_table = dhcpv6_table; +@@ -2301,6 +2377,7 @@ init_lflow_ctx(struct engine_node *node, + l_ctx_in->active_tunnels = &rt_data->active_tunnels; + l_ctx_in->related_lport_ids = &rt_data->related_lports.lport_ids; + l_ctx_in->chassis_tunnels = &non_vif_data->chassis_tunnels; ++ l_ctx_in->lb_hairpin_use_ct_mark = n_opts->lb_hairpin_use_ct_mark; + + l_ctx_out->flow_table = &fo->flow_table; + l_ctx_out->group_table = &fo->group_table; +@@ -2713,6 +2790,26 @@ lflow_output_sb_fdb_handler(struct engine_node *node, void *data) return handled; } @@ -947,7 +1349,37 @@ index 5069aedfc..f85af9353 100644 struct ed_type_pflow_output { /* Desired physical flows. */ struct ovn_desired_flow_table flow_table; -@@ -3303,6 +3324,8 @@ main(int argc, char *argv[]) +@@ -3147,6 +3244,9 @@ main(int argc, char *argv[]) + = ovsdb_idl_index_create2(ovnsb_idl_loop.idl, + &sbrec_fdb_col_mac, + &sbrec_fdb_col_dp_key); ++ struct ovsdb_idl_index *sbrec_mac_binding_by_datapath ++ = ovsdb_idl_index_create1(ovnsb_idl_loop.idl, ++ &sbrec_mac_binding_col_datapath); + + ovsdb_idl_track_add_all(ovnsb_idl_loop.idl); + ovsdb_idl_omit_alert(ovnsb_idl_loop.idl, +@@ -3217,6 +3317,7 @@ main(int argc, char *argv[]) + ENGINE_NODE(flow_output, "flow_output"); + ENGINE_NODE(addr_sets, "addr_sets"); + ENGINE_NODE_WITH_CLEAR_TRACK_DATA(port_groups, "port_groups"); ++ ENGINE_NODE(northd_options, "northd_options"); + + #define SB_NODE(NAME, NAME_STR) ENGINE_NODE_SB(NAME, NAME_STR); + SB_NODES +@@ -3265,6 +3366,11 @@ main(int argc, char *argv[]) + engine_add_input(&en_pflow_output, &en_ovs_open_vswitch, NULL); + engine_add_input(&en_pflow_output, &en_ovs_bridge, NULL); + ++ engine_add_input(&en_northd_options, &en_sb_sb_global, ++ en_northd_options_sb_sb_global_handler); ++ ++ engine_add_input(&en_lflow_output, &en_northd_options, NULL); ++ + engine_add_input(&en_lflow_output, &en_addr_sets, + lflow_output_addr_sets_handler); + engine_add_input(&en_lflow_output, &en_port_groups, +@@ -3303,6 +3409,8 @@ main(int argc, char *argv[]) lflow_output_sb_load_balancer_handler); engine_add_input(&en_lflow_output, &en_sb_fdb, lflow_output_sb_fdb_handler); @@ -956,11 +1388,58 @@ index 5069aedfc..f85af9353 100644 engine_add_input(&en_ct_zones, &en_ovs_open_vswitch, NULL); engine_add_input(&en_ct_zones, &en_ovs_bridge, NULL); +@@ -3363,6 +3471,8 @@ main(int argc, char *argv[]) + sbrec_datapath_binding_by_key); + engine_ovsdb_node_add_index(&en_sb_fdb, "dp_key", + sbrec_fdb_by_dp_key); ++ engine_ovsdb_node_add_index(&en_sb_mac_binding, "datapath", ++ sbrec_mac_binding_by_datapath); + + struct ed_type_lflow_output *lflow_output_data = + engine_get_internal_data(&en_lflow_output); diff --git a/controller/physical.c b/controller/physical.c -index 836fc769a..aa651b876 100644 +index 836fc769a..2f0f87489 100644 --- a/controller/physical.c +++ b/controller/physical.c -@@ -1477,10 +1477,12 @@ consider_mc_group(struct ovsdb_idl_index *sbrec_port_binding_by_name, +@@ -421,6 +421,12 @@ populate_remote_chassis_macs(const struct sbrec_chassis *my_chassis, + char *save_ptr2 = NULL; + char *chassis_mac_bridge = strtok_r(token, ":", &save_ptr2); + char *chassis_mac_str = strtok_r(NULL, "", &save_ptr2); ++ if (!chassis_mac_str) { ++ VLOG_WARN("Parsing of ovn-chassis-mac-mappings failed for: " ++ "\"%s\", the correct format is \"br-name1:MAC1\".", ++ token); ++ continue; ++ } + struct remote_chassis_mac *remote_chassis_mac = NULL; + remote_chassis_mac = xmalloc(sizeof *remote_chassis_mac); + hmap_insert(&remote_chassis_macs, &remote_chassis_mac->hmap_node, +@@ -1309,6 +1315,24 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name, + } + } + ++ /* Table 37, 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. */ ++ if (!strcmp(binding->type, "localport")) { ++ ofpbuf_clear(ofpacts_p); ++ put_resubmit(OFTABLE_LOCAL_OUTPUT, ofpacts_p); ++ match_init_catchall(&match); ++ match_set_reg(&match, MFF_LOG_INPORT - MFF_REG0, ++ binding->tunnel_key); ++ match_set_metadata(&match, htonll(binding->datapath->tunnel_key)); ++ ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150, ++ binding->header_.uuid.parts[0], &match, ++ ofpacts_p, &binding->header_.uuid); ++ } + } else if (!tun && !is_ha_remote) { + /* Remote port connected by localnet port */ + /* Table 38, priority 100. +@@ -1477,10 +1501,12 @@ consider_mc_group(struct ovsdb_idl_index *sbrec_port_binding_by_name, put_load(port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, &remote_ofpacts); put_resubmit(OFTABLE_CHECK_LOOPBACK, &remote_ofpacts); @@ -977,8 +1456,41 @@ index 836fc769a..aa651b876 100644 put_load(port->tunnel_key, MFF_LOG_OUTPORT, 0, 32, &ofpacts); put_resubmit(OFTABLE_CHECK_LOOPBACK, &ofpacts); } else if (!strcmp(port->type, "chassisredirect") +@@ -1824,32 +1850,6 @@ physical_run(struct physical_ctx *p_ctx, + ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150, 0, + &match, &ofpacts, hc_uuid); + +- /* Table 37, 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. */ +- match_init_catchall(&match); +- ofpbuf_clear(&ofpacts); +- put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts); +- const char *localport; +- SSET_FOR_EACH (localport, p_ctx->local_lports) { +- /* Iterate over all local logical ports and insert a drop +- * rule with higher priority for every localport in this +- * datapath. */ +- const struct sbrec_port_binding *pb = lport_lookup_by_name( +- p_ctx->sbrec_port_binding_by_name, localport); +- if (pb && !strcmp(pb->type, "localport")) { +- match_set_reg(&match, MFF_LOG_INPORT - MFF_REG0, pb->tunnel_key); +- match_set_metadata(&match, htonll(pb->datapath->tunnel_key)); +- ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 150, +- pb->header_.uuid.parts[0], +- &match, &ofpacts, hc_uuid); +- } +- } +- + /* Table 37, Priority 0. + * ======================= + * diff --git a/controller/pinctrl.c b/controller/pinctrl.c -index f0667807e..2dd1bc7bd 100644 +index f0667807e..cb9cc096d 100644 --- a/controller/pinctrl.c +++ b/controller/pinctrl.c @@ -1624,12 +1624,8 @@ pinctrl_handle_icmp(struct rconn *swconn, const struct flow *ip_flow, @@ -1311,7 +1823,22 @@ index f0667807e..2dd1bc7bd 100644 } static void -@@ -4564,16 +4518,15 @@ pinctrl_compose_ipv4(struct dp_packet *packet, struct eth_addr eth_src, +@@ -4051,12 +4005,14 @@ prepare_ipv6_ras(const struct shash *local_active_ports_ras, + void + pinctrl_wait(struct ovsdb_idl_txn *ovnsb_idl_txn) + { ++ ovs_mutex_lock(&pinctrl_mutex); + wait_put_mac_bindings(ovnsb_idl_txn); + wait_controller_event(ovnsb_idl_txn); + wait_put_vport_bindings(ovnsb_idl_txn); + int64_t new_seq = seq_read(pinctrl_main_seq); + seq_wait(pinctrl_main_seq, new_seq); + wait_put_fdbs(ovnsb_idl_txn); ++ ovs_mutex_unlock(&pinctrl_mutex); + } + + /* Called by ovn-controller. */ +@@ -4564,16 +4520,15 @@ pinctrl_compose_ipv4(struct dp_packet *packet, struct eth_addr eth_src, ovs_be32 ipv4_dst, uint8_t ip_proto, uint8_t ttl, uint16_t ip_payload_len) { @@ -1336,7 +1863,7 @@ index f0667807e..2dd1bc7bd 100644 nh->ip_ihl_ver = IP_IHL_VER(5, 4); nh->ip_tot_len = htons(sizeof *nh + ip_payload_len); nh->ip_tos = IP_DSCP_CS6; -@@ -4584,6 +4537,7 @@ pinctrl_compose_ipv4(struct dp_packet *packet, struct eth_addr eth_src, +@@ -4584,6 +4539,7 @@ pinctrl_compose_ipv4(struct dp_packet *packet, struct eth_addr eth_src, nh->ip_csum = 0; nh->ip_csum = csum(nh, sizeof *nh); @@ -1344,7 +1871,7 @@ index f0667807e..2dd1bc7bd 100644 } static void -@@ -4592,22 +4546,20 @@ pinctrl_compose_ipv6(struct dp_packet *packet, struct eth_addr eth_src, +@@ -4592,22 +4548,20 @@ pinctrl_compose_ipv6(struct dp_packet *packet, struct eth_addr eth_src, struct in6_addr *ipv6_dst, uint8_t ip_proto, uint8_t ttl, uint16_t ip_payload_len) { @@ -1376,7 +1903,7 @@ index f0667807e..2dd1bc7bd 100644 packet_set_ipv6(packet, ipv6_src, ipv6_dst, 0, 0, ttl); } -@@ -5400,10 +5352,6 @@ ip_mcast_querier_send_igmp(struct rconn *swconn, struct ip_mcast_snoop *ip_ms) +@@ -5400,10 +5354,6 @@ ip_mcast_querier_send_igmp(struct rconn *swconn, struct ip_mcast_snoop *ip_ms) ip_ms->cfg.query_ipv4_dst, IPPROTO_IGMP, 1, sizeof(struct igmpv3_query_header)); @@ -1387,7 +1914,7 @@ index f0667807e..2dd1bc7bd 100644 /* IGMP query max-response in tenths of seconds. */ uint8_t max_response = ip_ms->cfg.query_max_resp_s * 10; uint8_t qqic = max_response; -@@ -5449,15 +5397,10 @@ ip_mcast_querier_send_mld(struct rconn *swconn, struct ip_mcast_snoop *ip_ms) +@@ -5449,15 +5399,10 @@ ip_mcast_querier_send_mld(struct rconn *swconn, struct ip_mcast_snoop *ip_ms) IPPROTO_HOPOPTS, 1, IPV6_EXT_HEADER_LEN + MLD_QUERY_HEADER_LEN); @@ -1404,7 +1931,7 @@ index f0667807e..2dd1bc7bd 100644 /* MLD query max-response in milliseconds. */ uint16_t max_response = ip_ms->cfg.query_max_resp_s * 1000; uint8_t qqic = ip_ms->cfg.query_max_resp_s; -@@ -6033,6 +5976,8 @@ pinctrl_handle_put_nd_ra_opts( +@@ -6033,6 +5978,8 @@ pinctrl_handle_put_nd_ra_opts( struct dp_packet pkt_out; dp_packet_init(&pkt_out, new_packet_size); dp_packet_clear(&pkt_out); @@ -1413,7 +1940,7 @@ index f0667807e..2dd1bc7bd 100644 dp_packet_prealloc_tailroom(&pkt_out, new_packet_size); pkt_out_ptr = &pkt_out; -@@ -6155,23 +6100,26 @@ wait_controller_event(struct ovsdb_idl_txn *ovnsb_idl_txn) +@@ -6155,23 +6102,26 @@ wait_controller_event(struct ovsdb_idl_txn *ovnsb_idl_txn) static bool pinctrl_handle_empty_lb_backends_opts(struct ofpbuf *userdata) { @@ -1444,7 +1971,7 @@ index f0667807e..2dd1bc7bd 100644 case EMPTY_LB_VIP: vip = xmemdup0(userdata_opt_data, size); break; -@@ -6820,8 +6768,6 @@ bfd_monitor_put_bfd_msg(struct bfd_entry *entry, struct dp_packet *packet, +@@ -6820,8 +6770,6 @@ bfd_monitor_put_bfd_msg(struct bfd_entry *entry, struct dp_packet *packet, { int payload_len = sizeof(struct udp_header) + sizeof(struct bfd_msg); @@ -1453,7 +1980,7 @@ index f0667807e..2dd1bc7bd 100644 if (IN6_IS_ADDR_V4MAPPED(&entry->ip_src)) { ovs_be32 ip_src = in6_addr_get_mapped_ipv4(&entry->ip_src); ovs_be32 ip_dst = in6_addr_get_mapped_ipv4(&entry->ip_dst); -@@ -6833,13 +6779,13 @@ bfd_monitor_put_bfd_msg(struct bfd_entry *entry, struct dp_packet *packet, +@@ -6833,13 +6781,13 @@ bfd_monitor_put_bfd_msg(struct bfd_entry *entry, struct dp_packet *packet, MAXTTL, payload_len); } @@ -1469,7 +1996,7 @@ index f0667807e..2dd1bc7bd 100644 msg->vers_diag = (BFD_VERSION << 5); msg->mult = entry->local_mult; msg->length = BFD_PACKET_LEN; -@@ -7383,7 +7329,7 @@ svc_monitor_send_tcp_health_check__(struct rconn *swconn, +@@ -7383,7 +7331,7 @@ svc_monitor_send_tcp_health_check__(struct rconn *swconn, ip4_src, in6_addr_get_mapped_ipv4(&svc_mon->ip), IPPROTO_TCP, 63, TCP_HEADER_LEN); @@ -1478,7 +2005,7 @@ index f0667807e..2dd1bc7bd 100644 dp_packet_set_l4(&packet, th); th->tcp_dst = htons(svc_mon->proto_port); th->tcp_src = tcp_src; -@@ -7446,13 +7392,12 @@ svc_monitor_send_udp_health_check(struct rconn *swconn, +@@ -7446,13 +7394,12 @@ svc_monitor_send_udp_health_check(struct rconn *swconn, ip4_src, in6_addr_get_mapped_ipv4(&svc_mon->ip), IPPROTO_UDP, 63, UDP_HEADER_LEN + 8); @@ -1527,15 +2054,21 @@ index 55eb3c7b6..5d692f1d1 100644 UUID_ARGS(&uuid), start_conj_id, n_conjs, ret ? "true" : "false"); diff --git a/debian/changelog b/debian/changelog -index 0cc5f14ac..1a1c7364e 100644 +index 0cc5f14ac..abf5ab264 100644 --- a/debian/changelog +++ b/debian/changelog -@@ -1,3 +1,15 @@ +@@ -1,3 +1,21 @@ ++OVN (21.12.3-1) unstable; urgency=low ++ [ OVN team ] ++ * New upstream version ++ ++ -- OVN team Fri, 03 Jun 2022 11:53:58 -0400 ++ +OVN (21.12.2-1) unstable; urgency=low + [ OVN team ] + * New upstream version + -+ -- OVN team Fri, 11 Mar 2022 13:22:24 -0500 ++ -- OVN team Fri, 03 Jun 2022 11:53:58 -0400 + +OVN (21.12.1-1) unstable; urgency=low + [ OVN team ] @@ -1547,16 +2080,101 @@ index 0cc5f14ac..1a1c7364e 100644 * New upstream version diff --git a/include/ovn/actions.h b/include/ovn/actions.h -index cdef5fb03..0641b927e 100644 +index cdef5fb03..547797584 100644 --- a/include/ovn/actions.h +++ b/include/ovn/actions.h -@@ -807,5 +807,6 @@ void ovnacts_encode(const struct ovnact[], size_t ovnacts_len, +@@ -59,6 +59,8 @@ struct ovn_extend_table; + OVNACT(NEXT, ovnact_next) \ + OVNACT(LOAD, ovnact_load) \ + OVNACT(MOVE, ovnact_move) \ ++ OVNACT(PUSH, ovnact_push_pop) \ ++ OVNACT(POP, ovnact_push_pop) \ + OVNACT(EXCHANGE, ovnact_move) \ + OVNACT(DEC_TTL, ovnact_null) \ + OVNACT(CT_NEXT, ovnact_ct_next) \ +@@ -69,6 +71,7 @@ struct ovn_extend_table; + OVNACT(CT_DNAT_IN_CZONE, ovnact_ct_nat) \ + OVNACT(CT_SNAT_IN_CZONE, ovnact_ct_nat) \ + OVNACT(CT_LB, ovnact_ct_lb) \ ++ OVNACT(CT_LB_MARK, ovnact_ct_lb) \ + OVNACT(SELECT, ovnact_select) \ + OVNACT(CT_CLEAR, ovnact_null) \ + OVNACT(CLONE, ovnact_nest) \ +@@ -233,6 +236,12 @@ struct ovnact_move { + struct expr_field rhs; + }; + ++/* OVNACT_PUSH, OVNACT_POP. */ ++struct ovnact_push_pop { ++ struct ovnact ovnact; ++ struct expr_field field; ++}; ++ + /* OVNACT_CT_NEXT. */ + struct ovnact_ct_next { + struct ovnact ovnact; +@@ -273,7 +282,7 @@ struct ovnact_ct_lb_dst { + uint16_t port; + }; + +-/* OVNACT_CT_LB. */ ++/* OVNACT_CT_LB/OVNACT_CT_LB_MARK. */ + struct ovnact_ct_lb { + struct ovnact ovnact; + struct ovnact_ct_lb_dst *dsts; +@@ -799,6 +808,8 @@ struct ovnact_encode_params { + * 'lookup_fdb' to resubmit. */ + uint32_t ctrl_meter_id; /* Meter to be used if the resulting flow + sends packets to controller. */ ++ uint32_t common_nat_ct_zone; /* When performing NAT in a common CT zone, ++ this determines which CT zone to use */ + }; + + void ovnacts_encode(const struct ovnact[], size_t ovnacts_len, +@@ -807,5 +818,6 @@ void ovnacts_encode(const struct ovnact[], size_t ovnacts_len, 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); #endif /* ovn/actions.h */ +diff --git a/include/ovn/features.h b/include/ovn/features.h +index d12a8eb0d..8fbdbf19a 100644 +--- a/include/ovn/features.h ++++ b/include/ovn/features.h +@@ -21,7 +21,8 @@ + #include "smap.h" + + /* ovn-controller supported feature names. */ +-#define OVN_FEATURE_PORT_UP_NOTIF "port-up-notif" ++#define OVN_FEATURE_PORT_UP_NOTIF "port-up-notif" ++#define OVN_FEATURE_CT_NO_MASKED_LABEL "ct-no-masked-label" + + /* OVS datapath supported features. Based on availability OVN might generate + * different types of openflows. +diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h +index 2118f7933..18516634e 100644 +--- a/include/ovn/logical-fields.h ++++ b/include/ovn/logical-fields.h +@@ -36,8 +36,6 @@ enum ovn_controller_event { + * (32 bits). */ + #define MFF_LOG_SNAT_ZONE MFF_REG12 /* conntrack snat zone for gateway router + * (32 bits). */ +-#define MFF_LOG_NAT_ZONE MFF_LOG_DNAT_ZONE /* conntrack zone for both snat +- * and dnat. */ + #define MFF_LOG_CT_ZONE MFF_REG13 /* Logical conntrack zone for lports + * (32 bits). */ + #define MFF_LOG_INPORT MFF_REG14 /* Logical input port (32 bits). */ +@@ -176,6 +174,9 @@ const struct ovn_field *ovn_field_from_name(const char *name); + #define OVN_CT_BLOCKED 1 + #define OVN_CT_NATTED 2 + ++#define OVN_CT_ECMP_ETH_1ST_BIT 32 ++#define OVN_CT_ECMP_ETH_END_BIT 79 ++ + #define OVN_CT_STR(LABEL_VALUE) OVS_STRINGIZE(LABEL_VALUE) + #define OVN_CT_MASKED_STR(LABEL_VALUE) \ + OVS_STRINGIZE(LABEL_VALUE) "/" OVS_STRINGIZE(LABEL_VALUE) diff --git a/lib/acl-log.c b/lib/acl-log.c index 220b6dc30..9530dd763 100644 --- a/lib/acl-log.c @@ -1598,7 +2216,7 @@ index 4f23f790d..da7fa2f02 100644 #endif /* lib/acl-log.h */ diff --git a/lib/actions.c b/lib/actions.c -index da00ee349..c46772e78 100644 +index da00ee349..d5985b937 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -40,6 +40,7 @@ @@ -1609,7 +2227,196 @@ index da00ee349..c46772e78 100644 VLOG_DEFINE_THIS_MODULE(actions); -@@ -1842,19 +1843,20 @@ encode_event_empty_lb_backends_opts(struct ofpbuf *ofpacts, +@@ -570,6 +571,75 @@ ovnact_move_free(struct ovnact_move *move OVS_UNUSED) + { + } + ++ ++static void ++parse_push_pop(struct action_context *ctx, bool is_push) ++{ ++ lexer_force_match(ctx->lexer, LEX_T_LPAREN); ++ ++ struct expr_field f; ++ if (!expr_field_parse(ctx->lexer, ctx->pp->symtab, &f, &ctx->prereqs)) { ++ return; ++ } ++ size_t ofs = ctx->ovnacts->size; ++ char *error = expr_type_check(&f, f.n_bits, !is_push, ctx->scope); ++ if (error) { ++ ctx->ovnacts->size = ofs; ++ lexer_error(ctx->lexer, "%s", error); ++ free(error); ++ return; ++ } ++ ++ lexer_force_match(ctx->lexer, LEX_T_RPAREN); ++ ++ struct ovnact_push_pop *p; ++ if (is_push) { ++ p = ovnact_put_PUSH(ctx->ovnacts); ++ } else { ++ p = ovnact_put_POP(ctx->ovnacts); ++ } ++ p->field = f; ++} ++ ++static void ++format_PUSH(const struct ovnact_push_pop *push, struct ds *s) ++{ ++ ds_put_cstr(s, "push("); ++ expr_field_format(&push->field, s); ++ ds_put_cstr(s, ");"); ++} ++ ++static void ++encode_PUSH(const struct ovnact_push_pop *push, ++ const struct ovnact_encode_params *ep OVS_UNUSED, ++ struct ofpbuf *ofpacts) ++{ ++ ofpact_put_STACK_PUSH(ofpacts)->subfield = ++ expr_resolve_field(&push->field); ++} ++ ++static void ++format_POP(const struct ovnact_push_pop *pop, struct ds *s) ++{ ++ ds_put_cstr(s, "pop("); ++ expr_field_format(&pop->field, s); ++ ds_put_cstr(s, ");"); ++} ++ ++static void ++encode_POP(const struct ovnact_push_pop *pop, ++ const struct ovnact_encode_params *ep OVS_UNUSED, ++ struct ofpbuf *ofpacts) ++{ ++ ofpact_put_STACK_POP(ofpacts)->subfield = ++ expr_resolve_field(&pop->field); ++} ++ ++static void ++ovnact_push_pop_free(struct ovnact_push_pop *push OVS_UNUSED) ++{ ++} ++ + static void + parse_DEC_TTL(struct action_context *ctx) + { +@@ -1059,7 +1129,7 @@ encode_CT_DNAT_IN_CZONE(const struct ovnact_ct_nat *cn, + const struct ovnact_encode_params *ep, + struct ofpbuf *ofpacts) + { +- encode_ct_nat(cn, ep, false, MFF_LOG_NAT_ZONE, ofpacts); ++ encode_ct_nat(cn, ep, false, ep->common_nat_ct_zone, ofpacts); + } + + static void +@@ -1067,7 +1137,7 @@ encode_CT_SNAT_IN_CZONE(const struct ovnact_ct_nat *cn, + const struct ovnact_encode_params *ep, + struct ofpbuf *ofpacts) + { +- encode_ct_nat(cn, ep, true, MFF_LOG_NAT_ZONE, ofpacts); ++ encode_ct_nat(cn, ep, true, ep->common_nat_ct_zone, ofpacts); + } + + static void +@@ -1076,7 +1146,7 @@ ovnact_ct_nat_free(struct ovnact_ct_nat *ct_nat OVS_UNUSED) + } + + static void +-parse_ct_lb_action(struct action_context *ctx) ++parse_ct_lb_action(struct action_context *ctx, bool ct_lb_mark) + { + if (ctx->pp->cur_ltable >= ctx->pp->n_tables) { + lexer_error(ctx->lexer, "\"ct_lb\" action not allowed in last table."); +@@ -1182,7 +1252,8 @@ parse_ct_lb_action(struct action_context *ctx) + } + } + +- struct ovnact_ct_lb *cl = ovnact_put_CT_LB(ctx->ovnacts); ++ struct ovnact_ct_lb *cl = ct_lb_mark ? ovnact_put_CT_LB_MARK(ctx->ovnacts) ++ : ovnact_put_CT_LB(ctx->ovnacts); + cl->ltable = ctx->pp->cur_ltable + 1; + cl->dsts = dsts; + cl->n_dsts = n_dsts; +@@ -1190,9 +1261,13 @@ parse_ct_lb_action(struct action_context *ctx) + } + + static void +-format_CT_LB(const struct ovnact_ct_lb *cl, struct ds *s) ++format_ct_lb(const struct ovnact_ct_lb *cl, struct ds *s, bool ct_lb_mark) + { +- ds_put_cstr(s, "ct_lb"); ++ if (ct_lb_mark) { ++ ds_put_cstr(s, "ct_lb_mark"); ++ } else { ++ ds_put_cstr(s, "ct_lb"); ++ } + if (cl->n_dsts) { + ds_put_cstr(s, "(backends="); + for (size_t i = 0; i < cl->n_dsts; i++) { +@@ -1228,9 +1303,22 @@ format_CT_LB(const struct ovnact_ct_lb *cl, struct ds *s) + } + + static void +-encode_CT_LB(const struct ovnact_ct_lb *cl, ++format_CT_LB(const struct ovnact_ct_lb *cl, struct ds *s) ++{ ++ format_ct_lb(cl, s, false); ++} ++ ++static void ++format_CT_LB_MARK(const struct ovnact_ct_lb *cl, struct ds *s) ++{ ++ format_ct_lb(cl, s, true); ++} ++ ++static void ++encode_ct_lb(const struct ovnact_ct_lb *cl, + const struct ovnact_encode_params *ep, +- struct ofpbuf *ofpacts) ++ struct ofpbuf *ofpacts, ++ bool ct_lb_mark) + { + uint8_t recirc_table = cl->ltable + first_ptable(ep, ep->pipeline); + if (!cl->n_dsts) { +@@ -1299,8 +1387,9 @@ encode_CT_LB(const struct ovnact_ct_lb *cl, + ds_put_format(&ds, "),commit,table=%d,zone=NXM_NX_REG%d[0..15]," + "exec(set_field:" + OVN_CT_MASKED_STR(OVN_CT_NATTED) +- "->ct_label))", +- recirc_table, zone_reg); ++ "->%s))", ++ recirc_table, zone_reg, ++ ct_lb_mark ? "ct_mark" : "ct_label"); + } + + table_id = ovn_extend_table_assign_id(ep->group_table, ds_cstr(&ds), +@@ -1315,6 +1404,22 @@ encode_CT_LB(const struct ovnact_ct_lb *cl, + og->group_id = table_id; + } + ++static void ++encode_CT_LB(const struct ovnact_ct_lb *cl, ++ const struct ovnact_encode_params *ep, ++ struct ofpbuf *ofpacts) ++{ ++ encode_ct_lb(cl, ep, ofpacts, false); ++} ++ ++static void ++encode_CT_LB_MARK(const struct ovnact_ct_lb *cl, ++ const struct ovnact_encode_params *ep, ++ struct ofpbuf *ofpacts) ++{ ++ encode_ct_lb(cl, ep, ofpacts, true); ++} ++ + static void + ovnact_ct_lb_free(struct ovnact_ct_lb *ct_lb) + { +@@ -1842,19 +1947,20 @@ encode_event_empty_lb_backends_opts(struct ofpbuf *ofpacts, { for (const struct ovnact_gen_option *o = event->options; o < &event->options[event->n_options]; o++) { @@ -1642,7 +2449,16 @@ index da00ee349..c46772e78 100644 } } -@@ -2987,6 +2989,15 @@ parse_put_nd_ra_opts(struct action_context *ctx, const struct expr_field *dst, +@@ -2330,7 +2436,7 @@ validate_empty_lb_backends(struct action_context *ctx, + + switch (o->option->code) { + case EMPTY_LB_VIP: +- if (!inet_parse_active(c->string, 0, &ss, false)) { ++ if (!inet_parse_active(c->string, 0, &ss, false, NULL)) { + lexer_error(ctx->lexer, "Invalid load balancer VIP '%s'", + c->string); + return; +@@ -2987,6 +3093,15 @@ parse_put_nd_ra_opts(struct action_context *ctx, const struct expr_field *dst, case ND_OPT_MTU: ok = c->format == LEX_F_DECIMAL; break; @@ -1658,7 +2474,7 @@ index da00ee349..c46772e78 100644 } if (!ok) { -@@ -3017,6 +3028,109 @@ format_PUT_ND_RA_OPTS(const struct ovnact_put_opts *po, +@@ -3017,6 +3132,109 @@ format_PUT_ND_RA_OPTS(const struct ovnact_put_opts *po, format_put_opts("put_nd_ra_opts", po, s); } @@ -1768,7 +2584,7 @@ index da00ee349..c46772e78 100644 static void encode_put_nd_ra_option(const struct ovnact_gen_option *o, struct ofpbuf *ofpacts, ptrdiff_t ra_offset) -@@ -3091,6 +3205,46 @@ encode_put_nd_ra_option(const struct ovnact_gen_option *o, +@@ -3091,6 +3309,46 @@ encode_put_nd_ra_option(const struct ovnact_gen_option *o, sizeof(ovs_be32[4])); break; } @@ -1815,6 +2631,146 @@ index da00ee349..c46772e78 100644 } } +@@ -4044,6 +4302,10 @@ parse_action(struct action_context *ctx) + parse_set_action(ctx); + } else if (lexer_match_id(ctx->lexer, "next")) { + parse_NEXT(ctx); ++ } else if (lexer_match_id(ctx->lexer, "push")) { ++ parse_push_pop(ctx, true); ++ } else if (lexer_match_id(ctx->lexer, "pop")) { ++ parse_push_pop(ctx, false); + } else if (lexer_match_id(ctx->lexer, "output")) { + ovnact_put_OUTPUT(ctx->ovnacts); + } else if (lexer_match_id(ctx->lexer, "ip.ttl")) { +@@ -4061,7 +4323,9 @@ parse_action(struct action_context *ctx) + } else if (lexer_match_id(ctx->lexer, "ct_snat_in_czone")) { + parse_CT_SNAT_IN_CZONE(ctx); + } else if (lexer_match_id(ctx->lexer, "ct_lb")) { +- parse_ct_lb_action(ctx); ++ parse_ct_lb_action(ctx, false); ++ } else if (lexer_match_id(ctx->lexer, "ct_lb_mark")) { ++ parse_ct_lb_action(ctx, true); + } else if (lexer_match_id(ctx->lexer, "ct_clear")) { + ovnact_put_CT_CLEAR(ctx->ovnacts); + } else if (lexer_match_id(ctx->lexer, "clone")) { +diff --git a/lib/expr.c b/lib/expr.c +index e3f6bb892..30ed25c6e 100644 +--- a/lib/expr.c ++++ b/lib/expr.c +@@ -203,16 +203,17 @@ expr_combine(enum expr_type type, struct expr *a, struct expr *b) + } + + static void +-expr_insert_andor(struct expr *andor, struct expr *before, struct expr *new) ++expr_insert_andor(struct expr *andor, struct ovs_list *before, ++ struct expr *new) + { + if (new->type == andor->type) { + if (andor->type == EXPR_T_AND) { + /* Conjunction junction, what's your function? */ + } +- ovs_list_splice(&before->node, new->andor.next, &new->andor); +- free(new); ++ ovs_list_splice(before, new->andor.next, &new->andor); ++ expr_destroy(new); + } else { +- ovs_list_insert(&before->node, &new->node); ++ ovs_list_insert(before, &new->node); + } + } + +@@ -1955,7 +1956,8 @@ expr_annotate__(struct expr *expr, const struct shash *symtab, + expr_destroy(expr); + return NULL; + } +- expr_insert_andor(expr, next, new_sub); ++ expr_insert_andor(expr, next ? &next->node : &expr->andor, ++ new_sub); + } + *errorp = NULL; + return expr; +@@ -2155,7 +2157,7 @@ expr_evaluate_condition(struct expr *expr, + struct expr *e = expr_evaluate_condition(sub, is_chassis_resident, + c_aux); + e = expr_fix(e); +- expr_insert_andor(expr, next, e); ++ expr_insert_andor(expr, next ? &next->node : &expr->andor, e); + } + return expr_fix(expr); + +@@ -2188,7 +2190,8 @@ expr_simplify(struct expr *expr) + case EXPR_T_OR: + LIST_FOR_EACH_SAFE (sub, next, node, &expr->andor) { + ovs_list_remove(&sub->node); +- expr_insert_andor(expr, next, expr_simplify(sub)); ++ expr_insert_andor(expr, next ? &next->node : &expr->andor, ++ expr_simplify(sub)); + } + return expr_fix(expr); + +@@ -2298,12 +2301,13 @@ crush_and_string(struct expr *expr, const struct expr_symbol *symbol) + * EXPR_T_OR with EXPR_T_CMP subexpressions. */ + struct expr *sub, *next = NULL; + LIST_FOR_EACH_SAFE (sub, next, node, &expr->andor) { ++ struct ovs_list *next_list = next ? &next->node : &expr->andor; + ovs_list_remove(&sub->node); + struct expr *new = crush_cmps(sub, symbol); + switch (new->type) { + case EXPR_T_CMP: + if (!singleton) { +- ovs_list_insert(&next->node, &new->node); ++ ovs_list_insert(next_list, &new->node); + singleton = new; + } else { + bool match = !strcmp(new->cmp.string, singleton->cmp.string); +@@ -2317,7 +2321,7 @@ crush_and_string(struct expr *expr, const struct expr_symbol *symbol) + case EXPR_T_AND: + OVS_NOT_REACHED(); + case EXPR_T_OR: +- ovs_list_insert(&next->node, &new->node); ++ ovs_list_insert(next_list, &new->node); + break; + case EXPR_T_BOOLEAN: + if (!new->boolean) { +@@ -2413,7 +2417,7 @@ crush_and_numeric(struct expr *expr, const struct expr_symbol *symbol) + case EXPR_T_AND: + OVS_NOT_REACHED(); + case EXPR_T_OR: +- ovs_list_insert(&next->node, &new->node); ++ ovs_list_insert(next ? &next->node : &expr->andor, &new->node); + break; + case EXPR_T_BOOLEAN: + if (!new->boolean) { +@@ -2579,7 +2583,8 @@ crush_or(struct expr *expr, const struct expr_symbol *symbol) + * is now a disjunction of cmps over the same symbol. */ + LIST_FOR_EACH_SAFE (sub, next, node, &expr->andor) { + ovs_list_remove(&sub->node); +- expr_insert_andor(expr, next, crush_cmps(sub, symbol)); ++ expr_insert_andor(expr, next ? &next->node : &expr->andor, ++ crush_cmps(sub, symbol)); + } + expr = expr_fix(expr); + if (expr->type != EXPR_T_OR) { +@@ -2737,8 +2742,7 @@ expr_normalize_and(struct expr *expr) + + struct expr *a, *b; + LIST_FOR_EACH_SAFE (a, b, node, &expr->andor) { +- if (&b->node == &expr->andor +- || a->type != EXPR_T_CMP || b->type != EXPR_T_CMP ++ if (!b || a->type != EXPR_T_CMP || b->type != EXPR_T_CMP + || a->cmp.symbol != b->cmp.symbol) { + continue; + } else if (a->cmp.symbol->width +@@ -2815,7 +2819,8 @@ expr_normalize_or(struct expr *expr) + } + free(new); + } else { +- expr_insert_andor(expr, next, new); ++ expr_insert_andor(expr, next ? &next->node : &expr->andor, ++ new); + } + } else { + ovs_assert(sub->type == EXPR_T_CMP || diff --git a/lib/extend-table.c b/lib/extend-table.c index c708e24b9..32d541b55 100644 --- a/lib/extend-table.c @@ -1875,6 +2831,41 @@ index 2958a55e3..b098c5089 100644 if (!allowed) { VLOG_DBG("node: %s, recompute (%s) aborted", node->name, reason); +diff --git a/lib/logical-fields.c b/lib/logical-fields.c +index 352a48c89..ed3ec62e1 100644 +--- a/lib/logical-fields.c ++++ b/lib/logical-fields.c +@@ -133,6 +133,18 @@ ovn_init_symtab(struct shash *symtab) + /* Connection tracking state. */ + expr_symtab_add_field_scoped(symtab, "ct_mark", MFF_CT_MARK, NULL, false, + WR_CT_COMMIT); ++ expr_symtab_add_subfield_scoped(symtab, "ct_mark.blocked", NULL, ++ "ct_mark[" ++ OVN_CT_STR(OVN_CT_BLOCKED_BIT) ++ "]", ++ WR_CT_COMMIT); ++ expr_symtab_add_subfield_scoped(symtab, "ct_mark.natted", NULL, ++ "ct_mark[" ++ OVN_CT_STR(OVN_CT_NATTED_BIT) ++ "]", ++ WR_CT_COMMIT); ++ expr_symtab_add_subfield_scoped(symtab, "ct_mark.ecmp_reply_port", NULL, ++ "ct_mark[16..31]", WR_CT_COMMIT); + + expr_symtab_add_field_scoped(symtab, "ct_label", MFF_CT_LABEL, NULL, + false, WR_CT_COMMIT); +@@ -147,7 +159,10 @@ ovn_init_symtab(struct shash *symtab) + "]", + WR_CT_COMMIT); + expr_symtab_add_subfield_scoped(symtab, "ct_label.ecmp_reply_eth", NULL, +- "ct_label[32..79]", WR_CT_COMMIT); ++ "ct_label[" ++ OVN_CT_STR(OVN_CT_ECMP_ETH_1ST_BIT) ".." ++ OVN_CT_STR(OVN_CT_ECMP_ETH_END_BIT) "]", ++ WR_CT_COMMIT); + expr_symtab_add_subfield_scoped(symtab, "ct_label.ecmp_reply_port", NULL, + "ct_label[80..95]", WR_CT_COMMIT); + expr_symtab_add_subfield_scoped(symtab, "ct_label.label", NULL, diff --git a/lib/ovn-l7.h b/lib/ovn-l7.h index 9a33f5cda..49ecea81f 100644 --- a/lib/ovn-l7.h @@ -1921,11 +2912,74 @@ index 56ceed8e8..7edc4c0b6 100644 nodes = ovs_numa_get_n_numas(); if (nodes == OVS_NUMA_UNSPEC || nodes <= 0) { nodes = 1; +diff --git a/lib/ovn-util.c b/lib/ovn-util.c +index c3da413aa..ac63da5a2 100644 +--- a/lib/ovn-util.c ++++ b/lib/ovn-util.c +@@ -747,7 +747,7 @@ ip_address_and_port_from_lb_key(const char *key, char **ip_address, + uint16_t *port, int *addr_family) + { + struct sockaddr_storage ss; +- if (!inet_parse_active(key, 0, &ss, false)) { ++ if (!inet_parse_active(key, 0, &ss, false, NULL)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, "bad ip address or port for load balancer key %s", + key); +@@ -766,8 +766,11 @@ ip_address_and_port_from_lb_key(const char *key, char **ip_address, + } + + /* Increment this for any logical flow changes, if an existing OVN action is +- * modified or a stage is added to a logical pipeline. */ +-#define OVN_INTERNAL_MINOR_VER 3 ++ * modified or a stage is added to a logical pipeline. ++ * ++ * This value is also used to handle some backward compatibility during ++ * upgrading. It should never decrease or rewind. */ ++#define OVN_INTERNAL_MINOR_VER 4 + + /* Returns the OVN version. The caller must free the returned value. */ + char * +@@ -778,6 +781,24 @@ ovn_get_internal_version(void) + N_OVNACTS, OVN_INTERNAL_MINOR_VER); + } + ++unsigned int ++ovn_parse_internal_version_minor(const char *ver) ++{ ++ const char *p = ver + strlen(ver); ++ for (int i = 0; i < strlen(ver); i++) { ++ if (*p == '.') { ++ break; ++ } ++ p--; ++ } ++ ++ unsigned int minor; ++ if (ovs_scan(p, ".%u", &minor)) { ++ return minor; ++ } ++ return 0; ++} ++ + #ifdef DDLOG + /* Callbacks used by the ddlog northd code to print warnings and errors. */ + void diff --git a/lib/ovn-util.h b/lib/ovn-util.h -index a923c3b65..b212c64b7 100644 +index a923c3b65..a4f3187e3 100644 --- a/lib/ovn-util.h +++ b/lib/ovn-util.h -@@ -261,14 +261,16 @@ struct sctp_chunk_header { +@@ -247,6 +247,10 @@ bool ip_address_and_port_from_lb_key(const char *key, char **ip_address, + * value. */ + char *ovn_get_internal_version(void); + ++/* Parse the provided internal version string and return the "minor" part which ++ * is expected to be an unsigned integer followed by the last "." in the ++ * string. Returns 0 if the string can't be parsed. */ ++unsigned int ovn_parse_internal_version_minor(const char *ver); + + /* OVN Packet definitions. These may eventually find a home in OVS's + * packets.h file. For the time being, they live here because OVN uses them +@@ -261,14 +265,16 @@ struct sctp_chunk_header { BUILD_ASSERT_DECL(SCTP_CHUNK_HEADER_LEN == sizeof(struct sctp_chunk_header)); #define SCTP_INIT_CHUNK_LEN 16 @@ -1947,8 +3001,20 @@ index a923c3b65..b212c64b7 100644 /* These are the only SCTP chunk types that OVN cares about. * There is no need to define the other chunk types until they are +diff --git a/northd/en-lflow.c b/northd/en-lflow.c +index ffbdaf4e8..fa0dfcbe0 100644 +--- a/northd/en-lflow.c ++++ b/northd/en-lflow.c +@@ -60,6 +60,7 @@ void en_lflow_run(struct engine_node *node, void *data OVS_UNUSED) + lflow_input.meter_groups = &northd_data->meter_groups; + lflow_input.lbs = &northd_data->lbs; + lflow_input.bfd_connections = &northd_data->bfd_connections; ++ lflow_input.features = &northd_data->features; + lflow_input.ovn_internal_version_changed = + northd_data->ovn_internal_version_changed; + diff --git a/northd/northd.c b/northd/northd.c -index c714227b2..fbc29b554 100644 +index c714227b2..ac20ee849 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -112,18 +112,20 @@ enum ovn_stage { @@ -1984,12 +3050,54 @@ index c714227b2..fbc29b554 100644 \ /* Logical switch egress stages. */ \ PIPELINE_STAGE(SWITCH, OUT, PRE_LB, 0, "ls_out_pre_lb") \ -@@ -761,16 +763,6 @@ init_nat_entries(struct ovn_datapath *od) - return; - } +@@ -236,6 +238,17 @@ enum ovn_stage { + /* Register used for setting a label for ACLs in a Logical Switch. */ + #define REG_LABEL "reg3" + ++/* Register used for temporarily store ECMP eth.src to avoid masked ct_label ++ * access. It doesn't really occupy registers because the content of the ++ * register is saved to stack and then restored in the same flow. ++ * Note: the bits must match ct_label.ecmp_reply_eth defined in ++ * logical-fields.c */ ++#define REG_ECMP_ETH_FULL "xxreg1" ++#define REG_ECMP_ETH_FIELD REG_ECMP_ETH_FULL "[" \ ++ OVN_CT_STR(OVN_CT_ECMP_ETH_1ST_BIT) \ ++ ".." \ ++ OVN_CT_STR(OVN_CT_ECMP_ETH_END_BIT) "]" ++ + #define FLAGBIT_NOT_VXLAN "flags[1] == 0" -- if (od->n_l3dgw_ports > 1) { -- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + /* +@@ -376,6 +389,23 @@ ovn_stage_to_datapath_type(enum ovn_stage stage) + } + } + ++static void ++build_chassis_features(const struct northd_input *input_data, ++ struct chassis_features *chassis_features) ++{ ++ const struct sbrec_chassis *chassis; ++ ++ SBREC_CHASSIS_TABLE_FOR_EACH (chassis, input_data->sbrec_chassis) { ++ if (!smap_get_bool(&chassis->other_config, ++ OVN_FEATURE_CT_NO_MASKED_LABEL, ++ false)) { ++ chassis_features->ct_no_masked_label = false; ++ return; ++ } ++ } ++ chassis_features->ct_no_masked_label = true; ++} ++ + struct ovn_chassis_qdisc_queues { + struct hmap_node key_node; + uint32_t queue_id; +@@ -761,16 +791,6 @@ init_nat_entries(struct ovn_datapath *od) + return; + } + +- if (od->n_l3dgw_ports > 1) { +- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); - VLOG_WARN_RL(&rl, "NAT is configured on logical router %s, which has %" - PRIuSIZE" distributed gateway ports. NAT is not supported" - " yet when there is more than one distributed gateway " @@ -2001,7 +3109,7 @@ index c714227b2..fbc29b554 100644 od->nat_entries = xmalloc(od->nbr->n_nat * sizeof *od->nat_entries); for (size_t i = 0; i < od->nbr->n_nat; i++) { -@@ -1641,13 +1633,13 @@ destroy_routable_addresses(struct ovn_port_routable_addresses *ra) +@@ -1641,13 +1661,13 @@ destroy_routable_addresses(struct ovn_port_routable_addresses *ra) } static char **get_nat_addresses(const struct ovn_port *op, size_t *n, @@ -2017,7 +3125,117 @@ index c714227b2..fbc29b554 100644 if (!nats) { return; -@@ -2711,7 +2703,8 @@ join_logical_ports(struct northd_input *input_data, +@@ -1792,6 +1812,38 @@ lsp_is_router(const struct nbrec_logical_switch_port *nbsp) + return !strcmp(nbsp->type, "router"); + } + ++static bool ++lsp_is_type_changed(const struct sbrec_port_binding *sb, ++ const struct nbrec_logical_switch_port *nbsp, ++ bool *is_old_container_lport) ++{ ++ *is_old_container_lport = false; ++ if (!sb || !nbsp) { ++ return false; ++ } ++ ++ if (!sb->type[0] && !nbsp->type[0]) { ++ /* Two "VIF's" interface make sure both have parent_port ++ * set or both have parent_port unset, otherwisre they are ++ * different ports type. ++ */ ++ if ((!sb->parent_port && nbsp->parent_name) || ++ (sb->parent_port && !nbsp->parent_name)) { ++ *is_old_container_lport = true; ++ return true; ++ } else { ++ return false; ++ } ++ } ++ ++ /* Both lports are not "VIF's" it is safe to use strcmp. */ ++ if (sb->type[0] && nbsp->type[0]) { ++ return strcmp(sb->type, nbsp->type); ++ } ++ ++ return true; ++} ++ + static bool + lrport_is_enabled(const struct nbrec_logical_router_port *lrport) + { +@@ -2472,22 +2524,56 @@ join_logical_ports(struct northd_input *input_data, + VLOG_WARN_RL(&rl, "duplicate logical port %s", nbsp->name); + continue; + } else if (op && (!op->sb || op->sb->datapath == od->sb)) { +- ovn_port_set_nb(op, nbsp, NULL); +- ovs_list_remove(&op->list); +- +- uint32_t queue_id = smap_get_int(&op->sb->options, +- "qdisc_queue_id", 0); +- if (queue_id && op->sb->chassis) { +- add_chassis_queue( +- chassis_qdisc_queues, &op->sb->chassis->header_.uuid, +- queue_id); +- } ++ /* ++ * Handle cases where lport type was explicitly changed ++ * in the NBDB, in such cases: ++ * 1. remove the current sbrec of the affected lport from ++ * the port_binding table. ++ * ++ * 2. create a new sbrec with the same logical_port as the ++ * deleted lport and add it to the nb_only list which ++ * will make the northd handle this lport as a new ++ * created one and recompute everything that is needed ++ * for this lport. ++ * ++ * This change will affect container lport type changes ++ * only for now, this change is needed in container ++ * lport cases to avoid port type conflicts in the ++ * ovn-controller when the user clears the parent_port ++ * field in the container lport. ++ * ++ * This approach can be applied to all other lport types ++ * changes by removing the is_old_container_lport. ++ */ ++ bool is_old_container_lport = false; ++ if (op->sb && lsp_is_type_changed(op->sb, nbsp, ++ &is_old_container_lport) ++ && is_old_container_lport) { ++ ovs_list_remove(&op->list); ++ sbrec_port_binding_delete(op->sb); ++ ovn_port_destroy(ports, op); ++ op = ovn_port_create(ports, nbsp->name, nbsp, ++ NULL, NULL); ++ ovs_list_push_back(nb_only, &op->list); ++ } else { ++ ovn_port_set_nb(op, nbsp, NULL); ++ ovs_list_remove(&op->list); ++ ++ uint32_t queue_id = smap_get_int(&op->sb->options, ++ "qdisc_queue_id", 0); ++ if (queue_id && op->sb->chassis) { ++ add_chassis_queue( ++ chassis_qdisc_queues, ++ &op->sb->chassis->header_.uuid, ++ queue_id); ++ } + +- ovs_list_push_back(both, &op->list); ++ ovs_list_push_back(both, &op->list); + +- /* This port exists due to a SB binding, but should +- * not have been initialized fully. */ +- ovs_assert(!op->n_lsp_addrs && !op->n_ps_addrs); ++ /* This port exists due to a SB binding, but should ++ * not have been initialized fully. */ ++ ovs_assert(!op->n_lsp_addrs && !op->n_ps_addrs); ++ } + } else { + op = ovn_port_create(ports, nbsp->name, nbsp, NULL, NULL); + ovs_list_push_back(nb_only, &op->list); +@@ -2711,7 +2797,8 @@ join_logical_ports(struct northd_input *input_data, * The caller must free each of the n returned strings with free(), * and must free the returned array when it is no longer needed. */ static char ** @@ -2027,7 +3245,7 @@ index c714227b2..fbc29b554 100644 { size_t n_nats = 0; struct eth_addr mac; -@@ -2791,24 +2784,26 @@ get_nat_addresses(const struct ovn_port *op, size_t *n, bool routable_only) +@@ -2791,24 +2878,26 @@ get_nat_addresses(const struct ovn_port *op, size_t *n, bool routable_only) } } @@ -2072,7 +3290,7 @@ index c714227b2..fbc29b554 100644 } } -@@ -3376,7 +3371,10 @@ ovn_port_update_sbrec(struct northd_input *input_data, +@@ -3376,7 +3465,10 @@ ovn_port_update_sbrec(struct northd_input *input_data, if (nat_addresses && !strcmp(nat_addresses, "router")) { if (op->peer && op->peer->od && (chassis || op->peer->od->n_l3dgw_ports)) { @@ -2084,7 +3302,33 @@ index c714227b2..fbc29b554 100644 } /* Only accept manual specification of ethernet address * followed by IPv4 addresses on type "l3gateway" ports. */ -@@ -3803,6 +3801,7 @@ build_ovn_lbs(struct northd_input *input_data, +@@ -3661,12 +3753,13 @@ static bool + build_lb_vip_actions(struct ovn_lb_vip *lb_vip, + struct ovn_northd_lb_vip *lb_vip_nb, + struct ds *action, char *selection_fields, +- bool ls_dp) ++ bool ls_dp, bool ct_lb_mark) + { ++ const char *ct_lb_action = ct_lb_mark ? "ct_lb_mark" : "ct_lb"; + bool skip_hash_fields = false, reject = false; + + if (lb_vip_nb->lb_health_check) { +- ds_put_cstr(action, "ct_lb(backends="); ++ ds_put_format(action, "%s(backends=", ct_lb_action); + + size_t n_active_backends = 0; + for (size_t i = 0; i < lb_vip->n_backends; i++) { +@@ -3699,7 +3792,8 @@ build_lb_vip_actions(struct ovn_lb_vip *lb_vip, + } else if (lb_vip->empty_backend_rej && !lb_vip->n_backends) { + reject = true; + } else { +- ds_put_format(action, "ct_lb(backends=%s);", lb_vip_nb->backend_ips); ++ ds_put_format(action, "%s(backends=%s);", ct_lb_action, ++ lb_vip_nb->backend_ips); + } + + if (reject) { +@@ -3803,6 +3897,7 @@ build_ovn_lbs(struct northd_input *input_data, } /* Delete any stale SB load balancer rows. */ @@ -2092,7 +3336,7 @@ index c714227b2..fbc29b554 100644 const struct sbrec_load_balancer *sbrec_lb, *next; SBREC_LOAD_BALANCER_TABLE_FOR_EACH_SAFE (sbrec_lb, next, input_data->sbrec_load_balancer_table) { -@@ -3813,13 +3812,22 @@ build_ovn_lbs(struct northd_input *input_data, +@@ -3813,13 +3908,22 @@ build_ovn_lbs(struct northd_input *input_data, continue; } @@ -2118,7 +3362,145 @@ index c714227b2..fbc29b554 100644 /* Create SB Load balancer records if not present and sync * the SB load balancer columns. */ -@@ -6122,7 +6130,7 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows, +@@ -5889,13 +5993,18 @@ build_pre_lb(struct ovn_datapath *od, struct hmap *lflows) + } + + static void +-build_pre_stateful(struct ovn_datapath *od, struct hmap *lflows) ++build_pre_stateful(struct ovn_datapath *od, ++ const struct chassis_features *features, ++ struct hmap *lflows) + { + /* Ingress and Egress pre-stateful Table (Priority 0): Packets are + * allowed by default. */ + ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 0, "1", "next;"); + ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_STATEFUL, 0, "1", "next;"); + ++ const char *ct_lb_action = features->ct_no_masked_label ++ ? "ct_lb_mark" ++ : "ct_lb"; + const char *lb_protocols[] = {"tcp", "udp", "sctp"}; + struct ds actions = DS_EMPTY_INITIALIZER; + struct ds match = DS_EMPTY_INITIALIZER; +@@ -5906,8 +6015,8 @@ build_pre_stateful(struct ovn_datapath *od, struct hmap *lflows) + ds_put_format(&match, REGBIT_CONNTRACK_NAT" == 1 && ip4 && %s", + lb_protocols[i]); + ds_put_format(&actions, REG_ORIG_DIP_IPV4 " = ip4.dst; " +- REG_ORIG_TP_DPORT " = %s.dst; ct_lb;", +- lb_protocols[i]); ++ REG_ORIG_TP_DPORT " = %s.dst; %s;", ++ lb_protocols[i], ct_lb_action); + ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 120, + ds_cstr(&match), ds_cstr(&actions)); + +@@ -5916,20 +6025,20 @@ build_pre_stateful(struct ovn_datapath *od, struct hmap *lflows) + ds_put_format(&match, REGBIT_CONNTRACK_NAT" == 1 && ip6 && %s", + lb_protocols[i]); + ds_put_format(&actions, REG_ORIG_DIP_IPV6 " = ip6.dst; " +- REG_ORIG_TP_DPORT " = %s.dst; ct_lb;", +- lb_protocols[i]); ++ REG_ORIG_TP_DPORT " = %s.dst; %s;", ++ lb_protocols[i], ct_lb_action); + ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 120, + ds_cstr(&match), ds_cstr(&actions)); + } + +- ds_destroy(&actions); +- ds_destroy(&match); ++ ds_clear(&actions); ++ ds_put_format(&actions, "%s;", ct_lb_action); + + ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 110, +- REGBIT_CONNTRACK_NAT" == 1", "ct_lb;"); ++ REGBIT_CONNTRACK_NAT" == 1", ds_cstr(&actions)); + + ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_STATEFUL, 110, +- REGBIT_CONNTRACK_NAT" == 1", "ct_lb;"); ++ REGBIT_CONNTRACK_NAT" == 1", ds_cstr(&actions)); + + /* If REGBIT_CONNTRACK_DEFRAG is set as 1, then the packets should be + * sent to conntrack for tracking and defragmentation. */ +@@ -5938,10 +6047,15 @@ build_pre_stateful(struct ovn_datapath *od, struct hmap *lflows) + + ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_STATEFUL, 100, + REGBIT_CONNTRACK_DEFRAG" == 1", "ct_next;"); ++ ++ ds_destroy(&actions); ++ ds_destroy(&match); + } + + static void +-build_acl_hints(struct ovn_datapath *od, struct hmap *lflows) ++build_acl_hints(struct ovn_datapath *od, ++ const struct chassis_features *features, ++ struct hmap *lflows) + { + /* This stage builds hints for the IN/OUT_ACL stage. Based on various + * combinations of ct flags packets may hit only a subset of the logical +@@ -5963,6 +6077,7 @@ build_acl_hints(struct ovn_datapath *od, struct hmap *lflows) + + for (size_t i = 0; i < ARRAY_SIZE(stages); i++) { + enum ovn_stage stage = stages[i]; ++ const char *match; + + /* In any case, advance to the next stage. */ + if (!od->has_acls && !od->has_lb_vip) { +@@ -5992,8 +6107,10 @@ build_acl_hints(struct ovn_datapath *od, struct hmap *lflows) + * REGBIT_ACL_HINT_ALLOW_NEW. + * - drop ACLs. + */ +- ovn_lflow_add(lflows, od, stage, 6, +- "!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1", ++ match = features->ct_no_masked_label ++ ? "!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1" ++ : "!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1"; ++ ovn_lflow_add(lflows, od, stage, 6, match, + REGBIT_ACL_HINT_ALLOW_NEW " = 1; " + REGBIT_ACL_HINT_DROP " = 1; " + "next;"); +@@ -6009,11 +6126,13 @@ build_acl_hints(struct ovn_datapath *od, struct hmap *lflows) + * - allow ACLs in which case the traffic should be allowed so we set + * REGBIT_ACL_HINT_ALLOW. + * - drop ACLs in which case the traffic should be blocked and the +- * connection must be committed with ct_label.blocked set so we set ++ * connection must be committed with ct_mark.blocked set so we set + * REGBIT_ACL_HINT_BLOCK. + */ +- ovn_lflow_add(lflows, od, stage, 4, +- "!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0", ++ match = features->ct_no_masked_label ++ ? "!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0" ++ : "!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0"; ++ ovn_lflow_add(lflows, od, stage, 4, match, + REGBIT_ACL_HINT_ALLOW " = 1; " + REGBIT_ACL_HINT_BLOCK " = 1; " + "next;"); +@@ -6024,15 +6143,21 @@ build_acl_hints(struct ovn_datapath *od, struct hmap *lflows) + ovn_lflow_add(lflows, od, stage, 3, "!ct.est", + REGBIT_ACL_HINT_DROP " = 1; " + "next;"); +- ovn_lflow_add(lflows, od, stage, 2, "ct.est && ct_label.blocked == 1", ++ match = features->ct_no_masked_label ++ ? "ct.est && ct_mark.blocked == 1" ++ : "ct.est && ct_label.blocked == 1"; ++ ovn_lflow_add(lflows, od, stage, 2, match, + REGBIT_ACL_HINT_DROP " = 1; " + "next;"); + + /* Established connections that were previously allowed might hit + * drop ACLs in which case the connection must be committed with +- * ct_label.blocked set. ++ * ct_mark.blocked set. + */ +- ovn_lflow_add(lflows, od, stage, 1, "ct.est && ct_label.blocked == 0", ++ match = features->ct_no_masked_label ++ ? "ct.est && ct_mark.blocked == 0" ++ : "ct.est && ct_label.blocked == 0"; ++ ovn_lflow_add(lflows, od, stage, 1, match, + REGBIT_ACL_HINT_BLOCK " = 1; " + "next;"); + } +@@ -6122,7 +6247,7 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows, { struct ds match = DS_EMPTY_INITIALIZER; struct ds actions = DS_EMPTY_INITIALIZER; @@ -2127,9 +3509,18 @@ index c714227b2..fbc29b554 100644 char *next_action = xasprintf("next(pipeline=%s,table=%d);", -@@ -6163,7 +6171,15 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, +@@ -6158,12 +6283,23 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows, + + static void + consider_acl(struct hmap *lflows, struct ovn_datapath *od, +- struct nbrec_acl *acl, bool has_stateful, ++ struct nbrec_acl *acl, bool has_stateful, bool ct_masked_mark, + const struct shash *meter_groups, struct ds *match, struct ds *actions) { ++ const char *ct_blocked_match = ct_masked_mark ++ ? "ct_mark.blocked" ++ : "ct_label.blocked"; bool ingress = !strcmp(acl->direction, "from-lport") ? true :false; - enum ovn_stage stage = ingress ? S_SWITCH_IN_ACL : S_SWITCH_OUT_ACL; + enum ovn_stage stage; @@ -2144,7 +3535,40 @@ index c714227b2..fbc29b554 100644 if (!strcmp(acl->action, "allow-stateless")) { ds_clear(actions); -@@ -6342,6 +6358,72 @@ ovn_port_group_destroy(struct hmap *pgs, struct ovn_port_group *pg) +@@ -6197,7 +6333,7 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, + * It's also possible that a known connection was marked for + * deletion after a policy was deleted, but the policy was + * re-added while that connection is still known. We catch +- * that case here and un-set ct_label.blocked (which will be done ++ * that case here and un-set ct_mark.blocked (which will be done + * by ct_commit in the "stateful" stage) to indicate that the + * connection should be allowed to resume. + */ +@@ -6267,11 +6403,11 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, + ds_cstr(match), ds_cstr(actions), + &acl->header_); + } +- /* For an existing connection without ct_label set, we've ++ /* For an existing connection without ct_mark.blocked set, we've + * encountered a policy change. ACLs previously allowed + * this connection and we committed the connection tracking + * entry. Current policy says that we should drop this +- * connection. First, we set bit 0 of ct_label to indicate ++ * connection. First, we set ct_mark.blocked to indicate + * that this connection is set for deletion. By not + * specifying "next;", we implicitly drop the packet after + * updating conntrack state. We would normally defer +@@ -6281,7 +6417,8 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od, + ds_clear(match); + ds_clear(actions); + ds_put_cstr(match, REGBIT_ACL_HINT_BLOCK " == 1"); +- ds_put_cstr(actions, "ct_commit { ct_label.blocked = 1; }; "); ++ ds_put_format(actions, "ct_commit { %s = 1; }; ", ++ ct_blocked_match); + if (!strcmp(acl->action, "reject")) { + build_reject_acl_rules(od, lflows, stage, acl, match, + actions, &acl->header_, meter_groups); +@@ -6342,6 +6479,72 @@ ovn_port_group_destroy(struct hmap *pgs, struct ovn_port_group *pg) } } @@ -2217,7 +3641,24 @@ index c714227b2..fbc29b554 100644 static void build_port_group_lswitches(struct northd_input *input_data, struct hmap *pgs, -@@ -6405,6 +6487,8 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows, +@@ -6383,10 +6586,14 @@ build_port_group_lswitches(struct northd_input *input_data, + } + + static void +-build_acls(struct ovn_datapath *od, struct hmap *lflows, +- const struct hmap *port_groups, const struct shash *meter_groups) ++build_acls(struct ovn_datapath *od, const struct chassis_features *features, ++ struct hmap *lflows, const struct hmap *port_groups, ++ const struct shash *meter_groups) + { + bool has_stateful = od->has_stateful_acl || od->has_lb_vip; ++ const char *ct_blocked_match = features->ct_no_masked_label ++ ? "ct_mark.blocked" ++ : "ct_label.blocked"; + struct ds match = DS_EMPTY_INITIALIZER; + struct ds actions = DS_EMPTY_INITIALIZER; + +@@ -6405,6 +6612,8 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows, ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 0, "1", "next;"); } @@ -2226,9 +3667,67 @@ index c714227b2..fbc29b554 100644 if (has_stateful) { /* Ingress and Egress ACL Table (Priority 1). * -@@ -6463,7 +6547,8 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows, - "ct.rpl && ct_label.blocked == 0", - use_ct_inv_match ? " && !ct.inv" : ""); +@@ -6420,30 +6629,34 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows, + * subsequent packets will hit the flow at priority 0 that just + * uses "next;" + * +- * We also check for established connections that have ct_label.blocked ++ * We also check for established connections that have ct_mark.blocked + * set on them. That's a connection that was disallowed, but is + * now allowed by policy again since it hit this default-allow flow. +- * We need to set ct_label.blocked=0 to let the connection continue, ++ * We need to set ct_mark.blocked=0 to let the connection continue, + * which will be done by ct_commit() in the "stateful" stage. + * Subsequent packets will hit the flow at priority 0 that just + * uses "next;". */ ++ ds_clear(&match); ++ ds_put_format(&match, "ip && (!ct.est || (ct.est && %s == 1))", ++ ct_blocked_match); + ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 1, +- "ip && (!ct.est || (ct.est && ct_label.blocked == 1))", +- REGBIT_CONNTRACK_COMMIT" = 1; next;"); ++ ds_cstr(&match), ++ REGBIT_CONNTRACK_COMMIT" = 1; next;"); + ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 1, +- "ip && (!ct.est || (ct.est && ct_label.blocked == 1))", +- REGBIT_CONNTRACK_COMMIT" = 1; next;"); ++ ds_cstr(&match), ++ REGBIT_CONNTRACK_COMMIT" = 1; next;"); + + /* Ingress and Egress ACL Table (Priority 65532). + * + * Always drop traffic that's in an invalid state. Also drop + * reply direction packets for connections that have been marked +- * for deletion (bit 0 of ct_label is set). ++ * for deletion (ct_mark.blocked is set). + * + * This is enforced at a higher priority than ACLs can be defined. */ + ds_clear(&match); +- ds_put_format(&match, "%s(ct.est && ct.rpl && ct_label.blocked == 1)", +- use_ct_inv_match ? "ct.inv || " : ""); ++ ds_put_format(&match, "%s(ct.est && ct.rpl && %s == 1)", ++ use_ct_inv_match ? "ct.inv || " : "", ++ ct_blocked_match); + ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3, + ds_cstr(&match), "drop;"); + ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3, +@@ -6453,24 +6666,26 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows, + * + * Allow reply traffic that is part of an established + * conntrack entry that has not been marked for deletion +- * (bit 0 of ct_label). We only match traffic in the ++ * (ct_mark.blocked). We only match traffic in the + * reply direction because we want traffic in the request + * direction to hit the currently defined policy from ACLs. + * + * This is enforced at a higher priority than ACLs can be defined. */ + ds_clear(&match); + ds_put_format(&match, "ct.est && !ct.rel && !ct.new%s && " +- "ct.rpl && ct_label.blocked == 0", +- use_ct_inv_match ? " && !ct.inv" : ""); ++ "ct.rpl && %s == 0", ++ use_ct_inv_match ? " && !ct.inv" : "", ++ ct_blocked_match); ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3, - ds_cstr(&match), "next;"); + ds_cstr(&match), REGBIT_ACL_HINT_DROP" = 0; " @@ -2236,7 +3735,56 @@ index c714227b2..fbc29b554 100644 ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3, ds_cstr(&match), "next;"); -@@ -6670,6 +6755,10 @@ build_lb_rules(struct hmap *lflows, struct ovn_northd_lb *lb, + /* Ingress and Egress ACL Table (Priority 65535). + * + * Allow traffic that is related to an existing conntrack entry that +- * has not been marked for deletion (bit 0 of ct_label). ++ * has not been marked for deletion (ct_mark.blocked). + * + * This is enforced at a higher priority than ACLs can be defined. + * +@@ -6479,9 +6694,9 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows, + * related traffic such as an ICMP Port Unreachable through + * that's generated from a non-listening UDP port. */ + ds_clear(&match); +- ds_put_format(&match, "!ct.est && ct.rel && !ct.new%s && " +- "ct_label.blocked == 0", +- use_ct_inv_match ? " && !ct.inv" : ""); ++ ds_put_format(&match, "!ct.est && ct.rel && !ct.new%s && %s == 0", ++ use_ct_inv_match ? " && !ct.inv" : "", ++ ct_blocked_match); + ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3, + ds_cstr(&match), "next;"); + ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3, +@@ -6499,14 +6714,16 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows, + /* 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]; +- consider_acl(lflows, od, acl, has_stateful, meter_groups, &match, +- &actions); ++ consider_acl(lflows, od, acl, has_stateful, ++ features->ct_no_masked_label, ++ meter_groups, &match, &actions); + } + struct ovn_port_group *pg; + HMAP_FOR_EACH (pg, key_node, port_groups) { + if (ovn_port_group_ls_find(pg, &od->nbs->header_.uuid)) { + for (size_t i = 0; i < pg->nb_pg->n_acls; i++) { + consider_acl(lflows, od, pg->nb_pg->acls[i], has_stateful, ++ features->ct_no_masked_label, + meter_groups, &match, &actions); + } + } +@@ -6658,7 +6875,7 @@ build_qos(struct ovn_datapath *od, struct hmap *lflows) { + } + + static void +-build_lb_rules(struct hmap *lflows, struct ovn_northd_lb *lb, ++build_lb_rules(struct hmap *lflows, struct ovn_northd_lb *lb, bool ct_lb_mark, + struct ds *match, struct ds *action, + const struct shash *meter_groups) + { +@@ -6670,6 +6887,10 @@ build_lb_rules(struct hmap *lflows, struct ovn_northd_lb *lb, ds_clear(action); ds_clear(match); @@ -2247,7 +3795,17 @@ index c714227b2..fbc29b554 100644 /* Store the original destination IP to be used when generating * hairpin flows. */ -@@ -6716,8 +6805,8 @@ build_lb_rules(struct hmap *lflows, struct ovn_northd_lb *lb, +@@ -6704,7 +6925,8 @@ build_lb_rules(struct hmap *lflows, struct ovn_northd_lb *lb, + /* New connections in Ingress table. */ + const char *meter = NULL; + bool reject = build_lb_vip_actions(lb_vip, lb_vip_nb, action, +- lb->selection_fields, true); ++ lb->selection_fields, true, ++ ct_lb_mark); + + ds_put_format(match, "ct.new && %s.dst == %s", ip_match, + lb_vip->vip_str); +@@ -6716,8 +6938,8 @@ build_lb_rules(struct hmap *lflows, struct ovn_northd_lb *lb, struct ovn_lflow *lflow_ref = NULL; uint32_t hash = ovn_logical_flow_hash( @@ -2258,27 +3816,90 @@ index c714227b2..fbc29b554 100644 ds_cstr(match), ds_cstr(action)); for (size_t j = 0; j < lb->n_nb_ls; j++) { -@@ -6730,7 +6819,7 @@ build_lb_rules(struct hmap *lflows, struct ovn_northd_lb *lb, - continue; +@@ -6726,23 +6948,32 @@ build_lb_rules(struct hmap *lflows, struct ovn_northd_lb *lb, + if (reject) { + meter = copp_meter_get(COPP_REJECT, od->nbs->copp, + meter_groups); +- } else if (ovn_dp_group_add_with_reference(lflow_ref, od)) { +- continue; } - lflow_ref = ovn_lflow_add_at_with_hash(lflows, od, +- lflow_ref = ovn_lflow_add_at_with_hash(lflows, od, - S_SWITCH_IN_STATEFUL, priority, -+ S_SWITCH_IN_LB, priority, - ds_cstr(match), ds_cstr(action), - NULL, meter, &lb->nlb->header_, - OVS_SOURCE_LOCATOR, hash); -@@ -6741,8 +6830,9 @@ build_lb_rules(struct hmap *lflows, struct ovn_northd_lb *lb, +- ds_cstr(match), ds_cstr(action), +- NULL, meter, &lb->nlb->header_, +- OVS_SOURCE_LOCATOR, hash); ++ if (meter || !ovn_dp_group_add_with_reference(lflow_ref, od)) { ++ struct ovn_lflow *lflow = ovn_lflow_add_at_with_hash( ++ lflows, od, S_SWITCH_IN_LB, priority, ++ ds_cstr(match), ds_cstr(action), ++ NULL, meter, &lb->nlb->header_, ++ OVS_SOURCE_LOCATOR, hash); ++ lflow_ref = meter ? NULL : lflow; ++ } + } + } + } + static void - build_stateful(struct ovn_datapath *od, struct hmap *lflows) +-build_stateful(struct ovn_datapath *od, struct hmap *lflows) ++build_stateful(struct ovn_datapath *od, ++ const struct chassis_features *features, ++ struct hmap *lflows) { - /* Ingress and Egress stateful Table (Priority 0): Packets are ++ const char *ct_block_action = features->ct_no_masked_label ++ ? "ct_mark.blocked" ++ : "ct_label.blocked"; ++ struct ds actions = DS_EMPTY_INITIALIZER; ++ + /* Ingress LB, Ingress and Egress stateful Table (Priority 0): Packets are * allowed by default. */ + ovn_lflow_add(lflows, od, S_SWITCH_IN_LB, 0, "1", "next;"); ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, 0, "1", "next;"); ovn_lflow_add(lflows, od, S_SWITCH_OUT_STATEFUL, 0, "1", "next;"); -@@ -7006,7 +7096,7 @@ build_lrouter_groups(struct hmap *ports, struct ovs_list *lr_list) +@@ -6752,29 +6983,33 @@ build_stateful(struct ovn_datapath *od, struct hmap *lflows) + * We always set ct_mark.blocked to 0 here as + * any packet that makes it this far is part of a connection we + * want to allow to continue. */ ++ ds_put_format(&actions, "ct_commit { %s = 0; " ++ "ct_label.label = " REG_LABEL "; }; next;", ++ ct_block_action); + ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, 100, + REGBIT_CONNTRACK_COMMIT" == 1 && " + REGBIT_ACL_LABEL" == 1", +- "ct_commit { ct_label.blocked = 0; " +- "ct_label.label = " REG_LABEL "; }; next;"); ++ ds_cstr(&actions)); + ovn_lflow_add(lflows, od, S_SWITCH_OUT_STATEFUL, 100, + REGBIT_CONNTRACK_COMMIT" == 1 && " + REGBIT_ACL_LABEL" == 1", +- "ct_commit { ct_label.blocked = 0; " +- "ct_label.label = " REG_LABEL "; }; next;"); ++ ds_cstr(&actions)); + + /* If REGBIT_CONNTRACK_COMMIT is set as 1, then the packets should be +- * committed to conntrack. We always set ct_label.blocked to 0 here as ++ * committed to conntrack. We always set ct_mark.blocked to 0 here as + * any packet that makes it this far is part of a connection we + * want to allow to continue. */ ++ ds_clear(&actions); ++ ds_put_format(&actions, "ct_commit { %s = 0; }; next;", ct_block_action); + ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, 100, + REGBIT_CONNTRACK_COMMIT" == 1 && " + REGBIT_ACL_LABEL" == 0", +- "ct_commit { ct_label.blocked = 0; }; next;"); ++ ds_cstr(&actions)); + ovn_lflow_add(lflows, od, S_SWITCH_OUT_STATEFUL, 100, + REGBIT_CONNTRACK_COMMIT" == 1 && " + REGBIT_ACL_LABEL" == 0", +- "ct_commit { ct_label.blocked = 0; }; next;"); ++ ds_cstr(&actions)); ++ ds_destroy(&actions); + } + + static void +@@ -7006,7 +7241,7 @@ build_lrouter_groups(struct hmap *ports, struct ovs_list *lr_list) } /* @@ -2287,7 +3908,7 @@ index c714227b2..fbc29b554 100644 * switching domain. */ static void -@@ -7119,7 +7209,7 @@ lrouter_port_ipv6_reachable(const struct ovn_port *op, +@@ -7119,7 +7354,7 @@ lrouter_port_ipv6_reachable(const struct ovn_port *op, } /* @@ -2296,7 +3917,7 @@ index c714227b2..fbc29b554 100644 * that own the addresses. Other ARP/ND packets are still flooded in the * switching domain as regular broadcast. */ -@@ -7156,7 +7246,7 @@ build_lswitch_rport_arp_req_flow(const char *ips, +@@ -7156,7 +7391,7 @@ build_lswitch_rport_arp_req_flow(const char *ips, } /* @@ -2305,7 +3926,7 @@ index c714227b2..fbc29b554 100644 * that own the addresses. * Priorities: * - 80: self originated GARPs that need to follow regular processing. -@@ -7484,7 +7574,7 @@ build_lswitch_flows(const struct hmap *datapaths, +@@ -7484,7 +7719,7 @@ build_lswitch_flows(const struct hmap *datapaths, struct ovn_datapath *od; @@ -2314,7 +3935,31 @@ index c714227b2..fbc29b554 100644 HMAP_FOR_EACH (od, key_node, datapaths) { if (!od->nbs) { continue; -@@ -7553,7 +7643,7 @@ build_lswitch_lflows_admission_control(struct ovn_datapath *od, +@@ -7512,6 +7747,7 @@ build_lswitch_flows(const struct hmap *datapaths, + static void + build_lswitch_lflows_pre_acl_and_acl(struct ovn_datapath *od, + const struct hmap *port_groups, ++ const struct chassis_features *features, + struct hmap *lflows, + const struct shash *meter_groups) + { +@@ -7520,11 +7756,11 @@ build_lswitch_lflows_pre_acl_and_acl(struct ovn_datapath *od, + + build_pre_acls(od, port_groups, lflows); + build_pre_lb(od, lflows); +- build_pre_stateful(od, lflows); +- build_acl_hints(od, lflows); +- build_acls(od, lflows, port_groups, meter_groups); ++ build_pre_stateful(od, features, lflows); ++ build_acl_hints(od, features, lflows); ++ build_acls(od, features, lflows, port_groups, meter_groups); + build_qos(od, lflows); +- build_stateful(od, lflows); ++ build_stateful(od, features, lflows); + build_lb_hairpin(od, lflows); + } + } +@@ -7553,7 +7789,7 @@ build_lswitch_lflows_admission_control(struct ovn_datapath *od, } } @@ -2323,7 +3968,7 @@ index c714227b2..fbc29b554 100644 * and vtep ports. (priority 100); see ovn-northd.8.xml for the * rationale. */ -@@ -7575,7 +7665,7 @@ build_lswitch_arp_nd_responder_skip_local(struct ovn_port *op, +@@ -7575,7 +7811,7 @@ build_lswitch_arp_nd_responder_skip_local(struct ovn_port *op, } } @@ -2332,7 +3977,7 @@ index c714227b2..fbc29b554 100644 * (priority 50). */ static void build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op, -@@ -7835,7 +7925,7 @@ build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op, +@@ -7835,7 +8071,7 @@ build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op, } } @@ -2341,7 +3986,7 @@ index c714227b2..fbc29b554 100644 * (priority 0)*/ static void build_lswitch_arp_nd_responder_default(struct ovn_datapath *od, -@@ -7846,7 +7936,7 @@ build_lswitch_arp_nd_responder_default(struct ovn_datapath *od, +@@ -7846,7 +8082,7 @@ build_lswitch_arp_nd_responder_default(struct ovn_datapath *od, } } @@ -2350,7 +3995,7 @@ index c714227b2..fbc29b554 100644 * (priority 110)*/ static void build_lswitch_arp_nd_service_monitor(struct ovn_northd_lb *lb, -@@ -7894,7 +7984,7 @@ build_lswitch_arp_nd_service_monitor(struct ovn_northd_lb *lb, +@@ -7894,7 +8130,7 @@ build_lswitch_arp_nd_service_monitor(struct ovn_northd_lb *lb, } @@ -2359,7 +4004,7 @@ index c714227b2..fbc29b554 100644 * priority 100 flows. */ static void build_lswitch_dhcp_options_and_response(struct ovn_port *op, -@@ -7946,11 +8036,11 @@ build_lswitch_dhcp_options_and_response(struct ovn_port *op, +@@ -7946,11 +8182,11 @@ build_lswitch_dhcp_options_and_response(struct ovn_port *op, } } @@ -2374,7 +4019,7 @@ index c714227b2..fbc29b554 100644 * (priority 0). */ static void build_lswitch_dhcp_and_dns_defaults(struct ovn_datapath *od, -@@ -7965,7 +8055,7 @@ build_lswitch_dhcp_and_dns_defaults(struct ovn_datapath *od, +@@ -7965,7 +8201,7 @@ build_lswitch_dhcp_and_dns_defaults(struct ovn_datapath *od, } } @@ -2383,7 +4028,7 @@ index c714227b2..fbc29b554 100644 * priority 100 flows. */ static void -@@ -7993,7 +8083,7 @@ build_lswitch_dns_lookup_and_response(struct ovn_datapath *od, +@@ -7993,7 +8229,7 @@ build_lswitch_dns_lookup_and_response(struct ovn_datapath *od, } } @@ -2392,7 +4037,7 @@ index c714227b2..fbc29b554 100644 * external ports on chassis not binding those ports. * This makes the router pipeline to be run only on the chassis * binding the external ports. */ -@@ -8010,7 +8100,7 @@ build_lswitch_external_port(struct ovn_port *op, +@@ -8010,7 +8246,7 @@ build_lswitch_external_port(struct ovn_port *op, } } @@ -2401,7 +4046,7 @@ index c714227b2..fbc29b554 100644 * (priority 70 - 100). */ static void build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od, -@@ -8102,7 +8192,7 @@ build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od, +@@ -8102,7 +8338,7 @@ build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od, } @@ -2410,7 +4055,7 @@ index c714227b2..fbc29b554 100644 * (priority 90). */ static void build_lswitch_ip_mcast_igmp_mld(struct ovn_igmp_group *igmp_group, -@@ -8180,7 +8270,7 @@ build_lswitch_ip_mcast_igmp_mld(struct ovn_igmp_group *igmp_group, +@@ -8180,7 +8416,7 @@ build_lswitch_ip_mcast_igmp_mld(struct ovn_igmp_group *igmp_group, static struct ovs_mutex mcgroup_mutex = OVS_MUTEX_INITIALIZER; @@ -2419,7 +4064,237 @@ index c714227b2..fbc29b554 100644 static void build_lswitch_ip_unicast_lookup(struct ovn_port *op, struct hmap *lflows, -@@ -10675,6 +10765,12 @@ build_neigh_learning_flows_for_lrouter( +@@ -9219,6 +9455,7 @@ find_static_route_outport(struct ovn_datapath *od, const struct hmap *ports, + static void + add_ecmp_symmetric_reply_flows(struct hmap *lflows, + struct ovn_datapath *od, ++ bool ct_masked_mark, + const char *port_ip, + struct ovn_port *out_port, + const struct parsed_route *route, +@@ -9229,6 +9466,9 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows, + struct ds actions = DS_EMPTY_INITIALIZER; + struct ds ecmp_reply = DS_EMPTY_INITIALIZER; + char *cidr = normalize_v46_prefix(&route->prefix, route->plen); ++ const char *ct_ecmp_reply_port_match = ct_masked_mark ++ ? "ct_mark.ecmp_reply_port" ++ : "ct_label.ecmp_reply_port"; + + /* If symmetric ECMP replies are enabled, then packets that arrive over + * an ECMP route need to go through conntrack. +@@ -9257,8 +9497,8 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows, + ds_put_cstr(&match, " && (ct.new && !ct.est)"); + + ds_put_format(&actions, "ct_commit { ct_label.ecmp_reply_eth = eth.src;" +- " ct_label.ecmp_reply_port = %" PRId64 ";}; next;", +- out_port->sb->tunnel_key); ++ " %s = %" PRId64 ";}; next;", ++ ct_ecmp_reply_port_match, out_port->sb->tunnel_key); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100, + ds_cstr(&match), ds_cstr(&actions), + &st_route->header_); +@@ -9266,8 +9506,8 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows, + /* Bypass ECMP selection if we already have ct_label information + * for where to route the packet. + */ +- ds_put_format(&ecmp_reply, "ct.rpl && ct_label.ecmp_reply_port == %" +- PRId64, out_port->sb->tunnel_key); ++ ds_put_format(&ecmp_reply, "ct.rpl && %s == %"PRId64, ++ ct_ecmp_reply_port_match, out_port->sb->tunnel_key); + ds_clear(&match); + ds_put_format(&match, "%s && %s", ds_cstr(&ecmp_reply), + ds_cstr(route_match)); +@@ -9286,7 +9526,18 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows, + ds_cstr(&ecmp_reply), "next;", + &st_route->header_); + +- const char *action = "eth.dst = ct_label.ecmp_reply_eth; next;"; ++ /* Use REG_ECMP_ETH_FULL to pass the eth field from ct_label to eth.dst to ++ * avoid masked access to ct_label. Otherwise it may prevent OVS flow ++ * HW offloading to work for some NICs because masked-access of ct_label is ++ * not supported on those NICs due to HW limitations. ++ * ++ * Use push/pop to save the value of the register before using it and ++ * restore it immediately afterwards, so that the use of the register is ++ * temporary and doesn't interfere with other stages. */ ++ const char *action = "push(" REG_ECMP_ETH_FULL "); " ++ REG_ECMP_ETH_FULL " = ct_label;" ++ " eth.dst = " REG_ECMP_ETH_FIELD ";" ++ " pop(" REG_ECMP_ETH_FULL "); next;"; + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ARP_RESOLVE, + 200, ds_cstr(&ecmp_reply), + action, &st_route->header_); +@@ -9298,7 +9549,8 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows, + + static void + build_ecmp_route_flow(struct hmap *lflows, struct ovn_datapath *od, +- const struct hmap *ports, struct ecmp_groups_node *eg) ++ bool ct_masked_mark, const struct hmap *ports, ++ struct ecmp_groups_node *eg) + + { + bool is_ipv4 = IN6_IS_ADDR_V4MAPPED(&eg->prefix); +@@ -9352,7 +9604,8 @@ build_ecmp_route_flow(struct hmap *lflows, struct ovn_datapath *od, + if (smap_get(&od->nbr->options, "chassis") && + route_->ecmp_symmetric_reply && sset_add(&visited_ports, + out_port->key)) { +- add_ecmp_symmetric_reply_flows(lflows, od, lrp_addr_s, out_port, ++ add_ecmp_symmetric_reply_flows(lflows, od, ct_masked_mark, ++ lrp_addr_s, out_port, + route_, &route_match); + } + ds_clear(&match); +@@ -9547,8 +9800,10 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, + struct ovn_northd_lb_vip *vips_nb, + struct hmap *lflows, + struct ds *match, struct ds *action, +- const struct shash *meter_groups) ++ const struct shash *meter_groups, ++ bool ct_lb_mark) + { ++ const char *ct_natted = ct_lb_mark ? "ct_mark.natted" : "ct_label.natted"; + char *skip_snat_new_action = NULL; + char *skip_snat_est_action = NULL; + char *new_match; +@@ -9558,12 +9813,13 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, + ds_clear(action); + + bool reject = build_lb_vip_actions(lb_vip, vips_nb, action, +- lb->selection_fields, false); ++ lb->selection_fields, false, ++ ct_lb_mark); + + /* Higher priority rules are added for load-balancing in DNAT + * table. For every match (on a VIP[:port]), we add two flows. + * One flow is for specific matching on ct.new with an action +- * of "ct_lb($targets);". The other flow is for ct.est with ++ * of "ct_lb_mark($targets);". The other flow is for ct.est with + * an action of "next;". + */ + if (IN6_IS_ADDR_V4MAPPED(&lb_vip->vip)) { +@@ -9590,13 +9846,13 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, + REG_ORIG_TP_DPORT_ROUTER" == %d", + ds_cstr(match), lb->proto, lb_vip->vip_port); + est_match = xasprintf("ct.est && %s && %s && " +- REG_ORIG_TP_DPORT_ROUTER" == %d && " +- "ct_label.natted == 1", +- ds_cstr(match), lb->proto, lb_vip->vip_port); ++ REG_ORIG_TP_DPORT_ROUTER" == %d && %s == 1", ++ ds_cstr(match), lb->proto, lb_vip->vip_port, ++ ct_natted); + } else { + new_match = xasprintf("ct.new && %s", ds_cstr(match)); +- est_match = xasprintf("ct.est && %s && ct_label.natted == 1", +- ds_cstr(match)); ++ est_match = xasprintf("ct.est && %s && %s == 1", ++ ds_cstr(match), ct_natted); + } + + const char *ip_match = NULL; +@@ -9757,8 +10013,9 @@ next: + + static void + build_lswitch_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows, +- const struct shash *meter_groups, struct ds *match, +- struct ds *action) ++ const struct shash *meter_groups, ++ const struct chassis_features *features, ++ struct ds *match, struct ds *action) + { + if (!lb->n_nb_ls) { + return; +@@ -9794,7 +10051,8 @@ build_lswitch_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows, + * a higher priority rule for load balancing below also commits the + * connection, so it is okay if we do not hit the above match on + * REGBIT_CONNTRACK_COMMIT. */ +- build_lb_rules(lflows, lb, match, action, meter_groups); ++ build_lb_rules(lflows, lb, features->ct_no_masked_label, ++ match, action, meter_groups); + } + + /* If there are any load balancing rules, we should send the packet to +@@ -9864,8 +10122,9 @@ build_lrouter_defrag_flows_for_lb(struct ovn_northd_lb *lb, + + static void + build_lrouter_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows, +- const struct shash *meter_groups, struct ds *match, +- struct ds *action) ++ const struct shash *meter_groups, ++ const struct chassis_features *features, ++ struct ds *match, struct ds *action) + { + if (!lb->n_nb_lr) { + return; +@@ -9875,8 +10134,8 @@ build_lrouter_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows, + struct ovn_lb_vip *lb_vip = &lb->vips[i]; + + build_lrouter_nat_flows_for_lb(lb_vip, lb, &lb->vips_nb[i], +- lflows, match, action, +- meter_groups); ++ lflows, match, action, meter_groups, ++ features->ct_no_masked_label); + + if (!build_empty_lb_event_flow(lb_vip, lb->nlb, match, action)) { + continue; +@@ -10016,7 +10275,7 @@ static inline void + lrouter_nat_add_ext_ip_match(struct ovn_datapath *od, + struct hmap *lflows, struct ds *match, + const struct nbrec_nat *nat, +- bool is_v6, bool is_src, ovs_be32 mask) ++ bool is_v6, bool is_src, int cidr_bits) + { + struct nbrec_address_set *allowed_ext_ips = nat->allowed_ext_ips; + struct nbrec_address_set *exempted_ext_ips = nat->exempted_ext_ips; +@@ -10052,7 +10311,7 @@ lrouter_nat_add_ext_ip_match(struct ovn_datapath *od, + priority = 100 + 2; + } else { + /* S_ROUTER_OUT_SNAT uses priority (mask + 1 + 128 + 1) */ +- priority = count_1bits(ntohl(mask)) + 3; ++ priority = cidr_bits + 3; + + if (!od->is_gw_router) { + priority += 128; +@@ -10492,6 +10751,28 @@ build_adm_ctrl_flows_for_lrouter( + } + } + ++static int ++build_gateway_get_l2_hdr_size(struct ovn_port *op) ++{ ++ struct ovn_port *peer = op->peer; ++ ++ if (peer && peer->od && peer->od->nbs) { ++ /* Check if vlans are enabled on a localnet port running the logical ++ * switch connected to this logical router. ++ */ ++ for (size_t i = 0; i < peer->od->n_localnet_ports; i++) { ++ struct ovn_port *localnet_port = peer->od->localnet_ports[i]; ++ const struct nbrec_logical_switch_port *nbsp = localnet_port->nbsp; ++ ++ if (nbsp && nbsp->n_tag_request > 0) { ++ return VLAN_ETH_HEADER_LEN; ++ } ++ } ++ } ++ ++ return ETH_HEADER_LEN; ++} ++ + /* All 'gateway_mtu' and 'gateway_mtu_bypass' flows should be built with this + * function. + */ +@@ -10509,8 +10790,9 @@ build_gateway_mtu_flow(struct hmap *lflows, struct ovn_port *op, + + ds_clear(actions); + if (gw_mtu > 0) { ++ int l2_hdr_size = build_gateway_get_l2_hdr_size(op); + ds_put_format(actions, REGBIT_PKT_LARGER" = check_pkt_larger(%d); ", +- gw_mtu + VLAN_ETH_HEADER_LEN); ++ gw_mtu + l2_hdr_size); + } + + ds_put_format_valist(actions, extra_actions_fmt, extra_actions_args); +@@ -10675,6 +10957,12 @@ build_neigh_learning_flows_for_lrouter( copp_meter_get(COPP_ARP, od->nbr->copp, meter_groups)); @@ -2432,7 +4307,7 @@ index c714227b2..fbc29b554 100644 ovn_lflow_metered(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90, "nd_na", "put_nd(inport, nd.target, nd.tll); next;", copp_meter_get(COPP_ND_NA, od->nbr->copp, -@@ -10767,34 +10863,6 @@ build_ND_RA_flows_for_lrouter_port( +@@ -10767,34 +11055,6 @@ build_ND_RA_flows_for_lrouter_port( return; } @@ -2467,7 +4342,7 @@ index c714227b2..fbc29b554 100644 const char *address_mode = smap_get( &op->nbrp->ipv6_ra_configs, "address_mode"); -@@ -10810,11 +10878,6 @@ build_ND_RA_flows_for_lrouter_port( +@@ -10810,11 +11070,6 @@ build_ND_RA_flows_for_lrouter_port( return; } @@ -2479,7 +4354,7 @@ index c714227b2..fbc29b554 100644 ds_clear(match); ds_put_format(match, "inport == %s && ip6.dst == ff02::2 && nd_rs", op->json_key); -@@ -10839,6 +10902,22 @@ build_ND_RA_flows_for_lrouter_port( +@@ -10839,6 +11094,22 @@ build_ND_RA_flows_for_lrouter_port( ds_put_format(actions, ", router_preference = \"%s\"", prf); } @@ -2502,7 +4377,174 @@ index c714227b2..fbc29b554 100644 bool add_rs_response_flow = false; for (size_t i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { -@@ -13055,6 +13134,18 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, +@@ -10972,8 +11243,9 @@ build_ip_routing_flows_for_lrouter_port( + + static void + build_static_route_flows_for_lrouter( +- struct ovn_datapath *od, struct hmap *lflows, +- const struct hmap *ports, const struct hmap *bfd_connections) ++ struct ovn_datapath *od, const struct chassis_features *features, ++ struct hmap *lflows, const struct hmap *ports, ++ const struct hmap *bfd_connections) + { + if (od->nbr) { + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP, 150, +@@ -11016,7 +11288,8 @@ build_static_route_flows_for_lrouter( + HMAP_FOR_EACH (group, hmap_node, &ecmp_groups) { + /* add a flow in IP_ROUTING, and one flow for each member in + * IP_ROUTING_ECMP. */ +- build_ecmp_route_flow(lflows, od, ports, group); ++ build_ecmp_route_flow(lflows, od, features->ct_no_masked_label, ++ ports, group); + } + const struct unique_routes_node *ur; + HMAP_FOR_EACH (ur, hmap_node, &unique_routes) { +@@ -11696,6 +11969,7 @@ build_gateway_redirect_flows_for_lrouter( + } + for (size_t i = 0; i < od->n_l3dgw_ports; i++) { + const struct ovsdb_idl_row *stage_hint = NULL; ++ bool add_def_flow = true; + + if (od->l3dgw_ports[i]->nbrp) { + stage_hint = &od->l3dgw_ports[i]->nbrp->header_; +@@ -11714,7 +11988,44 @@ build_gateway_redirect_flows_for_lrouter( + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, 50, + ds_cstr(match), ds_cstr(actions), + stage_hint); ++ for (int j = 0; j < od->n_nat_entries; j++) { ++ const struct ovn_nat *nat = &od->nat_entries[j]; ++ ++ if (!lrouter_nat_is_stateless(nat->nb) || ++ strcmp(nat->nb->type, "dnat_and_snat") || ++ (!nat->nb->allowed_ext_ips && !nat->nb->exempted_ext_ips)) { ++ continue; ++ } ++ ++ struct ds match_ext = DS_EMPTY_INITIALIZER; ++ struct nbrec_address_set *as = nat->nb->allowed_ext_ips ++ ? nat->nb->allowed_ext_ips : nat->nb->exempted_ext_ips; ++ ds_put_format(&match_ext, "%s && ip%s.src == $%s", ++ ds_cstr(match), nat_entry_is_v6(nat) ? "6" : "4", ++ as->name); ++ ++ if (nat->nb->allowed_ext_ips) { ++ ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, ++ 75, ds_cstr(&match_ext), ++ ds_cstr(actions), stage_hint); ++ if (add_def_flow) { ++ ds_clear(&match_ext); ++ ds_put_format(&match_ext, "ip && ip%s.dst == %s", ++ nat_entry_is_v6(nat) ? "6" : "4", ++ nat->nb->external_ip); ++ ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 70, ++ ds_cstr(&match_ext), "drop;"); ++ add_def_flow = false; ++ } ++ } else if (nat->nb->exempted_ext_ips) { ++ ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, ++ 75, ds_cstr(&match_ext), "drop;", ++ stage_hint); ++ } ++ ds_destroy(&match_ext); ++ } + } ++ + /* Packets are allowed by default. */ + ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 0, "1", "next;"); + } +@@ -12453,8 +12764,7 @@ build_lrouter_in_unsnat_flow(struct hmap *lflows, struct ovn_datapath *od, + ds_put_format(match, "ip && ip%s.dst == %s", + is_v6 ? "6" : "4", nat->external_ip); + if (!strcmp(nat->type, "dnat_and_snat") && stateless) { +- ds_put_format(actions, "ip%s.dst=%s; next;", +- is_v6 ? "6" : "4", nat->logical_ip); ++ ds_put_format(actions, "next;"); + } else { + ds_put_cstr(actions, "ct_snat;"); + } +@@ -12479,8 +12789,7 @@ build_lrouter_in_unsnat_flow(struct hmap *lflows, struct ovn_datapath *od, + } + + if (!strcmp(nat->type, "dnat_and_snat") && stateless) { +- ds_put_format(actions, "ip%s.dst=%s; next;", +- is_v6 ? "6" : "4", nat->logical_ip); ++ ds_put_format(actions, "next;"); + } else { + ds_put_cstr(actions, "ct_snat_in_czone;"); + } +@@ -12514,7 +12823,7 @@ static void + build_lrouter_in_dnat_flow(struct hmap *lflows, struct ovn_datapath *od, + const struct nbrec_nat *nat, struct ds *match, + struct ds *actions, bool distributed, +- ovs_be32 mask, bool is_v6) ++ int cidr_bits, bool is_v6) + { + /* Ingress DNAT table: Packets enter the pipeline with destination + * IP address that needs to be DNATted from a external IP address +@@ -12532,7 +12841,7 @@ build_lrouter_in_dnat_flow(struct hmap *lflows, struct ovn_datapath *od, + ds_clear(actions); + if (nat->allowed_ext_ips || nat->exempted_ext_ips) { + lrouter_nat_add_ext_ip_match(od, lflows, match, nat, +- is_v6, true, mask); ++ is_v6, true, cidr_bits); + } + + if (!lport_addresses_is_empty(&od->dnat_force_snat_addrs)) { +@@ -12576,7 +12885,7 @@ build_lrouter_in_dnat_flow(struct hmap *lflows, struct ovn_datapath *od, + ds_clear(actions); + if (nat->allowed_ext_ips || nat->exempted_ext_ips) { + lrouter_nat_add_ext_ip_match(od, lflows, match, nat, +- is_v6, true, mask); ++ is_v6, true, cidr_bits); + } + + if (!strcmp(nat->type, "dnat_and_snat") && stateless) { +@@ -12633,8 +12942,7 @@ build_lrouter_out_undnat_flow(struct hmap *lflows, struct ovn_datapath *od, + + if (!strcmp(nat->type, "dnat_and_snat") && + lrouter_nat_is_stateless(nat)) { +- ds_put_format(actions, "ip%s.src=%s; next;", +- is_v6 ? "6" : "4", nat->external_ip); ++ ds_put_format(actions, "next;"); + } else { + ds_put_format(actions, + od->is_gw_router ? "ct_dnat;" : "ct_dnat_in_czone;"); +@@ -12679,8 +12987,7 @@ static void + build_lrouter_out_snat_flow(struct hmap *lflows, struct ovn_datapath *od, + const struct nbrec_nat *nat, struct ds *match, + struct ds *actions, bool distributed, +- struct eth_addr mac, ovs_be32 mask, +- int cidr_bits, bool is_v6) ++ struct eth_addr mac, int cidr_bits, bool is_v6) + { + /* Egress SNAT table: Packets enter the egress pipeline with + * source ip address that needs to be SNATted to a external ip +@@ -12698,13 +13005,14 @@ build_lrouter_out_snat_flow(struct hmap *lflows, struct ovn_datapath *od, + + if (nat->allowed_ext_ips || nat->exempted_ext_ips) { + lrouter_nat_add_ext_ip_match(od, lflows, match, nat, +- is_v6, false, mask); ++ is_v6, false, cidr_bits); + } + + if (!strcmp(nat->type, "dnat_and_snat") && stateless) { + ds_put_format(actions, "ip%s.src=%s; next;", + is_v6 ? "6" : "4", nat->external_ip); + } else { ++ ds_put_format(match, " && (!ct.trk || !ct.rpl)"); + ds_put_format(actions, "ct_snat(%s", nat->external_ip); + + if (nat->external_port_range[0]) { +@@ -12746,7 +13054,7 @@ build_lrouter_out_snat_flow(struct hmap *lflows, struct ovn_datapath *od, + + if (nat->allowed_ext_ips || nat->exempted_ext_ips) { + lrouter_nat_add_ext_ip_match(od, lflows, match, nat, +- is_v6, false, mask); ++ is_v6, false, cidr_bits); + } + + if (distributed) { +@@ -13055,6 +13363,18 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, return; } @@ -2521,7 +4563,158 @@ index c714227b2..fbc29b554 100644 struct sset nat_entries = SSET_INITIALIZER(&nat_entries); bool dnat_force_snat_ip = -@@ -14948,6 +15039,7 @@ ovnnb_db_run(struct northd_input *input_data, +@@ -13079,7 +13399,7 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, + is_v6); + /* S_ROUTER_IN_DNAT */ + build_lrouter_in_dnat_flow(lflows, od, nat, match, actions, distributed, +- mask, is_v6); ++ cidr_bits, is_v6); + + /* ARP resolve for NAT IPs. */ + if (od->is_gw_router) { +@@ -13118,7 +13438,7 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, + mac, is_v6); + /* S_ROUTER_OUT_SNAT */ + build_lrouter_out_snat_flow(lflows, od, nat, match, actions, distributed, +- mac, mask, cidr_bits, is_v6); ++ mac, cidr_bits, is_v6); + + /* S_ROUTER_IN_ADMISSION - S_ROUTER_IN_IP_INPUT */ + build_lrouter_ingress_flow(lflows, od, nat, match, actions, +@@ -13241,6 +13561,7 @@ struct lswitch_flow_build_info { + const struct shash *meter_groups; + const struct hmap *lbs; + const struct hmap *bfd_connections; ++ const struct chassis_features *features; + char *svc_check_match; + struct ds match; + struct ds actions; +@@ -13259,7 +13580,9 @@ build_lswitch_and_lrouter_iterate_by_od(struct ovn_datapath *od, + struct lswitch_flow_build_info *lsi) + { + /* Build Logical Switch Flows. */ +- build_lswitch_lflows_pre_acl_and_acl(od, lsi->port_groups, lsi->lflows, ++ build_lswitch_lflows_pre_acl_and_acl(od, lsi->port_groups, ++ lsi->features, ++ lsi->lflows, + lsi->meter_groups); + + build_fwd_group_lflows(od, lsi->lflows); +@@ -13279,7 +13602,8 @@ build_lswitch_and_lrouter_iterate_by_od(struct ovn_datapath *od, + &lsi->actions, lsi->meter_groups); + build_ND_RA_flows_for_lrouter(od, lsi->lflows); + build_ip_routing_pre_flows_for_lrouter(od, lsi->lflows); +- build_static_route_flows_for_lrouter(od, lsi->lflows, lsi->ports, ++ build_static_route_flows_for_lrouter(od, lsi->features, ++ lsi->lflows, lsi->ports, + lsi->bfd_connections); + build_mcast_lookup_flows_for_lrouter(od, lsi->lflows, &lsi->match, + &lsi->actions); +@@ -13409,10 +13733,12 @@ build_lflows_thread(void *arg) + build_lrouter_defrag_flows_for_lb(lb, lsi->lflows, + &lsi->match); + build_lrouter_flows_for_lb(lb, lsi->lflows, +- lsi->meter_groups, &lsi->match, +- &lsi->actions); ++ lsi->meter_groups, ++ lsi->features, ++ &lsi->match, &lsi->actions); + build_lswitch_flows_for_lb(lb, lsi->lflows, + lsi->meter_groups, ++ lsi->features, + &lsi->match, &lsi->actions); + } + } +@@ -13504,7 +13830,8 @@ build_lswitch_and_lrouter_flows(const struct hmap *datapaths, + struct hmap *igmp_groups, + const struct shash *meter_groups, + const struct hmap *lbs, +- const struct hmap *bfd_connections) ++ const struct hmap *bfd_connections, ++ const struct chassis_features *features) + { + + char *svc_check_match = xasprintf("eth.dst == %s", svc_monitor_mac); +@@ -13548,6 +13875,7 @@ build_lswitch_and_lrouter_flows(const struct hmap *datapaths, + lsiv[index].meter_groups = meter_groups; + lsiv[index].lbs = lbs; + lsiv[index].bfd_connections = bfd_connections; ++ lsiv[index].features = features; + lsiv[index].svc_check_match = svc_check_match; + lsiv[index].thread_lflow_counter = 0; + ds_init(&lsiv[index].match); +@@ -13586,6 +13914,7 @@ build_lswitch_and_lrouter_flows(const struct hmap *datapaths, + .meter_groups = meter_groups, + .lbs = lbs, + .bfd_connections = bfd_connections, ++ .features = features, + .svc_check_match = svc_check_match, + .match = DS_EMPTY_INITIALIZER, + .actions = DS_EMPTY_INITIALIZER, +@@ -13611,9 +13940,9 @@ build_lswitch_and_lrouter_flows(const struct hmap *datapaths, + &lsi.match); + build_lrouter_defrag_flows_for_lb(lb, lsi.lflows, &lsi.match); + build_lrouter_flows_for_lb(lb, lsi.lflows, lsi.meter_groups, +- &lsi.match, &lsi.actions); ++ lsi.features, &lsi.match, &lsi.actions); + build_lswitch_flows_for_lb(lb, lsi.lflows, lsi.meter_groups, +- &lsi.match, &lsi.actions); ++ lsi.features, &lsi.match, &lsi.actions); + } + stopwatch_stop(LFLOWS_LBS_STOPWATCH_NAME, time_msec()); + stopwatch_start(LFLOWS_IGMP_STOPWATCH_NAME, time_msec()); +@@ -13745,7 +14074,8 @@ void build_lflows(struct lflow_input *input_data, + input_data->port_groups, &lflows, + &mcast_groups, &igmp_groups, + input_data->meter_groups, input_data->lbs, +- input_data->bfd_connections); ++ input_data->bfd_connections, ++ input_data->features); + + /* Parallel build may result in a suboptimal hash. Resize the + * hash to a correct size before doing lookups */ +@@ -14801,6 +15131,7 @@ northd_init(struct northd_data *data) + hmap_init(&data->lbs); + hmap_init(&data->bfd_connections); + ovs_list_init(&data->lr_list); ++ memset(&data->features, 0, sizeof data->features); + data->ovn_internal_version_changed = false; + } + +@@ -14861,15 +15192,6 @@ ovnnb_db_run(struct northd_input *input_data, + if (!nb) { + nb = nbrec_nb_global_insert(ovnnb_txn); + } +- const struct sbrec_sb_global *sb = sbrec_sb_global_table_first( +- input_data->sbrec_sb_global_table); +- if (!sb) { +- sb = sbrec_sb_global_insert(ovnsb_txn); +- } +- if (nb->ipsec != sb->ipsec) { +- sbrec_sb_global_set_ipsec(sb, nb->ipsec); +- } +- sbrec_sb_global_set_options(sb, &nb->options); + + const char *mac_addr_prefix = set_mac_prefix(smap_get(&nb->options, + "mac_prefix")); +@@ -14915,8 +15237,6 @@ ovnnb_db_run(struct northd_input *input_data, + nbrec_nb_global_set_options(nb, &options); + } + +- smap_destroy(&options); +- + use_parallel_build = + (smap_get_bool(&nb->options, "use_parallel_build", false) && + can_parallelize_hashes(false)); +@@ -14932,6 +15252,7 @@ ovnnb_db_run(struct northd_input *input_data, + check_lsp_is_up = !smap_get_bool(&nb->options, + "ignore_lsp_down", true); + ++ build_chassis_features(input_data, &data->features); + build_datapaths(input_data, ovnsb_txn, &data->datapaths, &data->lr_list); + build_ovn_lbs(input_data, ovnsb_txn, &data->datapaths, &data->lbs); + build_lrouter_lbs(&data->datapaths, &data->lbs); +@@ -14948,6 +15269,7 @@ ovnnb_db_run(struct northd_input *input_data, build_meter_groups(input_data, &data->meter_groups); stopwatch_stop(BUILD_LFLOWS_CTX_STOPWATCH_NAME, time_msec()); stopwatch_start(CLEAR_LFLOWS_CTX_STOPWATCH_NAME, time_msec()); @@ -2529,10 +4722,86 @@ index c714227b2..fbc29b554 100644 ovn_update_ipv6_prefix(&data->ports); sync_address_sets(input_data, ovnsb_txn, &data->datapaths); +@@ -14956,6 +15278,26 @@ ovnnb_db_run(struct northd_input *input_data, + sync_dns_entries(input_data, ovnsb_txn, &data->datapaths); + cleanup_stale_fdp_entries(input_data, &data->datapaths); + stopwatch_stop(CLEAR_LFLOWS_CTX_STOPWATCH_NAME, time_msec()); ++ ++ /* Set up SB_Global (depends on chassis features). */ ++ const struct sbrec_sb_global *sb = sbrec_sb_global_table_first( ++ input_data->sbrec_sb_global_table); ++ if (!sb) { ++ sb = sbrec_sb_global_insert(ovnsb_txn); ++ } ++ if (nb->ipsec != sb->ipsec) { ++ sbrec_sb_global_set_ipsec(sb, nb->ipsec); ++ } ++ ++ /* Inform ovn-controllers whether LB flows will use ct_mark ++ * (i.e., only if all chassis support it). ++ */ ++ smap_replace(&options, "lb_hairpin_use_ct_mark", ++ data->features.ct_no_masked_label ? "true" : "false"); ++ if (!smap_equal(&sb->options, &options)) { ++ sbrec_sb_global_set_options(sb, &options); ++ } ++ smap_destroy(&options); + } + + /* Stores the list of chassis which references an ha_chassis_group. +diff --git a/northd/northd.h b/northd/northd.h +index ebcb40de7..0d9c7b802 100644 +--- a/northd/northd.h ++++ b/northd/northd.h +@@ -53,6 +53,10 @@ struct northd_input { + struct ovsdb_idl_index *sbrec_ip_mcast_by_dp; + }; + ++struct chassis_features { ++ bool ct_no_masked_label; ++}; ++ + struct northd_data { + /* Global state for 'en-northd'. */ + struct hmap datapaths; +@@ -63,6 +67,7 @@ struct northd_data { + struct hmap bfd_connections; + struct ovs_list lr_list; + bool ovn_internal_version_changed; ++ struct chassis_features features; + }; + + struct lflow_input { +@@ -84,6 +89,7 @@ struct lflow_input { + const struct shash *meter_groups; + const struct hmap *lbs; + const struct hmap *bfd_connections; ++ const struct chassis_features *features; + bool ovn_internal_version_changed; + }; + diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml -index 79f35bc16..ad79a32d2 100644 +index 79f35bc16..f2cee69d2 100644 --- a/northd/ovn-northd.8.xml +++ b/northd/ovn-northd.8.xml +@@ -550,7 +550,7 @@ +
    +
  • + Priority-120 flows that send the packets to connection tracker using +- ct_lb; as the action so that the already established ++ ct_lb_mark; as the action so that the already established + traffic destined to the load balancer VIP gets DNATted based on a hint + provided by the previous tables (with a match + for reg0[2] == 1 and on supported load balancer protocols +@@ -565,7 +565,7 @@ + A priority-110 flow sends the packets to connection tracker based + on a hint provided by the previous tables + (with a match for reg0[2] == 1) by using the +- ct_lb; action. This flow is added to handle ++ ct_lb_mark; action. This flow is added to handle + the traffic for load balancer VIPs whose protocol is not defined + (mainly for ICMP traffic). +
  • @@ -663,15 +663,16 @@
@@ -2555,17 +4824,42 @@ index 79f35bc16..ad79a32d2 100644

  • -@@ -746,7 +747,9 @@ +@@ -740,20 +741,22 @@ + A priority-65532 flow that allows any traffic in the reply + direction for a connection that has been committed to the + connection tracker (i.e., established flows), as long as +- the committed flow does not have ct_label.blocked set. ++ the committed flow does not have ct_mark.blocked set. + We only handle traffic in the reply direction here because + we want all packets going in the request direction to still go through the flows that implement the currently defined policy based on ACLs. If a connection is no longer allowed by - policy, ct_label.blocked will get set and packets in the +- policy, ct_label.blocked will get set and packets in the - reply direction will no longer be allowed, either. ++ policy, ct_mark.blocked will get set and packets in the + reply direction will no longer be allowed, either. This flow also + clears the register bits reg0[9] and + reg0[10].
  • + A priority-65532 flow that allows any traffic that is considered + related to a committed flow in the connection tracker (e.g., an + ICMP Port Unreachable from a non-listening UDP port), as long +- as the committed flow does not have ct_label.blocked set. ++ as the committed flow does not have ct_mark.blocked set. +
  • + +
  • +@@ -763,7 +766,7 @@ + +
  • + A priority-65532 flow that drops all traffic in the reply direction +- with ct_label.blocked set meaning that the connection ++ with ct_mark.blocked set meaning that the connection + should no longer be allowed due to a policy change. Packets + in the request direction are skipped here to let a newly created + ACL re-allow this connection. @@ -838,7 +841,7 @@
@@ -2575,6 +4869,24 @@ index 79f35bc16..ad79a32d2 100644
  • +@@ -851,7 +854,7 @@ + P.dst == PORT. For IPv6 VIPs, + the flow matches ct.new && ip && ip6.dst == + VIP && P && P.dst == +- PORT. The flow's action is ct_lb(args) ++ PORT. The flow's action is 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 args is the same as the address family +@@ -872,7 +875,7 @@ + ip4.dst == VIP. For IPv6 VIPs, + the flow matches ct.new && ip && ip6.dst == + VIP. The action on this flow is +- ct_lb(args), where args contains comma ++ ct_lb_mark(args), where args contains comma + separated IP addresses of the same address family as VIP. + For IPv4 traffic the flow also loads the original destination + IP and transport port in registers reg1 and @@ -889,7 +892,73 @@ Please note using --reject option will disable empty_lb SB controller event for this load balancer. @@ -2582,7 +4894,7 @@ index 79f35bc16..ad79a32d2 100644 +
+ +

Ingress table 13: from-lport ACLs after LB

-+ + +

+ Logical flows in this table closely reproduce those in the + ACL table in the OVN_Northbound database @@ -2592,7 +4904,7 @@ index 79f35bc16..ad79a32d2 100644 + limited range and have 1000 added to them to leave room for OVN default + flows at both higher and lower priorities. +

- ++ +
    +
  • + allow apply-after-lb ACLs translate into logical flows @@ -2748,6 +5060,20 @@ index 79f35bc16..ad79a32d2 100644

    This table handles the packets whose destination was not found or +@@ -1806,11 +1875,11 @@ output; +

      +
    • + A Priority-120 flow that send the packets to connection tracker using +- ct_lb; as the action so that the already established ++ ct_lb_mark; as the action so that the already established + traffic gets unDNATted from the backend IP to the load balancer VIP + based on a hint provided by the previous tables with a match + for reg0[2] == 1. If the packet was not DNATted earlier, +- then ct_lb functions like ct_next. ++ then ct_lb_mark functions like ct_next. +
    • + +
    • @@ -2178,6 +2247,12 @@ next; put_arp(inport, arp.spa, arp.sha); next;
    • @@ -2761,32 +5087,182 @@ index 79f35bc16..ad79a32d2 100644
    • A priority-90 flow with the match nd_na and applies the action -diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c -index 2b58bfcec..c56b29f2a 100644 ---- a/northd/ovn-northd.c -+++ b/northd/ovn-northd.c -@@ -513,14 +513,6 @@ update_sequence_numbers(int64_t loop_start_time, - } - - static void --add_column_noalert(struct ovsdb_idl *idl, -- const struct ovsdb_idl_column *column) --{ -- ovsdb_idl_add_column(idl, column); -- ovsdb_idl_omit_alert(idl, column); --} -- --static void - usage(void) - { - printf("\ -@@ -730,255 +722,10 @@ main(int argc, char *argv[]) - unixctl_command_register("nb-connection-status", "", 0, 0, - ovn_conn_show, ovnnb_idl_loop.idl); +@@ -2852,8 +2927,7 @@ icmp6 { + ip && ip6.dst == B + with an action ct_snat; . If the NAT rule is of type + dnat_and_snat and has stateless=true in the +- options, then the action would be ip4/6.dst= +- (B). ++ options, then the action would be next;. +

      -- /* We want to detect only selected changes to the ovn-sb db. */ -+ /* We want to detect all changes to the ovn-sb db. */ - struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER( +

      +@@ -2892,7 +2966,7 @@ icmp6 { + action ct_snat_in_czone; to unSNAT in the common + zone. If the NAT rule is of type dnat_and_snat and has + stateless=true in the options, then the action +- would be ip4/6.dst=(B). ++ would be next;. +

      + +

      +@@ -3026,14 +3100,14 @@ icmp6 { + && P && reg9[16..31] == + PORT (xxreg0 == VIP + in the IPv6 case) with an action of +- ct_lb(args), where args contains ++ ct_lb_mark(args), where args contains + comma separated IPv4 or IPv6 addresses (and optional port numbers) to + load balance to. If the router is configured to force SNAT any + load-balanced packets, the above action will be replaced by +- flags.force_snat_for_lb = 1; ct_lb(args);. ++ flags.force_snat_for_lb = 1; ct_lb_mark(args);. + If the load balancing rule is configured with skip_snat + set to true, the above action will be replaced by +- flags.skip_snat_for_lb = 1; ct_lb(args);. ++ flags.skip_snat_for_lb = 1; ct_lb_mark(args);. + If health check is enabled, then + args will only contain those endpoints whose service + monitor status entry in OVN_Southbound db is +@@ -3082,14 +3156,14 @@ icmp6 { + ct.new && ip4 && reg0 == + VIP (ip6 and xxreg0 == + VIP in the IPv6 case) with an action of +- ct_lb(args), where args contains ++ ct_lb_mark(args), where args contains + comma separated IPv4 or IPv6 addresses. If the router is configured + to force SNAT any load-balanced packets, the above action will be + replaced by flags.force_snat_for_lb = 1; +- ct_lb(args);. ++ ct_lb_mark(args);. + If the load balancing rule is configured with skip_snat + set to true, the above action will be replaced by +- flags.skip_snat_for_lb = 1; ct_lb(args);. ++ flags.skip_snat_for_lb = 1; ct_lb_mark(args);. +

      + +

      +@@ -3242,7 +3316,7 @@ icmp6 { + route with a destination routing policy will instead match if the + source IP address matches the static route's prefix. The flow uses + the action ct_commit { ct_label.ecmp_reply_eth = eth.src;" +- " ct_label.ecmp_reply_port = K;}; next; to commit ++ " ct_mark.ecmp_reply_port = K;}; next; to commit + the connection and storing eth.src and the ECMP + reply port binding tunnel key K in the + ct_label. +@@ -3379,12 +3453,15 @@ output; + reg8[16..31]. This step is skipped with a priority-10300 + rule if the traffic going out the ECMP route is reply traffic, and the + ECMP route was configured to use symmetric replies. Instead, the stored +- ct_label value is used to choose the destination. The least +- significant 48 bits of the ct_label tell the destination MAC +- address to which the packet should be sent. The next 16 bits tell the +- logical router port on which the packet should be sent. These values in +- the ct_label are set when the initial ingress traffic is +- received over the ECMP route. ++ values in conntrack is used to choose the destination. The ++ ct_label.ecmp_reply_eth tells the destination MAC address to ++ which the packet should be sent. The ct_mark.ecmp_reply_port ++ tells the logical router port on which the packet should be sent. These ++ values saved to the conntrack fields when the initial ingress traffic is ++ received over the ECMP route and committed to conntrack. The ++ priority-10300 flows in this stage set the outport, ++ while the eth.dst is set by flows at the ARP/ND Resolution ++ stage. +

      + +

      +@@ -3722,6 +3799,16 @@ outport = P +

      +
    • + ++
    • ++

      ++ Priority-200 flows that match ECMP reply traffic for the routes ++ configured to use symmetric replies, with actions ++ push(xxreg1); xxreg1 = ct_label; eth.dst = xxreg1[32..79]; pop(xxreg1); next;. ++ xxreg1 is used here to avoid masked access to ct_label, ++ to make the flow HW-offloading friendly. ++

      ++
    • ++ +
    • +

      + Static MAC bindings. MAC bindings can be known statically based on +@@ -4013,6 +4100,26 @@ icmp6 { + external ip and D is NAT external mac. +

    • + ++
    • ++ For each dnat_and_snat NAT rule with ++ stateless=true and allowed_ext_ips ++ configured, a priority-75 flow is programmed with match ++ ip4.dst == B and action ++ outport = CR; next; where B ++ is the NAT rule external IP and CR is the ++ chassisredirect port representing the instance ++ of the logical router distributed gateway port on the ++ gateway chassis. Moreover a priority-70 flow is programmed ++ with same match and action drop;. ++ For each dnat_and_snat NAT rule with ++ stateless=true and exempted_ext_ips ++ configured, a priority-75 flow is programmed with match ++ ip4.dst == B and action ++ drop; where B is the NAT rule ++ external IP. ++ A similar flow is added for IPv6 traffic. ++
    • ++ +
    • + For each NAT rule in the OVN Northbound database that can + be handled in a distributed manner, a priority-80 logical flow +@@ -4211,8 +4318,7 @@ nd_ns { + is the logical router gateway port, with an action + ct_dnat_in_czone;. If the NAT rule is of type + dnat_and_snat and has stateless=true in the +- options, then the action would be ip4/6.src= +- (B). ++ options, then the action would be next;. +

      + +

      +@@ -4329,7 +4435,8 @@ nd_ns { + to change the source IP address of a packet from an IP address of + A or to change the source IP address of a packet that + belongs to network A to B, a flow matches +- ip && ip4.src == A with an action ++ ip && ip4.src == A && ++ (!ct.trk || !ct.rpl) with an action + ct_snat(B);. The priority of the flow + is calculated based on the mask of A, with matches + having larger masks getting higher priorities. If the NAT rule is +diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c +index 2b58bfcec..c56b29f2a 100644 +--- a/northd/ovn-northd.c ++++ b/northd/ovn-northd.c +@@ -513,14 +513,6 @@ update_sequence_numbers(int64_t loop_start_time, + } + + static void +-add_column_noalert(struct ovsdb_idl *idl, +- const struct ovsdb_idl_column *column) +-{ +- ovsdb_idl_add_column(idl, column); +- ovsdb_idl_omit_alert(idl, column); +-} +- +-static void + usage(void) + { + printf("\ +@@ -730,255 +722,10 @@ main(int argc, char *argv[]) + unixctl_command_register("nb-connection-status", "", 0, 0, + ovn_conn_show, ovnnb_idl_loop.idl); + +- /* We want to detect only selected changes to the ovn-sb db. */ ++ /* We want to detect all changes to the ovn-sb db. */ + struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER( ovsdb_idl_create(ovnsb_db, &sbrec_idl_class, true, true)); - ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_sb_global); - add_column_noalert(ovnsb_idl_loop.idl, &sbrec_sb_global_col_nb_cfg); @@ -3121,7 +5597,7 @@ index 55977339a..9dd31197e 100644 "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}, diff --git a/ovn-nb.xml b/ovn-nb.xml -index 6a6972856..c705b89ea 100644 +index 6a6972856..c72e251be 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -925,6 +925,15 @@ @@ -3176,6 +5652,124 @@ index 6a6972856..c705b89ea 100644

      These columns control whether and how OVN logs packets that match an +@@ -2290,9 +2328,9 @@ + with the highest- + will have QoS applied to it. If the column is + specified, then matching packets will have DSCP marking applied. +- If the column is specified, then matching ++ If the column is specified, then matching + packets will have metering applied. and +- are not exclusive, so both marking and ++ are not exclusive, so both marking and + metering by defined for the same QoS entry. If no row matches, + packets will not have any QoS applied. +

      +diff --git a/ovn-sb.xml b/ovn-sb.xml +index 9ddacdf09..8c852db93 100644 +--- a/ovn-sb.xml ++++ b/ovn-sb.xml +@@ -199,6 +199,22 @@ + tunnel interfaces. + + ++ ++ ++

      ++ These options apply when ovn-controller configures ++ load balancer related flows. ++

      ++ ++ ++ This value is automatically set to true by ++ ovn-northd when action ct_lb_mark is used ++ for new load balancer sessions. ovn-controller then ++ knows that it should check ct_mark.natted to detect ++ load balanced traffic. ++ ++
      ++ + + + +@@ -1271,6 +1287,21 @@ +

      + + ++
      push(field);
      ++
      ++

      ++ Push the value of field to the stack top. ++

      ++
      ++ ++
      pop(field);
      ++
      ++

      ++ Pop the stack top and store the value to field, ++ which must be modifiable. ++

      ++
      ++ +
      ip.ttl--;
      +
      +

      +@@ -1955,21 +1986,19 @@ +

      + +
      ct_lb;
      +-
      ct_lb(ip[:port]...);
      ++
      ct_lb(backends=ip[:port][,...][; hash_fields=field1,field2,...]);
      +
      +

      +- With one or more arguments, ct_lb commits the packet ++ With arguments, ct_lb commits the packet + to the connection tracking table and DNATs the packet's destination + IP address (and port) to the IP address or addresses (and optional +- ports) specified in the string. If multiple comma-separated IP +- addresses are specified, each is given equal weight for picking the +- DNAT address. Processing automatically moves on to the next table, +- as if next; were specified, and later tables act on +- the packet as modified by the connection tracker. Connection +- tracking state is scoped by the logical port when the action is +- used in a flow for a logical switch, so overlapping +- addresses may be used. Connection tracking state is scoped by the +- logical topology when the action is used in a flow for a router. ++ ports) specified in the backends. If multiple ++ comma-separated IP addresses are specified, each is given equal ++ weight for picking the DNAT address. By default, ++ dp_hash is used as the OpenFlow group selection ++ method, but if hash_fields is specified, ++ hash is used as the selection method, and the fields ++ listed are used as the hash fields. +

      +

      + Without arguments, ct_lb sends the packet to the +@@ -1979,6 +2008,25 @@ + will automatically get DNATed to the same IP address as the first + packet in that connection. +

      ++

      ++ Processing automatically moves on to the next table, ++ as if next; were specified, and later tables act on ++ the packet as modified by the connection tracker. Connection ++ tracking state is scoped by the logical port when the action is ++ used in a flow for a logical switch, so overlapping ++ addresses may be used. Connection tracking state is scoped by the ++ logical topology when the action is used in a flow for a router. ++

      ++
      ++ ++
      ct_lb_mark;
      ++
      ct_lb_mark(backends=ip[:port][,...][; hash_fields=field1,field2,...]);
      ++
      ++

      ++ Same as ct_lb, except that it internally uses ct_mark ++ to store the NAT flag, while ct_lb uses ct_label for ++ the same purpose. ++

      +
      + +
      diff --git a/rhel/ovn-fedora.spec.in b/rhel/ovn-fedora.spec.in index 3fb854a37..821eb03cc 100644 --- a/rhel/ovn-fedora.spec.in @@ -3223,6 +5817,143 @@ index b76fa5cef..08e1d13e7 100644 # deletes the chassis via ovn-sbctl and check that it is readded back # with the log. AT_CHECK([ovn-sbctl chassis-del br-vtep]) +diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at +index 2f39e5f3e..bf76671de 100644 +--- a/tests/ovn-controller.at ++++ b/tests/ovn-controller.at +@@ -853,3 +853,132 @@ OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int | grep table=38 | grep -q "re + OVN_CLEANUP([hv1]) + AT_CLEANUP + ]) ++ ++AT_SETUP([ovn-controller - I-P handle lb_hairpin_use_ct_mark change]) ++ ++ovn_start --backup-northd=none ++ ++net_add n1 ++sim_add hv1 ++as hv1 ++check ovs-vsctl add-br br-phys ++ovn_attach n1 br-phys 192.168.0.1 ++check ovs-vsctl -- add-port br-int hv1-vif1 -- \ ++ set interface hv1-vif1 external-ids:iface-id=ls1-lp1 ++ ++check ovn-nbctl ls-add ls1 ++ ++check ovn-nbctl lsp-add ls1 ls1-lp1 \ ++-- lsp-set-addresses ls1-lp1 "f0:00:00:00:00:01" ++ ++wait_for_ports_up ++ovn-appctl -t ovn-controller vlog/set file:dbg ++ ++read_counter() { ++ ovn-appctl -t ovn-controller coverage/read-counter $1 ++} ++ ++# nb_cfg update in sb_global shouldn't trigger lflow_run. ++lflow_run_old=$(read_counter lflow_run) ++check ovn-nbctl --wait=hv sync ++lflow_run_new=$(read_counter lflow_run) ++AT_CHECK([echo $(($lflow_run_new - $lflow_run_old))], [0], [0 ++]) ++ ++# lb_hairpin_use_ct_mark update in sb_global:options should trigger lflow_run. ++# The below steps should cause lb_hairpin_use_ct_mark change twice. One by ++# ovn-sbctl, and the other by ovn-northd to change it back. ++ ++lflow_run_old=$(read_counter lflow_run) ++check ovn-sbctl set SB_Global . options:lb_hairpin_use_ct_mark=false ++check ovn-nbctl --wait=hv sync ++lflow_run_new=$(read_counter lflow_run) ++AT_CHECK([echo $(($lflow_run_new - $lflow_run_old))], [0], [2 ++]) ++ ++OVN_CLEANUP([hv1]) ++AT_CLEANUP ++ ++ ++AT_SETUP([ovn-controller - check ovn-chassis-mac-mappings]) ++ ++ovn_start ++ ++net_add n1 ++sim_add hv1 ++as hv1 ++ovs-vsctl add-br br-phys ++ovn_attach n1 br-phys 192.168.0.1 ++ ++pid=$(cat hv1/ovn-controller.pid) ++ ++# Add chassis with some ovn-chassis-mac-mappings ++AT_CHECK([ovn-sbctl chassis-add foo geneve 127.0.0.2]) ++AT_CHECK([ovn-sbctl set chassis foo other_config:ovn-chassis-mac-mappings="invalid1,invalid2,br1:00:00:00:00:00:00"]) ++AT_CHECK([ovn-nbctl --wait=hv sync]) ++ ++# Check if ovn-controller is still alive ++AT_CHECK([ps $pid], [0], [ignore]) ++# Check if we got warnings for invalid ++AT_CHECK([grep "Parsing of ovn-chassis-mac-mappings failed" hv1/ovn-controller.log | grep -q invalid1]) ++AT_CHECK([grep "Parsing of ovn-chassis-mac-mappings failed" hv1/ovn-controller.log | grep -q invalid2]) ++AT_CHECK([grep "Parsing of ovn-chassis-mac-mappings failed" hv1/ovn-controller.log | grep -q br1], [1]) ++ ++OVN_CLEANUP([hv1]) ++AT_CLEANUP ++ ++AT_SETUP([ovn-controller - localport can be recreated]) ++ ++ovn_start ++ ++net_add n1 ++sim_add hv1 ++as hv1 ++ovs-vsctl add-br br-phys ++ovn_attach n1 br-phys 192.168.0.1 ++ ++port_binding_cookie() { ++ name=$1 ++ ovn-sbctl --bare --columns _uuid find port_binding logical_port=$name |\ ++ cut -d '-' -f 1 | tr -d '\n' | sed 's/^0\{0,8\}//' ++} ++ ++create_localport() { ++ AT_CHECK([ovn-nbctl lsp-add ls0 metadata]) ++ AT_CHECK([ovn-nbctl lsp-set-type metadata localport]) ++ AT_CHECK([ovn-nbctl lsp-set-addresses metadata "00:00:00:00:10:25 192.168.10.25"]) ++} ++ ++bind_ports() { ++ AT_CHECK([ovs-vsctl add-port br-int vm0 -- set interface vm0 type=internal external_ids:iface-id=vm0]) ++ AT_CHECK([ovs-vsctl add-port br-int metadata -- set interface metadata type=internal external_ids:iface-id=metadata]) ++} ++ ++# Create one VIF and localport and bind it to chassis ++AT_CHECK([ovn-nbctl ls-add ls0]) ++AT_CHECK([ovn-nbctl lsp-add ls0 vm0]) ++AT_CHECK([ovn-nbctl lsp-set-addresses vm0 "00:00:00:00:10:10 192.168.10.10"]) ++create_localport ++bind_ports ++ ++# Check that localport has all physical flows defined ++OVS_WAIT_UNTIL([test 6 = $(as hv1 ovs-ofctl dump-flows br-int | grep -c $(port_binding_cookie metadata))]) ++ ++# Remove ls0 from local datapaths ++AT_CHECK([ovs-vsctl del-port br-int vm0]) ++AT_CHECK([ovn-appctl inc-engine/recompute]) ++ ++# Check that localports physical flows are removed ++OVS_WAIT_UNTIL([test 0 = $(as hv1 ovs-ofctl dump-flows br-int | grep -c $(port_binding_cookie metadata))]) ++ ++# The order is impotant, if the port is removed first, the bug wouldn't be triggered ++AT_CHECK([ovn-nbctl lsp-del metadata]) ++AT_CHECK([ovs-vsctl del-port br-int metadata]) ++create_localport ++bind_ports ++ ++# Check that localport has all physical flows re-defined ++OVS_WAIT_UNTIL([test 6 = $(as hv1 ovs-ofctl dump-flows br-int | grep -c $(port_binding_cookie metadata))]) ++ ++OVN_CLEANUP([hv1]) ++AT_CLEANUP diff --git a/tests/ovn-lflow-conj-ids.at b/tests/ovn-lflow-conj-ids.at index b5537c370..f819bf158 100644 --- a/tests/ovn-lflow-conj-ids.at @@ -3302,16 +6033,83 @@ index b5537c370..f819bf158 100644 --- Total 1 IDs used. ]) +diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at +index a43a1ce8f..75da4ba19 100644 +--- a/tests/ovn-nbctl.at ++++ b/tests/ovn-nbctl.at +@@ -587,6 +587,8 @@ AT_CHECK([ovn-nbctl --stateless lr-nat-add lr0 dnat_and_snat 40.0.0.3 192.168.1. + [ovn-nbctl: 40.0.0.3, 192.168.1.7: External ip cannot be shared across stateless and stateful NATs + ]) + ++AT_CHECK([ovn-nbctl --stateless --may-exist lr-nat-add lr0 dnat_and_snat 40.0.0.3 192.168.1.7]) ++ + dnl Deletes the NATs + AT_CHECK([ovn-nbctl lr-nat-del lr0 dnat_and_snat 30.0.0.3], [1], [], + [ovn-nbctl: no matching NAT with the type (dnat_and_snat) and external_ip (30.0.0.3) diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at -index 652903761..25bd8a217 100644 +index 652903761..a8689dfb0 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at +@@ -883,7 +883,7 @@ ovn-nbctl lr-nat-del R1 dnat_and_snat 172.16.1.1 + echo + echo "IPv4: stateless" + ovn-nbctl --wait=sb --stateless lr-nat-add R1 dnat_and_snat 172.16.1.1 50.0.0.11 +-check_flow_match_sets 2 0 0 2 2 0 0 ++check_flow_match_sets 2 0 0 1 1 0 0 + ovn-nbctl lr-nat-del R1 dnat_and_snat 172.16.1.1 + + echo +@@ -895,7 +895,7 @@ ovn-nbctl lr-nat-del R1 dnat_and_snat fd01::1 + echo + echo "IPv6: stateless" + ovn-nbctl --wait=sb --stateless lr-nat-add R1 dnat_and_snat fd01::1 fd11::2 +-check_flow_match_sets 2 0 0 0 0 2 2 ++check_flow_match_sets 2 0 0 0 0 1 1 + + AT_CLEANUP + ]) +@@ -1018,7 +1018,7 @@ AT_CHECK([grep -e "lr_out_snat" drflows | sed 's/table=../table=??/' | sort], [0 + AT_CHECK([grep -e "lr_out_snat" crflows | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(lr_out_snat ), priority=0 , match=(1), action=(next;) + table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) +- table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == 50.0.0.11 && ip4.dst == $allowed_range), action=(ct_snat(172.16.1.1);) ++ table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == 50.0.0.11 && ip4.dst == $allowed_range && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.1);) + ]) + + +@@ -1050,7 +1050,7 @@ AT_CHECK([grep -e "lr_out_snat" drflows2 | sed 's/table=../table=??/' | sort], [ + AT_CHECK([grep -e "lr_out_snat" crflows2 | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(lr_out_snat ), priority=0 , match=(1), action=(next;) + table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) +- table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == 50.0.0.11), action=(ct_snat(172.16.1.1);) ++ table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == 50.0.0.11 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.1);) + table=??(lr_out_snat ), priority=35 , match=(ip && ip4.src == 50.0.0.11 && ip4.dst == $disallowed_range), action=(next;) + ]) + +@@ -1079,7 +1079,7 @@ AT_CHECK([grep -e "lr_out_snat" drflows3 | sed 's/table=../table=??/' | sort], [ + AT_CHECK([grep -e "lr_out_snat" crflows3 | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(lr_out_snat ), priority=0 , match=(1), action=(next;) + table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) +- table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == 50.0.0.11 && ip4.dst == $allowed_range), action=(ct_snat(172.16.1.2);) ++ table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == 50.0.0.11 && ip4.dst == $allowed_range && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.2);) + ]) + + # Stateful FIP with DISALLOWED_IPs +@@ -1108,7 +1108,7 @@ AT_CHECK([grep -e "lr_out_snat" drflows4 | sed 's/table=../table=??/' | sort], [ + AT_CHECK([grep -e "lr_out_snat" crflows4 | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(lr_out_snat ), priority=0 , match=(1), action=(next;) + table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) +- table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == 50.0.0.11), action=(ct_snat(172.16.1.2);) ++ table=??(lr_out_snat ), priority=33 , match=(ip && ip4.src == 50.0.0.11 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.2);) + table=??(lr_out_snat ), priority=35 , match=(ip && ip4.src == 50.0.0.11 && ip4.dst == $disallowed_range), action=(next;) + ]) + @@ -1214,7 +1214,7 @@ check ovn-nbctl --wait=sb ls-lb-add sw0 lb1 AT_CAPTURE_FILE([sbflows]) OVS_WAIT_FOR_OUTPUT( [ovn-sbctl dump-flows sw0 | tee sbflows | grep 'priority=120.*backends' | sed 's/table=..//'], 0, [dnl - (ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80);) -+ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80);) ++ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);) ]) AS_BOX([Delete the Load_Balancer_Health_Check]) @@ -3320,7 +6118,7 @@ index 652903761..25bd8a217 100644 OVS_WAIT_FOR_OUTPUT( [ovn-sbctl dump-flows sw0 | tee sbflows2 | grep 'priority=120.*backends' | sed 's/table=..//'], [0], -[ (ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80);) -+[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80);) ++[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);) ]) AS_BOX([Create the Load_Balancer_Health_Check again.]) @@ -3329,7 +6127,7 @@ index 652903761..25bd8a217 100644 ovn-sbctl dump-flows sw0 | grep backends | grep priority=120 > lflows.txt AT_CHECK([cat lflows.txt | sed 's/table=..//'], [0], [dnl - (ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80);) -+ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80);) ++ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);) ]) AS_BOX([Get the uuid of both the service_monitor]) @@ -3338,7 +6136,7 @@ index 652903761..25bd8a217 100644 OVS_WAIT_FOR_OUTPUT( [ovn-sbctl dump-flows sw0 | tee sbflows 3 | grep 'priority=120.*backends' | sed 's/table=..//'], [0], -[ (ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80);) -+[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80);) ++[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);) ]) AS_BOX([Set the service monitor for sw1-p1 to offline]) @@ -3347,7 +6145,7 @@ index 652903761..25bd8a217 100644 OVS_WAIT_FOR_OUTPUT( [ovn-sbctl dump-flows sw0 | tee sbflows4 | grep 'priority=120.*backends' | sed 's/table=..//'], [0], -[ (ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80);) -+[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80);) ++[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.3:80);) ]) AS_BOX([Set the service monitor for sw0-p1 to offline]) @@ -3365,7 +6163,7 @@ index 652903761..25bd8a217 100644 OVS_WAIT_FOR_OUTPUT( [ovn-sbctl dump-flows sw0 | tee sbflows7 | grep backends | grep priority=120 | sed 's/table=..//'], 0, -[ (ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80);) -+[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80);) ++[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);) ]) AS_BOX([Set the service monitor for sw1-p1 to error]) @@ -3374,7 +6172,7 @@ index 652903761..25bd8a217 100644 | grep priority=120 > lflows.txt AT_CHECK([cat lflows.txt | sed 's/table=..//'], [0], [dnl - (ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80);) -+ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80);) ++ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.3:80);) ]) AS_BOX([Add one more vip to lb1]) @@ -3384,8 +6182,8 @@ index 652903761..25bd8a217 100644 0, -[ (ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80);) - (ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(reg1 = 10.0.0.40; reg2[[0..15]] = 1000; ct_lb(backends=10.0.0.3:1000);) -+[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80);) -+ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(reg0[[1]] = 0; reg1 = 10.0.0.40; reg2[[0..15]] = 1000; ct_lb(backends=10.0.0.3:1000);) ++[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.3:80);) ++ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(reg0[[1]] = 0; reg1 = 10.0.0.40; reg2[[0..15]] = 1000; ct_lb_mark(backends=10.0.0.3:1000);) ]) AS_BOX([Set the service monitor for sw1-p1 to online]) @@ -3395,8 +6193,8 @@ index 652903761..25bd8a217 100644 0, -[ (ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80);) - (ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(reg1 = 10.0.0.40; reg2[[0..15]] = 1000; ct_lb(backends=10.0.0.3:1000,20.0.0.3:80);) -+[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80);) -+ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(reg0[[1]] = 0; reg1 = 10.0.0.40; reg2[[0..15]] = 1000; ct_lb(backends=10.0.0.3:1000,20.0.0.3:80);) ++[ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);) ++ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(reg0[[1]] = 0; reg1 = 10.0.0.40; reg2[[0..15]] = 1000; ct_lb_mark(backends=10.0.0.3:1000,20.0.0.3:80);) ]) AS_BOX([Associate lb1 to sw1]) @@ -3406,8 +6204,8 @@ index 652903761..25bd8a217 100644 0, [dnl - (ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80);) - (ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(reg1 = 10.0.0.40; reg2[[0..15]] = 1000; ct_lb(backends=10.0.0.3:1000,20.0.0.3:80);) -+ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80);) -+ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(reg0[[1]] = 0; reg1 = 10.0.0.40; reg2[[0..15]] = 1000; ct_lb(backends=10.0.0.3:1000,20.0.0.3:80);) ++ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80);) ++ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.40 && tcp.dst == 1000), action=(reg0[[1]] = 0; reg1 = 10.0.0.40; reg2[[0..15]] = 1000; ct_lb_mark(backends=10.0.0.3:1000,20.0.0.3:80);) ]) AS_BOX([Now create lb2 same as lb1 but udp protocol.]) @@ -3455,9 +6253,9 @@ index 652903761..25bd8a217 100644 -sw0flows3: table=4 (ls_out_acl ), priority=2002 , match=((reg0[[9]] == 1) && outport == @pg0 && ip4 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=22); };) -sw0flows3: table=4 (ls_out_acl ), priority=2003 , match=((reg0[[10]] == 1) && outport == @pg0 && ip6 && udp), action=(ct_commit { ct_label.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=22); };) -sw0flows3: table=4 (ls_out_acl ), priority=2003 , match=((reg0[[9]] == 1) && outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=22); };) -+sw0flows3: table=4 (ls_out_acl ), priority=2002 , match=((reg0[[10]] == 1) && outport == @pg0 && ip4 && udp), action=(ct_commit { ct_label.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };) ++sw0flows3: table=4 (ls_out_acl ), priority=2002 , match=((reg0[[10]] == 1) && outport == @pg0 && ip4 && udp), action=(ct_commit { ct_mark.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };) +sw0flows3: table=4 (ls_out_acl ), priority=2002 , match=((reg0[[9]] == 1) && outport == @pg0 && ip4 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };) -+sw0flows3: table=4 (ls_out_acl ), priority=2003 , match=((reg0[[10]] == 1) && outport == @pg0 && ip6 && udp), action=(ct_commit { ct_label.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };) ++sw0flows3: table=4 (ls_out_acl ), priority=2003 , match=((reg0[[10]] == 1) && outport == @pg0 && ip6 && udp), action=(ct_commit { ct_mark.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };) +sw0flows3: table=4 (ls_out_acl ), priority=2003 , match=((reg0[[9]] == 1) && outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };) sw1flows3: table=4 (ls_out_acl ), priority=2001 , match=(reg0[[7]] == 1 && (outport == @pg0 && ip)), action=(reg0[[1]] = 1; next;) sw1flows3: table=4 (ls_out_acl ), priority=2001 , match=(reg0[[8]] == 1 && (outport == @pg0 && ip)), action=(next;) @@ -3465,39 +6263,115 @@ index 652903761..25bd8a217 100644 -sw1flows3: table=4 (ls_out_acl ), priority=2002 , match=((reg0[[9]] == 1) && outport == @pg0 && ip4 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=22); };) -sw1flows3: table=4 (ls_out_acl ), priority=2003 , match=((reg0[[10]] == 1) && outport == @pg0 && ip6 && udp), action=(ct_commit { ct_label.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=22); };) -sw1flows3: table=4 (ls_out_acl ), priority=2003 , match=((reg0[[9]] == 1) && outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=22); };) -+sw1flows3: table=4 (ls_out_acl ), priority=2002 , match=((reg0[[10]] == 1) && outport == @pg0 && ip4 && udp), action=(ct_commit { ct_label.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };) ++sw1flows3: table=4 (ls_out_acl ), priority=2002 , match=((reg0[[10]] == 1) && outport == @pg0 && ip4 && udp), action=(ct_commit { ct_mark.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };) +sw1flows3: table=4 (ls_out_acl ), priority=2002 , match=((reg0[[9]] == 1) && outport == @pg0 && ip4 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };) -+sw1flows3: table=4 (ls_out_acl ), priority=2003 , match=((reg0[[10]] == 1) && outport == @pg0 && ip6 && udp), action=(ct_commit { ct_label.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };) ++sw1flows3: table=4 (ls_out_acl ), priority=2003 , match=((reg0[[10]] == 1) && outport == @pg0 && ip6 && udp), action=(ct_commit { ct_mark.blocked = 1; }; reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };) +sw1flows3: table=4 (ls_out_acl ), priority=2003 , match=((reg0[[9]] == 1) && outport == @pg0 && ip6 && udp), action=(reg0 = 0; reject { /* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ outport <-> inport; next(pipeline=ingress,table=24); };) ]) AT_CLEANUP ]) -@@ -2228,7 +2228,7 @@ AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e +@@ -2208,28 +2208,28 @@ check ovn-nbctl --wait=sb \ + -- acl-add ls from-lport 2 "udp" allow-related \ + -- acl-add ls to-lport 2 "udp" allow-related + AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e ls_in_acl -e ls_out_acl | grep 'ct\.' | sort], [0], [dnl +- table=3 (ls_out_acl_hint ), priority=1 , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;) +- table=3 (ls_out_acl_hint ), priority=2 , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;) ++ table=3 (ls_out_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) ++ table=3 (ls_out_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;) + table=3 (ls_out_acl_hint ), priority=3 , match=(!ct.est), action=(reg0[[9]] = 1; next;) +- table=3 (ls_out_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;) ++ table=3 (ls_out_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;) + table=3 (ls_out_acl_hint ), priority=5 , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;) +- table=3 (ls_out_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) ++ table=3 (ls_out_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) + table=3 (ls_out_acl_hint ), priority=7 , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) +- table=4 (ls_out_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;) +- table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;) +- table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;) +- table=4 (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) +- table=8 (ls_in_acl_hint ), priority=1 , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;) +- table=8 (ls_in_acl_hint ), priority=2 , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;) ++ table=4 (ls_out_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;) ++ table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;) ++ table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(next;) ++ table=4 (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) ++ table=8 (ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) ++ table=8 (ls_in_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;) + table=8 (ls_in_acl_hint ), priority=3 , match=(!ct.est), action=(reg0[[9]] = 1; next;) +- table=8 (ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;) ++ table=8 (ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;) + table=8 (ls_in_acl_hint ), priority=5 , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;) +- table=8 (ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) ++ table=8 (ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) table=8 (ls_in_acl_hint ), priority=7 , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) - table=9 (ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;) - table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;) +- table=9 (ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;) +- table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;) - table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;) -+ table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;) - table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) +- table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) ++ table=9 (ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;) ++ table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;) ++ table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;) ++ table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) ]) -@@ -2240,6 +2240,7 @@ check ovn-nbctl --wait=sb \ + AS_BOX([Check match ct_state with load balancer]) +@@ -2240,39 +2240,40 @@ check ovn-nbctl --wait=sb \ -- ls-lb-add ls lb AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e ls_in_acl -e ls_out_acl | sort], [0], [dnl + table=13(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) table=3 (ls_out_acl_hint ), priority=0 , match=(1), action=(next;) - table=3 (ls_out_acl_hint ), priority=1 , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;) - table=3 (ls_out_acl_hint ), priority=2 , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;) -@@ -2271,7 +2272,7 @@ AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e +- table=3 (ls_out_acl_hint ), priority=1 , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;) +- table=3 (ls_out_acl_hint ), priority=2 , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;) ++ table=3 (ls_out_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) ++ table=3 (ls_out_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;) + table=3 (ls_out_acl_hint ), priority=3 , match=(!ct.est), action=(reg0[[9]] = 1; next;) +- table=3 (ls_out_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;) ++ table=3 (ls_out_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;) + table=3 (ls_out_acl_hint ), priority=5 , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;) +- table=3 (ls_out_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) ++ table=3 (ls_out_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) + table=3 (ls_out_acl_hint ), priority=7 , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) + table=4 (ls_out_acl ), priority=0 , match=(1), action=(next;) +- table=4 (ls_out_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;) ++ table=4 (ls_out_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;) + table=4 (ls_out_acl ), priority=1001 , match=(reg0[[7]] == 1 && (ip)), action=(reg0[[1]] = 1; next;) + table=4 (ls_out_acl ), priority=1001 , match=(reg0[[8]] == 1 && (ip)), action=(next;) + table=4 (ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;) +- table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;) +- table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;) +- table=4 (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) ++ table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;) ++ table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(next;) ++ table=4 (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) + table=4 (ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=8 (ls_in_acl_hint ), priority=0 , match=(1), action=(next;) +- table=8 (ls_in_acl_hint ), priority=1 , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;) +- table=8 (ls_in_acl_hint ), priority=2 , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;) ++ table=8 (ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) ++ table=8 (ls_in_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;) + table=8 (ls_in_acl_hint ), priority=3 , match=(!ct.est), action=(reg0[[9]] = 1; next;) +- table=8 (ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;) ++ table=8 (ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;) + table=8 (ls_in_acl_hint ), priority=5 , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;) +- table=8 (ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) ++ table=8 (ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) + table=8 (ls_in_acl_hint ), priority=7 , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) + table=9 (ls_in_acl ), priority=0 , match=(1), action=(next;) +- table=9 (ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;) ++ table=9 (ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;) + table=9 (ls_in_acl ), priority=1001 , match=(reg0[[7]] == 1 && (ip)), action=(reg0[[1]] = 1; next;) table=9 (ls_in_acl ), priority=1001 , match=(reg0[[8]] == 1 && (ip)), action=(next;) table=9 (ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) - table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;) +- table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;) - table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;) -+ table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;) - table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) +- table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) ++ table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;) ++ table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;) ++ table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) table=9 (ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) ]) + @@ -2280,6 +2281,7 @@ ovn-nbctl --wait=sb clear logical_switch ls acls ovn-nbctl --wait=sb clear logical_switch ls load_balancer @@ -3591,16 +6465,231 @@ index 652903761..25bd8a217 100644 ]) AT_CLEANUP -@@ -3889,12 +3891,16 @@ check_stateful_flows() { - table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && udp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = udp.dst; ct_lb;) +@@ -2914,12 +2916,12 @@ ovn-nbctl --wait=sb sync + flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_tcp}" + AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl + # tcp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80,tcp_flags=0 +-ct_lb { +- ct_lb { ++ct_lb_mark { ++ ct_lb_mark { + reg0[[6]] = 0; + *** chk_lb_hairpin_reply action not implemented; + reg0[[12]] = 0; +- ct_lb /* default (use --ct to customize) */ { ++ ct_lb_mark /* default (use --ct to customize) */ { + output("lsp2"); + }; + }; +@@ -2930,12 +2932,12 @@ ct_lb { + flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_udp}" + AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl + # udp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80 +-ct_lb { +- ct_lb { ++ct_lb_mark { ++ ct_lb_mark { + reg0[[6]] = 0; + *** chk_lb_hairpin_reply action not implemented; + reg0[[12]] = 0; +- ct_lb /* default (use --ct to customize) */ { ++ ct_lb_mark /* default (use --ct to customize) */ { + output("lsp2"); + }; + }; +@@ -2952,12 +2954,12 @@ ovn-nbctl --wait=sb sync + flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_tcp}" + AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl + # tcp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80,tcp_flags=0 +-ct_lb { +- ct_lb { ++ct_lb_mark { ++ ct_lb_mark { + reg0[[6]] = 0; + *** chk_lb_hairpin_reply action not implemented; + reg0[[12]] = 0; +- ct_lb /* default (use --ct to customize) */ { ++ ct_lb_mark /* default (use --ct to customize) */ { + output("lsp2"); + }; + }; +@@ -2968,12 +2970,12 @@ ct_lb { + flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_udp}" + AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl + # udp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80 +-ct_lb { +- ct_lb { ++ct_lb_mark { ++ ct_lb_mark { + reg0[[6]] = 0; + *** chk_lb_hairpin_reply action not implemented; + reg0[[12]] = 0; +- ct_lb /* default (use --ct to customize) */ { ++ ct_lb_mark /* default (use --ct to customize) */ { + output("lsp2"); + }; + }; +@@ -3070,12 +3072,12 @@ ovn-nbctl --wait=sb sync + flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_tcp}" + AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl + # tcp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80,tcp_flags=0 +-ct_lb { +- ct_lb { ++ct_lb_mark { ++ ct_lb_mark { + reg0[[6]] = 0; + *** chk_lb_hairpin_reply action not implemented; + reg0[[12]] = 0; +- ct_lb /* default (use --ct to customize) */ { ++ ct_lb_mark /* default (use --ct to customize) */ { + output("lsp2"); + }; + }; +@@ -3086,12 +3088,12 @@ ct_lb { + flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_udp}" + AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl + # udp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80 +-ct_lb { +- ct_lb { ++ct_lb_mark { ++ ct_lb_mark { + reg0[[6]] = 0; + *** chk_lb_hairpin_reply action not implemented; + reg0[[12]] = 0; +- ct_lb /* default (use --ct to customize) */ { ++ ct_lb_mark /* default (use --ct to customize) */ { + output("lsp2"); + }; + }; +@@ -3108,12 +3110,12 @@ ovn-nbctl --wait=sb sync + flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_tcp}" + AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl + # tcp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80,tcp_flags=0 +-ct_lb { +- ct_lb { ++ct_lb_mark { ++ ct_lb_mark { + reg0[[6]] = 0; + *** chk_lb_hairpin_reply action not implemented; + reg0[[12]] = 0; +- ct_lb /* default (use --ct to customize) */ { ++ ct_lb_mark /* default (use --ct to customize) */ { + output("lsp2"); + }; + }; +@@ -3124,12 +3126,12 @@ ct_lb { + flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_udp}" + AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl + # udp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80 +-ct_lb { +- ct_lb { ++ct_lb_mark { ++ ct_lb_mark { + reg0[[6]] = 0; + *** chk_lb_hairpin_reply action not implemented; + reg0[[12]] = 0; +- ct_lb /* default (use --ct to customize) */ { ++ ct_lb_mark /* default (use --ct to customize) */ { + output("lsp2"); + }; + }; +@@ -3528,10 +3530,10 @@ AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl + + AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl + table=6 (lr_in_dnat ), priority=0 , match=(1), action=(next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(ct_lb(backends=10.0.0.4:8080);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(ct_lb(backends=10.0.0.40:8080);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(ct_lb_mark(backends=10.0.0.4:8080);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(ct_lb_mark(backends=10.0.0.40:8080);) ]) -+ AT_CHECK([grep "ls_in_lb" sw0flows | sort], [0], [dnl -+ table=12(ls_in_lb ), priority=0 , match=(1), action=(next;) -+ table=12(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.4:8080);) -+ table=12(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.20 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.20; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.40:8080);) + AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl +@@ -3564,10 +3566,10 @@ AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl + + AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl + table=6 (lr_in_dnat ), priority=0 , match=(1), action=(next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.4:8080);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.40:8080);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080);) + ]) + + AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl +@@ -3610,10 +3612,10 @@ AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl + + AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl + table=6 (lr_in_dnat ), priority=0 , match=(1), action=(next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.4:8080);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.40:8080);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080);) + ]) + + AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl +@@ -3670,10 +3672,10 @@ AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl + + AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl + table=6 (lr_in_dnat ), priority=0 , match=(1), action=(next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.4:8080);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.40:8080);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080);) + ]) + + AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl +@@ -3716,8 +3718,8 @@ AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl + ]) + + AT_CHECK([grep "lr_in_dnat" lr0flows | grep skip_snat_for_lb | sort], [0], [dnl +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.20 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(flags.skip_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.20 && tcp && reg9[[16..31]] == 80), action=(flags.skip_snat_for_lb = 1; ct_lb(backends=10.0.0.40:8080);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.20 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.skip_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.20 && tcp && reg9[[16..31]] == 80), action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080);) + ]) + + AT_CHECK([grep "lr_out_snat" lr0flows | grep skip_snat_for_lb | sed 's/table=./table=?/' | sort], [0], [dnl +@@ -3880,21 +3882,25 @@ check_stateful_flows() { + AT_CHECK([grep "ls_in_pre_stateful" sw0flows | sort], [0], [dnl + table=7 (ls_in_pre_stateful ), priority=0 , match=(1), action=(next;) + table=7 (ls_in_pre_stateful ), priority=100 , match=(reg0[[0]] == 1), action=(ct_next;) +- table=7 (ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb;) +- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && sctp), action=(reg1 = ip4.dst; reg2[[0..15]] = sctp.dst; ct_lb;) +- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && tcp), action=(reg1 = ip4.dst; reg2[[0..15]] = tcp.dst; ct_lb;) +- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && udp), action=(reg1 = ip4.dst; reg2[[0..15]] = udp.dst; ct_lb;) +- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && sctp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = sctp.dst; ct_lb;) +- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && tcp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = tcp.dst; ct_lb;) +- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && udp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = udp.dst; ct_lb;) ++ table=7 (ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb_mark;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && sctp), action=(reg1 = ip4.dst; reg2[[0..15]] = sctp.dst; ct_lb_mark;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && tcp), action=(reg1 = ip4.dst; reg2[[0..15]] = tcp.dst; ct_lb_mark;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && udp), action=(reg1 = ip4.dst; reg2[[0..15]] = udp.dst; ct_lb_mark;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && sctp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = sctp.dst; ct_lb_mark;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && tcp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = tcp.dst; ct_lb_mark;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && udp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = udp.dst; ct_lb_mark;) +]) + ++ AT_CHECK([grep "ls_in_lb" sw0flows | sort], [0], [dnl ++ table=12(ls_in_lb ), priority=0 , match=(1), action=(next;) ++ table=12(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.4:8080);) ++ table=12(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.20 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.20; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.40:8080);) + ]) + AT_CHECK([grep "ls_in_stateful" sw0flows | sort], [0], [dnl - table=12(ls_in_stateful ), priority=0 , match=(1), action=(next;) - table=12(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;) @@ -3608,29 +6697,81 @@ index 652903761..25bd8a217 100644 - table=12(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.4:8080);) - table=12(ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.20 && tcp.dst == 80), action=(reg1 = 10.0.0.20; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.40:8080);) + table=14(ls_in_stateful ), priority=0 , match=(1), action=(next;) -+ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;) -+ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;) ++ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;) ++ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;) ]) AT_CHECK([grep "ls_out_pre_lb" sw0flows | sort], [0], [dnl -@@ -3957,10 +3963,14 @@ AT_CHECK([grep "ls_in_pre_stateful" sw0flows | sort], [0], [dnl - table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && udp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = udp.dst; ct_lb;) +@@ -3909,15 +3915,15 @@ check_stateful_flows() { + AT_CHECK([grep "ls_out_pre_stateful" sw0flows | sort], [0], [dnl + table=2 (ls_out_pre_stateful), priority=0 , match=(1), action=(next;) + table=2 (ls_out_pre_stateful), priority=100 , match=(reg0[[0]] == 1), action=(ct_next;) +- table=2 (ls_out_pre_stateful), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb;) ++ table=2 (ls_out_pre_stateful), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb_mark;) ]) -+AT_CHECK([grep "ls_in_lb" sw0flows | sort], [0], [dnl -+ table=12(ls_in_lb ), priority=0 , match=(1), action=(next;) + AT_CHECK([grep "ls_out_lb" sw0flows | sort], [0], []) + + AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl + table=7 (ls_out_stateful ), priority=0 , match=(1), action=(next;) +- table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;) +- table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;) ++ table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;) ++ 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;) + ]) + } + +@@ -3948,19 +3954,23 @@ AT_CHECK([grep "ls_in_pre_lb" sw0flows | sort], [0], [dnl + AT_CHECK([grep "ls_in_pre_stateful" sw0flows | sort], [0], [dnl + table=7 (ls_in_pre_stateful ), priority=0 , match=(1), action=(next;) + table=7 (ls_in_pre_stateful ), priority=100 , match=(reg0[[0]] == 1), action=(ct_next;) +- table=7 (ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb;) +- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && sctp), action=(reg1 = ip4.dst; reg2[[0..15]] = sctp.dst; ct_lb;) +- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && tcp), action=(reg1 = ip4.dst; reg2[[0..15]] = tcp.dst; ct_lb;) +- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && udp), action=(reg1 = ip4.dst; reg2[[0..15]] = udp.dst; ct_lb;) +- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && sctp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = sctp.dst; ct_lb;) +- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && tcp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = tcp.dst; ct_lb;) +- table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && udp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = udp.dst; ct_lb;) ++ table=7 (ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb_mark;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && sctp), action=(reg1 = ip4.dst; reg2[[0..15]] = sctp.dst; ct_lb_mark;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && tcp), action=(reg1 = ip4.dst; reg2[[0..15]] = tcp.dst; ct_lb_mark;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && udp), action=(reg1 = ip4.dst; reg2[[0..15]] = udp.dst; ct_lb_mark;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && sctp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = sctp.dst; ct_lb_mark;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && tcp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = tcp.dst; ct_lb_mark;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && udp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = udp.dst; ct_lb_mark;) +]) + ++AT_CHECK([grep "ls_in_lb" sw0flows | sort], [0], [dnl ++ table=12(ls_in_lb ), priority=0 , match=(1), action=(next;) + ]) + AT_CHECK([grep "ls_in_stateful" sw0flows | sort], [0], [dnl - table=12(ls_in_stateful ), priority=0 , match=(1), action=(next;) - table=12(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;) - table=12(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;) + table=14(ls_in_stateful ), priority=0 , match=(1), action=(next;) -+ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;) -+ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;) ++ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;) ++ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;) ]) AT_CHECK([grep "ls_out_pre_lb" sw0flows | sort], [0], [dnl +@@ -3974,13 +3984,13 @@ AT_CHECK([grep "ls_out_pre_lb" sw0flows | sort], [0], [dnl + AT_CHECK([grep "ls_out_pre_stateful" sw0flows | sort], [0], [dnl + table=2 (ls_out_pre_stateful), priority=0 , match=(1), action=(next;) + table=2 (ls_out_pre_stateful), priority=100 , match=(reg0[[0]] == 1), action=(ct_next;) +- table=2 (ls_out_pre_stateful), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb;) ++ table=2 (ls_out_pre_stateful), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb_mark;) + ]) + + AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl + table=7 (ls_out_stateful ), priority=0 , match=(1), action=(next;) +- table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;) +- table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;) ++ table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;) ++ 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;) + ]) + + AT_CLEANUP @@ -4004,9 +4014,9 @@ AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 2002 | sort], [0], [dnl table=9 (ls_in_acl ), priority=2002 , match=(reg0[[8]] == 1 && (tcp)), action=(reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; next;) ]) @@ -3639,11 +6780,22 @@ index 652903761..25bd8a217 100644 - table=12(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;) - table=12(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;) + table=14(ls_in_stateful ), priority=0 , match=(1), action=(next;) -+ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;) -+ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;) ++ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;) ++ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;) ]) AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 2002 | sort], [0], [dnl +@@ -4015,8 +4025,8 @@ AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 2002 | sort], [0], [dnl + ]) + AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl + table=7 (ls_out_stateful ), priority=0 , match=(1), action=(next;) +- table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;) +- table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;) ++ table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;) ++ 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;) + ]) + + # Add new ACL without label @@ -4033,9 +4043,9 @@ AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 2002 | sort], [0], [dnl table=9 (ls_in_acl ), priority=2002 , match=(reg0[[8]] == 1 && (udp)), action=(next;) ]) @@ -3652,11 +6804,22 @@ index 652903761..25bd8a217 100644 - table=12(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;) - table=12(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;) + table=14(ls_in_stateful ), priority=0 , match=(1), action=(next;) -+ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;) -+ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;) ++ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;) ++ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;) ]) AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 2002 | sort], [0], [dnl +@@ -4046,8 +4056,8 @@ AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 2002 | sort], [0], [dnl + ]) + AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl + table=7 (ls_out_stateful ), priority=0 , match=(1), action=(next;) +- table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;) +- table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;) ++ table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;) ++ 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;) + ]) + + # Delete new ACL with label @@ -4062,9 +4072,9 @@ AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 2002 | sort], [0], [dnl table=9 (ls_in_acl ), priority=2002 , match=(reg0[[8]] == 1 && (udp)), action=(next;) ]) @@ -3665,38 +6828,91 @@ index 652903761..25bd8a217 100644 - table=12(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;) - table=12(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;) + table=14(ls_in_stateful ), priority=0 , match=(1), action=(next;) -+ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;) -+ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;) ++ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;) ++ table=14(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;) ]) AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 2002 | sort], [0], [dnl -@@ -4093,7 +4103,7 @@ AT_CAPTURE_FILE([sw0flows]) +@@ -4073,8 +4083,8 @@ AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 2002 | sort], [0], [dnl + ]) + AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl + table=7 (ls_out_stateful ), priority=0 , match=(1), action=(next;) +- table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;) +- table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;) ++ table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;) ++ 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;) + ]) + AT_CLEANUP + ]) +@@ -4092,16 +4102,16 @@ ovn-sbctl dump-flows sw0 > sw0flows + AT_CAPTURE_FILE([sw0flows]) AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 6553 | sort], [0], [dnl - table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;) +- table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;) - table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;) -+ table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;) - table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) +- table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) ++ table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;) ++ table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;) ++ table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) table=9 (ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) ]) -@@ -4114,7 +4124,7 @@ AT_CAPTURE_FILE([sw0flows]) + + AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 6553 | sort], [0], [dnl +- table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;) +- table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;) +- table=4 (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) ++ table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;) ++ table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(next;) ++ table=4 (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) + table=4 (ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + ]) + +@@ -4112,16 +4122,16 @@ ovn-sbctl dump-flows sw0 > sw0flows + AT_CAPTURE_FILE([sw0flows]) + AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 6553 | sort], [0], [dnl - table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && ct_label.blocked == 0), action=(next;) - table=9 (ls_in_acl ), priority=65532, match=((ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) +- table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && ct_label.blocked == 0), action=(next;) +- table=9 (ls_in_acl ), priority=65532, match=((ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) - table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && ct.rpl && ct_label.blocked == 0), action=(next;) -+ table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && ct.rpl && ct_label.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;) ++ table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && ct_mark.blocked == 0), action=(next;) ++ table=9 (ls_in_acl ), priority=65532, match=((ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) ++ table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;) table=9 (ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) ]) -@@ -4137,7 +4147,7 @@ AT_CAPTURE_FILE([sw0flows]) + AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 6553 | sort], [0], [dnl +- table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && ct_label.blocked == 0), action=(next;) +- table=4 (ls_out_acl ), priority=65532, match=((ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) +- table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && ct.rpl && ct_label.blocked == 0), action=(next;) ++ table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && ct_mark.blocked == 0), action=(next;) ++ table=4 (ls_out_acl ), priority=65532, match=((ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) ++ table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && ct.rpl && ct_mark.blocked == 0), action=(next;) + table=4 (ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + ]) + +@@ -4136,16 +4146,16 @@ ovn-sbctl dump-flows sw0 > sw0flows + AT_CAPTURE_FILE([sw0flows]) AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 6553 | sort], [0], [dnl - table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;) +- table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;) - table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;) -+ table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;) - table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) +- table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) ++ table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;) ++ table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;) ++ table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) table=9 (ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) ]) + + AT_CHECK([grep -w "ls_out_acl" sw0flows | grep 6553 | sort], [0], [dnl +- table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;) +- table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;) +- table=4 (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) ++ table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;) ++ table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(next;) ++ table=4 (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) + table=4 (ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + ]) + @@ -4309,20 +4319,20 @@ ovn-nbctl --wait=sb lsp-set-dhcpv4-options sw0-port1 $CIDR_UUID ovn-sbctl dump-flows sw0 > sw0flows AT_CAPTURE_FILE([sw0flows]) @@ -3741,7 +6957,214 @@ index 652903761..25bd8a217 100644 ]) AT_CLEANUP -@@ -5336,6 +5346,23 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [ +@@ -4877,7 +4887,8 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [ + table=? (lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) + ]) + +-ovn-sbctl chassis-add gw1 geneve 127.0.0.1 ++check ovn-sbctl chassis-add gw1 geneve 127.0.0.1 \ ++ -- set chassis gw1 other_config:ct-no-masked-label="true" + + # Create a distributed gw port on lr0 + check ovn-nbctl ls-add public +@@ -4976,14 +4987,14 @@ AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl + AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl + table=6 (lr_in_dnat ), priority=0 , match=(1), action=(next;) + table=6 (lr_in_dnat ), priority=100 , match=(ip && ip4.dst == 172.168.0.20 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_dnat_in_czone(10.0.0.3);) +- table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 172.168.0.200 && ct_label.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;) +- table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 172.168.0.200 && is_chassis_resident("cr-lr0-public")), action=(ct_lb(backends=10.0.0.80,10.0.0.81);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_label.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_label.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb(backends=10.0.0.4:8080);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && is_chassis_resident("cr-lr0-public")), action=(ct_lb(backends=10.0.0.50:82,10.0.0.60:82);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && is_chassis_resident("cr-lr0-public")), action=(ct_lb(backends=10.0.0.50:6062,10.0.0.60:6062);) ++ table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 172.168.0.200 && ct_mark.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;) ++ table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 172.168.0.200 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.80,10.0.0.81);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_mark.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.4:8080);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062);) + ]) + + AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl +@@ -5044,14 +5055,14 @@ AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl + AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl + table=6 (lr_in_dnat ), priority=0 , match=(1), action=(next;) + table=6 (lr_in_dnat ), priority=100 , match=(ip && ip4.dst == 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);) +- table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 172.168.0.200 && ct_label.natted == 1), action=(next;) +- table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 172.168.0.200), action=(ct_lb(backends=10.0.0.80,10.0.0.81);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_label.natted == 1), action=(next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_label.natted == 1), action=(next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(ct_lb(backends=10.0.0.4:8080);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(ct_lb(backends=10.0.0.50:82,10.0.0.60:82);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(ct_lb(backends=10.0.0.50:6062,10.0.0.60:6062);) ++ table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 172.168.0.200 && ct_mark.natted == 1), action=(next;) ++ table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 172.168.0.200), action=(ct_lb_mark(backends=10.0.0.80,10.0.0.81);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_mark.natted == 1), action=(next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(ct_lb_mark(backends=10.0.0.4:8080);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062);) + ]) + + AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl +@@ -5071,11 +5082,12 @@ AT_CHECK([grep "lr_out_post_undnat" lr0flows | sed 's/table=./table=?/' | sort], + AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl + table=? (lr_out_snat ), priority=0 , match=(1), action=(next;) + table=? (lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) +- table=? (lr_out_snat ), priority=25 , match=(ip && ip4.src == 10.0.0.0/24), action=(ct_snat(172.168.0.10);) +- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.10), action=(ct_snat(172.168.0.30);) +- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.3), action=(ct_snat(172.168.0.20);) ++ table=? (lr_out_snat ), priority=25 , match=(ip && ip4.src == 10.0.0.0/24 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.10);) ++ table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.10 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.30);) ++ table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.3 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.20);) + ]) + ++ + # Set lb force snat logical router. + check ovn-nbctl --wait=sb set logical_router lr0 options:lb_force_snat_ip="router_ip" + check ovn-nbctl --wait=sb sync +@@ -5103,14 +5115,14 @@ AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl + AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl + table=6 (lr_in_dnat ), priority=0 , match=(1), action=(next;) + table=6 (lr_in_dnat ), priority=100 , match=(ip && ip4.dst == 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);) +- table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 172.168.0.200 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.80,10.0.0.81);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.4:8080);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.50:82,10.0.0.60:82);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.50:6062,10.0.0.60:6062);) ++ table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 172.168.0.200 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.80,10.0.0.81);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062);) + ]) + + AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl +@@ -5132,9 +5144,9 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [ + table=? (lr_out_snat ), priority=110 , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"), action=(ct_snat(172.168.0.10);) + table=? (lr_out_snat ), priority=110 , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"), action=(ct_snat(10.0.0.1);) + table=? (lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) +- table=? (lr_out_snat ), priority=25 , match=(ip && ip4.src == 10.0.0.0/24), action=(ct_snat(172.168.0.10);) +- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.10), action=(ct_snat(172.168.0.30);) +- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.3), action=(ct_snat(172.168.0.20);) ++ table=? (lr_out_snat ), priority=25 , match=(ip && ip4.src == 10.0.0.0/24 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.10);) ++ table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.10 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.30);) ++ table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.3 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.20);) + ]) + + # Add a LB VIP same as router ip. +@@ -5166,16 +5178,16 @@ AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl + AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl + table=6 (lr_in_dnat ), priority=0 , match=(1), action=(next;) + table=6 (lr_in_dnat ), priority=100 , match=(ip && ip4.dst == 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);) +- table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 172.168.0.200 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.80,10.0.0.81);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.4:8080);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.50:82,10.0.0.60:82);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.50:82,10.0.0.60:82);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.50:6062,10.0.0.60:6062);) ++ table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 172.168.0.200 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.80,10.0.0.81);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062);) + ]) + + AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl +@@ -5197,9 +5209,9 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [ + table=? (lr_out_snat ), priority=110 , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"), action=(ct_snat(172.168.0.10);) + table=? (lr_out_snat ), priority=110 , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"), action=(ct_snat(10.0.0.1);) + table=? (lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) +- table=? (lr_out_snat ), priority=25 , match=(ip && ip4.src == 10.0.0.0/24), action=(ct_snat(172.168.0.10);) +- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.10), action=(ct_snat(172.168.0.30);) +- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.3), action=(ct_snat(172.168.0.20);) ++ table=? (lr_out_snat ), priority=25 , match=(ip && ip4.src == 10.0.0.0/24 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.10);) ++ table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.10 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.30);) ++ table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.3 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.20);) + ]) + + # Add IPv6 router port and LB. +@@ -5242,18 +5254,18 @@ AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl + AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl + table=6 (lr_in_dnat ), priority=0 , match=(1), action=(next;) + table=6 (lr_in_dnat ), priority=100 , match=(ip && ip4.dst == 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);) +- table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 172.168.0.200 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.80,10.0.0.81);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip6 && xxreg0 == def0::2 && tcp && reg9[[16..31]] == 8000 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.4:8080);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.50:82,10.0.0.60:82);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.50:82,10.0.0.60:82);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.50:6062,10.0.0.60:6062);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip6 && xxreg0 == def0::2 && tcp && reg9[[16..31]] == 8000), action=(flags.force_snat_for_lb = 1; ct_lb(backends=[[aef0::2]]:80,[[aef0::3]]:80);) ++ table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 172.168.0.200 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.80,10.0.0.81);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip6 && xxreg0 == def0::2 && tcp && reg9[[16..31]] == 8000 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip6 && xxreg0 == def0::2 && tcp && reg9[[16..31]] == 8000), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=[[aef0::2]]:80,[[aef0::3]]:80);) + ]) + + AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl +@@ -5277,9 +5289,9 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [ + table=? (lr_out_snat ), priority=110 , match=(flags.force_snat_for_lb == 1 && ip6 && outport == "lr0-public"), action=(ct_snat(def0::10);) + table=? (lr_out_snat ), priority=110 , match=(flags.force_snat_for_lb == 1 && ip6 && outport == "lr0-sw0"), action=(ct_snat(aef0::1);) + table=? (lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) +- table=? (lr_out_snat ), priority=25 , match=(ip && ip4.src == 10.0.0.0/24), action=(ct_snat(172.168.0.10);) +- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.10), action=(ct_snat(172.168.0.30);) +- table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.3), action=(ct_snat(172.168.0.20);) ++ table=? (lr_out_snat ), priority=25 , match=(ip && ip4.src == 10.0.0.0/24 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.10);) ++ table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.10 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.30);) ++ table=? (lr_out_snat ), priority=33 , match=(ip && ip4.src == 10.0.0.3 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.20);) + ]) + + check ovn-nbctl lrp-del lr0-sw0 +@@ -5308,10 +5320,10 @@ AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl + + AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl + table=6 (lr_in_dnat ), priority=0 , match=(1), action=(next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && tcp && reg9[[16..31]] == 60 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && tcp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.50:6062,10.0.0.60:6062);) +- table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.50:6062,10.0.0.60:6062);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && tcp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && tcp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062);) ++ table=6 (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062);) + ]) + + AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl +@@ -5336,6 +5348,23 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [ AT_CLEANUP ]) @@ -3765,30 +7188,211 @@ index 652903761..25bd8a217 100644 OVN_FOR_EACH_NORTHD([ AT_SETUP([ovn -- Add tags to logical flows]) ovn_start -@@ -5718,6 +5745,12 @@ AT_CHECK([grep lr_in_gw_redirect lrflows | grep cr-DR | sed 's/table=../table=?? - table=??(lr_in_gw_redirect ), priority=50 , match=(outport == "DR-S3"), action=(outport = "cr-DR-S3"; next;) +@@ -5404,7 +5433,7 @@ AT_CAPTURE_FILE([lr0flows]) + + AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(lr_in_chk_pkt_len ), priority=0 , match=(1), action=(next;) +- table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); next;) ++ table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); next;) + table=??(lr_in_larger_pkts ), priority=0 , match=(1), action=(next;) + table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip4.dst = ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress, table=0); };) + table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };) +@@ -5413,8 +5442,8 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=. ]) -+# Check that ovn-northd logs a warning when trying to configure NAT -+# on the router with multiple distributed gw ports. Such configurations are -+# not supported yet. -+check ovn-nbctl lr-nat-add DR dnat_and_snat 42.42.42.1 20.0.0.2 -+AT_CHECK([grep -q 'NAT is configured on logical router DR, which has 2 distributed gateway ports. NAT is not supported yet when there is more than one distributed gateway port on the router.' northd/ovn-northd.log], [0]) + AT_CHECK([grep -E "lr_in_admission.*check_pkt_larger" lr0flows | sort], [0], [dnl +- table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;) +- table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;) ++ table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(reg9[[1]] = check_pkt_larger(1514); xreg0[[0..47]] = 00:00:20:20:12:13; next;) ++ table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); xreg0[[0..47]] = 00:00:20:20:12:13; next;) + ]) + + AT_CHECK([grep -E "lr_in_ip_input.*icmp4_error" lr0flows | sort], [0], [dnl +@@ -5435,7 +5464,7 @@ AT_CAPTURE_FILE([lr0flows]) + + AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(lr_in_chk_pkt_len ), priority=0 , match=(1), action=(next;) +- table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); next;) ++ table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); next;) + table=??(lr_in_larger_pkts ), priority=0 , match=(1), action=(next;) + table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip4.dst = ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress, table=0); };) + table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };) +@@ -5444,8 +5473,8 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=. + ]) + + AT_CHECK([grep -E "lr_in_admission.*check_pkt_larger" lr0flows | sort], [0], [dnl +- table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;) +- table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;) ++ table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); xreg0[[0..47]] = 00:00:20:20:12:13; next;) ++ table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); xreg0[[0..47]] = 00:00:20:20:12:13; next;) + ]) + + AT_CHECK([grep -E "lr_in_ip_input.*icmp4_error" lr0flows | sort], [0], [dnl +@@ -5463,7 +5492,7 @@ AT_CAPTURE_FILE([lr0flows]) + + AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(lr_in_chk_pkt_len ), priority=0 , match=(1), action=(next;) +- table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); next;) ++ table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); next;) + table=??(lr_in_chk_pkt_len ), priority=55 , match=(outport == "lr0-public" && (tcp)), action=(next;) + table=??(lr_in_larger_pkts ), priority=0 , match=(1), action=(next;) + table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip4.dst = ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress, table=0); };) +@@ -5473,8 +5502,8 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=. + ]) + + AT_CHECK([grep "lr_in_admission" lr0flows | grep -e "check_pkt_larger" -e "tcp" | sort], [0], [dnl +- table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;) +- table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;) ++ table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); xreg0[[0..47]] = 00:00:20:20:12:13; next;) ++ table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); xreg0[[0..47]] = 00:00:20:20:12:13; next;) + table=0 (lr_in_admission ), priority=55 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public" && (tcp)), action=(xreg0[[0..47]] = 00:00:20:20:12:13; next;) + table=0 (lr_in_admission ), priority=55 , match=(eth.mcast && inport == "lr0-public" && (tcp)), action=(xreg0[[0..47]] = 00:00:20:20:12:13; next;) + ]) +@@ -5487,8 +5516,8 @@ AT_CAPTURE_FILE([lr0flows]) + + AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(lr_in_chk_pkt_len ), priority=0 , match=(1), action=(next;) +- table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); next;) +- table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1418); next;) ++ table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); next;) ++ table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1414); next;) + table=??(lr_in_chk_pkt_len ), priority=55 , match=(outport == "lr0-public" && (tcp)), action=(next;) + table=??(lr_in_larger_pkts ), priority=0 , match=(1), action=(next;) + table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip4.dst = ip4.src; ip4.src = 172.168.0.100; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1400; next(pipeline=ingress, table=0); };) +@@ -5502,10 +5531,10 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=. + ]) + + AT_CHECK([grep "lr_in_admission.*check_pkt_larger" lr0flows | sort], [0], [dnl +- table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:00:00:ff:01 && inport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1418); xreg0[[0..47]] = 00:00:00:00:ff:01; next;) +- table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;) +- table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;) +- table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1418); xreg0[[0..47]] = 00:00:00:00:ff:01; next;) ++ table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:00:00:ff:01 && inport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1414); xreg0[[0..47]] = 00:00:00:00:ff:01; next;) ++ table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); xreg0[[0..47]] = 00:00:20:20:12:13; next;) ++ table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); xreg0[[0..47]] = 00:00:20:20:12:13; next;) ++ table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1414); xreg0[[0..47]] = 00:00:00:00:ff:01; next;) + ]) + + AT_CHECK([grep -E "lr_in_ip_input.*icmp4_error" lr0flows | sort], [0], [dnl +@@ -5525,8 +5554,8 @@ AT_CAPTURE_FILE([lr0flows]) + + AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(lr_in_chk_pkt_len ), priority=0 , match=(1), action=(next;) +- table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); next;) +- table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1418); next;) ++ table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); next;) ++ table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1414); next;) + table=??(lr_in_chk_pkt_len ), priority=55 , match=(outport == "lr0-public" && (tcp)), action=(next;) + table=??(lr_in_chk_pkt_len ), priority=55 , match=(outport == "lr0-sw0" && (tcp)), action=(next;) + table=??(lr_in_larger_pkts ), priority=0 , match=(1), action=(next;) +@@ -5541,10 +5570,10 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=. + ]) + + AT_CHECK([grep "lr_in_admission" lr0flows | grep -e "check_pkt_larger" -e "tcp" | sort], [0], [dnl +- table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:00:00:ff:01 && inport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1418); xreg0[[0..47]] = 00:00:00:00:ff:01; next;) +- table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;) +- table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;) +- table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1418); xreg0[[0..47]] = 00:00:00:00:ff:01; next;) ++ table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:00:00:ff:01 && inport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1414); xreg0[[0..47]] = 00:00:00:00:ff:01; next;) ++ table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); xreg0[[0..47]] = 00:00:20:20:12:13; next;) ++ table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); xreg0[[0..47]] = 00:00:20:20:12:13; next;) ++ table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1414); xreg0[[0..47]] = 00:00:00:00:ff:01; next;) + table=0 (lr_in_admission ), priority=55 , match=(eth.dst == 00:00:00:00:ff:01 && inport == "lr0-sw0" && (tcp)), action=(xreg0[[0..47]] = 00:00:00:00:ff:01; next;) + table=0 (lr_in_admission ), priority=55 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public" && (tcp)), action=(xreg0[[0..47]] = 00:00:20:20:12:13; next;) + table=0 (lr_in_admission ), priority=55 , match=(eth.mcast && inport == "lr0-public" && (tcp)), action=(xreg0[[0..47]] = 00:00:20:20:12:13; next;) +@@ -5558,7 +5587,7 @@ AT_CAPTURE_FILE([lr0flows]) + + AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(lr_in_chk_pkt_len ), priority=0 , match=(1), action=(next;) +- table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1418); next;) ++ table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1414); next;) + table=??(lr_in_chk_pkt_len ), priority=55 , match=(outport == "lr0-sw0" && (tcp)), action=(next;) + table=??(lr_in_larger_pkts ), priority=0 , match=(1), action=(next;) + table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip4.dst = ip4.src; ip4.src = 172.168.0.100; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1400; next(pipeline=ingress, table=0); };) +@@ -5567,6 +5596,19 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=. + table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw1" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1400; next(pipeline=ingress, table=0); };) + ]) + ++check ovn-nbctl --wait=sb clear logical_router_port lr0-sw0 options ++check ovn-nbctl --wait=sb set logical_router_port lr0-public options:gateway_mtu=1500 ++check ovn-nbctl lsp-add public ext-port ++check ovn-nbctl lsp-set-addresses ext-port unknown ++check ovn-nbctl lsp-set-type ext-port localnet ++check ovn-nbctl --wait=sb set Logical_Switch_Port ext-port tag_request=2 ++ovn-sbctl dump-flows lr0 > lr0flows ++ ++AT_CHECK([grep "lr_in_admission" lr0flows | grep -e "check_pkt_larger" | sort], [0], [dnl ++ table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 00:00:20:20:12:13 && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;) ++ table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;) ++]) + AT_CLEANUP ]) -@@ -5890,3 +5923,227 @@ AT_CHECK([grep -e "(lr_in_ip_routing ).*outport" lr0flows | sed 's/table=../ta +@@ -5578,6 +5620,7 @@ ovn_start + check ovn-sbctl chassis-add ch1 geneve 127.0.0.1 - AT_CLEANUP + check ovn-nbctl lr-add lr0 ++check ovn-nbctl set logical_router lr0 options:chassis=ch1 + check ovn-nbctl ls-add public + check ovn-nbctl lrp-add lr0 lr0-public 00:00:20:20:12:13 192.168.0.1/24 + check ovn-nbctl lsp-add public public-lr0 +@@ -5607,6 +5650,22 @@ AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed 's/192\.168\.0\..0/192. + table=??(lr_in_ip_routing_ecmp), priority=150 , match=(reg8[[0..15]] == 0), action=(next;) ]) + ++dnl The chassis was created with other_config:ct-no-masked-label=false, the flows ++dnl should be using ct_label.ecmp_reply_port. ++AT_CHECK([grep -e "lr_in_arp_resolve.*ecmp" lr0flows | sed 's/table=../table=??/'], [0], [dnl ++ table=??(lr_in_arp_resolve ), priority=200 , match=(ct.rpl && ct_label.ecmp_reply_port == 1), action=(push(xxreg1); xxreg1 = ct_label; eth.dst = xxreg1[[32..79]]; pop(xxreg1); next;) ++]) + -+OVN_FOR_EACH_NORTHD([ -+AT_SETUP([check exclude-lb-vips-from-garp option]) -+ovn_start ++dnl Simulate an ovn-controller upgrade to a version that supports ++dnl ct-no-masked-label. ovn-northd should start using ct_mark.ecmp_reply_port. + -+ovn-nbctl lr-add R1 -+ovn-nbctl set logical_router R1 options:chassis=hv1 ++check ovn-sbctl set chassis ch1 other_config:ct-no-masked-label=true ++check ovn-nbctl --wait=sb sync ++ovn-sbctl dump-flows lr0 > lr0flows ++AT_CHECK([grep -e "lr_in_arp_resolve.*ecmp" lr0flows | sed 's/table=../table=??/'], [0], [dnl ++ table=??(lr_in_arp_resolve ), priority=200 , match=(ct.rpl && ct_mark.ecmp_reply_port == 1), action=(push(xxreg1); xxreg1 = ct_label; eth.dst = xxreg1[[32..79]]; pop(xxreg1); next;) ++]) ++ + # add ecmp route with wrong nexthop + check ovn-nbctl --wait=sb --ecmp-symmetric-reply lr-route-add lr0 1.0.0.1 192.168.1.20 + +@@ -5718,6 +5777,12 @@ AT_CHECK([grep lr_in_gw_redirect lrflows | grep cr-DR | sed 's/table=../table=?? + table=??(lr_in_gw_redirect ), priority=50 , match=(outport == "DR-S3"), action=(outport = "cr-DR-S3"; next;) + ]) + ++# Check that ovn-northd logs a warning when trying to configure NAT ++# on the router with multiple distributed gw ports. Such configurations are ++# not supported yet. ++check ovn-nbctl lr-nat-add DR dnat_and_snat 42.42.42.1 20.0.0.2 ++AT_CHECK([grep -q 'NAT is configured on logical router DR, which has 2 distributed gateway ports. NAT is not supported yet when there is more than one distributed gateway port on the router.' northd/ovn-northd.log], [0]) ++ + AT_CLEANUP + ]) + +@@ -5802,7 +5867,7 @@ flow="eth.dst == 00:00:00:00:01:00 && inport == \"rtr-ls\" && ip4.src == 42.42.4 + AT_CHECK_UNQUOTED([ovn-trace --ct new --minimal "${flow}" --lb-dst 42.42.42.42:4242], [0], [dnl + # tcp,reg14=0x1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:01:00,nw_src=42.42.42.42,nw_dst=43.43.43.43,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=4343,tcp_flags=0 + ct_dnat /* assuming no un-dnat entry, so no change */ { +- ct_lb /* default (use --ct to customize) */ { ++ ct_lb_mark /* default (use --ct to customize) */ { + ip.ttl--; + eth.src = 00:00:00:00:01:00; + eth.dst = 00:00:00:00:00:00; +@@ -5890,3 +5955,371 @@ AT_CHECK([grep -e "(lr_in_ip_routing ).*outport" lr0flows | sed 's/table=../ta + + AT_CLEANUP + ]) ++ ++OVN_FOR_EACH_NORTHD([ ++AT_SETUP([check exclude-lb-vips-from-garp option]) ++ovn_start ++ ++ovn-nbctl lr-add R1 ++ovn-nbctl set logical_router R1 options:chassis=hv1 +ovn-nbctl lrp-add R1 R1-S1 02:ac:10:01:00:01 172.16.1.1/24 + +ovn-nbctl ls-add S1 @@ -3839,40 +7443,40 @@ index 652903761..25bd8a217 100644 + +AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_acl ), priority=0 , match=(1), action=(next;) -+ table=??(ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;) -+ table=??(ls_in_acl ), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(ct_commit { ct_label.blocked = 1; }; /* drop */) ++ table=??(ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;) ++ table=??(ls_in_acl ), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */) + table=??(ls_in_acl ), priority=2001 , match=(reg0[[9]] == 1 && (ip4)), action=(/* drop */) + table=??(ls_in_acl ), priority=2002 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg0[[1]] = 1; next;) + table=??(ls_in_acl ), priority=2002 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(next;) + table=??(ls_in_acl ), priority=2003 , match=(reg0[[7]] == 1 && (ip4 && icmp)), action=(reg0[[1]] = 1; next;) + table=??(ls_in_acl ), priority=2003 , match=(reg0[[8]] == 1 && (ip4 && icmp)), action=(next;) -+ table=??(ls_in_acl ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_label.blocked = 1; }; /* drop */) ++ table=??(ls_in_acl ), 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 ), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(/* drop */) + table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) -+ table=??(ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;) -+ table=??(ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;) -+ table=??(ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) ++ table=??(ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;) ++ table=??(ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;) ++ table=??(ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) + table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) -+ table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;) -+ table=??(ls_in_acl_hint ), priority=2 , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;) ++ table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) ++ table=??(ls_in_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;) + table=??(ls_in_acl_hint ), priority=3 , match=(!ct.est), action=(reg0[[9]] = 1; next;) -+ table=??(ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;) ++ table=??(ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;) + table=??(ls_in_acl_hint ), priority=5 , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;) -+ table=??(ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) ++ table=??(ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) + table=??(ls_in_acl_hint ), priority=7 , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) +]) + +AT_CHECK([grep -e "ls_in_lb" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_lb ), priority=0 , match=(1), action=(next;) -+ table=??(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 10.0.0.2), action=(reg0[[1]] = 0; reg1 = 10.0.0.2; ct_lb(backends=10.0.0.10);) ++ table=??(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 10.0.0.2), action=(reg0[[1]] = 0; reg1 = 10.0.0.2; ct_lb_mark(backends=10.0.0.10);) +]) + +AT_CHECK([grep -e "ls_in_stateful" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_stateful ), priority=0 , match=(1), action=(next;) -+ table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;) -+ table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;) ++ table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;) ++ 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;) +]) + +AS_BOX([Remove and add the ACLs back with the apply-after-lb option]) @@ -3891,40 +7495,40 @@ index 652903761..25bd8a217 100644 + +AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_acl ), priority=0 , match=(1), action=(next;) -+ table=??(ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;) ++ table=??(ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;) + table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) -+ table=??(ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;) -+ table=??(ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;) -+ table=??(ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) ++ table=??(ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;) ++ table=??(ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;) ++ table=??(ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) + table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) -+ table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(ct_commit { ct_label.blocked = 1; }; /* drop */) ++ table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */) + table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[9]] == 1 && (ip4)), action=(/* drop */) + table=??(ls_in_acl_after_lb ), priority=2002 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg0[[1]] = 1; next;) + table=??(ls_in_acl_after_lb ), priority=2002 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(next;) + table=??(ls_in_acl_after_lb ), priority=2003 , match=(reg0[[7]] == 1 && (ip4 && icmp)), action=(reg0[[1]] = 1; next;) + 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_label.blocked = 1; }; /* drop */) ++ table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */) + table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(/* drop */) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) -+ table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;) -+ table=??(ls_in_acl_hint ), priority=2 , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;) ++ table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) ++ table=??(ls_in_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;) + table=??(ls_in_acl_hint ), priority=3 , match=(!ct.est), action=(reg0[[9]] = 1; next;) -+ table=??(ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;) ++ table=??(ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;) + table=??(ls_in_acl_hint ), priority=5 , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;) -+ table=??(ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) ++ table=??(ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) + table=??(ls_in_acl_hint ), priority=7 , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) +]) + +AT_CHECK([grep -e "ls_in_lb" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_lb ), priority=0 , match=(1), action=(next;) -+ table=??(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 10.0.0.2), action=(reg0[[1]] = 0; reg1 = 10.0.0.2; ct_lb(backends=10.0.0.10);) ++ table=??(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 10.0.0.2), action=(reg0[[1]] = 0; reg1 = 10.0.0.2; ct_lb_mark(backends=10.0.0.10);) +]) + +AT_CHECK([grep -e "ls_in_stateful" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_stateful ), priority=0 , match=(1), action=(next;) -+ table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;) -+ table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;) ++ table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;) ++ 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;) +]) + +AS_BOX([Remove and add the ACLs back with a few ACLs with apply-after-lb option]) @@ -3943,40 +7547,40 @@ index 652903761..25bd8a217 100644 + +AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_acl ), priority=0 , match=(1), action=(next;) -+ table=??(ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;) ++ table=??(ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;) + table=??(ls_in_acl ), priority=2002 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg0[[1]] = 1; next;) + table=??(ls_in_acl ), priority=2002 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(next;) + table=??(ls_in_acl ), priority=2003 , match=(reg0[[7]] == 1 && (ip4 && icmp)), action=(reg0[[1]] = 1; next;) + table=??(ls_in_acl ), priority=2003 , match=(reg0[[8]] == 1 && (ip4 && icmp)), action=(next;) + table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) -+ table=??(ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;) -+ table=??(ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;) -+ table=??(ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) ++ table=??(ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;) ++ table=??(ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;) ++ table=??(ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) + table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) -+ table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(ct_commit { ct_label.blocked = 1; }; /* drop */) ++ table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[10]] == 1 && (ip4)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */) + 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_label.blocked = 1; }; /* drop */) ++ table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */) + table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(/* drop */) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) -+ table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;) -+ table=??(ls_in_acl_hint ), priority=2 , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;) ++ table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) ++ table=??(ls_in_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;) + table=??(ls_in_acl_hint ), priority=3 , match=(!ct.est), action=(reg0[[9]] = 1; next;) -+ table=??(ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;) ++ table=??(ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;) + table=??(ls_in_acl_hint ), priority=5 , match=(!ct.trk), action=(reg0[[8]] = 1; reg0[[9]] = 1; next;) -+ table=??(ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) ++ table=??(ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) + table=??(ls_in_acl_hint ), priority=7 , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) +]) + +AT_CHECK([grep -e "ls_in_lb" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_lb ), priority=0 , match=(1), action=(next;) -+ table=??(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 10.0.0.2), action=(reg0[[1]] = 0; reg1 = 10.0.0.2; ct_lb(backends=10.0.0.10);) ++ table=??(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 10.0.0.2), action=(reg0[[1]] = 0; reg1 = 10.0.0.2; ct_lb_mark(backends=10.0.0.10);) +]) + +AT_CHECK([grep -e "ls_in_stateful" lsflows | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_stateful ), priority=0 , match=(1), action=(next;) -+ table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_label.blocked = 0; }; next;) -+ table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_label.blocked = 0; ct_label.label = reg3; }; next;) ++ table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 0), action=(ct_commit { ct_mark.blocked = 0; }; next;) ++ table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;) +]) + +AT_CLEANUP @@ -4006,6 +7610,150 @@ index 652903761..25bd8a217 100644 + +AT_CLEANUP +]) ++ ++OVN_FOR_EACH_NORTHD([ ++AT_SETUP([Load balancer ct_lb_mark backwards compatibility]) ++AT_KEYWORDS([lb]) ++ovn_start ++ ++check ovn-nbctl \ ++ -- ls-add ls \ ++ -- lr-add lr -- set logical_router lr options:chassis=local \ ++ -- lb-add lb-test 66.66.66.66 42.42.42.2 \ ++ -- ls-lb-add ls lb-test \ ++ -- lr-lb-add lr lb-test ++ ++AS_BOX([No chassis registered - use ct_lb_mark and ct_mark.natted]) ++check ovn-nbctl --wait=sb sync ++AT_CHECK([ovn-sbctl lflow-list | grep -e natted -e ct_lb], [0], [dnl ++ table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 66.66.66.66 && ct_mark.natted == 1), action=(next;) ++ table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 66.66.66.66), action=(ct_lb_mark(backends=42.42.42.2);) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && sctp), action=(reg1 = ip4.dst; reg2[[0..15]] = sctp.dst; ct_lb_mark;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && tcp), action=(reg1 = ip4.dst; reg2[[0..15]] = tcp.dst; ct_lb_mark;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && udp), action=(reg1 = ip4.dst; reg2[[0..15]] = udp.dst; ct_lb_mark;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && sctp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = sctp.dst; ct_lb_mark;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && tcp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = tcp.dst; ct_lb_mark;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && udp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = udp.dst; ct_lb_mark;) ++ table=7 (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; reg1 = 66.66.66.66; ct_lb_mark(backends=42.42.42.2);) ++ table=2 (ls_out_pre_stateful), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb_mark;) ++]) ++ ++AS_BOX([Chassis registered that doesn't support ct_lb_mark - use ct_lb and ct_label.natted]) ++check ovn-sbctl chassis-add hv geneve 127.0.0.1 ++check ovn-nbctl --wait=sb sync ++AT_CHECK([ovn-sbctl lflow-list | grep -e natted -e ct_lb], [0], [dnl ++ table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 66.66.66.66 && ct_label.natted == 1), action=(next;) ++ table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 66.66.66.66), action=(ct_lb(backends=42.42.42.2);) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && sctp), action=(reg1 = ip4.dst; reg2[[0..15]] = sctp.dst; ct_lb;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && tcp), action=(reg1 = ip4.dst; reg2[[0..15]] = tcp.dst; ct_lb;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && udp), action=(reg1 = ip4.dst; reg2[[0..15]] = udp.dst; ct_lb;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && sctp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = sctp.dst; ct_lb;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && tcp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = tcp.dst; ct_lb;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && udp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = udp.dst; ct_lb;) ++ table=7 (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; reg1 = 66.66.66.66; ct_lb(backends=42.42.42.2);) ++ table=2 (ls_out_pre_stateful), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb;) ++]) ++ ++AS_BOX([Chassis upgrades and supports ct_lb_mark - use ct_lb_mark and ct_mark.natted]) ++check ovn-sbctl set chassis hv other_config:ct-no-masked-label=true ++check ovn-nbctl --wait=sb sync ++AT_CHECK([ovn-sbctl lflow-list | grep -e natted -e ct_lb], [0], [dnl ++ table=6 (lr_in_dnat ), priority=110 , match=(ct.est && ip4 && reg0 == 66.66.66.66 && ct_mark.natted == 1), action=(next;) ++ table=6 (lr_in_dnat ), priority=110 , match=(ct.new && ip4 && reg0 == 66.66.66.66), action=(ct_lb_mark(backends=42.42.42.2);) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && sctp), action=(reg1 = ip4.dst; reg2[[0..15]] = sctp.dst; ct_lb_mark;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && tcp), action=(reg1 = ip4.dst; reg2[[0..15]] = tcp.dst; ct_lb_mark;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && udp), action=(reg1 = ip4.dst; reg2[[0..15]] = udp.dst; ct_lb_mark;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && sctp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = sctp.dst; ct_lb_mark;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && tcp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = tcp.dst; ct_lb_mark;) ++ table=7 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && udp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = udp.dst; ct_lb_mark;) ++ table=7 (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; reg1 = 66.66.66.66; ct_lb_mark(backends=42.42.42.2);) ++ table=2 (ls_out_pre_stateful), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb_mark;) ++]) ++ ++AT_CLEANUP ++]) ++ ++OVN_FOR_EACH_NORTHD([ ++AT_SETUP([ACL ct_mark.blocked backwards compatibility]) ++AT_KEYWORDS([acl]) ++ovn_start ++ ++check ovn-nbctl \ ++ -- ls-add ls \ ++ -- acl-add ls from-lport 1 1 allow-related \ ++ -- --apply-after-lb acl-add ls from-lport 1 1 allow-related \ ++ -- acl-add ls to-lport 1 1 allow-related ++ ++AS_BOX([No chassis registered - use ct_mark.blocked]) ++check ovn-nbctl --wait=sb sync ++AT_CHECK([ovn-sbctl lflow-list | grep 'ls.*acl.*blocked' ], [0], [dnl ++ table=8 (ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) ++ table=8 (ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;) ++ table=8 (ls_in_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;) ++ table=8 (ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) ++ table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;) ++ table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;) ++ table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) ++ table=9 (ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;) ++ table=3 (ls_out_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) ++ table=3 (ls_out_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;) ++ table=3 (ls_out_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;) ++ table=3 (ls_out_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) ++ table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;) ++ table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(next;) ++ table=4 (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) ++ table=4 (ls_out_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;) ++]) ++ ++AS_BOX([Chassis registered that doesn't support ct_mark.blocked - use ct_label.blocked]) ++check ovn-sbctl chassis-add hv geneve 127.0.0.1 ++check ovn-nbctl --wait=sb sync ++AT_CHECK([ovn-sbctl lflow-list | grep 'ls.*acl.*blocked' ], [0], [dnl ++ table=8 (ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) ++ table=8 (ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;) ++ table=8 (ls_in_acl_hint ), priority=2 , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;) ++ table=8 (ls_in_acl_hint ), priority=1 , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;) ++ table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;) ++ table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;) ++ table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) ++ table=9 (ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;) ++ table=3 (ls_out_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) ++ table=3 (ls_out_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;) ++ table=3 (ls_out_acl_hint ), priority=2 , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;) ++ table=3 (ls_out_acl_hint ), priority=1 , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;) ++ table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;) ++ table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;) ++ table=4 (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) ++ table=4 (ls_out_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_label.blocked == 1))), action=(reg0[[1]] = 1; next;) ++]) ++ ++AS_BOX([Chassis upgrades and supports ct_mark.blocked - use ct_mark.blocked]) ++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 'ls.*acl.*blocked' ], [0], [dnl ++ table=8 (ls_in_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) ++ table=8 (ls_in_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;) ++ table=8 (ls_in_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;) ++ table=8 (ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) ++ table=9 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;) ++ table=9 (ls_in_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(reg0[[9]] = 0; reg0[[10]] = 0; next;) ++ table=9 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) ++ table=9 (ls_in_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;) ++ table=3 (ls_out_acl_hint ), priority=6 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 1), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) ++ table=3 (ls_out_acl_hint ), priority=4 , match=(!ct.new && ct.est && !ct.rpl && ct_mark.blocked == 0), action=(reg0[[8]] = 1; reg0[[10]] = 1; next;) ++ table=3 (ls_out_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;) ++ table=3 (ls_out_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) ++ table=4 (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(next;) ++ table=4 (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(next;) ++ table=4 (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) ++ table=4 (ls_out_acl ), priority=1 , match=(ip && (!ct.est || (ct.est && ct_mark.blocked == 1))), action=(reg0[[1]] = 1; next;) ++]) ++ ++AT_CLEANUP ++]) diff --git a/tests/ovn-performance.at b/tests/ovn-performance.at index 10341ad72..f92fbebf1 100644 --- a/tests/ovn-performance.at @@ -4035,10 +7783,109 @@ index 10341ad72..f92fbebf1 100644 j=$((i%2 + 1)) lp=lp$i diff --git a/tests/ovn.at b/tests/ovn.at -index 9ec62e321..0f71219b9 100644 +index 9ec62e321..2ff40667e 100644 --- a/tests/ovn.at +++ b/tests/ovn.at -@@ -3369,8 +3369,8 @@ wait_for_ports_up +@@ -200,6 +200,9 @@ ct_label.ecmp_reply_port = ct_label[80..95] + ct_label.label = ct_label[96..127] + ct_label.natted = ct_label[1] + ct_mark = NXM_NX_CT_MARK ++ct_mark.blocked = ct_mark[0] ++ct_mark.ecmp_reply_port = ct_mark[16..31] ++ct_mark.natted = ct_mark[1] + ct_state = NXM_NX_CT_STATE + ]]) + AT_CLEANUP +@@ -737,10 +740,10 @@ ip,nw_src=10.0.0.2: conjunction(1, 1/2) + ip,nw_src=10.0.0.3: conjunction(1, 1/2) + ]) + +-lflow="ip && (!ct.est || (ct.est && ct_label.blocked == 1))" ++lflow="ip && (!ct.est || (ct.est && ct_mark.blocked == 1))" + AT_CHECK([expr_to_flow "$lflow"], [0], [dnl +-ct_state=+est+trk,ct_label=0x1/0x1,ip +-ct_state=+est+trk,ct_label=0x1/0x1,ipv6 ++ct_state=+est+trk,ct_mark=0x1/0x1,ip ++ct_state=+est+trk,ct_mark=0x1/0x1,ipv6 + ct_state=-est+trk,ip + ct_state=-est+trk,ipv6 + ]) +@@ -1051,6 +1054,10 @@ ct_lb(backends=fd0f::2,fd0f::3; hash_fields="eth_src,eth_dst,ip_src,ip_dst,sctp_ + uses group: id(8), name(type=select,selection_method=hash,fields(eth_src,eth_dst,ip_src,ip_dst,sctp_src,sctp_dst),bucket=bucket_id=0,weight:100,actions=ct(nat(dst=fd0f::2),commit,table=19,zone=NXM_NX_REG13[0..15],exec(set_field:2/2->ct_label)),bucket=bucket_id=1,weight:100,actions=ct(nat(dst=fd0f::3),commit,table=19,zone=NXM_NX_REG13[0..15],exec(set_field:2/2->ct_label))) + has prereqs ip + ++ct_lb_mark(backends=192.168.1.2:80,192.168.1.3:80); ++ encodes as group:9 ++ uses group: id(9), name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:100,actions=ct(nat(dst=192.168.1.2:80),commit,table=19,zone=NXM_NX_REG13[0..15],exec(set_field:2/2->ct_mark)),bucket=bucket_id=1,weight:100,actions=ct(nat(dst=192.168.1.3:80),commit,table=19,zone=NXM_NX_REG13[0..15],exec(set_field:2/2->ct_mark))) ++ has prereqs ip + # ct_next + ct_next; + encodes as ct(table=19,zone=NXM_NX_REG13[0..15]) +@@ -1803,13 +1810,13 @@ handle_svc_check(reg0); + # select + reg9[16..31] = select(1=50, 2=100, 3, ); + formats as reg9[16..31] = select(1=50, 2=100, 3=100); +- encodes as group:9 +- uses group: id(9), name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:50,actions=load:1->xreg4[16..31],resubmit(,19),bucket=bucket_id=1,weight:100,actions=load:2->xreg4[16..31],resubmit(,19),bucket=bucket_id=2,weight:100,actions=load:3->xreg4[16..31],resubmit(,19)) ++ encodes as group:10 ++ uses group: id(10), name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:50,actions=load:1->xreg4[16..31],resubmit(,19),bucket=bucket_id=1,weight:100,actions=load:2->xreg4[16..31],resubmit(,19),bucket=bucket_id=2,weight:100,actions=load:3->xreg4[16..31],resubmit(,19)) + + reg0 = select(1, 2); + formats as reg0 = select(1=100, 2=100); +- encodes as group:10 +- uses group: id(10), name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:100,actions=load:1->xxreg0[96..127],resubmit(,19),bucket=bucket_id=1,weight:100,actions=load:2->xxreg0[96..127],resubmit(,19)) ++ encodes as group:11 ++ uses group: id(11), name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:100,actions=load:1->xxreg0[96..127],resubmit(,19),bucket=bucket_id=1,weight:100,actions=load:2->xxreg0[96..127],resubmit(,19)) + + reg0 = select(1=, 2); + Syntax error at `,' expecting weight. +@@ -1826,12 +1833,12 @@ reg0[0..14] = select(1, 2, 3); + + fwd_group(liveness=true, childports="eth0", "lsp1"); + formats as fwd_group(liveness="true", childports="eth0", "lsp1"); +- encodes as group:11 +- uses group: id(11), name(type=select,selection_method=dp_hash,bucket=watch_port:5,load=0x5->NXM_NX_REG15[0..15],resubmit(,64),bucket=watch_port:17,load=0x17->NXM_NX_REG15[0..15],resubmit(,64)) ++ encodes as group:12 ++ uses group: id(12), name(type=select,selection_method=dp_hash,bucket=watch_port:5,load=0x5->NXM_NX_REG15[0..15],resubmit(,64),bucket=watch_port:17,load=0x17->NXM_NX_REG15[0..15],resubmit(,64)) + + fwd_group(childports="eth0", "lsp1"); +- encodes as group:12 +- uses group: id(12), name(type=select,selection_method=dp_hash,bucket=load=0x5->NXM_NX_REG15[0..15],resubmit(,64),bucket=load=0x17->NXM_NX_REG15[0..15],resubmit(,64)) ++ encodes as group:13 ++ uses group: id(13), name(type=select,selection_method=dp_hash,bucket=load=0x5->NXM_NX_REG15[0..15],resubmit(,64),bucket=load=0x17->NXM_NX_REG15[0..15],resubmit(,64)) + + fwd_group(childports=eth0); + Syntax error at `eth0' expecting logical switch port. +@@ -1840,8 +1847,8 @@ fwd_group(); + Syntax error at `)' expecting `;'. + + fwd_group(childports="eth0", "lsp1"); +- encodes as group:12 +- uses group: id(12), name(type=select,selection_method=dp_hash,bucket=load=0x5->NXM_NX_REG15[0..15],resubmit(,64),bucket=load=0x17->NXM_NX_REG15[0..15],resubmit(,64)) ++ encodes as group:13 ++ uses group: id(13), name(type=select,selection_method=dp_hash,bucket=load=0x5->NXM_NX_REG15[0..15],resubmit(,64),bucket=load=0x17->NXM_NX_REG15[0..15],resubmit(,64)) + + fwd_group(liveness=xyzzy, childports="eth0", "lsp1"); + Syntax error at `xyzzy' expecting true or false. +@@ -1954,6 +1961,17 @@ reg1[1] = lookup_fdb(outport, ip4.src); + reg1[1] = lookup_fdb(ip4.src, eth.src); + Cannot use numeric field ip4.src where string field is required. + ++# push/pop ++push(xxreg0);push(xxreg1[10..20]);push(eth.src);pop(xxreg0[0..47]);pop(xxreg0[48..57]);pop(xxreg1); ++ formats as push(xxreg0); push(xxreg1[10..20]); push(eth.src); pop(xxreg0[0..47]); pop(xxreg0[48..57]); pop(xxreg1); ++ encodes as push:NXM_NX_XXREG0[],push:NXM_NX_XXREG1[10..20],push:NXM_OF_ETH_SRC[],pop:NXM_NX_XXREG0[0..47],pop:NXM_NX_XXREG0[48..57],pop:NXM_NX_XXREG1[] ++ ++pop(eth.type); ++ Field eth.type is not modifiable. ++ ++push(abc); ++ Syntax error at `abc' expecting field name. ++ + # Miscellaneous negative tests. + ; + Syntax error at `;'. +@@ -3369,8 +3387,8 @@ wait_for_ports_up ovn-sbctl dump-flows ls > lsflows AT_CAPTURE_FILE([lsflows]) @@ -4049,7 +7896,7 @@ index 9ec62e321..0f71219b9 100644 ]) for i in 1 2; do -@@ -3432,8 +3432,8 @@ wait_for_ports_up +@@ -3432,8 +3450,8 @@ wait_for_ports_up ovn-sbctl dump-flows ls > lsflows AT_CAPTURE_FILE([lsflows]) @@ -4060,7 +7907,25 @@ index 9ec62e321..0f71219b9 100644 ]) test_nd_na() { -@@ -8651,6 +8651,44 @@ expected="fffffffffffff0000000000108060001080006040001f00000000001c0a80003000000 +@@ -7244,7 +7262,7 @@ ovs-vsctl -- add-port br-int vif2 -- \ + # Allow some time for ovn-northd and ovn-controller to catch up. + wait_for_ports_up + check ovn-nbctl --wait=hv sync +-ovn-nbctl dump-flows > sbflows ++ovn-sbctl dump-flows > sbflows + AT_CAPTURE_FILE([sbflows]) + + for i in 1 2; do +@@ -7849,7 +7867,7 @@ wait_for_ports_up + check ovn-nbctl --wait=hv sync + sleep 1 + +-ovn-nbctl dump-flows > sbflows ++ovn-sbctl dump-flows > sbflows + AT_CAPTURE_FILE([sbflows]) + + for i in 1 2; do +@@ -8651,6 +8669,44 @@ expected="fffffffffffff0000000000108060001080006040001f00000000001c0a80003000000 echo $expected >> expout AT_CHECK([sort packets], [0], [expout]) @@ -4105,7 +7970,7 @@ index 9ec62e321..0f71219b9 100644 OVN_CLEANUP([hv1]) AT_CLEANUP -@@ -8965,33 +9003,59 @@ ovn-nbctl lsp-set-addresses lp2 $lp2_mac +@@ -8965,33 +9021,59 @@ ovn-nbctl lsp-set-addresses lp2 $lp2_mac ovn-nbctl --wait=sb sync wait_for_ports_up @@ -4171,7 +8036,7 @@ index 9ec62e321..0f71219b9 100644 # Send packet that should be allowed without logging. packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac && ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip && -@@ -9016,25 +9080,41 @@ packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac && +@@ -9016,25 +9098,41 @@ packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac && tcp && tcp.flags==2 && tcp.src==4365 && tcp.dst==85" as hv ovs-appctl -t ovn-controller inject-pkt "$packet" @@ -4220,7 +8085,7 @@ index 9ec62e321..0f71219b9 100644 ]) OVN_CLEANUP([hv]) -@@ -9323,6 +9403,10 @@ check ovn-nbctl --wait=hv qos-add lsw0 to-lport 1002 'inport=="lp2" && is_chassi +@@ -9323,6 +9421,10 @@ check ovn-nbctl --wait=hv qos-add lsw0 to-lport 1002 'inport=="lp2" && is_chassi AT_CHECK([as hv ovs-ofctl dump-meters br-int -O OpenFlow13 | grep meter | wc -l], [0], [4 ]) @@ -4231,7 +8096,7 @@ index 9ec62e321..0f71219b9 100644 OVN_CLEANUP([hv]) AT_CLEANUP ]) -@@ -9658,8 +9742,8 @@ as hv1 ovs-appctl netdev-dummy/receive vm1 $packet +@@ -9658,8 +9760,8 @@ as hv1 ovs-appctl netdev-dummy/receive vm1 $packet # expected packet at foo2 packet=${dst_mac}${src_mac}8100000208004500001c0000000040110000${src_ip}${dst_ip}0035111100080000 @@ -4242,7 +8107,7 @@ index 9ec62e321..0f71219b9 100644 # Send ip packets between foo1 and bar2 (different switch, different HV) src_mac="f00000010205" -@@ -9673,8 +9757,8 @@ as hv1 ovs-appctl netdev-dummy/receive vm1 $packet +@@ -9673,8 +9775,8 @@ as hv1 ovs-appctl netdev-dummy/receive vm1 $packet src_mac="000000010204" dst_mac="f00000010208" packet=${dst_mac}${src_mac}8100000108004500001c000000003f110100${src_ip}${dst_ip}0035111100080000 @@ -4253,7 +8118,7 @@ index 9ec62e321..0f71219b9 100644 # Send ip packets between foo1 and bar1 # (different switch, loopback to same vm but different tag) -@@ -9703,11 +9787,11 @@ as hv1 ovs-appctl netdev-dummy/receive vm1 $packet +@@ -9703,11 +9805,11 @@ as hv1 ovs-appctl netdev-dummy/receive vm1 $packet # expected packet at bar3 packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000 @@ -4268,7 +8133,7 @@ index 9ec62e321..0f71219b9 100644 src_mac="f00000010205" dst_mac="000000010203" src_ip=`ip_to_hex 192 168 1 2` -@@ -9723,7 +9807,7 @@ echo $packet >> expected1 +@@ -9723,7 +9825,7 @@ echo $packet >> expected1 OVN_CHECK_PACKETS([hv1/vm1-tx.pcap], [expected1]) # Send packets from vm1 to bar1. @@ -4277,7 +8142,7 @@ index 9ec62e321..0f71219b9 100644 src_mac="f00000010203" dst_mac="000000010202" src_ip=`ip_to_hex 172 16 1 2` -@@ -9739,6 +9823,7 @@ echo $packet >> expected1 +@@ -9739,6 +9841,7 @@ echo $packet >> expected1 OVN_CHECK_PACKETS([hv1/vm1-tx.pcap], [expected1]) # Send broadcast packet from foo1. foo1 should not receive the same packet. @@ -4285,7 +8150,7 @@ index 9ec62e321..0f71219b9 100644 src_mac="f00000010205" dst_mac="ffffffffffff" src_ip=`ip_to_hex 192 168 1 2` -@@ -9749,6 +9834,11 @@ as hv1 ovs-appctl netdev-dummy/receive vm1 $packet +@@ -9749,6 +9852,11 @@ as hv1 ovs-appctl netdev-dummy/receive vm1 $packet # expected packet at VM1 OVN_CHECK_PACKETS([hv1/vm1-tx.pcap], [expected1]) @@ -4297,7 +8162,7 @@ index 9ec62e321..0f71219b9 100644 # Test binding of parent and container ports. ovn-nbctl lsp-set-options vm1 requested-chassis=foo -@@ -11896,9 +11986,10 @@ options:rxq_pcap=${pcap_file}-rx.pcap +@@ -11896,9 +12004,10 @@ options:rxq_pcap=${pcap_file}-rx.pcap OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int | grep -c "ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0"`]) # This shell function sends a Router Solicitation packet. @@ -4309,7 +8174,7 @@ index 9ec62e321..0f71219b9 100644 local request=333300000002${src_mac}86dd6000000000103aff${src_lla}ff02000000000000000000000000000285000efc000000000101${src_mac} local len=24 -@@ -11908,6 +11999,18 @@ test_ipv6_ra() { +@@ -11908,6 +12017,18 @@ test_ipv6_ra() { mtu_opt=05010000${mtu} fi @@ -4328,7 +8193,7 @@ index 9ec62e321..0f71219b9 100644 if test ${#prefix_opt} != 0; then prefix_opt=${prefix_opt}fdad1234567800000000000000000000 len=`expr $len + ${#prefix_opt} / 2` -@@ -11916,7 +12019,7 @@ test_ipv6_ra() { +@@ -11916,7 +12037,7 @@ test_ipv6_ra() { len=$(printf "%x" $len) local lrp_mac=fa163e000001 local lrp_lla=fe80000000000000f8163efffe000001 @@ -4337,7 +8202,7 @@ index 9ec62e321..0f71219b9 100644 echo $reply >> $inport.expected as hv1 ovs-appctl netdev-dummy/receive hv1-vif${inport} $request -@@ -11954,6 +12057,9 @@ reset_pcap_file hv1-vif3 hv1/vif3 +@@ -11954,6 +12075,9 @@ reset_pcap_file hv1-vif3 hv1/vif3 ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:mtu=1500 ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:send_periodic="false" ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:router_preference="LOW" @@ -4347,7 +8212,7 @@ index 9ec62e321..0f71219b9 100644 # Make sure that ovn-controller has installed the corresponding OF Flow. OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int | grep -c "ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0"`]) -@@ -11964,8 +12070,11 @@ default_prefix_option_config=030440c0ffffffffffffffff00000000 +@@ -11964,8 +12088,11 @@ default_prefix_option_config=030440c0ffffffffffffffff00000000 src_mac=fa163e000003 src_lla=fe80000000000000f8163efffe000003 mtu=000005dc @@ -4360,7 +8225,7 @@ index 9ec62e321..0f71219b9 100644 # NXT_RESUME should be 2. OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) -@@ -11987,6 +12096,8 @@ reset_pcap_file hv1-vif3 hv1/vif3 +@@ -11987,6 +12114,8 @@ reset_pcap_file hv1-vif3 hv1/vif3 # Set the address mode to dhcpv6_stateful, router_preference to HIGH ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:address_mode=dhcpv6_stateful ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:router_preference="HIGH" @@ -4369,7 +8234,7 @@ index 9ec62e321..0f71219b9 100644 # Make sure that ovn-controller has installed the corresponding OF Flow. OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int | grep -c "ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0"`]) -@@ -11997,7 +12108,7 @@ src_mac=fa163e000004 +@@ -11997,7 +12126,7 @@ src_mac=fa163e000004 src_lla=fe80000000000000f8163efffe000004 mtu=000005dc @@ -4378,7 +8243,7 @@ index 9ec62e321..0f71219b9 100644 # NXT_RESUME should be 3. OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) -@@ -12019,6 +12130,7 @@ reset_pcap_file hv1-vif3 hv1/vif3 +@@ -12019,6 +12148,7 @@ reset_pcap_file hv1-vif3 hv1/vif3 # Set the address mode to dhcpv6_stateless, reset router preference to default ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:address_mode=dhcpv6_stateless ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:router_preference="MEDIUM" @@ -4386,7 +8251,7 @@ index 9ec62e321..0f71219b9 100644 # Make sure that ovn-controller has installed the corresponding OF Flow. OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int | grep -c "ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0"`]) -@@ -14290,7 +14402,7 @@ ovn-sbctl dump-flows sw0 > sw0-flows +@@ -14290,7 +14420,7 @@ ovn-sbctl dump-flows sw0 > sw0-flows AT_CAPTURE_FILE([sw0-flows]) AT_CHECK([grep -E 'ls_(in|out)_acl' sw0-flows |grep reject| sed 's/table=../table=??/' | sort], [0], [dnl @@ -4395,7 +8260,7 @@ index 9ec62e321..0f71219b9 100644 ]) -@@ -15135,6 +15247,92 @@ OVN_CLEANUP([hv1]) +@@ -15135,6 +15265,92 @@ OVN_CLEANUP([hv1]) AT_CLEANUP ]) @@ -4488,7 +8353,7 @@ index 9ec62e321..0f71219b9 100644 OVN_FOR_EACH_NORTHD([ AT_SETUP([Superseding ACLs with conjunction]) ovn_start -@@ -16181,17 +16379,17 @@ ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys +@@ -16181,17 +16397,17 @@ ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys AT_CHECK([ovn-sbctl dump-flows ls1 | grep "offerip = 10.0.0.6" | \ wc -l], [0], [0 ]) @@ -4510,7 +8375,7 @@ index 9ec62e321..0f71219b9 100644 grep controller | grep tp_src=546 | grep \ "ae.70.00.00.00.00.00.00.00.00.00.00.00.00.00.06" | wc -l], [0], [0 ]) -@@ -16799,7 +16997,7 @@ wait_for_ports_up ls1-lp_ext1 +@@ -16799,7 +17015,7 @@ wait_for_ports_up ls1-lp_ext1 # There should be a flow in hv2 to drop traffic from ls1-lp_ext1 destined # to router mac. AT_CHECK([as hv2 ovs-ofctl dump-flows br-int \ @@ -4519,7 +8384,239 @@ index 9ec62e321..0f71219b9 100644 grep -c "actions=drop"], [0], [1 ]) -@@ -18476,7 +18674,7 @@ check_row_count Port_Binding 1 logical_port=sw0-vir virtual_parent=sw0-p1 +@@ -17131,22 +17347,22 @@ test_ip_packet_larger() { + dst_mac="00000000ff01" # sw0-lr0 mac (internal router leg) + src_ip=`ip_to_hex 10 0 0 3` + dst_ip=`ip_to_hex 172 168 0 3` +- # Set the packet length to 118. +- pkt_len=0076 +- packet=${dst_mac}${src_mac}08004500${pkt_len}000000004001c3d9 +- orig_packet_l3=${src_ip}${dst_ip}0304000000000000 +- orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000 ++ # Set the packet length to 114. ++ pkt_len=0072 ++ packet=${dst_mac}${src_mac}08004500${pkt_len}000000004001c3dd ++ orig_packet_l3=${src_ip}${dst_ip}0304fcfb00000000 + orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000 + orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000 + orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000 + orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000 ++ orig_packet_l3=${orig_packet_l3}0000000000000000000000000000 + + packet=${packet}${orig_packet_l3} + + gw_ip_garp=ffffffffffff00002020121308060001080006040001000020201213aca80064000000000000aca80064 + + packet_bytes=$(expr ${#packet} / 2) +- mtu_needed=$(expr ${packet_bytes} - 18) ++ mtu_needed=$(expr ${packet_bytes} - 14) + + # If icmp_pmtu_reply_expected is 0, it means the packet is lesser than + # the gateway mtu and should be delivered to the provider bridge via the +@@ -17160,23 +17376,23 @@ test_ip_packet_larger() { + dst_mac="00000012af11" + src_ip=`ip_to_hex 10 0 0 3` + dst_ip=`ip_to_hex 172 168 0 3` +- expected=${dst_mac}${src_mac}08004500${pkt_len}000000003f01c4d9 +- expected=${expected}${src_ip}${dst_ip}0304000000000000 +- expected=${expected}000000000000000000000000000000000000 ++ expected=${dst_mac}${src_mac}08004500${pkt_len}000000003f01c4dd ++ expected=${expected}${src_ip}${dst_ip}0304fcfb00000000 + expected=${expected}000000000000000000000000000000000000 + expected=${expected}000000000000000000000000000000000000 + expected=${expected}000000000000000000000000000000000000 + expected=${expected}000000000000000000000000000000000000 ++ expected=${expected}0000000000000000000000000000 + echo $expected > br_phys_n1.expected + else + src_ip=`ip_to_hex 10 0 0 1` + dst_ip=`ip_to_hex 10 0 0 3` + # pkt len should be 146 (28 (icmp packet) + 118 (orig ip + payload)) +- reply_pkt_len=0092 +- ip_csum=f993 +- icmp_reply=${src_mac}${dst_mac}08004500${reply_pkt_len}00004000fe016867 ++ reply_pkt_len=008e ++ ip_csum=fc97 ++ icmp_reply=${src_mac}${dst_mac}08004500${reply_pkt_len}00004000fe01686b + icmp_reply=${icmp_reply}${src_ip}${dst_ip}0304${ip_csum}0000$(printf "%04x" $mtu) +- icmp_reply=${icmp_reply}4500${pkt_len}000000003f01c4d9 ++ icmp_reply=${icmp_reply}4500${pkt_len}000000003f01c4dd + icmp_reply=${icmp_reply}${orig_packet_l3} + echo $icmp_reply > hv1-vif1.expected + fi +@@ -17219,15 +17435,15 @@ test_ip_packet_larger_ext() { + dst_mac="$2" # lr0-public mac + src_ip=`ip_to_hex 172 168 0 4` + dst_ip="$3" +- # Set the packet length to 118. +- pkt_len=0076 ++ # Set the packet length to 114. ++ pkt_len=0072 + packet=${dst_mac}${src_mac}08004500${pkt_len}000000004001${checksum} + orig_packet_l3=${src_ip}${dst_ip}0900000000000000 + orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000 + orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000 + orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000 + orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000 +- orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000 ++ orig_packet_l3=${orig_packet_l3}0000000000000000000000000000 + packet=${packet}${orig_packet_l3} + + # A Gratuitous ARP (as shown next line) might be transmitted, but +@@ -17238,8 +17454,8 @@ test_ip_packet_larger_ext() { + src_ip="$3" + dst_ip=`ip_to_hex 172 168 0 4` + # pkt len should be 146 (28 (icmp packet) + 118 (orig ip + payload)) +- reply_pkt_len=0092 +- ip_csum=f397 ++ reply_pkt_len=008e ++ ip_csum=f39b + 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} +@@ -17271,10 +17487,10 @@ test_ip6_packet_larger() { + local payload=0000000000000000000000000000000000000000 + local payload=${payload}0000000000000000000000000000000000000000 + local payload=${payload}0000000000000000000000000000000000000000 +- local payload=${payload}0000000000000000000000000000000000000000 ++ local payload=${payload}00000000000000000000000000000000 + +- local ip6_hdr=6000000000583afe${ipv6_src}${ipv6_dst} +- local packet=${eth_dst}${eth_src}86dd${ip6_hdr}8000ec7662f00001${payload} ++ local ip6_hdr=6000000000543afe${ipv6_src}${ipv6_dst} ++ local packet=${eth_dst}${eth_src}86dd${ip6_hdr}8000ec7a62f00001${payload} + + as hv1 reset_pcap_file br-phys_n1 hv1/br-phys_n1 + as hv1 reset_pcap_file hv1-vif1 hv1/vif1 +@@ -17287,16 +17503,16 @@ test_ip6_packet_larger() { + AT_CAPTURE_FILE([trace-$mtu]) + + packet_bytes=$(expr ${#packet} / 2) +- mtu_needed=$(expr ${packet_bytes} - 18) ++ mtu_needed=$(expr ${packet_bytes} - 14) + if test $mtu -lt $mtu_needed; then + # First construct the inner IPv6 packet. +- inner_ip6=6000000000583afd${ipv6_src}${ipv6_dst} ++ inner_ip6=6000000000543afd${ipv6_src}${ipv6_dst} + inner_icmp6=8000000062f00001 + inner_icmp6_and_payload=$(icmp6_csum_inplace ${inner_icmp6}${payload} ${inner_ip6}) + inner_packet=${inner_ip6}${inner_icmp6_and_payload} + + # Then the outer. +- outer_ip6=6000000000883afe${ipv6_rt}${ipv6_src} ++ outer_ip6=6000000000843afe${ipv6_rt}${ipv6_src} + outer_icmp6_and_payload=$(icmp6_csum_inplace 020000000000$(printf "%04x" $mtu)${inner_packet} $outer_ip6) + outer_packet=${outer_ip6}${outer_icmp6_and_payload} + +@@ -17327,9 +17543,9 @@ test_ip6_packet_larger_ext() { + local payload=0000000000000000000000000000000000000000 + local payload=${payload}0000000000000000000000000000000000000000 + local payload=${payload}0000000000000000000000000000000000000000 +- local payload=${payload}0000000000000000000000000000000000000000 ++ local payload=${payload}00000000000000000000000000000000 + +- local ip6_hdr=6000000000583afe${ipv6_src}${ipv6_dst} ++ local ip6_hdr=6000000000543afe${ipv6_src}${ipv6_dst} + local packet=${eth_dst}${eth_src}86dd${ip6_hdr}9000${icmp_checksum}62f00001${payload} + + # Some ** ARP ** packets might still be received - ignore them +@@ -17344,13 +17560,13 @@ test_ip6_packet_larger_ext() { + AT_CAPTURE_FILE([trace-$mtu]) + + # First construct the inner IPv6 packet. +- inner_ip6=6000000000583afe${ipv6_src}${ipv6_dst} ++ inner_ip6=6000000000543afe${ipv6_src}${ipv6_dst} + inner_icmp6=9000000062f00001 + inner_icmp6_and_payload=$(icmp6_csum_inplace ${inner_icmp6}${payload} ${inner_ip6}) + inner_packet=${inner_ip6}${inner_icmp6_and_payload} + + # Then the outer. +- outer_ip6=6000000000883afe${ipv6_dst}${ipv6_src} ++ outer_ip6=6000000000843afe${ipv6_dst}${ipv6_src} + outer_icmp6_and_payload=$(icmp6_csum_inplace 020000000000$(printf "%04x" $mtu)${inner_packet} $outer_ip6) + outer_packet=${outer_ip6}${outer_icmp6_and_payload} + +@@ -17383,7 +17599,7 @@ logical_port=lr0-public mac="00\:00\:00\:12\:af\:11" + # Try different gateway mtus and send a 142-byte packet (corresponding + # to a 124-byte MTU). If the MTU is less than 124, ovn-controller + # should send icmp host not reachable with pmtu set to $mtu. +-for mtu in 100 500 118; do ++for mtu in 100 500 114; do + AS_BOX([testing mtu $mtu]) + check ovn-nbctl --wait=hv set logical_router_port lr0-public options:gateway_mtu=$mtu + ovn-sbctl dump-flows > sbflows-$mtu +@@ -17392,7 +17608,7 @@ for mtu in 100 500 118; do + OVS_WAIT_FOR_OUTPUT([ + as hv1 ovs-ofctl dump-flows br-int > br-int-flows-$mtu + AT_CAPTURE_FILE([br-int-flows-$mtu]) +- grep "check_pkt_larger($(expr $mtu + 18))" br-int-flows-$mtu | wc -l], [0], [4 ++ grep "check_pkt_larger($(expr $mtu + 14))" br-int-flows-$mtu | wc -l], [0], [4 + ]) + + AS_BOX([testing outgoing traffic mtu $mtu - IPv4]) +@@ -17410,20 +17626,20 @@ AT_CAPTURE_FILE([ext-sbflows-100]) + OVS_WAIT_FOR_OUTPUT([ + as hv1 ovs-ofctl dump-flows br-int > ext-br-int-flows-100 + AT_CAPTURE_FILE([ext-br-int-flows-100]) +- grep "check_pkt_larger(118)" ext-br-int-flows-100 | wc -l], [0], [4 ++ grep "check_pkt_larger(114)" ext-br-int-flows-100 | wc -l], [0], [4 + ]) + + AS_BOX([testing ingress traffic mtu 100 - IPv4]) +-test_ip_packet_larger_ext 1 000020201213 $(ip_to_hex 172 168 0 100) 20cf 100 22b2 ++test_ip_packet_larger_ext 1 000020201213 $(ip_to_hex 172 168 0 100) 20cf 100 22b6 + + AS_BOX([testing ingress traffic mtu 100 - IPv4 FIP]) +-test_ip_packet_larger_ext 2 f00000010204 $(ip_to_hex 172 168 0 110) 20c5 100 22a8 ++test_ip_packet_larger_ext 2 f00000010204 $(ip_to_hex 172 168 0 110) 20c5 100 22ac + + AS_BOX([testing ingress traffic mtu 100 - IPv6]) +-test_ip6_packet_larger_ext 1 000020201213 20000000000000000000000000000001 100 cc76 ++test_ip6_packet_larger_ext 1 000020201213 20000000000000000000000000000001 100 cc7a + + AS_BOX([testing ingress traffic mtu 100 - IPv6 FIP]) +-test_ip6_packet_larger_ext 2 f00000010204 20000000000000000000000000000002 100 cc75 ++test_ip6_packet_larger_ext 2 f00000010204 20000000000000000000000000000002 100 cc79 + + ovn-nbctl lsp-del sw0-lr0 + +@@ -17453,7 +17669,7 @@ logical_port=lr1-public mac="00\:00\:00\:12\:af\:11" + # Try different gateway mtus and send a 142-byte packet (corresponding + # to a 124-byte MTU). If the MTU is less than 124, ovn-controller + # should send icmp host not reachable with pmtu set to $mtu. +-for mtu in 100 500 118; do ++for mtu in 100 500 114; do + AS_BOX([testing gw mtu $mtu]) + check ovn-nbctl --wait=hv set logical_router_port lr1-public options:gateway_mtu=$mtu + ovn-sbctl dump-flows > sbflows-gw-$mtu +@@ -17462,7 +17678,7 @@ for mtu in 100 500 118; do + OVS_WAIT_FOR_OUTPUT([ + as hv1 ovs-ofctl dump-flows br-int > br-int-gw-flows-$mtu + AT_CAPTURE_FILE([br-int-gw-flows-$mtu]) +- grep "check_pkt_larger($(expr $mtu + 18))" br-int-gw-flows-$mtu | wc -l], [0], [3 ++ grep "check_pkt_larger($(expr $mtu + 14))" br-int-gw-flows-$mtu | wc -l], [0], [3 + ]) + + AS_BOX([testing outgoing traffic mtu $mtu for gw router - IPv4]) +@@ -17480,14 +17696,14 @@ AT_CAPTURE_FILE([ext-gw-sbflows-100]) + OVS_WAIT_FOR_OUTPUT([ + as hv1 ovs-ofctl dump-flows br-int > ext-br-int-gw-flows-100 + AT_CAPTURE_FILE([ext-br-int-gw-flows-100]) +- grep "check_pkt_larger(118)" ext-br-int-gw-flows-100 | wc -l], [0], [3 ++ grep "check_pkt_larger(114)" ext-br-int-gw-flows-100 | wc -l], [0], [3 + ]) + + AS_BOX([testing ingress traffic mtu 100 for gw router - IPv4]) +-test_ip_packet_larger_ext 1 000020201213 $(ip_to_hex 172 168 0 100) 20cf 100 22b2 ++test_ip_packet_larger_ext 1 000020201213 $(ip_to_hex 172 168 0 100) 20cf 100 22b6 + + AS_BOX([testing ingress traffic mtu 100 for gw router - IPv6]) +-test_ip6_packet_larger_ext 1 000020201213 20000000000000000000000000000001 100 cc76 ++test_ip6_packet_larger_ext 1 000020201213 20000000000000000000000000000001 100 cc7a + + OVN_CLEANUP([hv1]) + AT_CLEANUP +@@ -18476,7 +18692,7 @@ check_row_count Port_Binding 1 logical_port=sw0-vir virtual_parent=sw0-p1 wait_for_ports_up sw0-vir check ovn-nbctl --wait=hv sync AT_CHECK([test 2 = `cat hv1/ovn-controller.log | grep "pinctrl received packet-in" | \ @@ -4528,7 +8625,7 @@ index 9ec62e321..0f71219b9 100644 wait_row_count Port_Binding 1 logical_port=sw0-vir6 chassis=$hv1_ch_uuid check_row_count Port_Binding 1 logical_port=sw0-vir6 virtual_parent=sw0-p1 -@@ -18525,7 +18723,7 @@ eth_dst=00000000ff01 +@@ -18525,7 +18741,7 @@ eth_dst=00000000ff01 ip_src=$(ip_to_hex 10 0 0 10) ip_dst=$(ip_to_hex 172 168 0 101) send_icmp_packet 1 1 $eth_src $eth_dst $ip_src $ip_dst c4c9 0000000000000000000000 @@ -4537,16 +8634,51 @@ index 9ec62e321..0f71219b9 100644 priority=80,ip,reg15=0x3,metadata=0x3,nw_src=10.0.0.10 actions=drop ]) -@@ -21964,7 +22162,7 @@ OVS_WAIT_FOR_OUTPUT( - (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && sctp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = sctp.dst; ct_lb;) - (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && tcp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = tcp.dst; ct_lb;) - (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && udp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = udp.dst; ct_lb;) +@@ -21808,8 +22024,8 @@ AT_CHECK([for regex in ct_snat ct_dnat ip4.dst= ip4.src=; do + grep -c "$regex" sbflows; + done], [0], [0 + 0 +-2 +-2 ++1 ++1 + ]) + + echo "----------- Post Traffic hv1 dump -----------" +@@ -21956,22 +22172,22 @@ wait_row_count Service_Monitor 2 + AT_CAPTURE_FILE([sbflows]) + OVS_WAIT_FOR_OUTPUT( + [ovn-sbctl dump-flows > sbflows +- ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 | sed 's/table=..//'], 0, ++ ovn-sbctl dump-flows sw0 | grep ct_lb_mark | grep priority=120 | sed 's/table=..//'], 0, + [dnl +- (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && sctp), action=(reg1 = ip4.dst; reg2[[0..15]] = sctp.dst; ct_lb;) +- (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && tcp), action=(reg1 = ip4.dst; reg2[[0..15]] = tcp.dst; ct_lb;) +- (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && udp), action=(reg1 = ip4.dst; reg2[[0..15]] = udp.dst; ct_lb;) +- (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && sctp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = sctp.dst; ct_lb;) +- (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && tcp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = tcp.dst; ct_lb;) +- (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && udp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = udp.dst; ct_lb;) - (ls_in_stateful ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80; hash_fields="ip_dst,ip_src,tcp_dst,tcp_src");) -+ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb(backends=10.0.0.3:80,20.0.0.3:80; hash_fields="ip_dst,ip_src,tcp_dst,tcp_src");) ++ (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && sctp), action=(reg1 = ip4.dst; reg2[[0..15]] = sctp.dst; ct_lb_mark;) ++ (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && tcp), action=(reg1 = ip4.dst; reg2[[0..15]] = tcp.dst; ct_lb_mark;) ++ (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4 && udp), action=(reg1 = ip4.dst; reg2[[0..15]] = udp.dst; ct_lb_mark;) ++ (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && sctp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = sctp.dst; ct_lb_mark;) ++ (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && tcp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = tcp.dst; ct_lb_mark;) ++ (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip6 && udp), action=(xxreg1 = ip6.dst; reg2[[0..15]] = udp.dst; ct_lb_mark;) ++ (ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 10.0.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; reg1 = 10.0.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80; hash_fields="ip_dst,ip_src,tcp_dst,tcp_src");) ]) AT_CAPTURE_FILE([sbflows2]) -@@ -22006,7 +22204,7 @@ ovn-sbctl dump-flows sw0 > sbflows3 + OVS_WAIT_FOR_OUTPUT( + [ovn-sbctl dump-flows > sbflows2 +- ovn-sbctl dump-flows lr0 | grep ct_lb | grep priority=120 | sed 's/table=..//'], 0, +- [ (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb(backends=10.0.0.3:80,20.0.0.3:80; hash_fields="ip_dst,ip_src,tcp_dst,tcp_src");) ++ ovn-sbctl dump-flows lr0 | grep ct_lb_mark | grep priority=120 | sed 's/table=..//'], 0, ++ [ (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80; hash_fields="ip_dst,ip_src,tcp_dst,tcp_src");) + ]) + + # get the svc monitor mac. +@@ -22006,13 +22222,13 @@ ovn-sbctl dump-flows sw0 > sbflows3 AT_CHECK( [grep "ip4.dst == 10.0.0.10 && tcp.dst == 80" sbflows3 | grep priority=120 |\ sed 's/table=../table=??/'], [0], @@ -4555,7 +8687,318 @@ index 9ec62e321..0f71219b9 100644 ]) AT_CAPTURE_FILE([sbflows4]) -@@ -28539,6 +28737,10 @@ done + ovn-sbctl dump-flows lr0 > sbflows4 + AT_CHECK([grep lr_in_dnat sbflows4 | grep priority=120 | sed 's/table=..//' | sort], [0], [dnl +- (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_label.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;) ++ (lr_in_dnat ), priority=120 , match=(ct.est && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;) + (lr_in_dnat ), priority=120 , match=(ct.new && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && is_chassis_resident("cr-lr0-public")), action=(drop;) + ]) + +@@ -25070,6 +25286,7 @@ AT_CHECK([ + ovn-nbctl set Logical_Router $gw_uuid options:chassis=hv1 + ovn-nbctl --wait=hv sync + ++ovn-sbctl list logical_flow > lflows + # And ensure that ECMP symmetric reply flows are present only on hv1 + as hv1 ovs-ofctl dump-flows br-int > hv1flows + AT_CAPTURE_FILE([hv1flows]) +@@ -25080,11 +25297,11 @@ AT_CHECK([ + for hv in 1 2; do + grep table=15 hv${hv}flows | \ + grep "priority=100" | \ +- grep -c "ct(commit,zone=NXM_NX_REG11\\[[0..15\\]],.*exec(move:NXM_OF_ETH_SRC\\[[\\]]->NXM_NX_CT_LABEL\\[[32..79\\]],load:0x[[0-9]]->NXM_NX_CT_LABEL\\[[80..95\\]]))" ++ grep -c "ct(commit,zone=NXM_NX_REG11\\[[0..15\\]],.*exec(move:NXM_OF_ETH_SRC\\[[\\]]->NXM_NX_CT_LABEL\\[[32..79\\]],load:0x[[0-9]]->NXM_NX_CT_MARK\\[[16..31\\]]))" + + grep table=23 hv${hv}flows | \ + grep "priority=200" | \ +- grep -c "actions=move:NXM_NX_CT_LABEL\\[[32..79\\]]->NXM_OF_ETH_DST\\[[\\]]" ++ grep -c "move:NXM_NX_CT_LABEL\\[[\\]]->NXM_NX_XXREG1\\[[\\]],move:NXM_NX_XXREG1\\[[32..79\\]]->NXM_OF_ETH_DST" + done; :], [0], [dnl + 1 + 1 +@@ -25183,12 +25400,12 @@ AT_CHECK([ + AT_CHECK([ + test 0 -eq $(as hv2 ovs-ofctl dump-flows br-int table=15 | \ + grep "priority=100" | \ +- grep "ct(commit,zone=NXM_NX_REG11\\[[0..15\\]],exec(move:NXM_OF_ETH_SRC\\[[\\]]->NXM_NX_CT_LABEL\\[[32..79\\]],load:0x[[0-9]]->NXM_NX_CT_LABEL\\[[80..95\\]]))" -c) ++ grep "ct(commit,zone=NXM_NX_REG11\\[[0..15\\]],exec(move:NXM_OF_ETH_SRC\\[[\\]]->NXM_NX_CT_LABEL\\[[32..79\\]],load:0x[[0-9]]->NXM_NX_CT_MARK\\[[16..31\\]]))" -c) + ]) + AT_CHECK([ + test 0 -eq $(as hv2 ovs-ofctl dump-flows br-int table=21 | \ + grep "priority=200" | \ +- grep "actions=move:NXM_NX_CT_LABEL\\[[32..79\\]]->NXM_OF_ETH_DST\\[[\\]]" -c) ++ grep "actions=move:NXM_NX_CT_LABEL\\[[\\]]->NXM_OF_ETH_DST\\[[\\]]" -c) + ]) + + # Now make GW a gateway router on hv1 +@@ -25205,11 +25422,11 @@ AT_CHECK([ + for hv in 1 2; do + grep table=15 hv${hv}flows | \ + grep "priority=100" | \ +- grep -c "ct(commit,zone=NXM_NX_REG11\\[[0..15\\]],.*exec(move:NXM_OF_ETH_SRC\\[[\\]]->NXM_NX_CT_LABEL\\[[32..79\\]],load:0x[[0-9]]->NXM_NX_CT_LABEL\\[[80..95\\]]))" ++ grep -c "ct(commit,zone=NXM_NX_REG11\\[[0..15\\]],.*exec(move:NXM_OF_ETH_SRC\\[[\\]]->NXM_NX_CT_LABEL\\[[32..79\\]],load:0x[[0-9]]->NXM_NX_CT_MARK\\[[16..31\\]]))" + + grep table=23 hv${hv}flows | \ + grep "priority=200" | \ +- grep -c "actions=move:NXM_NX_CT_LABEL\\[[32..79\\]]->NXM_OF_ETH_DST\\[[\\]]" ++ grep -c "move:NXM_NX_CT_LABEL\\[[\\]]->NXM_NX_XXREG1\\[[\\]],move:NXM_NX_XXREG1\\[[32..79\\]]->NXM_OF_ETH_DST" + done; :], [0], [dnl + 1 + 1 +@@ -26427,6 +26644,7 @@ ovs-vsctl -- add-port br-int hv1-vif2 -- \ + options:tx_pcap=hv1/vif2-tx.pcap \ + options:rxq_pcap=hv1/vif2-rx.pcap \ + ofport-request=2 ++ovs-vsctl set open . external_ids:ovn-check-ct-label-for-lb-hairpin=false + + sim_add hv2 + as hv2 +@@ -26482,7 +26700,7 @@ OVS_WAIT_UNTIL( + ) + + AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=68 | ofctl_strip_all | grep -v NXST], [0], [dnl +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) + ]) + + AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=69], [0], [dnl +@@ -26509,9 +26727,9 @@ OVS_WAIT_UNTIL( + ) + + AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=68 | ofctl_strip_all | grep -v NXST], [0], [dnl +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) + ]) + + AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=69], [0], [dnl +@@ -26542,9 +26760,9 @@ OVS_WAIT_UNTIL( + ) + + AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=68 | ofctl_strip_all | grep -v NXST], [0], [dnl +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) + ]) + + AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=69 | grep -v NXST], [1], [dnl +@@ -26566,10 +26784,10 @@ OVS_WAIT_UNTIL( + ) + + AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=68 | ofctl_strip_all | grep -v NXST], [0], [dnl +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) + ]) + + AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=69 | grep -v NXST], [1], [dnl +@@ -26582,10 +26800,10 @@ AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=70 | ofctl_strip_all | grep - + ]) + + AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=68 | ofctl_strip_all | grep -v NXST], [0], [dnl +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) + ]) + + AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=69 | grep -v NXST], [1], [dnl +@@ -26608,11 +26826,11 @@ OVS_WAIT_UNTIL( + ) + + AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=68 | ofctl_strip_all | grep -v NXST], [0], [dnl +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) + ]) + + AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=69 | grep -v NXST], [1], [dnl +@@ -26626,11 +26844,11 @@ AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=70 | ofctl_strip_all | grep - + ]) + + AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=68 | ofctl_strip_all | grep -v NXST], [0], [dnl +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) + ]) + + AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=69 | grep -v NXST], [1], [dnl +@@ -26654,12 +26872,12 @@ OVS_WAIT_UNTIL( + ) + + AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=68 | ofctl_strip_all | grep -v NXST], [0], [dnl +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) + ]) + + AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=69 | grep -v NXST], [1], [dnl +@@ -26674,12 +26892,12 @@ AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=70 | ofctl_strip_all | grep - + ]) + + AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=68 | ofctl_strip_all | grep -v NXST], [0], [dnl +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) + ]) + + AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=69 | grep -v NXST], [1], [dnl +@@ -26706,12 +26924,12 @@ OVS_WAIT_UNTIL( + ) + + AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=68 | ofctl_strip_all | grep -v NXST], [0], [dnl +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) + ]) + + AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=69 | grep -v NXST], [1], [dnl +@@ -26726,12 +26944,12 @@ AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=70 | ofctl_strip_all | grep - + ]) + + AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=68 | ofctl_strip_all | grep -v NXST], [0], [dnl +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) + ]) + + AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=69 | grep -v NXST], [1], [dnl +@@ -26759,12 +26977,12 @@ check ovn-sbctl \ + -- remove load_balancer lb-ipv6-udp options hairpin_orig_tuple + + OVS_WAIT_FOR_OUTPUT([as hv1 ovs-ofctl dump-flows br-int table=68 | ofctl_strip_all | grep -v NXST], [0], [dnl +- table=68, priority=100,ct_state=+trk+dnat,ct_label=0x2/0x2,ct_ipv6_dst=8800::88,ct_nw_proto=17,ct_tp_dst=4040,udp6,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_state=+trk+dnat,ct_label=0x2/0x2,ct_ipv6_dst=8800::88,ct_nw_proto=6,ct_tp_dst=8080,tcp6,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_state=+trk+dnat,ct_label=0x2/0x2,ct_nw_dst=88.88.88.88,ct_nw_proto=17,ct_tp_dst=4040,udp,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_state=+trk+dnat,ct_label=0x2/0x2,ct_nw_dst=88.88.88.88,ct_nw_proto=6,ct_tp_dst=8080,tcp,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_state=+trk+dnat,ct_label=0x2/0x2,ct_nw_dst=88.88.88.90,ct_nw_proto=6,ct_tp_dst=8080,tcp,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_state=+trk+dnat,ct_label=0x2/0x2,ct_nw_dst=88.88.88.90,ct_nw_proto=6,ct_tp_dst=8080,tcp,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_state=+trk+dnat,ct_mark=0x2/0x2,ct_ipv6_dst=8800::88,ct_nw_proto=17,ct_tp_dst=4040,udp6,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_state=+trk+dnat,ct_mark=0x2/0x2,ct_ipv6_dst=8800::88,ct_nw_proto=6,ct_tp_dst=8080,tcp6,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_state=+trk+dnat,ct_mark=0x2/0x2,ct_nw_dst=88.88.88.88,ct_nw_proto=17,ct_tp_dst=4040,udp,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_state=+trk+dnat,ct_mark=0x2/0x2,ct_nw_dst=88.88.88.88,ct_nw_proto=6,ct_tp_dst=8080,tcp,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_state=+trk+dnat,ct_mark=0x2/0x2,ct_nw_dst=88.88.88.90,ct_nw_proto=6,ct_tp_dst=8080,tcp,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_state=+trk+dnat,ct_mark=0x2/0x2,ct_nw_dst=88.88.88.90,ct_nw_proto=6,ct_tp_dst=8080,tcp,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) + ]) + + AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=69 | grep -v NXST], [1], [dnl +@@ -26779,12 +26997,12 @@ OVS_WAIT_FOR_OUTPUT([as hv1 ovs-ofctl dump-flows br-int table=70 | ofctl_strip_a + ]) + + OVS_WAIT_FOR_OUTPUT([as hv2 ovs-ofctl dump-flows br-int table=68 | ofctl_strip_all | grep -v NXST], [0], [dnl +- table=68, priority=100,ct_state=+trk+dnat,ct_label=0x2/0x2,ct_ipv6_dst=8800::88,ct_nw_proto=17,ct_tp_dst=4040,udp6,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_state=+trk+dnat,ct_label=0x2/0x2,ct_ipv6_dst=8800::88,ct_nw_proto=6,ct_tp_dst=8080,tcp6,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_state=+trk+dnat,ct_label=0x2/0x2,ct_nw_dst=88.88.88.88,ct_nw_proto=17,ct_tp_dst=4040,udp,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_state=+trk+dnat,ct_label=0x2/0x2,ct_nw_dst=88.88.88.88,ct_nw_proto=6,ct_tp_dst=8080,tcp,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_state=+trk+dnat,ct_label=0x2/0x2,ct_nw_dst=88.88.88.90,ct_nw_proto=6,ct_tp_dst=8080,tcp,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_state=+trk+dnat,ct_label=0x2/0x2,ct_nw_dst=88.88.88.90,ct_nw_proto=6,ct_tp_dst=8080,tcp,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_state=+trk+dnat,ct_mark=0x2/0x2,ct_ipv6_dst=8800::88,ct_nw_proto=17,ct_tp_dst=4040,udp6,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_state=+trk+dnat,ct_mark=0x2/0x2,ct_ipv6_dst=8800::88,ct_nw_proto=6,ct_tp_dst=8080,tcp6,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_state=+trk+dnat,ct_mark=0x2/0x2,ct_nw_dst=88.88.88.88,ct_nw_proto=17,ct_tp_dst=4040,udp,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_state=+trk+dnat,ct_mark=0x2/0x2,ct_nw_dst=88.88.88.88,ct_nw_proto=6,ct_tp_dst=8080,tcp,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_state=+trk+dnat,ct_mark=0x2/0x2,ct_nw_dst=88.88.88.90,ct_nw_proto=6,ct_tp_dst=8080,tcp,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_state=+trk+dnat,ct_mark=0x2/0x2,ct_nw_dst=88.88.88.90,ct_nw_proto=6,ct_tp_dst=8080,tcp,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) + ]) + + AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=69 | grep -v NXST], [1], [dnl +@@ -26836,9 +27054,9 @@ OVS_WAIT_UNTIL( + ) + + AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=68 | ofctl_strip_all | grep -v NXST], [0], [dnl +- table=68, priority=100,ct_label=0x2/0x2,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) +- table=68, priority=100,ct_label=0x2/0x2,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) + ]) + + AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=69], [0], [dnl +@@ -27918,6 +28136,18 @@ check ovn-nbctl lsp-add ls vm-cont2 vm1 2 + + wait_for_ports_up + ++check ovn-nbctl clear logical_switch_port vm-cont1 parent_name ++check ovn-nbctl clear logical_switch_port vm-cont2 parent_name ++ ++wait_column "true" sb:Port_Binding up logical_port=vm1 ++wait_column "false" sb:Port_Binding up logical_port=vm-cont1 ++wait_column "false" sb:Port_Binding up logical_port=vm-cont2 ++ ++check ovn-nbctl set logical_switch_port vm-cont1 parent_name=vm1 ++check ovn-nbctl set logical_switch_port vm-cont2 parent_name=vm1 ++ ++wait_for_ports_up ++ + # Make vm1 as a child port of some non existent lport - foo. vm1, vm1-cont1 and + # vm1-cont2 should be released. + check ovn-nbctl --wait=sb set logical_switch_port vm1 parent_name=bar +@@ -28539,6 +28769,10 @@ done # Make sure all the above was performed with I-P (no recompute) AT_CHECK([test $(ovn-appctl -t ovn-controller coverage/read-counter lflow_run) == $lflow_run]) @@ -4566,7 +9009,7 @@ index 9ec62e321..0f71219b9 100644 OVN_CLEANUP([hv1]) AT_CLEANUP ]) -@@ -28726,8 +28928,8 @@ options arp_proxy='"169.254.239.254 169.254.239.2"' +@@ -28726,8 +28960,8 @@ options arp_proxy='"169.254.239.254 169.254.239.2"' ovn-sbctl dump-flows > sbflows AT_CAPTURE_FILE([sbflows]) @@ -4577,7 +9020,7 @@ index 9ec62e321..0f71219b9 100644 action=(eth.dst = eth.src; eth.src = 00:00:00:01:02:f1; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = 00:00:00:01:02:f1; arp.tpa <-> arp.spa; outport = inport; flags.loopback = 1; output;) ]) -@@ -29208,26 +29410,26 @@ done +@@ -29208,26 +29442,26 @@ done check ovn-nbctl --wait=hv sync # hv0 should see flows for lsp1 but not lsp2 @@ -4611,7 +9054,7 @@ index 9ec62e321..0f71219b9 100644 OVN_CLEANUP([hv1],[hv2]) AT_CLEANUP -@@ -29698,3 +29900,76 @@ OVS_WAIT_UNTIL([ +@@ -29698,3 +29932,238 @@ OVS_WAIT_UNTIL([ OVN_CLEANUP([hv1],[hv2]) AT_CLEANUP ]) @@ -4688,43 +9131,553 @@ index 9ec62e321..0f71219b9 100644 +OVN_CLEANUP([hv1]) +AT_CLEANUP +]) ++ ++OVN_FOR_EACH_NORTHD([ ++AT_SETUP([ovn -- lr mac_binding I-P update]) ++AT_KEYWORDS([mac_binding]) ++ovn_start ++ ++# Add chassis ++net_add n1 ++sim_add hv1 ++as hv1 ++check ovs-vsctl add-br br-phys ++check ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys ++ovn_attach n1 br-phys 192.168.0.1 ++ ++sim_add hv2 ++as hv2 ++check ovs-vsctl add-br br-phys ++check ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys ++ovn_attach n1 br-phys 192.168.0.2 ++ ++check as hv1 ovs-vsctl set open . external_ids:ovn-monitor-all=true ++check as hv2 ovs-vsctl set open . external_ids:ovn-monitor-all=true ++ ++# Wait until ovn-monitor-all is processed by ovn-controller. ++wait_row_count Chassis 1 name=hv1 other_config:ovn-monitor-all=true ++wait_row_count Chassis 1 name=hv2 other_config:ovn-monitor-all=true ++ ++check ovn-nbctl ls-add public ++check ovn-nbctl ls-add internal ++ ++check ovn-nbctl lsp-add public ln_port ++check ovn-nbctl lsp-set-addresses ln_port unknown ++check ovn-nbctl lsp-set-type ln_port localnet ++check ovn-nbctl lsp-set-options ln_port network_name=phys ++ ++check ovn-nbctl lsp-add public public-gw ++check ovn-nbctl lsp-set-type public-gw router ++check ovn-nbctl lsp-set-addresses public-gw router ++check ovn-nbctl lsp-set-options public-gw router-port=gw-public ++ ++check ovn-nbctl lsp-add internal internal-gw ++check ovn-nbctl lsp-set-type internal-gw router ++check ovn-nbctl lsp-set-addresses internal-gw router ++check ovn-nbctl lsp-set-options internal-gw router-port=gw-internal ++ ++check ovn-nbctl lsp-add internal vif1 ++check ovn-nbctl lsp-set-addresses vif1 "00:00:00:00:20:11 192.168.20.11" ++ ++check ovn-nbctl lsp-add internal vif2 ++check ovn-nbctl lsp-set-addresses vif2 "00:00:00:00:20:12 192.168.20.12" ++ ++check ovn-nbctl lr-add gw ++check ovn-nbctl lrp-add gw gw-public 00:00:00:00:10:01 192.168.10.1/24 ++check ovn-nbctl lrp-add gw gw-internal 00:00:00:00:20:01 192.168.20.1/24 ++ ++# Add a vif1 on HV1 ++check as hv1 ovs-vsctl add-port br-int vif1 -- \ ++ set Interface vif1 external-ids:iface-id=vif1 \ ++ options:tx_pcap=hv1/vif1-tx.pcap \ ++ options:rxq_pcap=hv1/vif1-rx.pcap ++OVS_WAIT_UNTIL([test x$(ovn-nbctl lsp-get-up vif1) = xup]) ++ ++check ovn-nbctl lrp-set-gateway-chassis gw-public hv1 ++check ovn-nbctl --wait=sb sync ++ ++test_mac_binding_flows() { ++ local hv=$1 mac=$2 count=$3 ++ OVS_WAIT_UNTIL([test $(as $hv ovs-ofctl dump-flows br-int | grep table=66 | grep priority=100 | grep -c actions=mod_dl_dst:${mac}) -eq ${count}]) ++} ++ ++# Create SB MAC_Binding entry on external gateway port ++gw_dp_uuid=$(fetch_column datapath_binding _uuid external_ids:name=gw) ++ovn-sbctl create mac_binding ip=192.168.10.10 logical_port=gw-public mac="00\:00\:00\:00\:10\:10" datapath=$gw_dp_uuid ++ ++test_mac_binding_flows hv1 00\:00\:00\:00\:10\:10 1 ++test_mac_binding_flows hv2 00\:00\:00\:00\:10\:10 0 ++ ++# Add a vif2 on HV2 ++as hv2 ovs-vsctl add-port br-int vif2 -- \ ++ set Interface vif2 external-ids:iface-id=vif2 \ ++ options:tx_pcap=hv1/vif2-tx.pcap \ ++ options:rxq_pcap=hv1/vif2-rx.pcap ++OVS_WAIT_UNTIL([test x$(ovn-nbctl lsp-get-up vif2) = xup]) ++ ++test_mac_binding_flows hv1 00\:00\:00\:00\:10\:10 1 ++test_mac_binding_flows hv2 00\:00\:00\:00\:10\:10 1 ++ ++OVN_CLEANUP([hv1], [hv2]) ++AT_CLEANUP ++]) ++ ++AT_SETUP([snat-ct-zone with common NAT zone]) ++# This test sets up a couple of simple NATs. OVN will program logical ++# flows for ct_snat_in_czone() and ct_dnat_in_czone() as a result. We ++# want to ensure that the common zone used by these flows is the DNAT ++# zone. Then, we will set the snat-ct-zone option on our datapath and ++# ensure that the flows now use the SNAT zone as the common zone. ++ ++ovn_start ++ ++net_add n1 ++sim_add hv1 ++as hv1 ++check ovs-vsctl add-br br-phys ++ovn_attach n1 br-phys 192.168.0.1 ++check ovs-vsctl add-port br-int ls0-hv -- set Interface ls0-hv external-ids:iface-id=ls0-hv ++ ++check ovn-nbctl lr-add lr0 ++ ++check ovn-nbctl ls-add ls0 ++check ovn-nbctl lsp-add ls0 ls0-lr0 ++check ovn-nbctl lsp-set-type ls0-lr0 router ++check ovn-nbctl lsp-set-addresses ls0-lr0 router ++check ovn-nbctl lrp-add lr0 lr0-ls0 00:00:00:00:00:01 10.0.0.1 ++ ++check ovn-nbctl lsp-add ls0 ls0-hv ++check ovn-nbctl lsp-set-addresses ls0-hv "00:00:00:00:00:02 10.0.0.2" ++ ++check ovn-nbctl ls-add ext ++check ovn-nbctl lsp-add ext ext-lr0 ++check ovn-nbctl lsp-set-type ext-lr0 router ++check ovn-nbctl lsp-set-addresses ext-lr0 router ++check ovn-nbctl lrp-add lr0 lr0-ext 00:00:00:00:01:01 20.0.0.1 ++ ++check ovn-nbctl lrp-set-gateway-chassis lr0-ext hv1 ++ ++check ovn-nbctl lr-nat-add lr0 snat 172.16.0.2 10.0.0.0/24 ++check ovn-nbctl lr-nat-add lr0 dnat 172.16.0.2 10.0.0.2 ++ ++check ovn-nbctl --wait=hv sync ++ ++# Use constants so that if tables or registers change, this test can ++# be updated easily. ++DNAT_TABLE=14 ++SNAT_TABLE=43 ++DNAT_ZONE_REG="NXM_NX_REG11[[0..15]]" ++SNAT_ZONE_REG="NXM_NX_REG12[[0..15]]" ++ ++dnat_zone=$(ovs-ofctl dump-flows br-int | grep table=$DNAT_TABLE | grep -o zone=.*, | cut -d '=' -f 2) ++dnat_zone=${dnat_zone::-1} ++snat_zone=$(ovs-ofctl dump-flows br-int | grep table=$SNAT_TABLE | grep priority=153 | grep -o zone=.*, | cut -d '=' -f 2) ++snat_zone=${snat_zone::-1} ++ ++# For now, we expect that the common zone is the dnat zone ++ ++check test "$dnat_zone" = "$DNAT_ZONE_REG" ++check test "$snat_zone" = "$DNAT_ZONE_REG" ++ ++check ovn-nbctl --wait=hv set logical_router lr0 options:snat-ct-zone=666 ++ ++dnat_zone=$(ovs-ofctl dump-flows br-int | grep table=$DNAT_TABLE | grep -o zone=.*, | cut -d '=' -f 2) ++dnat_zone=${dnat_zone::-1} ++snat_zone=$(ovs-ofctl dump-flows br-int | grep table=$SNAT_TABLE | grep priority=153 | grep -o zone=.*, | cut -d '=' -f 2) ++snat_zone=${snat_zone::-1} ++ ++# Now with an snat-ct-zone set, the common zone is the snat zone ++ ++check test "$dnat_zone" = "$SNAT_ZONE_REG" ++check test "$snat_zone" = "$SNAT_ZONE_REG" ++ ++OVN_CLEANUP([hv1]) ++AT_CLEANUP diff --git a/tests/system-ovn.at b/tests/system-ovn.at -index 7f6cb32dc..5f41722d9 100644 +index 7f6cb32dc..82e7554ba 100644 --- a/tests/system-ovn.at +++ b/tests/system-ovn.at @@ -1448,6 +1448,32 @@ OVS_START_L7([bar1], [http]) OVS_START_L7([bar2], [http]) OVS_START_L7([bar3], [http]) -+# Add ACLs (after lb) to drop the traffic if destined to backend ips. -+check ovn-nbctl --apply-after-lb acl-add foo from-lport 1002 "ip4 && ip4.dst == {172.16.1.2,172.16.1.3,172.16.1.4} && ct.new" drop -+check ovn-nbctl --wait=hv sync -+ -+AT_CHECK([ip netns exec foo1 wget 30.0.0.1 -t 3 -T 1], [4], [ignore], [ignore]) -+ -+AT_CHECK([ovs-appctl dpctl/flush-conntrack]) -+ -+# Clear the apply-after-lb option. The traffic will be allowed. -+check ovn-nbctl clear acl . options -+ovn-nbctl --wait=hv sync -+ -+OVS_WAIT_FOR_OUTPUT([ -+ for i in `seq 1 20`; do -+ ip netns exec foo1 wget 30.0.0.1 -t 5 -T 1 --retry-connrefused -v -o wget$i.log; -+ done -+ ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | \ -+ sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl -+tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=172.16.1.2,dst=192.168.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) -+tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=172.16.1.3,dst=192.168.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) -+tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=172.16.1.4,dst=192.168.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) -+]) -+ -+ovn-nbctl acl-del foo from-lport 1002 "ip4 && ip4.dst == {172.16.1.2,172.16.1.3,172.16.1.4} && ct.new" -+ovn-nbctl --wait=hv sync -+ - dnl Should work with the virtual IP 30.0.0.1 address through NAT ++# Add ACLs (after lb) to drop the traffic if destined to backend ips. ++check ovn-nbctl --apply-after-lb acl-add foo from-lport 1002 "ip4 && ip4.dst == {172.16.1.2,172.16.1.3,172.16.1.4} && ct.new" drop ++check ovn-nbctl --wait=hv sync ++ ++AT_CHECK([ip netns exec foo1 wget 30.0.0.1 -t 3 -T 1], [4], [ignore], [ignore]) ++ ++AT_CHECK([ovs-appctl dpctl/flush-conntrack]) ++ ++# Clear the apply-after-lb option. The traffic will be allowed. ++check ovn-nbctl clear acl . options ++ovn-nbctl --wait=hv sync ++ ++OVS_WAIT_FOR_OUTPUT([ ++ for i in `seq 1 20`; do ++ ip netns exec foo1 wget 30.0.0.1 -t 5 -T 1 --retry-connrefused -v -o wget$i.log; ++ done ++ ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | \ ++ sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl ++tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=172.16.1.2,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=172.16.1.3,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=172.16.1.4,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++]) ++ ++ovn-nbctl acl-del foo from-lport 1002 "ip4 && ip4.dst == {172.16.1.2,172.16.1.3,172.16.1.4} && ct.new" ++ovn-nbctl --wait=hv sync ++ + dnl Should work with the virtual IP 30.0.0.1 address through NAT + dnl Each server should have at least one connection. + dnl With 20 requests, one server might not receive any connection +@@ -1459,9 +1485,9 @@ OVS_WAIT_FOR_OUTPUT([ + done + ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | \ + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=172.16.1.2,dst=192.168.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=172.16.1.3,dst=192.168.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=172.16.1.4,dst=192.168.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=172.16.1.2,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=172.16.1.3,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=172.16.1.4,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + dnl Should work with the virtual IP 30.0.0.3 address through NAT +@@ -1472,9 +1498,9 @@ OVS_WAIT_FOR_OUTPUT([ + done + ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.3) | \ + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=192.168.1.2,dst=30.0.0.3,sport=,dport=),reply=(src=172.16.1.2,dst=192.168.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=192.168.1.2,dst=30.0.0.3,sport=,dport=),reply=(src=172.16.1.3,dst=192.168.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=192.168.1.2,dst=30.0.0.3,sport=,dport=),reply=(src=172.16.1.4,dst=192.168.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=192.168.1.2,dst=30.0.0.3,sport=,dport=),reply=(src=172.16.1.2,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=192.168.1.2,dst=30.0.0.3,sport=,dport=),reply=(src=172.16.1.3,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=192.168.1.2,dst=30.0.0.3,sport=,dport=),reply=(src=172.16.1.4,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + dnl Test load-balancing that includes L4 ports in NAT. +@@ -1485,9 +1511,9 @@ OVS_WAIT_FOR_OUTPUT([ + done + ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | \ + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=172.16.1.2,dst=192.168.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=172.16.1.3,dst=192.168.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=172.16.1.4,dst=192.168.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=172.16.1.2,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=172.16.1.3,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=172.16.1.4,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + # Configure selection_fields. +@@ -1507,9 +1533,9 @@ OVS_WAIT_FOR_OUTPUT([ + done + ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | \ + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=172.16.1.2,dst=192.168.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=172.16.1.3,dst=192.168.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=172.16.1.4,dst=192.168.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=172.16.1.2,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=172.16.1.3,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=172.16.1.4,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + AT_CHECK([ovs-appctl dpctl/flush-conntrack]) +@@ -1716,9 +1742,9 @@ done + dnl Each server should have at least one connection. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::1) | grep -v fe80 | \ + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=fd01::2,dst=fd03::1,sport=,dport=),reply=(src=fd02::2,dst=fd01::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=fd01::2,dst=fd03::1,sport=,dport=),reply=(src=fd02::3,dst=fd01::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=fd01::2,dst=fd03::1,sport=,dport=),reply=(src=fd02::4,dst=fd01::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=fd01::2,dst=fd03::1,sport=,dport=),reply=(src=fd02::2,dst=fd01::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=fd01::2,dst=fd03::1,sport=,dport=),reply=(src=fd02::3,dst=fd01::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=fd01::2,dst=fd03::1,sport=,dport=),reply=(src=fd02::4,dst=fd01::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + dnl Should work with the virtual IP fd03::3 address through NAT +@@ -1730,9 +1756,9 @@ done + dnl Each server should have at least one connection. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::3) | grep -v fe80 | \ + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=fd01::2,dst=fd03::3,sport=,dport=),reply=(src=fd02::2,dst=fd01::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=fd01::2,dst=fd03::3,sport=,dport=),reply=(src=fd02::3,dst=fd01::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=fd01::2,dst=fd03::3,sport=,dport=),reply=(src=fd02::4,dst=fd01::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=fd01::2,dst=fd03::3,sport=,dport=),reply=(src=fd02::2,dst=fd01::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=fd01::2,dst=fd03::3,sport=,dport=),reply=(src=fd02::3,dst=fd01::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=fd01::2,dst=fd03::3,sport=,dport=),reply=(src=fd02::4,dst=fd01::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + dnl Test load-balancing that includes L4 ports in NAT. +@@ -1744,9 +1770,9 @@ done + dnl Each server should have at least one connection. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::2) | grep -v fe80 | \ + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd02::2,dst=fd01::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd02::3,dst=fd01::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd02::4,dst=fd01::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd02::2,dst=fd01::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd02::3,dst=fd01::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd02::4,dst=fd01::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + # Configure selection_fields. +@@ -1767,9 +1793,9 @@ done + dnl Each server should have at least one connection. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::2) | grep -v fe80 | \ + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd02::2,dst=fd01::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd02::3,dst=fd01::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd02::4,dst=fd01::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd02::2,dst=fd01::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd02::3,dst=fd01::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd02::4,dst=fd01::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + AT_CHECK([ovs-appctl dpctl/flush-conntrack]) +@@ -1915,9 +1941,9 @@ done + dnl Each server should have at least one connection. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | \ + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=192.168.1.3,dst=192.168.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=192.168.1.4,dst=192.168.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=192.168.1.5,dst=192.168.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=192.168.1.3,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=192.168.1.4,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=192.168.1.5,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + dnl Test load-balancing that includes L4 ports in NAT. +@@ -1929,9 +1955,9 @@ done + dnl Each server should have at least one connection. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | \ + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.1.3,dst=192.168.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.1.4,dst=192.168.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.1.5,dst=192.168.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.1.3,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.1.4,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=192.168.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.1.5,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + +@@ -2026,9 +2052,9 @@ done + dnl Each server should have at least one connection. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::1) | grep -v fe80 | \ + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=fd01::2,dst=fd03::1,sport=,dport=),reply=(src=fd01::3,dst=fd01::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=fd01::2,dst=fd03::1,sport=,dport=),reply=(src=fd01::4,dst=fd01::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=fd01::2,dst=fd03::1,sport=,dport=),reply=(src=fd01::5,dst=fd01::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=fd01::2,dst=fd03::1,sport=,dport=),reply=(src=fd01::3,dst=fd01::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=fd01::2,dst=fd03::1,sport=,dport=),reply=(src=fd01::4,dst=fd01::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=fd01::2,dst=fd03::1,sport=,dport=),reply=(src=fd01::5,dst=fd01::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + dnl Test load-balancing that includes L4 ports in NAT. +@@ -2040,9 +2066,9 @@ done + dnl Each server should have at least one connection. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::2) | grep -v fe80 | \ + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd01::3,dst=fd01::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd01::4,dst=fd01::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd01::5,dst=fd01::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd01::3,dst=fd01::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd01::4,dst=fd01::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=fd01::2,dst=fd03::2,sport=,dport=),reply=(src=fd01::5,dst=fd01::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + +@@ -2180,8 +2206,8 @@ done dnl Each server should have at least one connection. - dnl With 20 requests, one server might not receive any connection + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + dnl Test load-balancing that includes L4 ports in NAT. +@@ -2193,8 +2219,8 @@ done + dnl Each server should have at least one connection. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + check_est_flows () { +@@ -2236,8 +2262,8 @@ done + dnl Each server should have at least one connection. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0.2) | +@@ -2276,8 +2302,8 @@ done + dnl Each server should have at least one connection. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0.2) | +@@ -2527,8 +2553,8 @@ done + dnl Each server should have at least one connection. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::1) | grep -v fe80 | + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=fd72::2,dst=fd30::1,sport=,dport=),reply=(src=fd11::2,dst=fd72::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=fd72::2,dst=fd30::1,sport=,dport=),reply=(src=fd12::2,dst=fd72::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=fd72::2,dst=fd30::1,sport=,dport=),reply=(src=fd11::2,dst=fd72::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=fd72::2,dst=fd30::1,sport=,dport=),reply=(src=fd12::2,dst=fd72::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + dnl Test load-balancing that includes L4 ports in NAT. +@@ -2540,8 +2566,8 @@ done + dnl Each server should have at least one connection. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::2) | grep -v fe80 | + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=fd72::2,dst=fd30::2,sport=,dport=),reply=(src=fd11::2,dst=fd72::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=fd72::2,dst=fd30::2,sport=,dport=),reply=(src=fd12::2,dst=fd72::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=fd72::2,dst=fd30::2,sport=,dport=),reply=(src=fd11::2,dst=fd72::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=fd72::2,dst=fd30::2,sport=,dport=),reply=(src=fd12::2,dst=fd72::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + OVS_APP_EXIT_AND_WAIT([ovn-controller]) +@@ -2705,8 +2731,8 @@ done + dnl Each server should have at least one connection. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=172.16.1.3,dst=30.0.0.1,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.3,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=172.16.1.3,dst=30.0.0.1,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.3,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=172.16.1.3,dst=30.0.0.1,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.3,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=172.16.1.3,dst=30.0.0.1,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.3,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + dnl Force SNAT should have worked. +@@ -2878,8 +2904,8 @@ done + dnl Each server should have at least one connection. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::1) | grep -v fe80 | + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=fd72::3,dst=fd30::1,sport=,dport=),reply=(src=fd11::2,dst=fd72::3,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=fd72::3,dst=fd30::1,sport=,dport=),reply=(src=fd12::2,dst=fd72::3,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=fd72::3,dst=fd30::1,sport=,dport=),reply=(src=fd11::2,dst=fd72::3,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=fd72::3,dst=fd30::1,sport=,dport=),reply=(src=fd12::2,dst=fd72::3,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + dnl Force SNAT should have worked. +@@ -3094,13 +3120,13 @@ done + dnl Each server should have at least one connection. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=172.16.1.3,dst=30.0.0.1,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.3,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=172.16.1.3,dst=30.0.0.1,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.3,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=172.16.1.3,dst=30.0.0.1,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.3,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=172.16.1.3,dst=30.0.0.1,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.3,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::1) | grep -v fe80 | + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=fd72::3,dst=fd30::1,sport=,dport=),reply=(src=fd11::2,dst=fd72::3,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=fd72::3,dst=fd30::1,sport=,dport=),reply=(src=fd12::2,dst=fd72::3,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=fd72::3,dst=fd30::1,sport=,dport=),reply=(src=fd11::2,dst=fd72::3,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=fd72::3,dst=fd30::1,sport=,dport=),reply=(src=fd12::2,dst=fd72::3,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + dnl Force SNAT should have worked. +@@ -3240,8 +3266,8 @@ done + dnl Each server should have at least one connection. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.1.10) | + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=172.16.1.2,dst=172.16.1.10,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=172.16.1.2,dst=172.16.1.10,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=172.16.1.2,dst=172.16.1.10,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=172.16.1.2,dst=172.16.1.10,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + dnl Test load-balancing that includes L4 ports in NAT. +@@ -3253,8 +3279,8 @@ done + dnl Each server should have at least one connection. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.1.11) | + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=172.16.1.2,dst=172.16.1.11,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=172.16.1.2,dst=172.16.1.11,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=172.16.1.2,dst=172.16.1.11,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=172.16.1.2,dst=172.16.1.11,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + OVS_APP_EXIT_AND_WAIT([ovn-controller]) +@@ -3383,8 +3409,8 @@ done + dnl Each server should have at least one connection. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd72::10) | grep -v fe80 | + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=fd72::2,dst=fd72::10,sport=,dport=),reply=(src=fd01::2,dst=fd72::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=fd72::2,dst=fd72::10,sport=,dport=),reply=(src=fd02::2,dst=fd72::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=fd72::2,dst=fd72::10,sport=,dport=),reply=(src=fd01::2,dst=fd72::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=fd72::2,dst=fd72::10,sport=,dport=),reply=(src=fd02::2,dst=fd72::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + dnl Test load-balancing that includes L4 ports in NAT. +@@ -3396,8 +3422,8 @@ done + dnl Each server should have at least one connection. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd72::11) | grep -v fe80 | + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=fd72::2,dst=fd72::11,sport=,dport=),reply=(src=fd01::2,dst=fd72::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=fd72::2,dst=fd72::11,sport=,dport=),reply=(src=fd02::2,dst=fd72::2,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=fd72::2,dst=fd72::11,sport=,dport=),reply=(src=fd01::2,dst=fd72::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=fd72::2,dst=fd72::11,sport=,dport=),reply=(src=fd02::2,dst=fd72::2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + OVS_APP_EXIT_AND_WAIT([ovn-controller]) +@@ -4392,8 +4418,8 @@ OVS_WAIT_UNTIL([test 2 = `ovn-sbctl --bare --columns status find \ + service_monitor | sed '/^$/d' | grep online | wc -l`]) + + OVS_WAIT_UNTIL( +- [ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 | grep "ip4.dst == 10.0.0.10" > lflows.txt +- test 1 = `cat lflows.txt | grep "ct_lb(backends=10.0.0.3:80,20.0.0.3:80)" | wc -l`] ++ [ovn-sbctl dump-flows sw0 | grep ct_lb_mark | grep priority=120 | grep "ip4.dst == 10.0.0.10" > lflows.txt ++ test 1 = `cat lflows.txt | grep "ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80)" | wc -l`] + ) + + # From sw0-p2 send traffic to vip - 10.0.0.10 +@@ -4406,8 +4432,8 @@ done + dnl Each server should have at least one connection. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.0.0.10) | \ + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=10.0.0.4,dst=10.0.0.10,sport=,dport=),reply=(src=10.0.0.3,dst=10.0.0.4,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) +-tcp,orig=(src=10.0.0.4,dst=10.0.0.10,sport=,dport=),reply=(src=20.0.0.3,dst=10.0.0.4,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=10.0.0.4,dst=10.0.0.10,sport=,dport=),reply=(src=10.0.0.3,dst=10.0.0.4,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++tcp,orig=(src=10.0.0.4,dst=10.0.0.10,sport=,dport=),reply=(src=20.0.0.3,dst=10.0.0.4,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + # Stop webserer in sw0-p1 +@@ -4418,8 +4444,8 @@ OVS_WAIT_UNTIL([test 1 = `ovn-sbctl --bare --columns status find \ + service_monitor logical_port=sw0-p1 | sed '/^$/d' | grep offline | wc -l`]) + + OVS_WAIT_UNTIL( +- [ovn-sbctl dump-flows sw0 | grep ct_lb | grep priority=120 | grep "ip4.dst == 10.0.0.10" > lflows.txt +- test 1 = `cat lflows.txt | grep "ct_lb(backends=20.0.0.3:80)" | wc -l`] ++ [ovn-sbctl dump-flows sw0 | grep ct_lb_mark | grep priority=120 | grep "ip4.dst == 10.0.0.10" > lflows.txt ++ test 1 = `cat lflows.txt | grep "ct_lb_mark(backends=20.0.0.3:80)" | wc -l`] + ) + + ovs-appctl dpctl/flush-conntrack +@@ -4431,7 +4457,7 @@ done + + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.0.0.10) | \ + sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +-tcp,orig=(src=10.0.0.4,dst=10.0.0.10,sport=,dport=),reply=(src=20.0.0.3,dst=10.0.0.4,sport=,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=10.0.0.4,dst=10.0.0.10,sport=,dport=),reply=(src=20.0.0.3,dst=10.0.0.4,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + # Create udp load balancer. @@ -4895,6 +4921,247 @@ aef0::3 udp port 90" | uniq | wc -l) ]) @@ -5042,7 +9995,146 @@ index 7f6cb32dc..5f41722d9 100644 kill $(pidof tcpdump) ovn-nbctl set logical_router_port rp-sw0 options:prefix=false -@@ -6667,8 +6927,25 @@ OVS_WAIT_UNTIL([ +@@ -5366,7 +5626,7 @@ sed -e 's/port=2001/port=/g' \ + -e 's/state=[[0-9_A-Z]]*/state=/g' \ + -e 's/zone=[[0-9]]*/zone=/' | sort], [0], [dnl + tcp,orig=(src=42.42.42.3,dst=42.42.42.2,sport=,dport=4242),reply=(src=42.42.42.2,dst=42.42.42.3,sport=4242,dport=),zone=,protoinfo=(state=) +-tcp,orig=(src=42.42.42.3,dst=66.66.66.66,sport=,dport=666),reply=(src=42.42.42.2,dst=42.42.42.3,sport=4242,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=42.42.42.3,dst=66.66.66.66,sport=,dport=666),reply=(src=42.42.42.2,dst=42.42.42.3,sport=4242,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + # Start IPv4 TCP connection to backend IP from vm2 which would require +@@ -5385,7 +5645,7 @@ sed -e 's/port=2001/port=/g' \ + -e 's/zone=[[0-9]]*/zone=/' | sort], [0], [dnl + tcp,orig=(src=42.42.42.3,dst=42.42.42.2,sport=,dport=4242),reply=(src=42.42.42.2,dst=42.42.42.3,sport=4242,dport=),zone=,protoinfo=(state=) + tcp,orig=(src=42.42.42.3,dst=42.42.42.2,sport=,dport=4242),reply=(src=42.42.42.2,dst=42.42.42.3,sport=4242,dport=),zone=,protoinfo=(state=) +-tcp,orig=(src=42.42.42.3,dst=66.66.66.66,sport=,dport=666),reply=(src=42.42.42.2,dst=42.42.42.3,sport=4242,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=42.42.42.3,dst=66.66.66.66,sport=,dport=666),reply=(src=42.42.42.2,dst=42.42.42.3,sport=4242,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + AT_CLEANUP +@@ -5462,7 +5722,7 @@ sed -e 's/port=2001/port=/g' \ + -e 's/state=[[0-9_A-Z]]*/state=/g' \ + -e 's/zone=[[0-9]]*/zone=/' | sort], [0], [dnl + tcp,orig=(src=4242::3,dst=4242::2,sport=,dport=4242),reply=(src=4242::2,dst=4242::3,sport=4242,dport=),zone=,protoinfo=(state=) +-tcp,orig=(src=4242::3,dst=6666::1,sport=,dport=666),reply=(src=4242::2,dst=4242::3,sport=4242,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=4242::3,dst=6666::1,sport=,dport=666),reply=(src=4242::2,dst=4242::3,sport=4242,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + # Start IPv6 TCP connection to backend IP from vm2 which would require +@@ -5481,7 +5741,7 @@ sed -e 's/port=2001/port=/g' \ + -e 's/zone=[[0-9]]*/zone=/' | sort], [0], [dnl + tcp,orig=(src=4242::3,dst=4242::2,sport=,dport=4242),reply=(src=4242::2,dst=4242::3,sport=4242,dport=),zone=,protoinfo=(state=) + tcp,orig=(src=4242::3,dst=4242::2,sport=,dport=4242),reply=(src=4242::2,dst=4242::3,sport=4242,dport=),zone=,protoinfo=(state=) +-tcp,orig=(src=4242::3,dst=6666::1,sport=,dport=666),reply=(src=4242::2,dst=4242::3,sport=4242,dport=),zone=,labels=0x2,protoinfo=(state=) ++tcp,orig=(src=4242::3,dst=6666::1,sport=,dport=666),reply=(src=4242::2,dst=4242::3,sport=4242,dport=),zone=,mark=2,protoinfo=(state=) + ]) + + AT_CLEANUP +@@ -5693,17 +5953,17 @@ NS_CHECK_EXEC([bob1], [ping -q -c 20 -i 0.3 -w 15 10.0.0.2 | FORMAT_PING], \ + # and just ensure that the known ethernet address is present. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.0.1) | \ + sed -e 's/zone=[[0-9]]*/zone=/' | +-sed -e 's/labels=0x[[0-9a-f]]*00000401020400000000/labels=0x00000401020400000000/'], [0], [dnl +-icmp,orig=(src=172.16.0.1,dst=10.0.0.2,id=,type=8,code=0),reply=(src=10.0.0.2,dst=172.16.0.1,id=,type=0,code=0),zone=,labels=0x00000401020400000000 ++sed -e 's/mark=[[0-9]]*/mark=/'], [0], [dnl ++icmp,orig=(src=172.16.0.1,dst=10.0.0.2,id=,type=8,code=0),reply=(src=10.0.0.2,dst=172.16.0.1,id=,type=0,code=0),zone=,mark=,labels=0x401020400000000 + ]) + + # Ensure datapaths show conntrack states as expected + # Like with conntrack entries, we shouldn't try to predict + # port binding tunnel keys. So omit them from expected labels. +-AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(+new-est-rpl+trk).*ct(.*label=0x.*00000401020400000000/.*)' -c], [0], [dnl ++AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(+new-est-rpl+trk).*ct(.*label=0x401020400000000/.*)' -c], [0], [dnl + 1 + ]) +-AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(-new+est+rpl+trk).*ct_label(0x.*00000401020400000000/.*)' -c], [0], [dnl ++AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(-new+est+rpl+trk).*ct_label(0x401020400000000)' -c], [0], [dnl + 1 + ]) + +@@ -5857,11 +6117,11 @@ NS_CHECK_EXEC([bob1], [ping -q -c 20 -i 0.3 -w 15 fd01::2 | FORMAT_PING], \ + # Ensure datapaths show conntrack states as expected + # Like with conntrack entries, we shouldn't try to predict + # port binding tunnel keys. So omit them from expected labels. +-AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(+new-est-rpl+trk).*ct(.*label=0x200000401020400000000/.*)' -c], [0], [dnl ++AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(+new-est-rpl+trk).*ct(.*label=0x401020400000000/.*)' -c], [0], [dnl + 1 + ]) + +-AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(-new+est+rpl+trk).*ct_label(0x.*00000401020400000000/.*)' -c], [0], [dnl ++AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(-new+est+rpl+trk).*ct_label(0x401020400000000)' -c], [0], [dnl + 1 + ]) + +@@ -5870,8 +6130,8 @@ AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(-new+est+rpl+trk).*ct_lab + # and just ensure that the known ethernet address is present. + AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd01::2) | \ + sed -e 's/zone=[[0-9]]*/zone=/' | +-sed -e 's/labels=0x[[0-9a-f]]*00000401020400000000/labels=0x00000401020400000000/'], [0], [dnl +-icmpv6,orig=(src=fd07::1,dst=fd01::2,id=,type=128,code=0),reply=(src=fd01::2,dst=fd07::1,id=,type=129,code=0),zone=,labels=0x00000401020400000000 ++sed -e 's/mark=[[0-9]]*/mark=/'], [0], [dnl ++icmpv6,orig=(src=fd07::1,dst=fd01::2,id=,type=128,code=0),reply=(src=fd01::2,dst=fd07::1,id=,type=129,code=0),zone=,mark=,labels=0x401020400000000 + ]) + + ovs-ofctl dump-flows br-int +@@ -6320,7 +6580,7 @@ AT_CHECK([ovs-appctl dpctl/dump-flows | grep ct_state | grep -v ipv6 -c], [1], [ + 0 + ]) + +-AT_CHECK([ovs-appctl dpctl/dump-flows | grep ct_label | grep -v ipv6 -c], [1], [dnl ++AT_CHECK([ovs-appctl dpctl/dump-flows | grep ct_mark | grep -v ipv6 -c], [1], [dnl + 0 + ]) + +@@ -6336,7 +6596,7 @@ ovs-appctl dpctl/dump-flows + + AT_CHECK([ovs-appctl dpctl/dump-flows | grep ct_state | grep -v ipv6 -c], [0], [ignore]) + +-AT_CHECK([ovs-appctl dpctl/dump-flows | grep ct_label | grep -v ipv6 -c], [0], [ignore]) ++AT_CHECK([ovs-appctl dpctl/dump-flows | grep ct_mark | grep -v ipv6 -c], [0], [ignore]) + + # Clear ACL for sw0 + check ovn-nbctl --wait=hv clear logical_switch sw0 acls +@@ -6356,7 +6616,7 @@ AT_CHECK([ovs-appctl dpctl/dump-flows | grep ct_state | grep -v ipv6 -c], [1], [ + 0 + ]) + +-AT_CHECK([ovs-appctl dpctl/dump-flows | grep ct_label | grep -v ipv6 -c], [1], [dnl ++AT_CHECK([ovs-appctl dpctl/dump-flows | grep ct_mark | grep -v ipv6 -c], [1], [dnl + 0 + ]) + +@@ -6470,10 +6730,25 @@ NS_CHECK_EXEC([vm1], [ping -q -c 3 -i 0.3 -w 2 172.18.2.10 | FORMAT_PING], \ + [0], [dnl + 3 packets transmitted, 3 received, 0% packet loss, time 0ms + ]) +-kill $(pidof ovn-controller) + +-as ovn-sb +-OVS_APP_EXIT_AND_WAIT([ovsdb-server]) ++dnat_and_snat_uuid=$(fetch_column nb:NAT _uuid external_ip=172.18.2.10) ++ovn-nbctl set NAT $dnat_and_snat_uuid options:stateless=true ++ ++# A ping from vm1 should hairpin in lr1 and successfully DNAT to vm2 ++NS_CHECK_EXEC([vm1], [ping -q -c 3 -i 0.3 -w 2 172.18.2.10 | FORMAT_PING], \ ++[0], [dnl ++3 packets transmitted, 3 received, 0% packet loss, time 0ms ++]) ++# A ping from vm2 should hairpin in lr1 and successfully DNAT to vm2 ++NS_CHECK_EXEC([vm2], [ping -q -c 3 -i 0.3 -w 2 172.18.2.10 | FORMAT_PING], \ ++[0], [dnl ++3 packets transmitted, 3 received, 0% packet loss, time 0ms ++]) ++ ++kill $(pidof ovn-controller) ++ ++as ovn-sb ++OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + + as ovn-nb + OVS_APP_EXIT_AND_WAIT([ovsdb-server]) +@@ -6667,8 +6942,25 @@ OVS_WAIT_UNTIL([ test "${n_reject}" = "2" ]) kill $(pidof tcpdump) @@ -5068,7 +10160,7 @@ index 7f6cb32dc..5f41722d9 100644 NS_EXEC([sw01], [tcpdump -l -n -i sw01 icmp -Q in > reject.pcap &]) check ovn-nbctl --wait=hv ls-copp-del sw0 reject -@@ -6814,6 +7091,148 @@ check ovn-nbctl acl-add sw0 from-lport 1001 "ip" allow-related +@@ -6814,6 +7106,148 @@ check ovn-nbctl acl-add sw0 from-lport 1001 "ip" allow-related check ovn-nbctl acl-add sw0 to-lport 1001 "ip" allow-related @@ -5217,7 +10309,7 @@ index 7f6cb32dc..5f41722d9 100644 ADD_NAMESPACES(sw0-p1) ADD_VETH(sw0-p1, sw0-p1, br-int, "10.0.0.2/24", "50:54:00:00:00:02", \ "10.0.0.1") -@@ -7009,3 +7428,204 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d +@@ -7009,3 +7443,323 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d AT_CLEANUP ]) @@ -5422,6 +10514,192 @@ index 7f6cb32dc..5f41722d9 100644 + +AT_CLEANUP +]) ++ ++OVN_FOR_EACH_NORTHD([ ++AT_SETUP([East-West traffic with gateway router if DNAT configured]) ++AT_KEYWORDS([ovnnat]) ++ ++CHECK_CONNTRACK() ++CHECK_CONNTRACK_NAT() ++ovn_start ++OVS_TRAFFIC_VSWITCHD_START() ++ADD_BR([br-int]) ++# Set external-ids in br-int needed for ovn-controller ++ovs-vsctl \ ++ -- set Open_vSwitch . external-ids:system-id=hv1 \ ++ -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ ++ -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ ++ -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ ++ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true ++ ++# Start ovn-controller ++start_daemon ovn-controller ++# Logical network: ++# One LR - R1 has two switches: sw0 and sw1 ++# sw0 -- R1 -- sw1 ++# Logical port 'sw01' in switch 'sw0'. ++# Logical port 'sw11' in switch 'sw1'. ++# nc server running in sw01 ++# nc client running on sw11 ++ ++check ovn-nbctl lr-add R1 ++check ovn-nbctl ls-add sw0 ++check ovn-nbctl ls-add sw1 ++ ++check ovn-nbctl lrp-add R1 rp-sw0 00:00:01:01:02:03 192.168.1.1/24 ++check ovn-nbctl lrp-add R1 rp-sw1 00:00:03:01:02:03 192.168.2.1/24 ++check ovn-nbctl set logical_router R1 options:chassis=hv1 ++ ++check ovn-nbctl lsp-add sw0 sw0-rp -- set Logical_Switch_Port sw0-rp \ ++ type=router options:router-port=rp-sw0 \ ++ -- lsp-set-addresses sw0-rp router ++check ovn-nbctl lsp-add sw1 sw1-rp -- set Logical_Switch_Port sw1-rp \ ++ type=router options:router-port=rp-sw1 \ ++ -- lsp-set-addresses sw1-rp router ++ ++ADD_NAMESPACES(sw01) ++ADD_VETH(sw01, sw01, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \ ++ "192.168.1.1") ++check ovn-nbctl lsp-add sw0 sw01 \ ++ -- lsp-set-addresses sw01 "f0:00:00:01:02:03 192.168.1.2" ++ ++ADD_NAMESPACES(sw11) ++ADD_VETH(sw11, sw11, br-int, "192.168.2.2/24", "f0:00:00:02:02:03", \ ++ "192.168.2.1") ++check ovn-nbctl lsp-add sw1 sw11 \ ++ -- lsp-set-addresses sw11 "f0:00:00:02:02:03 192.168.2.2" ++ ++NETNS_DAEMONIZE([sw01], [nc -k -l 8000], [nc-sw01.pid]) ++ ++test_ping() { ++ NS_CHECK_EXEC([$1], [ping -q -c 1 $2 -w 2 | FORMAT_PING], \ ++[0], [dnl ++1 packets transmitted, 1 received, 0% packet loss, time 0ms ++]) ++} ++ ++# Only SNAT ++check ovn-nbctl --wait=hv lr-nat-add R1 snat 172.16.1.21 192.168.2.0/24 ++ ++echo "foo" > foo ++NS_CHECK_EXEC([sw11], [nc 192.168.1.2 8000 < foo]) ++test_ping sw11 192.168.1.2 ++ ++# Ensure nat has been hit ++OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep -v "n_packets=0" | grep 'nat(src=172.16.1.21)']) ++# Ensure conntrack entry is present ++OVS_WAIT_FOR_OUTPUT([ ++ ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.168.2.2) | \ ++ sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl ++icmp,orig=(src=192.168.2.2,dst=192.168.1.2,id=,type=8,code=0),reply=(src=192.168.1.2,dst=192.168.2.2,id=,type=0,code=0),zone= ++tcp,orig=(src=192.168.2.2,dst=192.168.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=192.168.2.2,sport=,dport=),zone=,protoinfo=(state=) ++]) ++ ++AT_CHECK([ovs-appctl dpctl/flush-conntrack]) ++ ++# SNAT and DNAT. using Logical IP ++ovn-nbctl --wait=hv lr-nat-add R1 dnat_and_snat 172.16.1.2 192.168.1.2 ++NS_CHECK_EXEC([sw11], [nc 192.168.1.2 8000 < foo ]) ++test_ping sw11 192.168.1.2 ++ ++# Ensure conntrack entry is present ++OVS_WAIT_FOR_OUTPUT([ ++ ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.168.2.2) | \ ++ sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl ++icmp,orig=(src=192.168.2.2,dst=192.168.1.2,id=,type=8,code=0),reply=(src=192.168.1.2,dst=192.168.2.2,id=,type=0,code=0),zone= ++tcp,orig=(src=192.168.2.2,dst=192.168.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=192.168.2.2,sport=,dport=),zone=,protoinfo=(state=) ++]) ++ ++AT_CHECK([ovs-appctl dpctl/flush-conntrack]) ++ ++# SNAT and DNAT. using floating IP ++NS_CHECK_EXEC([sw11], [nc 172.16.1.2 8000 < foo ]) ++test_ping sw11 172.16.1.2 ++ ++# Ensure conntrack entry is present ++OVS_WAIT_FOR_OUTPUT([ ++ ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.168.2.2) | \ ++ sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl ++icmp,orig=(src=192.168.2.2,dst=172.16.1.2,id=,type=8,code=0),reply=(src=192.168.1.2,dst=192.168.2.2,id=,type=0,code=0),zone= ++tcp,orig=(src=192.168.2.2,dst=172.16.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=192.168.2.2,sport=,dport=),zone=,protoinfo=(state=) ++]) ++ ++AT_CHECK([ovs-appctl dpctl/flush-conntrack]) ++ ++OVS_APP_EXIT_AND_WAIT([ovn-controller]) ++as ++OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d ++/connection dropped.*/d"]) ++ ++AT_CLEANUP ++]) +diff --git a/tests/test-ovn.c b/tests/test-ovn.c +index d79c6a5bc..6704f612b 100644 +--- a/tests/test-ovn.c ++++ b/tests/test-ovn.c +@@ -1351,6 +1351,7 @@ test_parse_actions(struct ovs_cmdl_context *ctx OVS_UNUSED) + .ct_snat_vip_ptable = OFTABLE_CT_SNAT_HAIRPIN, + .fdb_ptable = OFTABLE_GET_FDB, + .fdb_lookup_ptable = OFTABLE_LOOKUP_FDB, ++ .common_nat_ct_zone = MFF_LOG_DNAT_ZONE, + }; + struct ofpbuf ofpacts; + ofpbuf_init(&ofpacts, 0); +diff --git a/utilities/ovn-ctl b/utilities/ovn-ctl +index b789d57be..d91f95669 100755 +--- a/utilities/ovn-ctl ++++ b/utilities/ovn-ctl +@@ -42,8 +42,21 @@ ovn_ic_db_conf_file="$ovn_etcdir/ovn-ic-db-params.conf" + + pidfile_is_running () { + pidfile=$1 +- test -e "$pidfile" && [ -s "$pidfile" ] && pid=`cat "$pidfile"` && pid_exists "$pid" +-} >/dev/null 2>&1 ++ cmd=$2 ++ if [ ! -s "$pidfile" ]; then ++ # file missing or empty ++ return 1 ++ fi ++ pid=`cat "$pidfile"` ++ if ! pid_exists $pid; then ++ # pid is dead ++ return 1 ++ fi ++ if [ -n "$cmd" ]; then ++ return $(pid_comm_check "$cmd" "$pid") ++ fi ++ return 0 ++} + + stop_nb_ovsdb() { + OVS_RUNDIR=${OVS_RUNDIR} stop_ovn_daemon ovnnb_db $DB_NB_PIDFILE $DB_NB_CTRL_SOCK +@@ -199,7 +212,7 @@ start_ovsdb__() { + ovn_install_dir "$ovn_etcdir" + + # Check and eventually start ovsdb-server for DB +- if pidfile_is_running $db_pid_file; then ++ if pidfile_is_running $db_pid_file ovsdb-server; then + return + fi + +diff --git a/utilities/ovn-dbctl.c b/utilities/ovn-dbctl.c +index 791caabb2..7eedbbebb 100644 +--- a/utilities/ovn-dbctl.c ++++ b/utilities/ovn-dbctl.c +@@ -202,6 +202,13 @@ ovn_dbctl_main(int argc, char *argv[], + error = ctl_parse_commands(argc - optind, argv_ + optind, + &local_options, &commands, &n_commands); + if (error) { ++ ovsdb_idl_destroy(idl); ++ idl = the_idl = NULL; ++ ++ for (int i = 0; i < argc; i++) { ++ free(argv_[i]); ++ } ++ free(argv_); + ctl_fatal("%s", error); + } + diff --git a/utilities/ovn-nbctl.8.xml b/utilities/ovn-nbctl.8.xml index 80a564660..6be37d21a 100644 --- a/utilities/ovn-nbctl.8.xml @@ -5450,7 +10728,7 @@ index 80a564660..6be37d21a 100644
      [--type={switch | port-group}] acl-del entity [direction [priority match]]
      diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c -index 55b0f5124..3a41f4c61 100644 +index 55b0f5124..910eeb2f5 100644 --- a/utilities/ovn-nbctl.c +++ b/utilities/ovn-nbctl.c @@ -2113,6 +2113,7 @@ nbctl_pre_acl(struct ctl_context *ctx) @@ -5483,7 +10761,50 @@ index 55b0f5124..3a41f4c61 100644 /* Check if same acl already exists for the ls/portgroup */ size_t n_acls = pg ? pg->n_acls : ls->n_acls; struct nbrec_acl **acls = pg ? pg->acls : ls->acls; -@@ -6968,7 +6977,8 @@ static const struct ctl_command_syntax nbctl_commands[] = { +@@ -2828,7 +2837,7 @@ nbctl_lb_add(struct ctl_context *ctx) + } + + struct sockaddr_storage ss_vip; +- if (!inet_parse_active(lb_vip, 0, &ss_vip, false)) { ++ if (!inet_parse_active(lb_vip, 0, &ss_vip, false, NULL)) { + ctl_error(ctx, "%s: should be an IP address (or an IP address " + "and a port number with : as a separator).", lb_vip); + return; +@@ -2858,7 +2867,7 @@ nbctl_lb_add(struct ctl_context *ctx) + struct sockaddr_storage ss_dst; + + if (lb_vip_port) { +- if (!inet_parse_active(token, -1, &ss_dst, false)) { ++ if (!inet_parse_active(token, -1, &ss_dst, false, NULL)) { + ctl_error(ctx, "%s: should be an IP address and a port " + "number with : as a separator.", token); + goto out; +@@ -3004,7 +3013,7 @@ lb_info_add_smap(const struct nbrec_load_balancer *lb, + const struct smap_node *node = nodes[i]; + + struct sockaddr_storage ss; +- if (!inet_parse_active(node->key, 0, &ss, false)) { ++ if (!inet_parse_active(node->key, 0, &ss, false, NULL)) { + continue; + } + +@@ -4736,9 +4745,12 @@ nbctl_lr_nat_add(struct ctl_context *ctx) + struct smap nat_options = SMAP_INITIALIZER(&nat_options); + if (!strcmp(smap_get(&nat->options, "stateless"), + "true") || stateless) { +- ctl_error(ctx, "%s, %s: External ip cannot be shared " +- "across stateless and stateful NATs", +- new_external_ip, new_logical_ip); ++ if (!may_exist) { ++ ctl_error(ctx, "%s, %s: External ip cannot be shared " ++ "across stateless and stateful NATs", ++ new_external_ip, new_logical_ip); ++ } ++ should_return = true; + } + } + } +@@ -6968,7 +6980,8 @@ static const struct ctl_command_syntax nbctl_commands[] = { /* acl commands. */ { "acl-add", 5, 6, "{SWITCH | PORTGROUP} DIRECTION PRIORITY MATCH ACTION", nbctl_pre_acl, nbctl_acl_add, NULL, @@ -5494,10 +10815,163 @@ index 55b0f5124..3a41f4c61 100644 nbctl_pre_acl, nbctl_acl_del, NULL, "--type=", RW }, { "acl-list", 1, 1, "{SWITCH | PORTGROUP}", diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c -index 0795913d3..ece5803f2 100644 +index 0795913d3..4d3523616 100644 --- a/utilities/ovn-trace.c +++ b/utilities/ovn-trace.c -@@ -2457,12 +2457,14 @@ execute_select(const struct ovnact_select *select, +@@ -214,7 +214,7 @@ static void + parse_lb_option(const char *s) + { + struct sockaddr_storage ss; +- if (!inet_parse_active(s, 0, &ss, false)) { ++ if (!inet_parse_active(s, 0, &ss, false, NULL)) { + ovs_fatal(0, "%s: bad address", s); + } + +@@ -1388,7 +1388,8 @@ ovntrace_node_prune_summary(struct ovs_list *nodes) + sub->type == OVNTRACE_NODE_TABLE) { + /* Replace 'sub' by its children, if any, */ + ovs_list_remove(&sub->node); +- ovs_list_splice(&next->node, sub->subs.next, &sub->subs); ++ ovs_list_splice(next ? &next->node : nodes, sub->subs.next, ++ &sub->subs); + ovntrace_node_destroy(sub); + } + } +@@ -1432,7 +1433,8 @@ ovntrace_node_prune_hard(struct ovs_list *nodes) + sub->type == OVNTRACE_NODE_OUTPUT) { + /* Replace 'sub' by its children, if any, */ + ovs_list_remove(&sub->node); +- ovs_list_splice(&next->node, sub->subs.next, &sub->subs); ++ ovs_list_splice(next ? &next->node : nodes, sub->subs.next, ++ &sub->subs); + ovntrace_node_destroy(sub); + } + } +@@ -1523,6 +1525,59 @@ execute_exchange(const struct ovnact_move *move, struct flow *uflow, + mf_subfield_swap(&a, &b, uflow, NULL); + } + ++static void ++execute_push(const struct ovnact_push_pop *p, struct ofpbuf *stack, ++ struct flow *uflow OVS_UNUSED, struct ovs_list *super) ++{ ++ struct mf_subfield sf = expr_resolve_field(&p->field); ++ union mf_subvalue sv; ++ mf_read_subfield(&sf, uflow, &sv); ++ ++ struct ds s = DS_EMPTY_INITIALIZER; ++ ds_put_cstr(&s, "push("); ++ expr_field_format(&p->field, &s); ++ ds_put_cstr(&s, ") -> "); ++ mf_format_subvalue(&sv, &s); ++ ++ ovntrace_node_append(super, OVNTRACE_NODE_MODIFY, "%s", ds_cstr(&s)); ++ ds_destroy(&s); ++ ++ uint8_t bytes = DIV_ROUND_UP(sf.n_bits, 8); ++ nx_stack_push(stack, &sv.u8[sizeof sv - bytes], bytes); ++} ++ ++static void ++execute_pop(const struct ovnact_push_pop *p, struct ofpbuf *stack, ++ struct flow *uflow OVS_UNUSED, struct ovs_list *super) ++{ ++ struct mf_subfield sf = expr_resolve_field(&p->field); ++ struct ds s = DS_EMPTY_INITIALIZER; ++ ds_put_cstr(&s, "pop("); ++ expr_field_format(&p->field, &s); ++ ds_put_cstr(&s, ") <- "); ++ ++ uint8_t src_bytes; ++ const void *src = nx_stack_pop(stack, &src_bytes); ++ if (src) { ++ union mf_subvalue sv; ++ uint8_t dst_bytes = DIV_ROUND_UP(sf.n_bits, 8); ++ ++ if (src_bytes < dst_bytes) { ++ memset(&sv.u8[sizeof sv - dst_bytes], 0, ++ dst_bytes - src_bytes); ++ } ++ memcpy(&sv.u8[sizeof sv - src_bytes], src, src_bytes); ++ mf_write_subfield_flow(&sf, &sv, uflow); ++ mf_format_subvalue(&sv, &s); ++ } else { ++ ds_put_cstr(&s, "/* empty stack */"); ++ } ++ ++ ovntrace_node_append(super, OVNTRACE_NODE_MODIFY, "%s", ds_cstr(&s)); ++ ++ ds_destroy(&s); ++} ++ + static void + trace__(const struct ovntrace_datapath *dp, struct flow *uflow, + uint8_t table_id, enum ovnact_pipeline pipeline, +@@ -1749,6 +1804,10 @@ execute_icmp4(const struct ovnact_nest *on, + { + struct flow icmp4_flow = *uflow; + ++ if (loopback && icmp4_flow.tp_src == htons(ICMP4_DST_UNREACH)) { ++ return; /* Avoid recirculation. */ ++ } ++ + /* Update fields for ICMP. */ + if (loopback) { + icmp4_flow.dl_dst = uflow->dl_src; +@@ -1781,6 +1840,10 @@ execute_icmp6(const struct ovnact_nest *on, + { + struct flow icmp6_flow = *uflow; + ++ if (loopback && icmp6_flow.tp_src == htons(ICMP6_DST_UNREACH)) { ++ return; /* Avoid recirculation. */ ++ } ++ + /* Update fields for ICMPv6. */ + if (loopback) { + icmp6_flow.dl_dst = uflow->dl_src; +@@ -1880,6 +1943,11 @@ execute_tcp_reset(const struct ovnact_nest *on, + bool loopback, enum ovnact_pipeline pipeline, + struct ovs_list *super) + { ++ struct flow tcp_flow = *uflow; ++ if (loopback && tcp_flow.tcp_flags == htons(TCP_RST)) { ++ return; /* Avoid recirculation. */ ++ } ++ + if (get_dl_type(uflow) == htons(ETH_TYPE_IP)) { + execute_tcp4_reset(on, dp, uflow, table_id, loopback, pipeline, super); + } else { +@@ -1912,6 +1980,7 @@ execute_sctp4_abort(const struct ovnact_nest *on, + sctp_flow.nw_ttl = 255; + sctp_flow.tp_src = uflow->tp_src; + sctp_flow.tp_dst = uflow->tp_dst; ++ sctp_flow.tcp_flags = htons(TCP_RST); + + struct ovntrace_node *node = ovntrace_node_append( + super, OVNTRACE_NODE_TRANSFORMATION, "sctp_abort"); +@@ -1961,6 +2030,11 @@ execute_sctp_abort(const struct ovnact_nest *on, + bool loopback, enum ovnact_pipeline pipeline, + struct ovs_list *super) + { ++ struct flow sctp_flow = *uflow; ++ if (loopback && sctp_flow.tcp_flags == htons(TCP_RST)) { ++ return; /* Avoid recirculation. */ ++ } ++ + if (get_dl_type(uflow) == htons(ETH_TYPE_IP)) { + execute_sctp4_abort(on, dp, uflow, table_id, loopback, + pipeline, super); +@@ -2409,7 +2483,8 @@ execute_ct_lb(const struct ovnact_ct_lb *ct_lb, + } + + struct ovntrace_node *node = ovntrace_node_append( +- super, OVNTRACE_NODE_TRANSFORMATION, "ct_lb%s", ++ super, OVNTRACE_NODE_TRANSFORMATION, "%s%s", ++ ct_lb->ovnact.type == OVNACT_CT_LB_MARK ? "ct_lb_mark" : "ct_lb", + ds_cstr_ro(&comment)); + ds_destroy(&comment); + trace__(dp, &ct_lb_flow, ct_lb->ltable, pipeline, &node->subs); +@@ -2457,12 +2532,14 @@ execute_select(const struct ovnact_select *select, static void execute_log(const struct ovnact_log *log, struct flow *uflow, @@ -5514,7 +10988,43 @@ index 0795913d3..ece5803f2 100644 log_verdict_to_string(log->verdict), log_severity_to_string(log->severity), packet_str); -@@ -2726,7 +2728,8 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len, +@@ -2555,6 +2632,8 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len, + return; + } + ++ struct ofpbuf stack; ++ ofpbuf_init(&stack, 0); + struct ds s = DS_EMPTY_INITIALIZER; + const struct ovnact *a; + OVNACT_FOR_EACH (a, ovnacts, ovnacts_len) { +@@ -2585,6 +2664,14 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len, + execute_exchange(ovnact_get_EXCHANGE(a), uflow, super); + break; + ++ case OVNACT_PUSH: ++ execute_push(ovnact_get_PUSH(a), &stack, uflow, super); ++ break; ++ ++ case OVNACT_POP: ++ execute_pop(ovnact_get_POP(a), &stack, uflow, super); ++ break; ++ + case OVNACT_DEC_TTL: + if (is_ip_any(uflow)) { + if (uflow->nw_ttl) { +@@ -2632,6 +2719,11 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len, + execute_ct_lb(ovnact_get_CT_LB(a), dp, uflow, pipeline, super); + break; + ++ case OVNACT_CT_LB_MARK: ++ execute_ct_lb(ovnact_get_CT_LB_MARK(a), dp, uflow, pipeline, ++ super); ++ break; ++ + case OVNACT_SELECT: + execute_select(ovnact_get_SELECT(a), dp, uflow, + pipeline, super); +@@ -2726,7 +2818,8 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len, break; case OVNACT_LOG: @@ -5524,3 +11034,11 @@ index 0795913d3..ece5803f2 100644 break; case OVNACT_SET_METER: +@@ -2820,6 +2913,7 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len, + break; + } + } ++ ofpbuf_uninit(&stack); + ds_destroy(&s); + } + diff --git a/SPECS/ovn-2021.spec b/SPECS/ovn-2021.spec index 25df317..61a8805 100644 --- a/SPECS/ovn-2021.spec +++ b/SPECS/ovn-2021.spec @@ -51,7 +51,7 @@ Summary: Open Virtual Network support Group: System Environment/Daemons URL: http://www.ovn.org/ Version: 21.12.0 -Release: 46%{?commit0:.%{date}git%{shortcommit0}}%{?dist} +Release: 82%{?commit0:.%{date}git%{shortcommit0}}%{?dist} Provides: openvswitch%{pkgver}-ovn-common = %{?epoch:%{epoch}:}%{version}-%{release} Obsoletes: openvswitch%{pkgver}-ovn-common < 2.11.0-1 @@ -62,8 +62,8 @@ License: ASL 2.0 and LGPLv2+ and SISSL # Always pull an upstream release, since this is what we rebase to. Source: https://github.com/ovn-org/ovn/archive/v%{version}.tar.gz#/ovn-%{version}.tar.gz -%define ovscommit 498cedc483f3239c839c55b4d9f2261b61fb6ace -%define ovsshortcommit 498cedc +%define ovscommit 45ecaa9e574d63496e54a4093128302e2c2e10d0 +%define ovsshortcommit 45ecaa9 Source10: https://github.com/openvswitch/ovs/archive/%{ovscommit}.tar.gz#/openvswitch-%{ovsshortcommit}.tar.gz %define ovsdir ovs-%{ovscommit} @@ -528,6 +528,186 @@ fi %{_unitdir}/ovn-controller-vtep.service %changelog +* Fri Jul 01 2022 Adrian Moreno - 21.12.0-82 +- ovs: Bump submodule to newer version (#2102618) +[Gerrit: 2c3ed6dba9ebeaab29072784e5f479bc2dcd6747] +[Upstream: 2c3ed6dba9ebeaab29072784e5f479bc2dcd6747] + +* Wed Jun 29 2022 Lorenzo Bianconi - 21.12.0-81 +- northd: add condition for stateless nat drop flow in S_ROUTER_IN_GW_REDIRECT pipeline (#2094980) +[Gerrit: 9b1666fc4c8865ce8520ed8791b858b817883825] +[Upstream: 9b1666fc4c8865ce8520ed8791b858b817883825] + +* Mon Jun 27 2022 Xavier Simonart - 21.12.0-80 +- northd: avoid snat on reply packets (#2061593) +[Gerrit: 6c96b2fdb6bcb728fe32a8f7dced5880be1164b9] +[Upstream: 8b3e1afc30f3cf0ef9857fdc68f619b6fbed10dc] + +* Mon Jun 27 2022 Ihar Hrachyshka - 21.12.0-79 +- tests: ovn-nbctl dump-flows -> ovn-sbctl dump-flows +[Gerrit: 8dbc5da61ae44f4666396f4fc254b7dcb8ed5d62] +[Upstream: 8dbc5da61ae44f4666396f4fc254b7dcb8ed5d62] + +* Mon Jun 27 2022 Ihar Hrachyshka - 21.12.0-78 +- Fix memleak in ovn-nbctl when args can't be parsed +[Gerrit: 27d8c91524468e494a7cf45b19d857665acf1113] +[Upstream: 27d8c91524468e494a7cf45b19d857665acf1113] + +* Tue Jun 14 2022 Ihar Hrachyshka - 21.12.0-77 +- Fix pidfile_is_running when $cmd is not passed +[Gerrit: cc3c32534ecb00d3547e41e75d2243bc57c7662b] +[Upstream: 6e57adfe5a35fc36ef290c6e9ae7e616f73cd3d2] + +* Thu Jun 09 2022 Ihar Hrachyshka - 21.12.0-76 +- Lock pinctrl_mutex for pinctrl_wait +[Gerrit: a5fc01db2eea699887353a35ea17bf97ae9cc119] +[Upstream: a5fc01db2eea699887353a35ea17bf97ae9cc119] + +* Thu Jun 09 2022 Terry Wilson - 21.12.0-75 +- Ensure pid belongs to ovsdb-server in ovn-ctl +[Gerrit: 4cb3f9d9940e936c72cead63023bb74fc84b2cad] +[Upstream: 4cb3f9d9940e936c72cead63023bb74fc84b2cad] + +* Thu Jun 09 2022 Terry Wilson - 21.12.0-74 +- Handle re-used pids in pidfile_is_running +[Gerrit: ab7d5b978e4f944f6bd9438ab5749d902164e160] +[Upstream: ab7d5b978e4f944f6bd9438ab5749d902164e160] + +* Fri Jun 03 2022 Mark Michelson - 21.12.0-73 +- Prepare for 21.12.3. +[Gerrit: 1d8dc96261148db2df0daf3a1b32e16c64eb8882] +[Upstream: 1d8dc96261148db2df0daf3a1b32e16c64eb8882] + +* Fri Jun 03 2022 Mark Michelson - 21.12.0-72 +- Set release date for 21.12.2. +[Gerrit: effc3aa676c7bc2f204dda74410e05ea9c6fa9b4] +[Upstream: effc3aa676c7bc2f204dda74410e05ea9c6fa9b4] + +* Fri Jun 03 2022 Dumitru Ceara - 21.12.0-71 +- northd: Use ct_mark.blocked and ecmp_reply_port only when all chassis support it. (#2091565) +[Gerrit: ad3b6566bccfb6bc2341fe215be6fb83748434fe] +[Upstream: ad3b6566bccfb6bc2341fe215be6fb83748434fe] + +* Fri Jun 03 2022 Dumitru Ceara - 21.12.0-70 +- northd: ovn-controller: Use ct_mark.natted only when ct_lb_mark is used. +[Gerrit: 22f4cbb55131a453d3e23c86c3613b948a9f835d] +[Upstream: 22f4cbb55131a453d3e23c86c3613b948a9f835d] + +* Wed Jun 01 2022 Dumitru Ceara - 21.12.0-69 +- northd: Use ct_lb_mark only when all chassis support it. (#2091565) +[Gerrit: 6069caef46a36e8c12b7fbc01f40841db5a17c4b] +[Upstream: 3fd4db6] + +* Fri May 27 2022 Ales Musil - 21.12.0-68 +- binding.c: Make sure that localport is removed from local datapath (#2076604) +[Gerrit: 31834973214431fd658f9b2eb2102399afee2d3f] +[Upstream: 321f13ea1281ce9d5c13a8f9b7a5efc0ca7b3cab] + +* Fri May 27 2022 Ales Musil - 21.12.0-67 +- physical.c: Move localport remote output flow definition (#2076604) +[Gerrit: 832afe772d2585c14db86a640bb2dd55b9958bde] +[Upstream: 14e19ba2c885c30f0cc95d3b9bd74e87bbbc352a] + +* Tue May 24 2022 Ales Musil - 21.12.0-66 +- physical.c: Avoid NULL ptr deref in populate_remote_chassis_macs (#2082341) +[Gerrit: 885b8c176af5305d035591b0f371220d45820a13] +[Upstream: d2b767fff257af55d2be7e4fe842539b7cb7f058] + +* Tue May 24 2022 Han Zhou - 21.12.0-65 +- Use ct_mark for masked access to make flows HW-offloading friendly. (#1957786) +[Gerrit: 07f6522a4c98bc393b7495724d133485809143f3] +[Upstream: a075230e4a0fcc166251271db1c8ae01b993c9cf] + +* Tue May 24 2022 Han Zhou - 21.12.0-64 +- ovn-controller: Handle SB_Global:options:northd_internal_version in I-P engine. +[Gerrit: 00d4e7e70bb07b461e3a1b0eb2c20e12b175e0b1] +[Upstream: c2eeb2c98ea860dbbc7eee5e9bae8a65769b0da3] + +* Mon May 23 2022 Han Zhou - 21.12.0-63 +- ovn-northd: Improve the doc and tests for ecmp-symmetric-reply. +[Gerrit: 18f016bd7a203419adba4e1ee8753d93978a81be] +[Upstream: bf55f7a655abb7aa0c3e5d537e79595ae13e89f2] + +* Mon May 23 2022 Han Zhou - 21.12.0-62 +- actions: Add stack push and pop actions. +[Gerrit: f282d8b0a4f1e587755b7214325669f626af8748] +[Upstream: 8ce847737f2db7b82b2e0296ff3b39551393d839] + +* Mon May 23 2022 Han Zhou - 21.12.0-61 +- actions: Add action ct_lb_mark. +[Gerrit: c3a8af65541b8aefebe6ff0d140f7a49c29316dc] +[Upstream: 3357440a3f1e8426953f96b41f72b88b43b86c42] + +* Mon May 23 2022 Han Zhou - 21.12.0-60 +- ovn-sb.xml: Fix ct_lb documentation. +[Gerrit: b4556e9f9db30290e4a2a65128e4c51dc2d07482] +[Upstream: 9eb7b4ec75e6773eb8f1770cc03f2fb0d391262a] + +* Thu May 19 2022 Lorenzo Bianconi - 21.12.0-59 +- northd: fix stateless nat with allowed_ext_ips (#2066990) +[Gerrit: 93cee76c74bc03a498dabee5d853e572a70c6d41] +[Upstream: 93cee76c74bc03a498dabee5d853e572a70c6d41] + +* Wed May 18 2022 Dumitru Ceara - 21.12.0-58 +- ovn-controller: Consider zone 0 as a valid zone when restoring. (#2087194) +[Gerrit: 311c19ee758dc3e7778ed233572703262ecd94fb] +[Upstream: 3a8fe34c789f09135c1356ace442793dd6fc2f1c] + +* Wed May 18 2022 Mary Manohar - 21.12.0-57 +- ovn-controller: Set Port_Binding.up field only if the Southbound DB is aware of this field +[Gerrit: f5d4d59ed3488cc296e0b9b2a860ce28f99f5cb0] +[Upstream: f5d4d59ed3488cc296e0b9b2a860ce28f99f5cb0] + +* Wed May 18 2022 Mark Michelson - 21.12.0-56 +- northd: Honor ct-snat-zone option for common case. (#2061619) +[Gerrit: 961f9a1afd08641ecdcbb874a5269d0834e067b8] +[Upstream: 961f9a1afd08641ecdcbb874a5269d0834e067b8] + +* Mon May 16 2022 Mohammad Heib - 21.12.0-55 +- northd: handle container lport type update (#2037433) +[Gerrit: 5a72c9d0512bed484e35af5c9f4a2efdf860001c] +[Upstream: cd3b685043fa9758df3665bf3e3fc972048698a6] + +* Mon May 16 2022 Lorenzo Bianconi - 21.12.0-54 +- northd: fix lflow grouping in build_lb_rules +[Gerrit: f1c1c60e27639dcbaef9dd27ae32be6bad04106d] +[Upstream: 664f2aa752c48b699499051fa2dbf3a53effd482] + +* Wed May 11 2022 Ihar Hrachyshka - 21.12.0-53 +- docs: fix a typo in bandwidth column name +[Gerrit: 716a7e483bb143f1ff4b1bcddf16f79a05207a77] +[Upstream: 716a7e483bb143f1ff4b1bcddf16f79a05207a77] + +* Wed May 11 2022 Ales Musil - 21.12.0-52 +- ci: ovn-kubernetes: Add missing socat package +[Gerrit: 8714282cce4c18ec1476b1d6b204289fd153955a] +[Upstream: 8714282cce4c18ec1476b1d6b204289fd153955a] + +* Tue May 10 2022 Lorenzo Bianconi - 21.12.0-51 +- utilities: ovn-trace: fix reject action crash (#2074537) +[Gerrit: 7e9654c03fbb1ac820079afdd6e8d6292435225d] +[Upstream: 7e9654c03fbb1ac820079afdd6e8d6292435225d] + +* Tue May 10 2022 Lorenzo Bianconi - 21.12.0-50 +- utilities: nbctl: do not report errors for stateless nat if --may-exist is provided (#2066551) +[Gerrit: 1feca481e0113b2521ee343868b8c9d3af1b4fd0] +[Upstream: 1feca481e0113b2521ee343868b8c9d3af1b4fd0] + +* Tue May 10 2022 Ales Musil - 21.12.0-49 +- lflow: Add MAC bindings when new datapath is added to chassis (#2069783) +[Gerrit: a5f3fb891cd255124581eab858cdd779d686e282] +[Upstream: a5f3fb891cd255124581eab858cdd779d686e282] + +* Mon May 09 2022 Lorenzo Bianconi - 21.12.0-48 +- northd: fix nat-v6 with exempted_ext_ips configuration (#2066611) +[Gerrit: 59fa1b99a6d1c42ed49a077f8be60041aae72a84] +[Upstream: 59fa1b99a6d1c42ed49a077f8be60041aae72a84] + +* Mon May 09 2022 Lorenzo Bianconi - 21.12.0-47 +- northd: dynamically compute l2 hdr len for check_pkt_larger action (#2075121) +[Gerrit: 5c185cfcf9c8fac03c42f1248f3e5e4caa74c77a] +[Upstream: 5c185cfcf9c8fac03c42f1248f3e5e4caa74c77a] + * Mon Apr 25 2022 Numan Siddique - 21.12.0-46 - ovn-northd: Add flow to use eth.src if nd.tll is 0 in put_nd() action. (#2078026) [Gerrit: 30bc0f402ef89b5383c0a0a679df51206e488f64]