From eaa8cd326b53de182c317b1b47b00cec78bc464c Mon Sep 17 00:00:00 2001 From: Alfredo Moralejo Date: May 30 2023 14:25:34 +0000 Subject: Import ovn23.03-23.03.0-50.el9fdp.src.rpm from FDP --- diff --git a/.ovn.metadata b/.ovn.metadata index 5b5b237..e8741e5 100644 --- a/.ovn.metadata +++ b/.ovn.metadata @@ -1,5 +1,5 @@ 002450621b33c5690060345b0aac25bc2426d675 SOURCES/docutils-0.12.tar.gz -f9cfb42d90c2c5417825087573feb01117be91f3 SOURCES/openvswitch-a787fbb.tar.gz -ba9c555a492827e129a040e0fa95bfe7e95792a0 SOURCES/ovn-22.12.0.tar.gz +c39c740cd246836bcb125432d2205d0f76504bc0 SOURCES/openvswitch-8986d4d.tar.gz +4b5217eba8aa5b020946395afa94e48ae81957e8 SOURCES/ovn-23.03.0.tar.gz d34f96421a86004aa5d26ecf975edefd09f948b1 SOURCES/Pygments-1.4.tar.gz 6beb30f18ffac3de7689b7fd63e9a8a7d9c8df3a SOURCES/Sphinx-1.1.3.tar.gz diff --git a/SOURCES/ovn22.12.patch b/SOURCES/ovn22.12.patch deleted file mode 100644 index 6277eee..0000000 --- a/SOURCES/ovn22.12.patch +++ /dev/null @@ -1,3404 +0,0 @@ -diff --git a/.ci/ovn-kubernetes/Dockerfile b/.ci/ovn-kubernetes/Dockerfile -index e74b620be..1884724ec 100644 ---- a/.ci/ovn-kubernetes/Dockerfile -+++ b/.ci/ovn-kubernetes/Dockerfile -@@ -1,5 +1,5 @@ - ARG OVNKUBE_COMMIT=master --ARG LIBOVSDB_COMMIT=8081fe24e48f -+ARG LIBOVSDB_COMMIT=a6a173993830 - - FROM fedora:35 AS ovnbuilder - -@@ -47,9 +47,17 @@ RUN GO111MODULE=on go install github.com/ovn-org/libovsdb/cmd/modelgen@${LIBOVSD - # Clone OVN Kubernetes and build the binary based on the commit passed as argument - WORKDIR /root - RUN git clone https://github.com/ovn-org/ovn-kubernetes.git --WORKDIR /root/ovn-kubernetes/go-controller -+WORKDIR /root/ovn-kubernetes - RUN git checkout ${OVNKUBE_COMMIT} && git log -n 1 - -+# Copy the ovn-kubernetes scripts from the OVN sources and apply any -+# custom changes if needed. -+RUN mkdir -p /tmp/ovn/.ci/ovn-kubernetes -+COPY .ci/ovn-kubernetes /tmp/ovn/.ci/ovn-kubernetes -+WORKDIR /tmp/ovn -+RUN .ci/ovn-kubernetes/prepare.sh /root/ovn-kubernetes -+ -+WORKDIR /root/ovn-kubernetes/go-controller - # Make sure we use the OVN NB/SB schema from the local code. - COPY --from=ovnbuilder /tmp/ovn/ovn-nb.ovsschema pkg/nbdb/ovn-nb.ovsschema - COPY --from=ovnbuilder /tmp/ovn/ovn-sb.ovsschema pkg/sbdb/ovn-sb.ovsschema -diff --git a/.ci/ovn-kubernetes/custom.patch b/.ci/ovn-kubernetes/custom.patch -new file mode 100644 -index 000000000..e69de29bb -diff --git a/.ci/ovn-kubernetes/prepare.sh b/.ci/ovn-kubernetes/prepare.sh -new file mode 100755 -index 000000000..8fc9652af ---- /dev/null -+++ b/.ci/ovn-kubernetes/prepare.sh -@@ -0,0 +1,20 @@ -+#!/bin/bash -+ -+set -ev -+ -+ovnk8s_path=$1 -+topdir=$PWD -+ -+pushd ${ovnk8s_path} -+ -+# Add here any custom operations that need to performed on the -+# ovn-kubernetes cloned repo, e.g., custom patches. -+ -+# git apply --allow-empty is too new so not all git versions from major -+# distros support it, just check if the custom patch file is not empty -+# before applying it. -+[ -s ${topdir}/.ci/ovn-kubernetes/custom.patch ] && \ -+ git apply -v ${topdir}/.ci/ovn-kubernetes/custom.patch -+ -+popd # ${ovnk8s_path} -+exit 0 -diff --git a/.github/workflows/ovn-kubernetes.yml b/.github/workflows/ovn-kubernetes.yml -index 344937e53..840ecd1e0 100644 ---- a/.github/workflows/ovn-kubernetes.yml -+++ b/.github/workflows/ovn-kubernetes.yml -@@ -16,7 +16,7 @@ env: - GO_VERSION: "1.18.4" - K8S_VERSION: v1.24.0 - OVNKUBE_COMMIT: "master" -- LIBOVSDB_COMMIT: "98c0bad3cff1" -+ LIBOVSDB_COMMIT: "a6a173993830" - KIND_CLUSTER_NAME: ovn - KIND_INSTALL_INGRESS: true - KIND_ALLOW_SYSTEM_WRITES: true -@@ -73,6 +73,7 @@ jobs: - env: - JOB_NAME: "${{ matrix.target }}-${{ matrix.ha }}-${{ matrix.gateway-mode }}-${{ matrix.ipfamily }}-${{ matrix.disable-snat-multiple-gws }}-${{ matrix.second-bridge }}" - OVN_HYBRID_OVERLAY_ENABLE: "${{ matrix.target == 'control-plane' }}" -+ KIND_INSTALL_METALLB: "${{ matrix.target == 'control-plane' }}" - OVN_MULTICAST_ENABLE: "${{ matrix.target == 'control-plane' }}" - OVN_EMPTY_LB_EVENTS: "${{ matrix.target == 'control-plane' }}" - OVN_HA: "true" -@@ -91,12 +92,19 @@ jobs: - go-version: ${{ env.GO_VERSION }} - id: go - -+ - name: Check out ovn -+ uses: actions/checkout@v3 -+ - - name: Check out ovn-kubernetes - uses: actions/checkout@v3 - with: - path: src/github.com/ovn-org/ovn-kubernetes - repository: ovn-org/ovn-kubernetes - -+ - name: Prepare -+ run: | -+ .ci/ovn-kubernetes/prepare.sh src/github.com/ovn-org/ovn-kubernetes -+ - - name: Set up environment - run: | - export GOPATH=$(go env GOPATH) -diff --git a/Makefile.am b/Makefile.am -index c8f770146..f7758d114 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -90,6 +90,8 @@ EXTRA_DIST = \ - .ci/osx-build.sh \ - .ci/osx-prepare.sh \ - .ci/ovn-kubernetes/Dockerfile \ -+ .ci/ovn-kubernetes/prepare.sh \ -+ .ci/ovn-kubernetes/custom.patch \ - .github/workflows/test.yml \ - .github/workflows/ovn-kubernetes.yml \ - boot.sh \ -diff --git a/NEWS b/NEWS -index 0920b44e2..acb8065bc 100644 ---- a/NEWS -+++ b/NEWS -@@ -1,3 +1,6 @@ -+OVN v22.12.1 - xx xxx xxxx -+-------------------------- -+ - OVN v22.12.0 - 16 Dec 2022 - -------------------------- - - Add load balancer "affinity_timeout" option to configure load balancing -diff --git a/build-aux/sodepends.py b/build-aux/sodepends.py -index 343fda1af..7b1f9c840 100755 ---- a/build-aux/sodepends.py -+++ b/build-aux/sodepends.py -@@ -63,7 +63,8 @@ def sodepends(include_info, filenames, dst): - continue - - # Open file. -- include_dirs = [info[0] for info in include_info] -+ include_dirs = [info[1] if len(info) == 2 else info[0] -+ for info in include_info] - fn = soutil.find_file(include_dirs, toplevel) - if not fn: - ok = False -diff --git a/configure.ac b/configure.ac -index 101467253..357758e0c 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -13,7 +13,7 @@ - # limitations under the License. - - AC_PREREQ(2.63) --AC_INIT(ovn, 22.12.0, bugs@openvswitch.org) -+AC_INIT(ovn, 22.12.1, bugs@openvswitch.org) - AC_CONFIG_MACRO_DIR([m4]) - AC_CONFIG_AUX_DIR([build-aux]) - AC_CONFIG_HEADERS([config.h]) -diff --git a/controller/chassis.c b/controller/chassis.c -index 685d9b2ae..98f8da2be 100644 ---- a/controller/chassis.c -+++ b/controller/chassis.c -@@ -352,6 +352,7 @@ chassis_build_other_config(const struct ovs_chassis_cfg *ovs_cfg, - smap_replace(config, OVN_FEATURE_PORT_UP_NOTIF, "true"); - smap_replace(config, OVN_FEATURE_CT_NO_MASKED_LABEL, "true"); - smap_replace(config, OVN_FEATURE_MAC_BINDING_TIMESTAMP, "true"); -+ smap_replace(config, OVN_FEATURE_CT_LB_RELATED, "true"); - } - - /* -@@ -469,6 +470,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_LB_RELATED, -+ false)) { -+ return true; -+ } -+ - return false; - } - -diff --git a/controller/lflow.c b/controller/lflow.c -index bb47bb0c7..4b1cfe318 100644 ---- a/controller/lflow.c -+++ b/controller/lflow.c -@@ -1567,9 +1567,6 @@ add_lb_vip_hairpin_reply_action(struct in6_addr *vip6, ovs_be32 vip, - /* Hairpin replies have the same nw_proto as packets that created the - * session. - */ -- union mf_value imm_proto = { -- .u8 = lb_proto, -- }; - ol_spec = ofpbuf_put_zeros(ofpacts, sizeof *ol_spec); - ol_spec->dst.field = mf_from_id(MFF_IP_PROTO); - ol_spec->src.field = mf_from_id(MFF_IP_PROTO); -@@ -1577,16 +1574,21 @@ add_lb_vip_hairpin_reply_action(struct in6_addr *vip6, ovs_be32 vip, - ol_spec->dst.n_bits = ol_spec->dst.field->n_bits; - ol_spec->n_bits = ol_spec->dst.n_bits; - ol_spec->dst_type = NX_LEARN_DST_MATCH; -- ol_spec->src_type = NX_LEARN_SRC_IMMEDIATE; -- mf_write_subfield_value(&ol_spec->dst, &imm_proto, &match); -- -- /* Push value last, as this may reallocate 'ol_spec' */ -- imm_bytes = DIV_ROUND_UP(ol_spec->dst.n_bits, 8); -- src_imm = ofpbuf_put_zeros(ofpacts, OFPACT_ALIGN(imm_bytes)); -- memcpy(src_imm, &imm_proto, imm_bytes); - - /* Hairpin replies have source port == . */ - if (has_l4_port) { -+ union mf_value imm_proto = { -+ .u8 = lb_proto, -+ }; -+ -+ ol_spec->src_type = NX_LEARN_SRC_IMMEDIATE; -+ mf_write_subfield_value(&ol_spec->dst, &imm_proto, &match); -+ -+ /* Push value last, as this may reallocate 'ol_spec' */ -+ imm_bytes = DIV_ROUND_UP(ol_spec->dst.n_bits, 8); -+ src_imm = ofpbuf_put_zeros(ofpacts, OFPACT_ALIGN(imm_bytes)); -+ memcpy(src_imm, &imm_proto, imm_bytes); -+ - ol_spec = ofpbuf_put_zeros(ofpacts, sizeof *ol_spec); - switch (lb_proto) { - case IPPROTO_TCP: -@@ -1610,6 +1612,8 @@ add_lb_vip_hairpin_reply_action(struct in6_addr *vip6, ovs_be32 vip, - ol_spec->n_bits = ol_spec->dst.n_bits; - ol_spec->dst_type = NX_LEARN_DST_MATCH; - ol_spec->src_type = NX_LEARN_SRC_FIELD; -+ } else { -+ ol_spec->src_type = NX_LEARN_SRC_FIELD; - } - - /* Set MLF_LOOKUP_LB_HAIRPIN_BIT for hairpin replies. */ -diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c -index 73c33a6bf..c899283dc 100644 ---- a/controller/ovn-controller.c -+++ b/controller/ovn-controller.c -@@ -755,6 +755,11 @@ update_ct_zones(const struct shash *binding_lports, - } - bitmap_set1(ct_zone_bitmap, snat_req_node->data); - node->data = snat_req_node->data; -+ } else { -+ add_pending_ct_zone_entry(pending_ct_zones, CT_ZONE_OF_QUEUED, -+ snat_req_node->data, true, snat_req_node->name); -+ bitmap_set1(ct_zone_bitmap, snat_req_node->data); -+ simap_put(ct_zones, snat_req_node->name, snat_req_node->data); - } - } - -diff --git a/controller/pinctrl.c b/controller/pinctrl.c -index 82da6ae73..e4d530138 100644 ---- a/controller/pinctrl.c -+++ b/controller/pinctrl.c -@@ -1419,7 +1419,6 @@ prepare_ipv6_prefixd(struct ovsdb_idl_txn *ovnsb_idl_txn, - - struct buffer_info { - struct ofpbuf ofpacts; -- ofp_port_t ofp_port; - struct dp_packet *p; - }; - -@@ -1495,7 +1494,6 @@ buffered_push_packet(struct buffered_packets *bp, - union mf_value pkt_mark_value; - mf_get_value(pkt_mark_field, &md->flow, &pkt_mark_value); - ofpact_put_set_field(&bi->ofpacts, pkt_mark_field, &pkt_mark_value, NULL); -- bi->ofp_port = md->flow.in_port.ofp_port; - - struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&bi->ofpacts); - resubmit->in_port = OFPP_CONTROLLER; -@@ -1531,7 +1529,7 @@ buffered_send_packets(struct rconn *swconn, struct buffered_packets *bp, - .ofpacts = bi->ofpacts.data, - .ofpacts_len = bi->ofpacts.size, - }; -- match_set_in_port(&po.flow_metadata, bi->ofp_port); -+ match_set_in_port(&po.flow_metadata, OFPP_CONTROLLER); - queue_msg(swconn, ofputil_encode_packet_out(&po, proto)); - - ofpbuf_uninit(&bi->ofpacts); -diff --git a/debian/changelog b/debian/changelog -index 6f5a9ac2a..d658774f6 100644 ---- a/debian/changelog -+++ b/debian/changelog -@@ -1,3 +1,9 @@ -+OVN (22.12.1-1) unstable; urgency=low -+ [ OVN team ] -+ * New upstream version -+ -+ -- OVN team Fri, 16 Dec 2022 09:52:44 -0500 -+ - ovn (22.12.0-1) unstable; urgency=low - - * New upstream version -diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c -index 73ce77e5c..9a80a7f68 100644 ---- a/ic/ovn-ic.c -+++ b/ic/ovn-ic.c -@@ -1911,13 +1911,112 @@ main(int argc, char *argv[]) - struct ovsdb_idl_loop ovnisb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER( - ovsdb_idl_create(ovn_ic_sb_db, &icsbrec_idl_class, true, true)); - -- /* ovn-nb db. XXX: add only needed tables and columns */ -+ /* ovn-nb db. */ - struct ovsdb_idl_loop ovnnb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER( -- ovsdb_idl_create(ovnnb_db, &nbrec_idl_class, true, true)); -- -- /* ovn-sb db. XXX: add only needed tables and columns */ -+ ovsdb_idl_create(ovnnb_db, &nbrec_idl_class, false, true)); -+ -+ ovsdb_idl_add_table(ovnnb_idl_loop.idl, &nbrec_table_nb_global); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, &nbrec_nb_global_col_name); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, &nbrec_nb_global_col_options); -+ -+ ovsdb_idl_add_table(ovnnb_idl_loop.idl, -+ &nbrec_table_logical_router_static_route); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_router_static_route_col_route_table); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_router_static_route_col_ip_prefix); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_router_static_route_col_nexthop); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_router_static_route_col_external_ids); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_router_static_route_col_options); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_router_static_route_col_policy); -+ -+ ovsdb_idl_add_table(ovnnb_idl_loop.idl, &nbrec_table_logical_router); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_router_col_name); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_router_col_static_routes); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_router_col_ports); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_router_col_options); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_router_col_external_ids); -+ -+ ovsdb_idl_add_table(ovnnb_idl_loop.idl, &nbrec_table_logical_router_port); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_router_port_col_name); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_router_port_col_networks); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_router_port_col_external_ids); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_router_port_col_options); -+ -+ ovsdb_idl_add_table(ovnnb_idl_loop.idl, &nbrec_table_logical_switch); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_switch_col_name); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_switch_col_ports); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_switch_col_other_config); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_switch_col_external_ids); -+ -+ ovsdb_idl_add_table(ovnnb_idl_loop.idl, &nbrec_table_logical_switch_port); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_switch_port_col_name); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_switch_port_col_addresses); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_switch_port_col_options); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_switch_port_col_type); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_switch_port_col_up); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_switch_port_col_addresses); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_switch_port_col_enabled); -+ ovsdb_idl_add_column(ovnnb_idl_loop.idl, -+ &nbrec_logical_switch_port_col_external_ids); -+ -+ /* 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_create(ovnsb_db, &sbrec_idl_class, false, true)); -+ -+ ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_chassis); -+ ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_encaps); -+ ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_name); -+ ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_hostname); -+ ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_other_config); -+ -+ ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_encap); -+ ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_encap_col_chassis_name); -+ ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_encap_col_type); -+ ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_encap_col_ip); -+ ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_encap_col_options); -+ -+ ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_datapath_binding); -+ ovsdb_idl_add_column(ovnsb_idl_loop.idl, -+ &sbrec_datapath_binding_col_external_ids); -+ -+ ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_port_binding); -+ ovsdb_idl_add_column(ovnsb_idl_loop.idl, -+ &sbrec_port_binding_col_datapath); -+ ovsdb_idl_add_column(ovnsb_idl_loop.idl, -+ &sbrec_port_binding_col_mac); -+ ovsdb_idl_add_column(ovnsb_idl_loop.idl, -+ &sbrec_port_binding_col_options); -+ ovsdb_idl_add_column(ovnsb_idl_loop.idl, -+ &sbrec_port_binding_col_logical_port); -+ ovsdb_idl_add_column(ovnsb_idl_loop.idl, -+ &sbrec_port_binding_col_external_ids); -+ ovsdb_idl_add_column(ovnsb_idl_loop.idl, -+ &sbrec_port_binding_col_chassis); - - /* Create IDL indexes */ - struct ovsdb_idl_index *nbrec_ls_by_name -diff --git a/include/ovn/features.h b/include/ovn/features.h -index 679f67457..5bcd68739 100644 ---- a/include/ovn/features.h -+++ b/include/ovn/features.h -@@ -24,6 +24,7 @@ - #define OVN_FEATURE_PORT_UP_NOTIF "port-up-notif" - #define OVN_FEATURE_CT_NO_MASKED_LABEL "ct-no-masked-label" - #define OVN_FEATURE_MAC_BINDING_TIMESTAMP "mac-binding-timestamp" -+#define OVN_FEATURE_CT_LB_RELATED "ovn-ct-lb-related" - - /* OVS datapath supported features. Based on availability OVN might generate - * different types of openflows. -diff --git a/include/ovn/lex.h b/include/ovn/lex.h -index 9159b7a26..64d33361f 100644 ---- a/include/ovn/lex.h -+++ b/include/ovn/lex.h -@@ -29,6 +29,8 @@ - - struct ds; - -+#define LEX_TEMPLATE_PREFIX '^' -+ - /* Token type. */ - enum lex_type { - LEX_T_END, /* end of input */ -diff --git a/lib/lb.c b/lib/lb.c -index 43628bba7..c13d07b99 100644 ---- a/lib/lb.c -+++ b/lib/lb.c -@@ -314,11 +314,10 @@ ovn_lb_vip_destroy(struct ovn_lb_vip *vip) - free(vip->backends); - } - --void --ovn_lb_vip_format(const struct ovn_lb_vip *vip, struct ds *s, bool template) -+static void -+ovn_lb_vip_format__(const struct ovn_lb_vip *vip, struct ds *s, -+ bool needs_brackets) - { -- bool needs_brackets = vip->address_family == AF_INET6 && vip->port_str -- && !template; - if (needs_brackets) { - ds_put_char(s, '['); - } -@@ -331,6 +330,30 @@ ovn_lb_vip_format(const struct ovn_lb_vip *vip, struct ds *s, bool template) - } - } - -+/* Formats the VIP in the way the ovn-controller expects it, that is, -+ * template IPv6 variables need to be between brackets too. -+ */ -+static char * -+ovn_lb_vip6_template_format_internal(const struct ovn_lb_vip *vip) -+{ -+ struct ds s = DS_EMPTY_INITIALIZER; -+ -+ if (vip->vip_str && *vip->vip_str == LEX_TEMPLATE_PREFIX) { -+ ovn_lb_vip_format__(vip, &s, true); -+ } else { -+ ovn_lb_vip_format(vip, &s, !!vip->port_str); -+ } -+ return ds_steal_cstr(&s); -+} -+ -+void -+ovn_lb_vip_format(const struct ovn_lb_vip *vip, struct ds *s, bool template) -+{ -+ bool needs_brackets = vip->address_family == AF_INET6 && vip->port_str -+ && !template; -+ ovn_lb_vip_format__(vip, s, needs_brackets); -+} -+ - void - ovn_lb_vip_backends_format(const struct ovn_lb_vip *vip, struct ds *s, - bool template) -@@ -512,6 +535,7 @@ ovn_northd_lb_create(const struct nbrec_load_balancer *nbrec_lb) - lb->n_vips = smap_count(&nbrec_lb->vips); - lb->vips = xcalloc(lb->n_vips, sizeof *lb->vips); - lb->vips_nb = xcalloc(lb->n_vips, sizeof *lb->vips_nb); -+ smap_init(&lb->template_vips); - lb->controller_event = smap_get_bool(&nbrec_lb->options, "event", false); - - bool routable = smap_get_bool(&nbrec_lb->options, "add_route", false); -@@ -560,6 +584,12 @@ ovn_northd_lb_create(const struct nbrec_load_balancer *nbrec_lb) - } else { - sset_add(&lb->ips_v6, lb_vip->vip_str); - } -+ -+ if (lb->template && address_family == AF_INET6) { -+ smap_add_nocopy(&lb->template_vips, -+ ovn_lb_vip6_template_format_internal(lb_vip), -+ xstrdup(node->value)); -+ } - n_vips++; - } - -@@ -604,6 +634,15 @@ ovn_northd_lb_find(const struct hmap *lbs, const struct uuid *uuid) - return NULL; - } - -+const struct smap * -+ovn_northd_lb_get_vips(const struct ovn_northd_lb *lb) -+{ -+ if (!smap_is_empty(&lb->template_vips)) { -+ return &lb->template_vips; -+ } -+ return &lb->nlb->vips; -+} -+ - void - ovn_northd_lb_add_lr(struct ovn_northd_lb *lb, size_t n, - struct ovn_datapath **ods) -@@ -637,6 +676,7 @@ ovn_northd_lb_destroy(struct ovn_northd_lb *lb) - } - free(lb->vips); - free(lb->vips_nb); -+ smap_destroy(&lb->template_vips); - sset_destroy(&lb->ips_v4); - sset_destroy(&lb->ips_v6); - free(lb->selection_fields); -diff --git a/lib/lb.h b/lib/lb.h -index 55a41ae0b..55becc1bf 100644 ---- a/lib/lb.h -+++ b/lib/lb.h -@@ -19,6 +19,7 @@ - - #include - #include -+#include "lib/smap.h" - #include "openvswitch/hmap.h" - #include "ovn-util.h" - #include "sset.h" -@@ -62,6 +63,9 @@ struct ovn_northd_lb { - char *selection_fields; - struct ovn_lb_vip *vips; - struct ovn_northd_lb_vip *vips_nb; -+ struct smap template_vips; /* Slightly changed template VIPs, populated -+ * if needed. Until now it's only required -+ * for IPv6 template load balancers. */ - size_t n_vips; - - enum lb_neighbor_responder_mode neigh_mode; -@@ -130,6 +134,7 @@ struct ovn_northd_lb_backend { - struct ovn_northd_lb *ovn_northd_lb_create(const struct nbrec_load_balancer *); - struct ovn_northd_lb *ovn_northd_lb_find(const struct hmap *, - const struct uuid *); -+const struct smap *ovn_northd_lb_get_vips(const struct ovn_northd_lb *); - void ovn_northd_lb_destroy(struct ovn_northd_lb *); - void ovn_northd_lb_add_lr(struct ovn_northd_lb *lb, size_t n, - struct ovn_datapath **ods); -diff --git a/lib/lex.c b/lib/lex.c -index 5251868b5..a8b9812bb 100644 ---- a/lib/lex.c -+++ b/lib/lex.c -@@ -782,7 +782,7 @@ next: - p = lex_parse_port_group(p, token); - break; - -- case '^': -+ case LEX_TEMPLATE_PREFIX: - p = lex_parse_template(p, token); - break; - -@@ -1061,7 +1061,7 @@ lexer_parse_template_string(const char *s, const struct smap *template_vars, - struct sset *template_vars_ref) - { - /* No '^' means no templates. */ -- if (!strchr(s, '^')) { -+ if (!strchr(s, LEX_TEMPLATE_PREFIX)) { - return lex_str_use(s); - } - -diff --git a/lib/ovn-util.c b/lib/ovn-util.c -index 86b98acf7..69ab56423 100644 ---- a/lib/ovn-util.c -+++ b/lib/ovn-util.c -@@ -825,24 +825,6 @@ 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 809ff1d36..48dc846ad 100644 ---- a/lib/ovn-util.h -+++ b/lib/ovn-util.h -@@ -70,6 +70,23 @@ struct lport_addresses { - struct ipv6_netaddr *ipv6_addrs; - }; - -+static inline bool -+ipv6_is_all_router(const struct in6_addr *addr) -+{ -+ return ipv6_addr_equals(addr, &in6addr_all_routers); -+} -+ -+static const struct in6_addr in6addr_all_site_routers = {{{ -+ 0xff,0x05,0x00,0x00,0x00,0x00,0x00,0x00, -+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02 -+}}}; -+ -+static inline bool -+ipv6_is_all_site_router(const struct in6_addr *addr) -+{ -+ return ipv6_addr_equals(addr, &in6addr_all_site_routers); -+} -+ - bool is_dynamic_lsp_address(const char *address); - bool extract_addresses(const char *address, struct lport_addresses *, - int *ofs); -@@ -248,11 +265,6 @@ 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 - * and OVS does not. -diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c -index 363e384bd..a7b735333 100644 ---- a/northd/inc-proc-northd.c -+++ b/northd/inc-proc-northd.c -@@ -34,10 +34,13 @@ - #include "en-lflow.h" - #include "en-northd-output.h" - #include "en-sync-sb.h" -+#include "unixctl.h" - #include "util.h" - - VLOG_DEFINE_THIS_MODULE(inc_proc_northd); - -+static unixctl_cb_func chassis_features_list; -+ - #define NB_NODES \ - NB_NODE(nb_global, "nb_global") \ - NB_NODE(copp, "copp") \ -@@ -306,6 +309,12 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, - engine_ovsdb_node_add_index(&en_sb_address_set, - "sbrec_address_set_by_name", - sbrec_address_set_by_name); -+ -+ struct northd_data *northd_data = -+ engine_get_internal_data(&en_northd); -+ unixctl_command_register("debug/chassis-features-list", "", 0, 0, -+ chassis_features_list, -+ &northd_data->features); - } - - void inc_proc_northd_run(struct ovsdb_idl_txn *ovnnb_txn, -@@ -354,3 +363,20 @@ void inc_proc_northd_cleanup(void) - engine_cleanup(); - engine_set_context(NULL); - } -+ -+static void -+chassis_features_list(struct unixctl_conn *conn, int argc OVS_UNUSED, -+ const char *argv[] OVS_UNUSED, void *features_) -+{ -+ struct chassis_features *features = features_; -+ struct ds ds = DS_EMPTY_INITIALIZER; -+ -+ ds_put_format(&ds, "ct_no_masked_label: %s\n", -+ features->ct_no_masked_label ? "true" : "false"); -+ ds_put_format(&ds, "ct_lb_related: %s\n", -+ features->ct_lb_related ? "true" : "false"); -+ ds_put_format(&ds, "mac_binding_timestamp: %s\n", -+ features->mac_binding_timestamp ? "true" : "false"); -+ unixctl_command_reply(conn, ds_cstr(&ds)); -+ ds_destroy(&ds); -+} -diff --git a/northd/northd.c b/northd/northd.c -index 841ae9cc5..9cedec909 100644 ---- a/northd/northd.c -+++ b/northd/northd.c -@@ -125,11 +125,11 @@ enum ovn_stage { - PIPELINE_STAGE(SWITCH, IN, LB_AFF_CHECK, 11, "ls_in_lb_aff_check") \ - PIPELINE_STAGE(SWITCH, IN, LB, 12, "ls_in_lb") \ - PIPELINE_STAGE(SWITCH, IN, LB_AFF_LEARN, 13, "ls_in_lb_aff_learn") \ -- PIPELINE_STAGE(SWITCH, IN, ACL_AFTER_LB, 14, "ls_in_acl_after_lb") \ -- PIPELINE_STAGE(SWITCH, IN, STATEFUL, 15, "ls_in_stateful") \ -- PIPELINE_STAGE(SWITCH, IN, PRE_HAIRPIN, 16, "ls_in_pre_hairpin") \ -- PIPELINE_STAGE(SWITCH, IN, NAT_HAIRPIN, 17, "ls_in_nat_hairpin") \ -- PIPELINE_STAGE(SWITCH, IN, HAIRPIN, 18, "ls_in_hairpin") \ -+ PIPELINE_STAGE(SWITCH, IN, PRE_HAIRPIN, 14, "ls_in_pre_hairpin") \ -+ PIPELINE_STAGE(SWITCH, IN, NAT_HAIRPIN, 15, "ls_in_nat_hairpin") \ -+ PIPELINE_STAGE(SWITCH, IN, HAIRPIN, 16, "ls_in_hairpin") \ -+ PIPELINE_STAGE(SWITCH, IN, ACL_AFTER_LB, 17, "ls_in_acl_after_lb") \ -+ PIPELINE_STAGE(SWITCH, IN, STATEFUL, 18, "ls_in_stateful") \ - PIPELINE_STAGE(SWITCH, IN, ARP_ND_RSP, 19, "ls_in_arp_rsp") \ - PIPELINE_STAGE(SWITCH, IN, DHCP_OPTIONS, 20, "ls_in_dhcp_options") \ - PIPELINE_STAGE(SWITCH, IN, DHCP_RESPONSE, 21, "ls_in_dhcp_response") \ -@@ -215,6 +215,7 @@ enum ovn_stage { - #define REGBIT_ACL_LABEL "reg0[13]" - #define REGBIT_FROM_RAMP "reg0[14]" - #define REGBIT_PORT_SEC_DROP "reg0[15]" -+#define REGBIT_ACL_HINT_ALLOW_REL "reg0[17]" - - #define REG_ORIG_DIP_IPV4 "reg1" - #define REG_ORIG_DIP_IPV6 "xxreg1" -@@ -430,6 +431,13 @@ build_chassis_features(const struct northd_input *input_data, - const struct sbrec_chassis *chassis; - - SBREC_CHASSIS_TABLE_FOR_EACH (chassis, input_data->sbrec_chassis) { -+ /* Only consider local AZ chassis. Remote ones don't install -+ * flows generated by the local northd. -+ */ -+ if (smap_get_bool(&chassis->other_config, "is-remote", false)) { -+ continue; -+ } -+ - bool ct_no_masked_label = - smap_get_bool(&chassis->other_config, - OVN_FEATURE_CT_NO_MASKED_LABEL, -@@ -446,6 +454,15 @@ build_chassis_features(const struct northd_input *input_data, - chassis_features->mac_binding_timestamp) { - chassis_features->mac_binding_timestamp = false; - } -+ -+ bool ct_lb_related = -+ smap_get_bool(&chassis->other_config, -+ OVN_FEATURE_CT_LB_RELATED, -+ false); -+ if (!ct_lb_related && -+ chassis_features->ct_lb_related) { -+ chassis_features->ct_lb_related = false; -+ } - } - } - -@@ -4410,7 +4427,7 @@ sync_lbs(struct northd_input *input_data, struct ovsdb_idl_txn *ovnsb_txn, - - /* Update columns. */ - sbrec_load_balancer_set_name(lb->slb, lb->nlb->name); -- sbrec_load_balancer_set_vips(lb->slb, &lb->nlb->vips); -+ sbrec_load_balancer_set_vips(lb->slb, ovn_northd_lb_get_vips(lb)); - sbrec_load_balancer_set_protocol(lb->slb, lb->nlb->protocol); - sbrec_load_balancer_set_datapath_group(lb->slb, dpg->dp_group); - sbrec_load_balancer_set_options(lb->slb, &options); -@@ -4849,7 +4866,7 @@ ovn_igmp_group_get_ports(const struct sbrec_igmp_group *sb_igmp_group, - struct ovn_port *port = - ovn_port_find(ovn_ports, sb_igmp_group->ports[i]->logical_port); - -- if (!port) { -+ if (!port || !port->nbsp) { - continue; - } - -@@ -6758,7 +6775,8 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, - ct_blocked_match); - ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3, - ds_cstr(&match), REGBIT_ACL_HINT_DROP" = 0; " -- REGBIT_ACL_HINT_BLOCK" = 0; next;"); -+ REGBIT_ACL_HINT_BLOCK" = 0; " -+ REGBIT_ACL_HINT_ALLOW_REL" = 1; next;"); - ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3, - ds_cstr(&match), "next;"); - -@@ -6774,14 +6792,21 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, - * a dynamically negotiated FTP data channel), but will allow - * related traffic such as an ICMP Port Unreachable through - * that's generated from a non-listening UDP port. */ -+ const char *ct_in_acl_action = -+ features->ct_lb_related -+ ? REGBIT_ACL_HINT_ALLOW_REL" = 1; ct_commit_nat;" -+ : REGBIT_ACL_HINT_ALLOW_REL" = 1; next;"; -+ const char *ct_out_acl_action = features->ct_lb_related -+ ? "ct_commit_nat;" -+ : "next;"; - ds_clear(&match); - 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), "ct_commit_nat;"); -+ ds_cstr(&match), ct_in_acl_action); - ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3, -- ds_cstr(&match), "ct_commit_nat;"); -+ ds_cstr(&match), ct_out_acl_action); - - /* Ingress and Egress ACL Table (Priority 65532). - * -@@ -6790,6 +6815,11 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, - "nd || nd_ra || nd_rs || mldv1 || mldv2", "next;"); - ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3, - "nd || nd_ra || nd_rs || mldv1 || mldv2", "next;"); -+ -+ /* Reply and related traffic matched by an "allow-related" ACL -+ * should be allowed in the ls_in_acl_after_lb stage too. */ -+ ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, UINT16_MAX - 3, -+ REGBIT_ACL_HINT_ALLOW_REL" == 1", "next;"); - } - - /* Ingress or Egress ACL Table (Various priorities). */ -@@ -7838,7 +7868,7 @@ build_lrouter_groups(struct hmap *ports, struct ovs_list *lr_list) - } - - /* -- * Ingress table 24: Flows that flood self originated ARP/RARP/ND packets in -+ * Ingress table 25: Flows that flood self originated ARP/RARP/ND packets in - * the switching domain. - */ - static void -@@ -7952,7 +7982,7 @@ lrouter_port_ipv6_reachable(const struct ovn_port *op, - } - - /* -- * Ingress table 24: Flows that forward ARP/ND requests only to the routers -+ * Ingress table 25: Flows that forward ARP/ND requests only to the routers - * that own the addresses. Other ARP/ND packets are still flooded in the - * switching domain as regular broadcast. - */ -@@ -7989,7 +8019,7 @@ build_lswitch_rport_arp_req_flow(const char *ips, - } - - /* -- * Ingress table 24: Flows that forward ARP/ND requests only to the routers -+ * Ingress table 25: Flows that forward ARP/ND requests only to the routers - * that own the addresses. - * Priorities: - * - 80: self originated GARPs that need to follow regular processing. -@@ -8318,7 +8348,8 @@ build_lswitch_flows(const struct hmap *datapaths, - - struct ovn_datapath *od; - -- /* Ingress table 25: Destination lookup for unknown MACs (priority 0). */ -+ /* Ingress table 25/26: Destination lookup for unknown MACs -+ * (priority 0). */ - HMAP_FOR_EACH (od, key_node, datapaths) { - if (!od->nbs) { - continue; -@@ -8393,7 +8424,7 @@ build_lswitch_lflows_admission_control(struct ovn_datapath *od, - } - } - --/* Ingress table 18: ARP/ND responder, skip requests coming from localnet -+/* Ingress table 19: ARP/ND responder, skip requests coming from localnet - * ports. (priority 100); see ovn-northd.8.xml for the rationale. */ - - static void -@@ -8411,7 +8442,7 @@ build_lswitch_arp_nd_responder_skip_local(struct ovn_port *op, - } - } - --/* Ingress table 18: ARP/ND responder, reply for known IPs. -+/* Ingress table 19: ARP/ND responder, reply for known IPs. - * (priority 50). */ - static void - build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op, -@@ -8671,7 +8702,7 @@ build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op, - } - } - --/* Ingress table 18: ARP/ND responder, by default goto next. -+/* Ingress table 19: ARP/ND responder, by default goto next. - * (priority 0)*/ - static void - build_lswitch_arp_nd_responder_default(struct ovn_datapath *od, -@@ -8682,7 +8713,7 @@ build_lswitch_arp_nd_responder_default(struct ovn_datapath *od, - } - } - --/* Ingress table 18: ARP/ND responder for service monitor source ip. -+/* Ingress table 19: ARP/ND responder for service monitor source ip. - * (priority 110)*/ - static void - build_lswitch_arp_nd_service_monitor(struct ovn_northd_lb *lb, -@@ -8730,7 +8761,7 @@ build_lswitch_arp_nd_service_monitor(struct ovn_northd_lb *lb, - } - - --/* Logical switch ingress table 19 and 20: DHCP options and response -+/* Logical switch ingress table 20 and 21: DHCP options and response - * priority 100 flows. */ - static void - build_lswitch_dhcp_options_and_response(struct ovn_port *op, -@@ -8782,11 +8813,11 @@ build_lswitch_dhcp_options_and_response(struct ovn_port *op, - } - } - --/* Ingress table 19 and 20: DHCP options and response, by default goto -+/* Ingress table 20 and 21: DHCP options and response, by default goto - * next. (priority 0). -- * Ingress table 21 and 22: DNS lookup and response, by default goto next. -+ * Ingress table 22 and 23: DNS lookup and response, by default goto next. - * (priority 0). -- * Ingress table 23 - External port handling, by default goto next. -+ * Ingress table 24 - External port handling, by default goto next. - * (priority 0). */ - static void - build_lswitch_dhcp_and_dns_defaults(struct ovn_datapath *od, -@@ -8801,7 +8832,7 @@ build_lswitch_dhcp_and_dns_defaults(struct ovn_datapath *od, - } - } - --/* Logical switch ingress table 21 and 22: DNS lookup and response -+/* Logical switch ingress table 22 and 23: DNS lookup and response - * priority 100 flows. - */ - static void -@@ -8829,7 +8860,7 @@ build_lswitch_dns_lookup_and_response(struct ovn_datapath *od, - } - } - --/* Table 23: External port. Drop ARP request for router ips from -+/* Table 24: External port. Drop ARP request for router ips from - * external ports on chassis not binding those ports. - * This makes the router pipeline to be run only on the chassis - * binding the external ports. */ -@@ -8846,7 +8877,7 @@ build_lswitch_external_port(struct ovn_port *op, - } - } - --/* Ingress table 24: Destination lookup, broadcast and multicast handling -+/* Ingress table 25: Destination lookup, broadcast and multicast handling - * (priority 70 - 100). */ - static void - build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od, -@@ -8931,7 +8962,7 @@ build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od, - } - - --/* Ingress table 24: Add IP multicast flows learnt from IGMP/MLD -+/* Ingress table 25: Add IP multicast flows learnt from IGMP/MLD - * (priority 90). */ - static void - build_lswitch_ip_mcast_igmp_mld(struct ovn_igmp_group *igmp_group, -@@ -8973,9 +9004,11 @@ build_lswitch_ip_mcast_igmp_mld(struct ovn_igmp_group *igmp_group, - igmp_group->mcgroup.name); - } else { - /* RFC 4291, section 2.7.1: Skip groups that correspond to all -- * hosts. -+ * hosts, all link-local routers and all site routers. - */ -- if (ipv6_is_all_hosts(&igmp_group->address)) { -+ if (ipv6_is_all_hosts(&igmp_group->address) || -+ ipv6_is_all_router(&igmp_group->address) || -+ ipv6_is_all_site_router(&igmp_group->address)) { - return; - } - if (atomic_compare_exchange_strong( -@@ -9013,7 +9046,7 @@ build_lswitch_ip_mcast_igmp_mld(struct ovn_igmp_group *igmp_group, - - static struct ovs_mutex mcgroup_mutex = OVS_MUTEX_INITIALIZER; - --/* Ingress table 24: Destination lookup, unicast handling (priority 50), */ -+/* Ingress table 25: Destination lookup, unicast handling (priority 50), */ - static void - build_lswitch_ip_unicast_lookup(struct ovn_port *op, - struct hmap *lflows, -@@ -10471,9 +10504,11 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, - struct hmap *lflows, - struct ds *match, struct ds *action, - const struct shash *meter_groups, -- bool ct_lb_mark) -+ const struct chassis_features *features) - { -- const char *ct_natted = ct_lb_mark ? "ct_mark.natted" : "ct_label.natted"; -+ const char *ct_natted = features->ct_no_masked_label -+ ? "ct_mark.natted" -+ : "ct_label.natted"; - char *skip_snat_new_action = NULL; - char *skip_snat_est_action = NULL; - char *new_match; -@@ -10484,7 +10519,7 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, - - bool reject = build_lb_vip_actions(lb_vip, vips_nb, action, - lb->selection_fields, false, -- ct_lb_mark); -+ features->ct_no_masked_label); - bool drop = !!strncmp(ds_cstr(action), "ct_lb", strlen("ct_lb")); - if (!drop) { - /* Remove the trailing ");". */ -@@ -10506,9 +10541,11 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, - } - - if (lb->skip_snat) { -- skip_snat_new_action = xasprintf("flags.skip_snat_for_lb = 1; %s%s", -- ds_cstr(action), -- drop ? "" : "; skip_snat);"); -+ const char *skip_snat = features->ct_lb_related && !drop -+ ? "; skip_snat" -+ : ""; -+ skip_snat_new_action = xasprintf("flags.skip_snat_for_lb = 1; %s%s);", -+ ds_cstr(action), skip_snat); - skip_snat_est_action = xasprintf("flags.skip_snat_for_lb = 1; " - "next;"); - } -@@ -10641,9 +10678,11 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, - skip_snat_new_action, est_match, - skip_snat_est_action, lflows, prio, meter_groups); - -- char *new_actions = xasprintf("flags.force_snat_for_lb = 1; %s%s", -- ds_cstr(action), -- drop ? "" : "; force_snat);"); -+ const char *force_snat = features->ct_lb_related && !drop -+ ? "; force_snat" -+ : ""; -+ char *new_actions = xasprintf("flags.force_snat_for_lb = 1; %s%s);", -+ ds_cstr(action), force_snat); - build_gw_lrouter_nat_flows_for_lb(lb, gw_router_force_snat, - n_gw_router_force_snat, reject, new_match, - new_actions, est_match, -@@ -10898,7 +10937,7 @@ build_lrouter_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows, - - build_lrouter_nat_flows_for_lb(lb_vip, lb, &lb->vips_nb[i], - lflows, match, action, meter_groups, -- features->ct_no_masked_label); -+ features); - - if (!build_empty_lb_event_flow(lb_vip, lb, match, action)) { - continue; -@@ -14208,7 +14247,7 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, - const struct hmap *ports, struct ds *match, - struct ds *actions, - const struct shash *meter_groups, -- bool ct_lb_mark) -+ const struct chassis_features *features) - { - if (!od->nbr) { - return; -@@ -14239,9 +14278,11 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, - * a dynamically negotiated FTP data channel), but will allow - * related traffic such as an ICMP Port Unreachable through - * that's generated from a non-listening UDP port. */ -- if (od->has_lb_vip) { -+ if (od->has_lb_vip && features->ct_lb_related) { - ds_clear(match); -- const char *ct_flag_reg = ct_lb_mark ? "ct_mark" : "ct_label"; -+ const char *ct_flag_reg = features->ct_no_masked_label -+ ? "ct_mark" -+ : "ct_label"; - - ds_put_cstr(match, "ct.rel && !ct.est && !ct.new"); - size_t match_len = match->length; -@@ -14328,6 +14369,23 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, - sset_add(&nat_entries, nat->external_ip); - } else { - if (!sset_contains(&nat_entries, nat->external_ip)) { -+ /* Drop packets coming in from external that still has -+ * destination IP equals to the NAT external IP, to avoid loop. -+ * The packets must have gone through DNAT/unSNAT stage but -+ * failed to convert the destination. */ -+ ds_clear(match); -+ ds_put_format( -+ match, "inport == %s && outport == %s && ip%s.dst == %s", -+ l3dgw_port->json_key, l3dgw_port->json_key, -+ is_v6 ? "6" : "4", nat->external_ip); -+ ovn_lflow_add_with_hint(lflows, od, -+ S_ROUTER_IN_ARP_RESOLVE, -+ 150, ds_cstr(match), -+ debug_drop_action(), -+ &nat->header_); -+ /* Now for packets coming from other (downlink) LRPs, allow ARP -+ * resolve for the NAT IP, so that such packets can be -+ * forwarded for E/W NAT. */ - ds_clear(match); - ds_put_format( - match, "outport == %s && %s == %s", -@@ -14464,7 +14522,7 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, - - if (od->nbr->n_nat) { - ds_clear(match); -- const char *ct_natted = ct_lb_mark ? -+ const char *ct_natted = features->ct_no_masked_label ? - "ct_mark.natted" : - "ct_label.natted"; - ds_put_format(match, "ip && %s == 1", ct_natted); -@@ -14581,7 +14639,7 @@ build_lswitch_and_lrouter_iterate_by_od(struct ovn_datapath *od, - build_lrouter_arp_nd_for_datapath(od, lsi->lflows, lsi->meter_groups); - build_lrouter_nat_defrag_and_lb(od, lsi->lflows, lsi->ports, &lsi->match, - &lsi->actions, lsi->meter_groups, -- lsi->features->ct_no_masked_label); -+ lsi->features); - build_lb_affinity_default_flows(od, lsi->lflows); - } - -@@ -16073,6 +16131,7 @@ northd_init(struct northd_data *data) - data->features = (struct chassis_features) { - .ct_no_masked_label = true, - .mac_binding_timestamp = true, -+ .ct_lb_related = true, - }; - data->ovn_internal_version_changed = false; - } -diff --git a/northd/northd.h b/northd/northd.h -index ff8727cb7..4d9055296 100644 ---- a/northd/northd.h -+++ b/northd/northd.h -@@ -71,6 +71,7 @@ struct northd_input { - struct chassis_features { - bool ct_no_masked_label; - bool mac_binding_timestamp; -+ bool ct_lb_related; - }; - - struct northd_data { -diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml -index 058cbf71a..4de015e40 100644 ---- a/northd/ovn-northd.8.xml -+++ b/northd/ovn-northd.8.xml -@@ -790,8 +790,9 @@ - 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]. If ACL logging and logging of related packets -- is enabled, then a companion priority-65533 flow will be installed that -+ reg0[10] and sets register bit reg0[17]. -+ If ACL logging and logging of related packets is enabled, then a -+ companion priority-65533 flow will be installed that - accomplishes the same thing but also logs the traffic. - - -@@ -1028,92 +1029,7 @@ - - - --

Ingress table 14: from-lport ACLs after LB

-- --

-- Logical flows in this table closely reproduce those in the -- ACL table in the OVN_Northbound database -- for the from-lport direction with the option -- apply-after-lb set to true. -- The priority values from the ACL table have a -- 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 -- with the next; action. If there are any stateful ACLs -- (including both before-lb and after-lb ACLs) -- on this datapath, then allow ACLs translate to -- ct_commit; next; (which acts as a hint for the next tables -- to commit the connection to conntrack). In case the ACL -- has a label then reg3 is loaded with the label value and -- reg0[13] bit is set to 1 (which acts as a hint for the -- next tables to commit the label to conntrack). --
  • --
  • -- allow-related apply-after-lb ACLs translate into logical -- flows with the ct_commit(ct_label=0/1); next; actions -- for new connections and reg0[1] = 1; next; for existing -- connections. In case the ACL has a label then -- reg3 is loaded with the label value and -- reg0[13] bit is set to 1 (which acts as a hint for the -- next tables to commit the label to conntrack). --
  • --
  • -- allow-stateless apply-after-lb ACLs translate into logical -- flows with the next; action. --
  • --
  • -- reject apply-after-lb ACLs translate into logical -- flows with the -- tcp_reset { output <-> inport; -- next(pipeline=egress,table=5);} -- action for TCP connections,icmp4/icmp6 action -- for UDP connections, and sctp_abort {output <-%gt; inport; -- next(pipeline=egress,table=5);} action for SCTP associations. --
  • --
  • -- Other apply-after-lb ACLs translate to drop; for new -- or untracked connections and ct_commit(ct_label=1/1); for -- known connections. Setting ct_label marks a connection -- as one that was previously allowed, but should no longer be -- allowed due to a policy change. --
  • --
-- --
    --
  • -- One priority-0 fallback flow that matches all packets and advances to -- the next table. --
  • --
-- --

Ingress Table 15: Stateful

-- --
    --
  • -- A priority 100 flow is added which commits the packet to the conntrack -- and sets the most significant 32-bits of ct_label with the -- reg3 value based on the hint provided by previous tables -- (with a match for reg0[1] == 1 && reg0[13] == 1). -- This is used by the ACLs with label to commit the label -- value to conntrack. --
  • -- --
  • -- For ACLs without label, a second priority-100 flow commits -- packets to connection tracker using ct_commit; next; -- action based on a hint provided by the previous tables (with a match -- for reg0[1] == 1 && reg0[13] == 0). --
  • --
  • -- A priority-0 flow that simply moves traffic to the next table. --
  • --
-- --

Ingress Table 16: Pre-Hairpin

-+

Ingress Table 14: Pre-Hairpin

-
    -
  • - If the logical switch has load balancer(s) configured, then a -@@ -1131,7 +1047,7 @@ -
  • -
- --

Ingress Table 17: Nat-Hairpin

-+

Ingress Table 15: Nat-Hairpin

-
    -
  • - If the logical switch has load balancer(s) configured, then a -@@ -1166,7 +1082,7 @@ -
  • -
- --

Ingress Table 18: Hairpin

-+

Ingress Table 16: Hairpin

-
    -
  • -

    -@@ -1200,6 +1116,100 @@ -

  • -
- -+

Ingress table 17: from-lport ACLs after LB

-+ -+

-+ Logical flows in this table closely reproduce those in the -+ ACL table in the OVN_Northbound database -+ for the from-lport direction with the option -+ apply-after-lb set to true. -+ The priority values from the ACL table have a -+ 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 -+ with the next; action. If there are any stateful ACLs -+ (including both before-lb and after-lb ACLs) -+ on this datapath, then allow ACLs translate to -+ ct_commit; next; (which acts as a hint for the next tables -+ to commit the connection to conntrack). In case the ACL -+ has a label then reg3 is loaded with the label value and -+ reg0[13] bit is set to 1 (which acts as a hint for the -+ next tables to commit the label to conntrack). -+
  • -+
  • -+ allow-related apply-after-lb ACLs translate into logical -+ flows with the ct_commit(ct_label=0/1); next; actions -+ for new connections and reg0[1] = 1; next; for existing -+ connections. In case the ACL has a label then -+ reg3 is loaded with the label value and -+ reg0[13] bit is set to 1 (which acts as a hint for the -+ next tables to commit the label to conntrack). -+
  • -+
  • -+ allow-stateless apply-after-lb ACLs translate into logical -+ flows with the next; action. -+
  • -+
  • -+ reject apply-after-lb ACLs translate into logical -+ flows with the -+ tcp_reset { output <-> inport; -+ next(pipeline=egress,table=5);} -+ action for TCP connections,icmp4/icmp6 action -+ for UDP connections, and sctp_abort {output <-%gt; inport; -+ next(pipeline=egress,table=5);} action for SCTP associations. -+
  • -+
  • -+ Other apply-after-lb ACLs translate to drop; for new -+ or untracked connections and ct_commit(ct_label=1/1); for -+ known connections. Setting ct_label marks a connection -+ as one that was previously allowed, but should no longer be -+ allowed due to a policy change. -+
  • -+
-+ -+
    -+
  • -+ One priority-65532 flow matching packets with reg0[17] -+ set (either replies to existing sessions or traffic related to -+ existing sessions) and allows these by advancing to the next -+ table. -+
  • -+
-+ -+
    -+
  • -+ One priority-0 fallback flow that matches all packets and advances to -+ the next table. -+
  • -+
-+ -+

Ingress Table 18: Stateful

-+ -+
    -+
  • -+ A priority 100 flow is added which commits the packet to the conntrack -+ and sets the most significant 32-bits of ct_label with the -+ reg3 value based on the hint provided by previous tables -+ (with a match for reg0[1] == 1 && reg0[13] == 1). -+ This is used by the ACLs with label to commit the label -+ value to conntrack. -+
  • -+ -+
  • -+ For ACLs without label, a second priority-100 flow commits -+ packets to connection tracker using ct_commit; next; -+ action based on a hint provided by the previous tables (with a match -+ for reg0[1] == 1 && reg0[13] == 0). -+
  • -+
  • -+ A priority-0 flow that simply moves traffic to the next table. -+
  • -+
-+ -

Ingress Table 19: ARP/ND responder

- -

-@@ -4257,13 +4267,17 @@ outport = P - For each row in the NAT table with IPv4 address - A in the column of -- table, a priority-100 -- flow with the match outport === P && -- reg0 == A has actions eth.dst = E; -- next;, where P is the distributed logical router -- port, E is the Ethernet address if set in the -- column -- of table for of type -+ table, below two flows are -+ programmed: -+

-+ -+

-+ A priority-100 flow with the match outport == P -+ && reg0 == A has actions eth.dst = -+ E; next;, where P is the distributed -+ logical router port, E is the Ethernet address if set in -+ the -+ column of table for of type - dnat_and_snat, otherwise the Ethernet address of the - distributed logical router port. Note that if the - is not -@@ -4273,9 +4287,18 @@ outport = P - will be added. -

- -+

-+ Corresponding to the above flow, a priority-150 flow with the match -+ inport == P && outport == P -+ && ip4.dst == A has actions -+ drop; to exclude packets that have gone through -+ DNAT/unSNAT stage but failed to convert the destination, to avoid -+ loop. -+

-+ -

- For IPv6 NAT entries, same flows are added, but using the register -- xxreg0 for the match. -+ xxreg0 and field ip6 for the match. -

- - -diff --git a/ovn-architecture.7.xml b/ovn-architecture.7.xml -index b2e00d6e4..cb1064f71 100644 ---- a/ovn-architecture.7.xml -+++ b/ovn-architecture.7.xml -@@ -2832,8 +2832,7 @@ - The maximum number of networks is reduced to 4096. - -
  • -- The maximum number of ports per network is reduced to 4096. (Including -- multicast group ports.) -+ The maximum number of ports per network is reduced to 2048. -
  • -
  • - ACLs matching against logical ingress port identifiers are not supported. -diff --git a/tests/atlocal.in b/tests/atlocal.in -index 0b9a31276..02e9ce9bb 100644 ---- a/tests/atlocal.in -+++ b/tests/atlocal.in -@@ -166,6 +166,9 @@ fi - # Set HAVE_TCPDUMP - find_command tcpdump - -+# Set HAVE_XXD -+find_command xxd -+ - # Set HAVE_LFTP - find_command lftp - -diff --git a/tests/network-functions.at b/tests/network-functions.at -index c583bc31e..a2481c55c 100644 ---- a/tests/network-functions.at -+++ b/tests/network-functions.at -@@ -128,12 +128,18 @@ OVS_START_SHELL_HELPERS - # hex_to_binary HEXDIGITS - # - # Converts the pairs of HEXDIGITS into bytes and prints them on stdout. --hex_to_binary() { -- printf $(while test -n "$1"; do -- printf '\\%03o' 0x$(expr "$1" : '\(..\)') -- set -- "${1##??}" -- done) --} -+if test x$HAVE_XXD = xno; then -+ hex_to_binary() { -+ printf $(while test -n "$1"; do -+ printf '\\%03o' 0x$(expr "$1" : '\(..\)') -+ set -- "${1##??}" -+ done) -+ } -+else -+ hex_to_binary() { -+ echo $1 | xxd -r -p -+ } -+fi - - # tcpdump_hex TITLE PACKET - # -diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at -index 6bc9ba75d..e2f4fc85c 100644 ---- a/tests/ovn-controller.at -+++ b/tests/ovn-controller.at -@@ -2499,3 +2499,30 @@ AT_CHECK([GET_LOCAL_TEMPLATE_VARS], [1], []) - - AT_CLEANUP - ]) -+ -+OVN_FOR_EACH_NORTHD([ -+AT_SETUP([ovn-controller - Requested SNAT Zone in router creation transaction]) -+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 -+ -+dnl This is key. Add the snat-ct-zone when creating the logical router and then -+dnl do not make any further changes to the logical router settings. -+check ovn-nbctl lr-add lr0 -- set Logical_Router lr0 options:snat-ct-zone=666 -+check ovn-nbctl lrp-add lr0 lrp-gw 01:00:00:00:00:01 172.16.0.1 -+check ovn-nbctl lrp-set-gateway-chassis lrp-gw hv1 -+ -+check ovn-nbctl --wait=hv sync -+ -+lr_uuid=$(fetch_column Datapath_Binding _uuid external_ids:name=lr0) -+ct_zones=$(ovn-appctl -t ovn-controller ct-zone-list) -+zone_num=$(printf "$ct_zones" | grep ${lr_uuid}_snat | cut -d ' ' -f 2) -+ -+check test "$zone_num" -eq 666 -+ -+AT_CLEANUP -+]) -diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at -index c25d1122c..072102f36 100644 ---- a/tests/ovn-northd.at -+++ b/tests/ovn-northd.at -@@ -2232,9 +2232,9 @@ check ovn-nbctl acl-add sw0 to-lport 1002 'outport == "sw0-p1" && ip4.src == 10. - check ovn-nbctl acl-add sw0 to-lport 1002 'outport == "sw0-p1" && ip4.src == 10.0.0.13' allow - check ovn-nbctl acl-add pg0 to-lport 1002 'outport == "pg0" && ip4.src == 10.0.0.11' drop - --acl1=$(ovn-nbctl --bare --column _uuid,match find acl | grep -B1 '10.0.0.12' | head -1) --acl2=$(ovn-nbctl --bare --column _uuid,match find acl | grep -B1 '10.0.0.13' | head -1) --acl3=$(ovn-nbctl --bare --column _uuid,match find acl | grep -B1 '10.0.0.11' | head -1) -+acl1=$(ovn-nbctl --bare --column _uuid,match find acl | grep -F -B1 '10.0.0.12' | head -1) -+acl2=$(ovn-nbctl --bare --column _uuid,match find acl | grep -F -B1 '10.0.0.13' | head -1) -+acl3=$(ovn-nbctl --bare --column _uuid,match find acl | grep -F -B1 '10.0.0.11' | head -1) - check ovn-nbctl set acl $acl1 log=true severity=alert meter=meter_me name=acl_one - check ovn-nbctl set acl $acl2 log=true severity=info meter=meter_me name=acl_two - check ovn-nbctl set acl $acl3 log=true severity=info meter=meter_me name=acl_three -@@ -2472,8 +2472,8 @@ AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e - table=7 (ls_in_acl_hint ), priority=7 , match=(ct.new && !ct.est), action=(reg0[[7]] = 1; reg0[[9]] = 1; next;) - table=8 (ls_in_acl ), priority=1 , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;) - table=8 (ls_in_acl ), priority=1 , match=(ip && ct.est && ct_mark.blocked == 1), action=(reg0[[1]] = 1; next;) -- table=8 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(ct_commit_nat;) -- table=8 (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=8 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;) -+ table=8 (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; reg0[[17]] = 1; next;) - table=8 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) - ]) - -@@ -2485,7 +2485,8 @@ 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=14(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) -+ table=17(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) -+ table=17(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;) - table=3 (ls_out_acl_hint ), priority=0 , match=(1), action=(next;) - table=3 (ls_out_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) - table=3 (ls_out_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;) -@@ -2518,8 +2519,8 @@ AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e - table=8 (ls_in_acl ), priority=1001 , match=(reg0[[7]] == 1 && (ip)), action=(reg0[[1]] = 1; next;) - table=8 (ls_in_acl ), priority=1001 , match=(reg0[[8]] == 1 && (ip)), action=(next;) - table=8 (ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) -- table=8 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(ct_commit_nat;) -- table=8 (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=8 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;) -+ table=8 (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; reg0[[17]] = 1; next;) - table=8 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) - table=8 (ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) - ]) -@@ -2528,7 +2529,7 @@ ovn-nbctl --wait=sb clear logical_switch ls acls - ovn-nbctl --wait=sb clear logical_switch ls load_balancer - - AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e ls_in_acl -e ls_out_acl | sort], [0], [dnl -- table=14(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) -+ table=17(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) - table=3 (ls_out_acl_hint ), priority=65535, match=(1), action=(next;) - table=4 (ls_out_acl ), priority=65535, match=(1), action=(next;) - table=7 (ls_in_acl_hint ), priority=65535, match=(1), action=(next;) -@@ -4360,8 +4361,8 @@ ovn-sbctl dump-flows sw0 > sw0flows - AT_CAPTURE_FILE([sw0flows]) - - AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl -- table=? (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(ct_commit_nat;) -- 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.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;) -+ 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; reg0[[17]] = 1; 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;) - ]) -@@ -4380,9 +4381,9 @@ ovn-sbctl dump-flows sw0 > sw0flows - AT_CAPTURE_FILE([sw0flows]) - - AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl -- table=? (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && ct_mark.blocked == 0), action=(ct_commit_nat;) -+ table=? (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;) - table=? (ls_in_acl ), priority=65532, match=((ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) -- table=? (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=? (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; reg0[[17]] = 1; next;) - table=? (ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) - ]) - -@@ -4404,8 +4405,8 @@ ovn-sbctl dump-flows sw0 > sw0flows - AT_CAPTURE_FILE([sw0flows]) - - AT_CHECK([grep -w "ls_in_acl" sw0flows | grep 6553 | sort | sed 's/table=./table=?/'], [0], [dnl -- table=? (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(ct_commit_nat;) -- 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.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;) -+ 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; reg0[[17]] = 1; 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;) - ]) -@@ -5139,7 +5140,8 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [ - ]) - - check ovn-sbctl chassis-add gw1 geneve 127.0.0.1 \ -- -- set chassis gw1 other_config:ct-no-masked-label="true" -+ -- set chassis gw1 other_config:ct-no-masked-label="true" \ -+ -- set chassis gw1 other_config:ovn-ct-lb-related="true" - - # Create a distributed gw port on lr0 - check ovn-nbctl ls-add public -@@ -6685,11 +6687,12 @@ AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], - 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_mark.blocked == 0), action=(ct_commit_nat;) -- 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.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;) -+ 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; reg0[[17]] = 1; 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=65532, match=(reg0[[17]] == 1), action=(next;) - table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) - table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) - table=??(ls_in_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;) -@@ -6730,8 +6733,8 @@ AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], - table=??(ls_in_acl ), priority=1 , match=(ip && !ct.est), action=(reg0[[1]] = 1; next;) - table=??(ls_in_acl ), priority=1 , match=(ip && 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_mark.blocked == 0), action=(ct_commit_nat;) -- 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.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;) -+ 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; reg0[[17]] = 1; 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;) -@@ -6743,6 +6746,7 @@ AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], - table=??(ls_in_acl_after_lb ), priority=2003 , match=(reg0[[8]] == 1 && (ip4 && icmp)), action=(next;) - table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */) - table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(/* drop */) -+ table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;) - table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) - table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) - table=??(ls_in_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;) -@@ -6787,8 +6791,8 @@ AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], - 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_mark.blocked == 0), action=(ct_commit_nat;) -- 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.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;) -+ 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; reg0[[17]] = 1; 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;) -@@ -6796,6 +6800,7 @@ AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], - table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[9]] == 1 && (ip4)), action=(/* drop */) - table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */) - table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(/* drop */) -+ table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;) - table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) - table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) - table=??(ls_in_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;) -@@ -7219,11 +7224,12 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/ - table=??(ls_in_acl ), priority=1001 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg0[[1]] = 1; next;) - table=??(ls_in_acl ), priority=1001 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(next;) - table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) -- table=??(ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(ct_commit_nat;) -- 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.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;) -+ 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; reg0[[17]] = 1; 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=(drop;) -+ table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;) - table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) - table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) - table=??(ls_in_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;) -@@ -7342,13 +7348,14 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/ - table=??(ls_in_acl ), priority=1 , match=(ip && !ct.est), action=(drop;) - table=??(ls_in_acl ), priority=1 , match=(ip && 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_mark.blocked == 0), action=(ct_commit_nat;) -- 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.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;) -+ 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; reg0[[17]] = 1; 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=(drop;) - table=??(ls_in_acl_after_lb ), priority=1001 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg0[[1]] = 1; next;) - table=??(ls_in_acl_after_lb ), priority=1001 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(next;) -+ table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;) - table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) - table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) - table=??(ls_in_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;) -@@ -7467,11 +7474,12 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/ - table=??(ls_in_acl ), priority=1 , match=(ip && !ct.est), action=(drop;) - table=??(ls_in_acl ), priority=1 , match=(ip && 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_mark.blocked == 0), action=(ct_commit_nat;) -- 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.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;) -+ 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; reg0[[17]] = 1; 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=(drop;) -+ table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;) - table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) - table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) - table=??(ls_in_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;) -@@ -7775,7 +7783,7 @@ sort | sed 's/table=../table=??/' ], [0], [dnl - table=??(ls_in_check_port_sec), priority=100 , match=(vlan.present), action=(drop;) - table=??(ls_in_check_port_sec), priority=50 , match=(1), action=(reg0[[15]] = check_in_port_sec(); next;) - table=??(ls_in_check_port_sec), priority=70 , match=(inport == "localnetport"), action=(set_queue(10); reg0[[15]] = check_in_port_sec(); next;) -- table=??(ls_in_check_port_sec), priority=70 , match=(inport == "sw0p1"), action=(reg0[[14]] = 1; next(pipeline=ingress, table=18);) -+ table=??(ls_in_check_port_sec), priority=70 , match=(inport == "sw0p1"), action=(reg0[[14]] = 1; next(pipeline=ingress, table=16);) - table=??(ls_in_check_port_sec), priority=70 , match=(inport == "sw0p2"), action=(set_queue(10); reg0[[15]] = check_in_port_sec(); next;) - table=??(ls_in_apply_port_sec), priority=0 , match=(1), action=(next;) - table=??(ls_in_apply_port_sec), priority=50 , match=(reg0[[15]] == 1), action=(drop;) -@@ -7832,6 +7840,22 @@ AT_CHECK([ovn-sbctl lflow-list | grep -e natted -e ct_lb], [0], [dnl - table=2 (ls_out_pre_stateful), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb;) - ]) - -+check ovn-nbctl --wait=sb set logical_router lr options:lb_force_snat_ip="42.42.42.1" -+AT_CHECK([ovn-sbctl lflow-list | grep lr_in_dnat], [0], [dnl -+ table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 66.66.66.66 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) -+ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 66.66.66.66), action=(flags.force_snat_for_lb = 1; ct_lb(backends=42.42.42.2);) -+ table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) -+]) -+check ovn-nbctl remove logical_router lr options lb_force_snat_ip -+ -+check ovn-nbctl --wait=sb set load_balancer lb-test options:skip_snat="true" -+AT_CHECK([ovn-sbctl lflow-list | grep lr_in_dnat], [0], [dnl -+ table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 66.66.66.66 && ct_label.natted == 1), action=(flags.skip_snat_for_lb = 1; next;) -+ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 66.66.66.66), action=(flags.skip_snat_for_lb = 1; ct_lb(backends=42.42.42.2);) -+ table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) -+]) -+check ovn-nbctl remove load_balancer lb-test options skip_snat -+ - 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 -@@ -7865,8 +7889,8 @@ AT_CHECK([ovn-sbctl lflow-list | grep 'ls.*acl.*blocked' ], [0], [dnl - table=7 (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=7 (ls_in_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;) - table=7 (ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) -- table=8 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(ct_commit_nat;) -- table=8 (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=8 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;) -+ table=8 (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; reg0[[17]] = 1; next;) - table=8 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) - table=8 (ls_in_acl ), priority=1 , match=(ip && 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;) -@@ -7887,15 +7911,15 @@ AT_CHECK([ovn-sbctl lflow-list | grep 'ls.*acl.*blocked' ], [0], [dnl - table=7 (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=7 (ls_in_acl_hint ), priority=2 , match=(ct.est && ct_label.blocked == 1), action=(reg0[[9]] = 1; next;) - table=7 (ls_in_acl_hint ), priority=1 , match=(ct.est && ct_label.blocked == 0), action=(reg0[[10]] = 1; next;) -- table=8 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(ct_commit_nat;) -- table=8 (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=8 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(reg0[[17]] = 1; next;) -+ table=8 (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; reg0[[17]] = 1; next;) - table=8 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) - table=8 (ls_in_acl ), priority=1 , match=(ip && 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=(ct_commit_nat;) -+ 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_label.blocked == 1), action=(reg0[[1]] = 1; next;) -@@ -7909,15 +7933,15 @@ AT_CHECK([ovn-sbctl lflow-list | grep 'ls.*acl.*blocked' ], [0], [dnl - table=7 (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=7 (ls_in_acl_hint ), priority=2 , match=(ct.est && ct_mark.blocked == 1), action=(reg0[[9]] = 1; next;) - table=7 (ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) -- table=8 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(ct_commit_nat;) -- table=8 (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=8 (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; next;) -+ table=8 (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; reg0[[17]] = 1; next;) - table=8 (ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) - table=8 (ls_in_acl ), priority=1 , match=(ip && 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=(ct_commit_nat;) -+ 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_mark.blocked == 1), action=(reg0[[1]] = 1; next;) -@@ -8437,3 +8461,156 @@ check_row_count sb:Chassis_Template_Var 0 - - AT_CLEANUP - ]) -+ -+OVN_FOR_EACH_NORTHD_NO_HV([ -+AT_SETUP([Load balancer CT related 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 192.168.0.1 192.168.1.10 \ -+ -- ls-lb-add ls lb-test \ -+ -- lr-lb-add lr lb-test -+ -+m4_define([DUMP_FLOWS_SORTED], [sed 's/table=[[0-9]]\{1,2\}/table=?/' | sort]) -+ -+AS_BOX([No chassis registered - CT related flows should be installed]) -+check ovn-nbctl --wait=sb sync -+ovn-sbctl dump-flows | DUMP_FLOWS_SORTED > lflows0 -+ -+AT_CHECK([grep -e "lr_in_defrag" -e "lr_in_dnat" lflows0], [0], [dnl -+ table=? (lr_in_defrag ), priority=0 , match=(1), action=(next;) -+ table=? (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 192.168.0.1), action=(reg0 = 192.168.0.1; ct_dnat;) -+ table=? (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;) -+ table=? (lr_in_dnat ), priority=0 , match=(1), action=(next;) -+ table=? (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 192.168.0.1 && ct_mark.natted == 1), action=(next;) -+ table=? (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 192.168.0.1), action=(ct_lb_mark(backends=192.168.1.10);) -+ table=? (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) -+ table=? (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) -+ table=? (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) -+]) -+ -+AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows0 | grep "priority=65532"], [0], [dnl -+ table=? (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;) -+ 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; reg0[[17]] = 1; 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_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(ct_commit_nat;) -+ table=? (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(next;) -+ table=? (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) -+ table=? (ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) -+ table=?(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;) -+]) -+ -+ -+AS_BOX([Chassis registered that doesn't support CT related]) -+check ovn-sbctl chassis-add hv geneve 127.0.0.1 -+check ovn-nbctl --wait=sb sync -+ovn-sbctl dump-flows | DUMP_FLOWS_SORTED > lflows1 -+ -+AT_CHECK([grep -e "lr_in_defrag" -e "lr_in_dnat" lflows1], [0], [dnl -+ table=? (lr_in_defrag ), priority=0 , match=(1), action=(next;) -+ table=? (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 192.168.0.1), action=(reg0 = 192.168.0.1; ct_dnat;) -+ table=? (lr_in_dnat ), priority=0 , match=(1), action=(next;) -+ table=? (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 192.168.0.1 && ct_label.natted == 1), action=(next;) -+ table=? (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 192.168.0.1), action=(ct_lb(backends=192.168.1.10);) -+]) -+ -+check ovn-nbctl --wait=sb set logical_router lr options:lb_force_snat_ip="192.168.1.1" -+AT_CHECK([ovn-sbctl lflow-list | grep lr_in_dnat], [0], [dnl -+ table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 192.168.0.1 && ct_label.natted == 1), action=(flags.force_snat_for_lb = 1; next;) -+ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 192.168.0.1), action=(flags.force_snat_for_lb = 1; ct_lb(backends=192.168.1.10);) -+ table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) -+]) -+check ovn-nbctl remove logical_router lr options lb_force_snat_ip -+ -+check ovn-nbctl --wait=sb set load_balancer lb-test options:skip_snat="true" -+AT_CHECK([ovn-sbctl lflow-list | grep lr_in_dnat], [0], [dnl -+ table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 192.168.0.1 && ct_label.natted == 1), action=(flags.skip_snat_for_lb = 1; next;) -+ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 192.168.0.1), action=(flags.skip_snat_for_lb = 1; ct_lb(backends=192.168.1.10);) -+ table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) -+]) -+check ovn-nbctl remove load_balancer lb-test options skip_snat -+ -+AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows1 | grep "priority=65532"], [0], [dnl -+ table=? (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(reg0[[17]] = 1; 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; reg0[[17]] = 1; 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=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) -+ table=? (ls_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_label.blocked == 0), action=(next;) -+ table=? (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;) -+ table=? (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) -+ table=? (ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) -+ table=?(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;) -+]) -+ -+AS_BOX([Chassis upgrades and supports CT related]) -+check ovn-sbctl set chassis hv other_config:ct-no-masked-label=true -+check ovn-sbctl set chassis hv other_config:ovn-ct-lb-related=true -+check ovn-nbctl --wait=sb sync -+ovn-sbctl dump-flows | DUMP_FLOWS_SORTED > lflows2 -+ -+AT_CHECK([grep -e "lr_in_defrag" -e "lr_in_dnat" lflows2], [0], [dnl -+ table=? (lr_in_defrag ), priority=0 , match=(1), action=(next;) -+ table=? (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 192.168.0.1), action=(reg0 = 192.168.0.1; ct_dnat;) -+ table=? (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;) -+ table=? (lr_in_dnat ), priority=0 , match=(1), action=(next;) -+ table=? (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 192.168.0.1 && ct_mark.natted == 1), action=(next;) -+ table=? (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 192.168.0.1), action=(ct_lb_mark(backends=192.168.1.10);) -+ table=? (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) -+ table=? (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) -+ table=? (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) -+]) -+ -+AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows2 | grep "priority=65532"], [0], [dnl -+ table=? (ls_in_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(reg0[[17]] = 1; ct_commit_nat;) -+ 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; reg0[[17]] = 1; 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_out_acl ), priority=65532, match=(!ct.est && ct.rel && !ct.new && !ct.inv && ct_mark.blocked == 0), action=(ct_commit_nat;) -+ table=? (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(next;) -+ table=? (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) -+ table=? (ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) -+ table=?(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;) -+]) -+ -+AT_CLEANUP -+]) -+ -+OVN_FOR_EACH_NORTHD_NO_HV([ -+AT_SETUP([Chassis-feature compatibitility - remote chassis]) -+ovn_start -+ -+AS_BOX([Local chassis]) -+check ovn-sbctl chassis-add hv1 geneve 127.0.0.1 \ -+ -- set chassis hv1 other_config:ct-no-masked-label=true \ -+ -- set chassis hv1 other_config:ovn-ct-lb-related=true \ -+ -- set chassis hv1 other_config:mac-binding-timestamp=true -+ -+check ovn-nbctl --wait=sb sync -+ -+AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE debug/chassis-features-list], [0], [dnl -+ct_no_masked_label: true -+ct_lb_related: true -+mac_binding_timestamp: true -+]) -+ -+AS_BOX([Remote chassis]) -+check ovn-sbctl chassis-add hv2 geneve 127.0.0.2 \ -+ -- set chassis hv2 other_config:is-remote=true \ -+ -- set chassis hv2 other_config:ct-no-masked-label=false \ -+ -- set chassis hv2 other_config:ovn-ct-lb-related=false \ -+ -- set chassis hv2 other_config:mac-binding-timestamp=false -+ -+check ovn-nbctl --wait=sb sync -+ -+AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE debug/chassis-features-list], [0], [dnl -+ct_no_masked_label: true -+ct_lb_related: true -+mac_binding_timestamp: true -+]) -+ -+AT_CLEANUP -+]) -diff --git a/tests/ovn.at b/tests/ovn.at -index ad2014de6..f77a4983d 100644 ---- a/tests/ovn.at -+++ b/tests/ovn.at -@@ -4461,7 +4461,12 @@ for i in 1 2 3; do - done - - # Gracefully terminate daemons --OVN_CLEANUP([hv1],[hv2],[vtep]) -+ -+OVN_CLEANUP_SBOX([hv1]) -+OVN_CLEANUP_SBOX([hv2]) -+OVS_WAIT_UNTIL([test `as vtep ovs-vsctl list-ports vtep_bfd | wc -l` -eq 0]) -+OVN_CLEANUP([vtep]) -+ - OVN_CLEANUP_VSWITCH([hv3]) - - AT_CLEANUP -@@ -25064,8 +25069,10 @@ OVN_FOR_EACH_NORTHD([ - AT_SETUP([interconnection]) - - ovn_init_ic_db --n_az=5 --n_ts=5 -+# The number needs to stay relatively low due to high memory consumption -+# with address sanitizers enabled. -+n_az=3 -+n_ts=3 - for i in `seq 1 $n_az`; do - ovn_start az$i - done -@@ -28416,24 +28423,39 @@ wait_row_count Port_Binding 1 logical_port=lsp-cont1 chassis=$ch - OVN_CLEANUP([hv1]) - AT_CLEANUP - -+# TEST_LR_DROP_TRAFFIC_FOR_OWN_IPS [ DGP | GR ] - # Test dropping traffic destined to router owned IPs. --OVN_FOR_EACH_NORTHD([ --AT_SETUP([gateway router drop traffic for own IPs]) -+m4_define([TEST_LR_DROP_TRAFFIC_FOR_OWN_IPS], [ - ovn_start - --ovn-nbctl lr-add r1 -- set logical_router r1 options:chassis=hv1 --ovn-nbctl ls-add s1 -- --# Connnect r1 to s1. --ovn-nbctl lrp-add r1 lrp-r1-s1 00:00:00:00:01:01 10.0.1.1/24 --ovn-nbctl lsp-add s1 lsp-s1-r1 -- set Logical_Switch_Port lsp-s1-r1 type=router \ -- options:router-port=lrp-r1-s1 addresses=router -- --# Create logical port p1 in s1 --ovn-nbctl lsp-add s1 p1 \ -+ovn-nbctl lr-add r1 # Gateway router or LR with DGP on the ext side -+ovn-nbctl ls-add ext # simulate external LS -+ovn-nbctl ls-add s2 # simulate internal LS -+ -+# Connnect r1 to ext. -+ovn-nbctl lrp-add r1 lrp-r1-ext 00:00:00:00:01:01 10.0.1.1/24 -+if test X"$1" = X"DGP"; then -+ ovn-nbctl lrp-set-gateway-chassis lrp-r1-ext hv1 1 -+else -+ ovn-nbctl set logical_router r1 options:chassis=hv1 -+fi -+ovn-nbctl lsp-add ext lsp-ext-r1 -- set Logical_Switch_Port lsp-ext-r1 type=router \ -+ options:router-port=lrp-r1-ext addresses=router -+ -+# Connnect r1 to s2. -+ovn-nbctl lrp-add r1 lrp-r1-s2 00:00:00:00:02:01 10.0.2.1/24 -+ovn-nbctl lsp-add s2 lsp-s2-r1 -- set Logical_Switch_Port lsp-s2-r1 type=router \ -+ options:router-port=lrp-r1-s2 addresses=router -+ -+# Create logical port p1 in ext -+ovn-nbctl lsp-add ext p1 \ - -- lsp-set-addresses p1 "f0:00:00:00:01:02 10.0.1.2" \ - -- lsp-set-port-security p1 "f0:00:00:00:01:02 10.0.1.2" - -+# Create logical port p2 in s2 -+ovn-nbctl lsp-add s2 p2 \ -+-- lsp-set-addresses p2 "f0:00:00:00:02:02 10.0.2.2" -+ - # Create two hypervisor and create OVS ports corresponding to logical ports. - net_add n1 - -@@ -28447,6 +28469,12 @@ ovs-vsctl -- add-port br-int hv1-vif1 -- \ - options:rxq_pcap=hv1/vif1-rx.pcap \ - ofport-request=1 - -+ovs-vsctl -- add-port br-int hv1-vif2 -- \ -+ set interface hv1-vif2 external-ids:iface-id=p2 \ -+ options:tx_pcap=hv1/vif2-tx.pcap \ -+ options:rxq_pcap=hv1/vif2-rx.pcap \ -+ ofport-request=2 -+ - # Pre-populate the hypervisors' ARP tables so that we don't lose any - # packets for ARP resolution (native tunneling doesn't queue packets - # for ARP resolution). -@@ -28457,9 +28485,10 @@ ovn-nbctl --wait=hv sync - - sw_key=$(ovn-sbctl --bare --columns tunnel_key list datapath_binding r1) - -+echo sw_key: $sw_key - AT_CHECK([ovn-sbctl lflow-list | grep lr_in_arp_resolve | grep 10.0.1.1], [1], []) - --# Send ip packets from p1 to lrp-r1-s1 -+# Send ip packets from p1 to lrp-r1-ext - src_mac="f00000000102" - dst_mac="000000000101" - src_ip=`ip_to_hex 10 0 1 2` -@@ -28478,10 +28507,10 @@ AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep -E "table=11, n_packets=1,.* - ]) - - # Use the router IP as SNAT IP. --ovn-nbctl set logical_router r1 options:lb_force_snat_ip=10.0.1.1 -+ovn-nbctl lr-nat-add r1 snat 10.0.1.1 10.8.8.0/24 - ovn-nbctl --wait=hv sync - --# Send ip packets from p1 to lrp-r1-s1 -+# Send ip packets from p1 to lrp-r1-ext - src_mac="f00000000102" - dst_mac="000000000101" - src_ip=`ip_to_hex 10 0 1 2` -@@ -28496,11 +28525,53 @@ AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep "actions=controller" | grep - ]) - - # The packet should've been dropped in the lr_in_arp_resolve stage. --AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep -E "table=25, n_packets=1,.* priority=2,ip,metadata=0x${sw_key},nw_dst=10.0.1.1 actions=drop" -c], [0], [dnl -+if test X"$1" = X"DGP"; then -+ prio=150 -+ inport=reg14 -+ outport=reg15 -+else -+ prio=2 -+fi -+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep -E "table=25, n_packets=1,.* priority=$prio,ip,$inport.*$outport.*metadata=0x${sw_key},nw_dst=10.0.1.1 actions=drop" -c], [0], [dnl - 1 - ]) - -+# Send ip packets from p2 to lrp-r1-ext -+src_mac="f00000000202" -+dst_mac="000000000201" -+src_ip=`ip_to_hex 10 0 2 2` -+dst_ip=`ip_to_hex 10 0 1 1` -+packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000 -+as hv1 ovs-appctl netdev-dummy/receive hv1-vif2 $packet -+ -+# Still no packet-ins should reach ovn-controller. -+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep "actions=controller" | grep -v n_packets=0 -c], [1], [dnl -+0 -+]) -+ -+if test X"$1" = X"DGP"; then -+ # The packet dst should be resolved once for E/W centralized NAT purpose. -+ AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep -E "table=25, n_packets=1,.* priority=100,reg0=0xa000101,reg15=.*metadata=0x${sw_key} actions=mod_dl_dst:00:00:00:00:01:01,resubmit" -c], [0], [dnl -+1 -+]) -+fi -+ -+# The packet should've been finally dropped in the lr_in_arp_resolve stage. -+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep -E "table=25, n_packets=2,.* priority=$prio,ip,$inport.*$outport.*metadata=0x${sw_key},nw_dst=10.0.1.1 actions=drop" -c], [0], [dnl -+1 -+]) - OVN_CLEANUP([hv1]) -+]) -+ -+OVN_FOR_EACH_NORTHD([ -+AT_SETUP([gateway router drop traffic for own IPs]) -+TEST_LR_DROP_TRAFFIC_FOR_OWN_IPS(GR) -+AT_CLEANUP -+]) -+ -+OVN_FOR_EACH_NORTHD([ -+AT_SETUP([distributed gateway port drop traffic for own IPs]) -+TEST_LR_DROP_TRAFFIC_FOR_OWN_IPS(DGP) - AT_CLEANUP - ]) - -diff --git a/tests/system-ovn.at b/tests/system-ovn.at -index 99ad14aa5..1e6767846 100644 ---- a/tests/system-ovn.at -+++ b/tests/system-ovn.at -@@ -1618,8 +1618,8 @@ OVS_WAIT_UNTIL([ - ovn-nbctl --reject lb-add lb3 30.0.0.10:80 "" - ovn-nbctl ls-lb-add foo lb3 - # Filter reset segments --NS_CHECK_EXEC([foo1], [tcpdump -c 1 -neei foo1 ip[[33:1]]=0x14 > rst.pcap 2>/dev/null &]) --sleep 1 -+NS_CHECK_EXEC([foo1], [tcpdump -l -c 1 -neei foo1 ip[[33:1]]=0x14 > rst.pcap 2>tcpdump_err &]) -+OVS_WAIT_UNTIL([grep "listening" tcpdump_err]) - NS_CHECK_EXEC([foo1], [wget -q 30.0.0.10],[4]) - - OVS_WAIT_UNTIL([ -@@ -1734,13 +1734,11 @@ OVS_START_L7([bar2], [http6]) - OVS_START_L7([bar3], [http6]) - - dnl Should work with the virtual IP fd03::1 address through NAT --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([foo1], [wget http://[[fd03::1]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log || (ovs-ofctl -O OpenFlow13 dump-flows br-int && false)]) -+OVS_WAIT_FOR_OUTPUT([ -+for i in `seq 1 10`; do -+ NS_EXEC([foo1], [wget http://[[fd03::1]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log || (ovs-ofctl -O OpenFlow13 dump-flows br-int && false)]) - done -- --dnl Each server should have at least one connection. --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::1) | grep -v fe80 | \ -+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=,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=) -@@ -1748,27 +1746,25 @@ tcp,orig=(src=fd01::2,dst=fd03::1,sport=,dport=),reply=(src=fd - ]) - - dnl Should work with the virtual IP fd03::3 address through NAT --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([foo1], [wget http://[[fd03::3]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+OVS_WAIT_FOR_OUTPUT([ -+for i in `seq 1 10`; do -+ NS_EXEC([foo1], [wget http://[[fd03::3]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) - done -- - dnl Each server should have at least one connection. --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::3) | grep -v fe80 | \ -+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=,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=) - ]) - -+OVS_WAIT_FOR_OUTPUT([ - dnl Test load-balancing that includes L4 ports in NAT. --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([foo1], [wget http://[[fd03::2]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+for i in `seq 1 10`; do -+ NS_EXEC([foo1], [wget http://[[fd03::2]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) - done -- - dnl Each server should have at least one connection. --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::2) | grep -v fe80 | \ -+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=,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=) -@@ -1784,14 +1780,14 @@ OVS_WAIT_UNTIL([ - - AT_CHECK([ovs-appctl dpctl/flush-conntrack]) - -+OVS_WAIT_FOR_OUTPUT([ - dnl Test load-balancing that includes L4 ports in NAT. --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([foo1], [wget http://[[fd03::2]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+for i in `seq 1 10`; do -+ NS_EXEC([foo1], [wget http://[[fd03::2]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) - done - - dnl Each server should have at least one connection. --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::2) | grep -v fe80 | \ -+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=,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=) -@@ -1933,13 +1929,13 @@ OVS_START_L7([foo3], [http]) - OVS_START_L7([foo4], [http]) - - dnl Should work with the virtual IP address through NAT --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([foo1], [wget 30.0.0.1 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+OVS_WAIT_FOR_OUTPUT([ -+for i in `seq 1 10`; do -+ NS_EXEC([foo1], [wget 30.0.0.1 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) - done - - dnl Each server should have at least one connection. --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | \ -+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=,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=) -@@ -1947,20 +1943,19 @@ tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(s - ]) - - dnl Test load-balancing that includes L4 ports in NAT. --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([foo1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+OVS_WAIT_FOR_OUTPUT([ -+for i in `seq 1 10`; do -+ NS_EXEC([foo1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) - done - - dnl Each server should have at least one connection. --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | \ -+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=,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=) - ]) - -- - OVS_APP_EXIT_AND_WAIT([ovn-controller]) - - as ovn-sb -@@ -2044,13 +2039,13 @@ OVS_START_L7([foo3], [http6]) - OVS_START_L7([foo4], [http6]) - - dnl Should work with the virtual IP address through NAT --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([foo1], [wget http://[[fd03::1]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+OVS_WAIT_FOR_OUTPUT([ -+for i in `seq 1 10`; do -+ NS_EXEC([foo1], [wget http://[[fd03::1]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) - done - - dnl Each server should have at least one connection. --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::1) | grep -v fe80 | \ -+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=,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=) -@@ -2058,20 +2053,19 @@ tcp,orig=(src=fd01::2,dst=fd03::1,sport=,dport=),reply=(src=fd - ]) - - dnl Test load-balancing that includes L4 ports in NAT. --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([foo1], [wget http://[[fd03::2]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+OVS_WAIT_FOR_OUTPUT([ -+for i in `seq 1 10`; do -+ NS_EXEC([foo1], [wget http://[[fd03::2]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) - done - - dnl Each server should have at least one connection. --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd03::2) | grep -v fe80 | \ -+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=,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=) - ]) - -- - OVS_APP_EXIT_AND_WAIT([ovn-controller]) - - as ovn-sb -@@ -2199,27 +2193,27 @@ OVS_START_L7([bar1], [http]) - - check ovs-appctl dpctl/flush-conntrack - dnl Should work with the virtual IP address through NAT --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([alice1], [wget 30.0.0.1 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+OVS_WAIT_FOR_OUTPUT([ -+for i in `seq 1 10`; do -+ NS_EXEC([alice1], [wget 30.0.0.1 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) - done - - dnl Each server should have at least one connection. --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | -+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=,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=) - ]) - - check ovs-appctl dpctl/flush-conntrack -+OVS_WAIT_FOR_OUTPUT([ - dnl Test load-balancing that includes L4 ports in NAT. --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([alice1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+for i in `seq 1 10`; do -+ NS_EXEC([alice1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) - done - - dnl Each server should have at least one connection. --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | -+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=,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=) -@@ -2256,23 +2250,23 @@ OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-flows br-int table=43 | \ - grep 'nat(src=20.0.0.2)']) - - check ovs-appctl dpctl/flush-conntrack -+exp_ct1="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=10,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=10,protoinfo=(state=)" -+exp_ct2="tcp,orig=(src=172.16.1.2,dst=192.168.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=20.0.0.2,sport=,dport=),zone=,protoinfo=(state=) -+tcp,orig=(src=172.16.1.2,dst=192.168.2.2,sport=,dport=),reply=(src=192.168.2.2,dst=20.0.0.2,sport=,dport=),zone=,protoinfo=(state=)" -+ - dnl Test load-balancing that includes L4 ports in NAT. --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([alice1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+OVS_WAIT_FOR_OUTPUT_UNQUOTED([ -+for i in `seq 1 10`; do -+ NS_EXEC([alice1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) - 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=,mark=10,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=10,protoinfo=(state=) --]) -+ct1=$(ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | sed -e 's/zone=[[0-9]]*/zone=/') -+ct2=$(ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0.2) | sed -e 's/zone=[[0-9]]*/zone=/') - --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0.2) | --sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl --tcp,orig=(src=172.16.1.2,dst=192.168.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=20.0.0.2,sport=,dport=),zone=,protoinfo=(state=) --tcp,orig=(src=172.16.1.2,dst=192.168.2.2,sport=,dport=),reply=(src=192.168.2.2,dst=20.0.0.2,sport=,dport=),zone=,protoinfo=(state=) -+test "x$ct1 = x$exp_ct1" && test "x$ct2 = x$exp_ct2" -+], [0], [dnl - ]) - - OVS_WAIT_UNTIL([check_est_flows], [check established flows]) -@@ -2298,22 +2292,21 @@ rm -f wget*.log - - check ovs-appctl dpctl/flush-conntrack - dnl Test load-balancing that includes L4 ports in NAT. --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([alice1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+exp_ct1="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=10,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=10,protoinfo=(state=)" -+exp_ct2="tcp,orig=(src=172.16.1.2,dst=192.168.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=20.0.0.2,sport=,dport=),zone=,protoinfo=(state=) -+tcp,orig=(src=172.16.1.2,dst=192.168.2.2,sport=,dport=),reply=(src=192.168.2.2,dst=20.0.0.2,sport=,dport=),zone=,protoinfo=(state=)" -+ -+OVS_WAIT_FOR_OUTPUT_UNQUOTED([ -+for i in `seq 1 10`; do -+ NS_EXEC([alice1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) - 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=,mark=10,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=10,protoinfo=(state=) --]) -- --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0.2) | --sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl --tcp,orig=(src=172.16.1.2,dst=192.168.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=20.0.0.2,sport=,dport=),zone=,protoinfo=(state=) --tcp,orig=(src=172.16.1.2,dst=192.168.2.2,sport=,dport=),reply=(src=192.168.2.2,dst=20.0.0.2,sport=,dport=),zone=,protoinfo=(state=) -+ct1=$(ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | sed -e 's/zone=[[0-9]]*/zone=/') -+ct2=$(ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0.2) | sed -e 's/zone=[[0-9]]*/zone=/') -+test "x$ct1 = x$exp_ct1" && test "x$ct2 = x$exp_ct2" -+], [0], [dnl - ]) - - OVS_WAIT_UNTIL([check_est_flows], [check established flows]) -@@ -2549,26 +2542,26 @@ OVS_START_L7([foo1], [http6]) - OVS_START_L7([bar1], [http6]) - - dnl Should work with the virtual IP address through NAT --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([alice1], [wget http://[[fd30::1]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+OVS_WAIT_FOR_OUTPUT_UNQUOTED([ -+for i in `seq 1 10`; do -+ NS_EXEC([alice1], [wget http://[[fd30::1]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) - done - - dnl Each server should have at least one connection. --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::1) | grep -v fe80 | -+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=,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. --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([alice1], [wget http://[[fd30::2]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+OVS_WAIT_FOR_OUTPUT_UNQUOTED([ -+for i in `seq 1 10`; do -+ NS_EXEC([alice1], [wget http://[[fd30::2]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) - done - - dnl Each server should have at least one connection. --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::2) | grep -v fe80 | -+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=,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=) -@@ -2727,24 +2720,24 @@ OVS_START_L7([foo1], [http]) - OVS_START_L7([bar1], [http]) - - dnl Should work with the virtual IP address through NAT --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([alice1], [wget 30.0.0.1 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+exp_ct1="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=10,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=10,protoinfo=(state=)" -+exp_ct2="tcp,orig=(src=172.16.1.3,dst=192.168.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=20.0.0.2,sport=,dport=),zone=,protoinfo=(state=) -+tcp,orig=(src=172.16.1.3,dst=192.168.2.2,sport=,dport=),reply=(src=192.168.2.2,dst=20.0.0.2,sport=,dport=),zone=,protoinfo=(state=)" -+ -+OVS_WAIT_FOR_OUTPUT_UNQUOTED([ -+for i in `seq 1 10`; do -+ NS_EXEC([alice1], [wget 30.0.0.1 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) - 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=,mark=10,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=10,protoinfo=(state=) --]) -- -+ct1=$(ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | sed -e 's/zone=[[0-9]]*/zone=/') - dnl Force SNAT should have worked. --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0) | --sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl --tcp,orig=(src=172.16.1.3,dst=192.168.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=20.0.0.2,sport=,dport=),zone=,protoinfo=(state=) --tcp,orig=(src=172.16.1.3,dst=192.168.2.2,sport=,dport=),reply=(src=192.168.2.2,dst=20.0.0.2,sport=,dport=),zone=,protoinfo=(state=) -+ct2=$(ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0) | sed -e 's/zone=[[0-9]]*/zone=/') -+test "x$ct1 = x$exp_ct1" && test "x$ct2 = x$exp_ct2" -+], [0], [dnl - ]) -+ - OVS_APP_EXIT_AND_WAIT([ovn-controller]) - - as ovn-sb -@@ -2900,24 +2893,24 @@ OVS_START_L7([foo1], [http6]) - OVS_START_L7([bar1], [http6]) - - dnl Should work with the virtual IP address through NAT --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([alice1], [wget http://[[fd30::1]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+exp_ct1="tcp,orig=(src=fd72::3,dst=fd30::1,sport=,dport=),reply=(src=fd11::2,dst=fd72::3,sport=,dport=),zone=,mark=10,protoinfo=(state=) -+tcp,orig=(src=fd72::3,dst=fd30::1,sport=,dport=),reply=(src=fd12::2,dst=fd72::3,sport=,dport=),zone=,mark=10,protoinfo=(state=) -+exp_ct2=tcp,orig=(src=fd72::3,dst=fd11::2,sport=,dport=),reply=(src=fd11::2,dst=fd20::2,sport=,dport=),zone=,protoinfo=(state=) -+tcp,orig=(src=fd72::3,dst=fd12::2,sport=,dport=),reply=(src=fd12::2,dst=fd20::2,sport=,dport=),zone=,protoinfo=(state=)" -+ -+OVS_WAIT_FOR_OUTPUT_UNQUOTED([ -+for i in `seq 1 10`; do -+ NS_EXEC([alice1], [wget http://[[fd30::1]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) - 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=,mark=10,protoinfo=(state=) --tcp,orig=(src=fd72::3,dst=fd30::1,sport=,dport=),reply=(src=fd12::2,dst=fd72::3,sport=,dport=),zone=,mark=10,protoinfo=(state=) --]) -- -+ct1=$(ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::1) | grep -v fe80 | sed -e 's/zone=[[0-9]]*/zone=/') - dnl Force SNAT should have worked. --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd20::2) | grep -v fe80 | --sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl --tcp,orig=(src=fd72::3,dst=fd11::2,sport=,dport=),reply=(src=fd11::2,dst=fd20::2,sport=,dport=),zone=,protoinfo=(state=) --tcp,orig=(src=fd72::3,dst=fd12::2,sport=,dport=),reply=(src=fd12::2,dst=fd20::2,sport=,dport=),zone=,protoinfo=(state=) -+ct2=$(ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd20::2) | grep -v fe80 | sed -e 's/zone=[[0-9]]*/zone=/') -+test "x$ct1 = x$exp_ct1" && test "x$ct2 = x$exp_ct2" -+], [0], [dnl - ]) -+ - OVS_APP_EXIT_AND_WAIT([ovn-controller]) - - as ovn-sb -@@ -3111,39 +3104,32 @@ OVS_START_L7([foo16], [http6]) - OVS_START_L7([bar16], [http6]) - - dnl Should work with the virtual IP address through NAT --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([alice1], [wget 30.0.0.1 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) --done -- --for i in `seq 1 20`; do -- echo Request ${i}_6 -- NS_CHECK_EXEC([alice16], [wget http://[[fd30::1]] -t 5 -T 1 --retry-connrefused -v -o wget${i}_6.log]) -+exp_ct1="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=10,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=10,protoinfo=(state=)" -+exp_ct2="tcp,orig=(src=fd72::3,dst=fd30::1,sport=,dport=),reply=(src=fd11::2,dst=fd72::3,sport=,dport=),zone=,mark=10,protoinfo=(state=) -+tcp,orig=(src=fd72::3,dst=fd30::1,sport=,dport=),reply=(src=fd12::2,dst=fd72::3,sport=,dport=),zone=,mark=10,protoinfo=(state=)" -+exp_ct3="tcp,orig=(src=172.16.1.3,dst=192.168.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=20.0.0.2,sport=,dport=),zone=,protoinfo=(state=) -+tcp,orig=(src=172.16.1.3,dst=192.168.2.2,sport=,dport=),reply=(src=192.168.2.2,dst=20.0.0.2,sport=,dport=),zone=,protoinfo=(state=)" -+exp_ct4="tcp,orig=(src=fd72::3,dst=fd11::2,sport=,dport=),reply=(src=fd11::2,dst=fd20::2,sport=,dport=),zone=,protoinfo=(state=) -+tcp,orig=(src=fd72::3,dst=fd12::2,sport=,dport=),reply=(src=fd12::2,dst=fd20::2,sport=,dport=),zone=,protoinfo=(state=)" -+ -+OVS_WAIT_FOR_OUTPUT_UNQUOTED([ -+for i in `seq 1 10`; do -+ NS_EXEC([alice1], [wget 30.0.0.1 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+ NS_EXEC([alice16], [wget http://[[fd30::1]] -t 5 -T 1 --retry-connrefused -v -o wget${i}_6.log]) - 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=,mark=10,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=10,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=,mark=10,protoinfo=(state=) --tcp,orig=(src=fd72::3,dst=fd30::1,sport=,dport=),reply=(src=fd12::2,dst=fd72::3,sport=,dport=),zone=,mark=10,protoinfo=(state=) --]) -+ct1=$(ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | sed -e 's/zone=[[0-9]]*/zone=/') -+ct2=$(ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::1) | grep -v fe80 | sed -e 's/zone=[[0-9]]*/zone=/') - - dnl Force SNAT should have worked. --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0) | --sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl --tcp,orig=(src=172.16.1.3,dst=192.168.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=20.0.0.2,sport=,dport=),zone=,protoinfo=(state=) --tcp,orig=(src=172.16.1.3,dst=192.168.2.2,sport=,dport=),reply=(src=192.168.2.2,dst=20.0.0.2,sport=,dport=),zone=,protoinfo=(state=) --]) --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd20::2) | grep -v fe80 | --sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl --tcp,orig=(src=fd72::3,dst=fd11::2,sport=,dport=),reply=(src=fd11::2,dst=fd20::2,sport=,dport=),zone=,protoinfo=(state=) --tcp,orig=(src=fd72::3,dst=fd12::2,sport=,dport=),reply=(src=fd12::2,dst=fd20::2,sport=,dport=),zone=,protoinfo=(state=) -+ct3=$(ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0) | sed -e 's/zone=[[0-9]]*/zone=/') -+ct4=$(ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd20::2) | grep -v fe80 | sed -e 's/zone=[[0-9]]*/zone=/') -+test "x$ct1 = x$exp_ct1" && test "x$ct2 = x$exp_ct2" && test "x$ct3 = x$exp_ct3" && test "x$ct4 = x$exp_ct4" -+], [0], [dnl - ]) -+ - OVS_APP_EXIT_AND_WAIT([ovn-controller]) - - as ovn-sb -@@ -3262,26 +3248,26 @@ OVS_START_L7([foo1], [http]) - OVS_START_L7([bar1], [http]) - - dnl Should work with the virtual IP address through NAT --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([alice1], [wget 172.16.1.10 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+OVS_WAIT_FOR_OUTPUT_UNQUOTED([ -+for i in `seq 1 10`; do -+ NS_EXEC([alice1], [wget 172.16.1.10 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) - done - - dnl Each server should have at least one connection. --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.1.10) | -+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=,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. --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([alice1], [wget 172.16.1.11:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+OVS_WAIT_FOR_OUTPUT_UNQUOTED([ -+for i in `seq 1 10`; do -+ NS_EXEC([alice1], [wget 172.16.1.11:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) - done - - dnl Each server should have at least one connection. --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.1.11) | -+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=,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=) -@@ -3405,26 +3391,26 @@ OVS_START_L7([foo1], [http6]) - OVS_START_L7([bar1], [http6]) - - dnl Should work with the virtual IP address through NAT --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([alice1], [wget http://[[fd72::10]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+OVS_WAIT_FOR_OUTPUT_UNQUOTED([ -+for i in `seq 1 10`; do -+ NS_EXEC([alice1], [wget http://[[fd72::10]] -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) - done - - dnl Each server should have at least one connection. --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd72::10) | grep -v fe80 | -+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=,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. --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([alice1], [wget http://[[fd72::11]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+OVS_WAIT_FOR_OUTPUT_UNQUOTED([ -+for i in `seq 1 10`; do -+ NS_EXEC([alice1], [wget http://[[fd72::11]]:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) - done - - dnl Each server should have at least one connection. --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd72::11) | grep -v fe80 | -+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=,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=) -@@ -3598,8 +3584,8 @@ icmp,orig=(src=192.168.2.2,dst=172.16.1.2,id=,type=8,code=0),reply=(src - ]) - - # Try to ping external network --NS_CHECK_EXEC([ext-net], [tcpdump -n -c 3 -i ext-veth dst 172.16.1.3 and icmp > ext-net.pcap &]) --sleep 1 -+NS_CHECK_EXEC([ext-net], [tcpdump -l -n -c 3 -i ext-veth dst 172.16.1.3 and icmp > ext-net.pcap 2>tcpdump_err &]) -+OVS_WAIT_UNTIL([grep "listening" tcpdump_err]) - AT_CHECK([ovn-nbctl lr-nat-del R1 snat]) - NS_CHECK_EXEC([foo1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.1 | FORMAT_PING], \ - [0], [dnl -@@ -4507,17 +4493,15 @@ OVS_WAIT_UNTIL( - [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 --for i in `seq 1 20`; do -- echo Request $i -- ovn-sbctl list service_monitor -- NS_CHECK_EXEC([sw0-p2], [wget 10.0.0.10 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) --done -+#dnl Each server should have at least one connection. -+OVS_WAIT_FOR_OUTPUT([ -+ for i in `seq 1 10`; do -+ NS_EXEC([sw0-p2], [wget 10.0.0.10 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+ 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 -+ 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=,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=) - ]) -@@ -4649,10 +4633,12 @@ ovn-nbctl lb-add lb-ipv4-tcp 88.88.88.88:8080 42.42.42.1:4041 tcp - ovn-nbctl lb-add lb-ipv4-tcp-dup 88.88.88.89:8080 42.42.42.1:4041 tcp - ovn-nbctl lb-add lb-ipv4-udp 88.88.88.88:4040 42.42.42.1:2021 udp - ovn-nbctl lb-add lb-ipv4-udp-dup 88.88.88.89:4040 42.42.42.1:2021 udp -+ovn-nbctl lb-add lb-ipv4 88.88.88.90 42.42.42.1 - ovn-nbctl ls-lb-add sw lb-ipv4-tcp - ovn-nbctl ls-lb-add sw lb-ipv4-tcp-dup - ovn-nbctl ls-lb-add sw lb-ipv4-udp - ovn-nbctl ls-lb-add sw lb-ipv4-udp-dup -+ovn-nbctl ls-lb-add sw lb-ipv4 - - ovn-nbctl lr-add rtr - ovn-nbctl lrp-add rtr rtr-sw 00:00:00:00:01:00 42.42.42.254/24 -@@ -4668,28 +4654,39 @@ ADD_VETH(lsp, lsp, br-int, "42.42.42.1/24", "00:00:00:00:00:01", \ - ovn-nbctl --wait=hv -t 3 sync - - # Start IPv4 TCP server on lsp. --NS_CHECK_EXEC([lsp], [timeout 2s nc -k -l 42.42.42.1 4041 &], [0]) -+NETNS_DAEMONIZE([lsp], [nc -l -k 42.42.42.1 4041], [lsp0.pid]) - - # Check that IPv4 TCP hairpin connection succeeds on both VIPs. - NS_CHECK_EXEC([lsp], [nc 88.88.88.88 8080 -z], [0], [ignore], [ignore]) - NS_CHECK_EXEC([lsp], [nc 88.88.88.89 8080 -z], [0], [ignore], [ignore]) -+NS_CHECK_EXEC([lsp], [nc 88.88.88.90 4041 -z], [0], [ignore], [ignore]) - - # Capture IPv4 UDP hairpinned packets. - filter="dst 42.42.42.1 and dst port 2021 and udp" --NS_CHECK_EXEC([lsp], [tcpdump -nn -c 2 -i lsp ${filter} > lsp.pcap &]) -- --sleep 1 -+NS_CHECK_EXEC([lsp], [tcpdump -l -nn -c 3 -i lsp ${filter} > lsp.pcap 2>tcpdump_err &]) -+OVS_WAIT_UNTIL([grep "listening" tcpdump_err]) - - # Generate IPv4 UDP hairpin traffic. - NS_CHECK_EXEC([lsp], [echo a | nc -u 88.88.88.88 4040 &], [0]) - NS_CHECK_EXEC([lsp], [echo a | nc -u 88.88.88.89 4040 &], [0]) -+NS_CHECK_EXEC([lsp], [echo a | nc -u 88.88.88.90 2021 &], [0]) - - # Check hairpin traffic. - OVS_WAIT_UNTIL([ - total_pkts=$(cat lsp.pcap | wc -l) -- test "${total_pkts}" = "2" -+ test "${total_pkts}" = "3" - ]) - -+ovn-nbctl pg-add pg0 lsp -+ovn-nbctl --apply-after-lb acl-add pg0 from-lport 1004 "ip4 && ip4.dst == 10.0.0.2" drop -+ovn-nbctl --apply-after-lb acl-add pg0 from-lport 1002 "ip4 && tcp" allow-related -+ovn-nbctl --apply-after-lb acl-add pg0 from-lport 1002 "ip4 && udp" allow -+ovn-nbctl --wait=hv sync -+ -+## Check that IPv4 TCP hairpin connection succeeds on both VIPs. -+NS_CHECK_EXEC([lsp], [nc 88.88.88.88 8080 -z], [0], [ignore], [ignore]) -+NS_CHECK_EXEC([lsp], [nc 88.88.88.89 8080 -z], [0], [ignore], [ignore]) -+ - OVS_APP_EXIT_AND_WAIT([ovn-controller]) - - as ovn-sb -@@ -4736,10 +4733,12 @@ ovn-nbctl lb-add lb-ipv6-tcp [[8800::0088]]:8080 [[4200::1]]:4041 tcp - ovn-nbctl lb-add lb-ipv6-tcp-dup [[8800::0089]]:8080 [[4200::1]]:4041 tcp - ovn-nbctl lb-add lb-ipv6-udp [[8800::0088]]:4040 [[4200::1]]:2021 udp - ovn-nbctl lb-add lb-ipv6-udp-dup [[8800::0089]]:4040 [[4200::1]]:2021 udp -+ovn-nbctl lb-add lb-ipv6 8800::0090 4200::1 - ovn-nbctl ls-lb-add sw lb-ipv6-tcp - ovn-nbctl ls-lb-add sw lb-ipv6-tcp-dup - ovn-nbctl ls-lb-add sw lb-ipv6-udp - ovn-nbctl ls-lb-add sw lb-ipv6-udp-dup -+ovn-nbctl ls-lb-add sw lb-ipv6 - - ovn-nbctl lr-add rtr - ovn-nbctl lrp-add rtr rtr-sw 00:00:00:00:01:00 4200::00ff/64 -@@ -4754,28 +4753,39 @@ OVS_WAIT_UNTIL([test "$(ip netns exec lsp ip a | grep 4200::1 | grep tentative)" - ovn-nbctl --wait=hv -t 3 sync - - # Start IPv6 TCP server on lsp. --NS_CHECK_EXEC([lsp], [timeout 2s nc -k -l 4200::1 4041 &], [0]) -+NETNS_DAEMONIZE([lsp], [nc -l -k 4200::1 4041], [lsp0.pid]) - - # Check that IPv6 TCP hairpin connection succeeds on both VIPs. - NS_CHECK_EXEC([lsp], [nc 8800::0088 8080 -z], [0], [ignore], [ignore]) - NS_CHECK_EXEC([lsp], [nc 8800::0089 8080 -z], [0], [ignore], [ignore]) -+NS_CHECK_EXEC([lsp], [nc 8800::0090 4041 -z], [0], [ignore], [ignore]) - - # Capture IPv6 UDP hairpinned packets. - filter="dst 4200::1 and dst port 2021 and udp" --NS_CHECK_EXEC([lsp], [tcpdump -nn -c 2 -i lsp $filter > lsp.pcap &]) -- --sleep 1 -+NS_CHECK_EXEC([lsp], [tcpdump -l -nn -c 3 -i lsp $filter > lsp.pcap 2>tcpdump_err &]) -+OVS_WAIT_UNTIL([grep "listening" tcpdump_err]) - - # Generate IPv6 UDP hairpin traffic. - NS_CHECK_EXEC([lsp], [echo a | nc -u 8800::0088 4040 &], [0]) - NS_CHECK_EXEC([lsp], [echo a | nc -u 8800::0089 4040 &], [0]) -+NS_CHECK_EXEC([lsp], [echo a | nc -u 8800::0090 2021 &], [0]) - - # Check hairpin traffic. - OVS_WAIT_UNTIL([ - total_pkts=$(cat lsp.pcap | wc -l) -- test "${total_pkts}" = "2" -+ test "${total_pkts}" = "3" - ]) - -+ovn-nbctl pg-add pg0 lsp -+ovn-nbctl --apply-after-lb acl-add pg0 from-lport 1002 "ip6 && tcp" allow-related -+ovn-nbctl --apply-after-lb acl-add pg0 from-lport 1002 "ip6 && udp" allow -+ovn-nbctl --apply-after-lb acl-add pg0 from-lport 1000 "ip6" drop -+ovn-nbctl --wait=hv sync -+ -+# Check that IPv6 TCP hairpin connection succeeds on both VIPs. -+NS_CHECK_EXEC([lsp], [nc 8800::0088 8080 -z], [0], [ignore], [ignore]) -+NS_CHECK_EXEC([lsp], [nc 8800::0089 8080 -z], [0], [ignore], [ignore]) -+ - OVS_APP_EXIT_AND_WAIT([ovn-controller]) - - as ovn-sb -@@ -4938,7 +4948,7 @@ OVS_WAIT_UNTIL([ - ip netns exec sw0-p1-rej nc -u 10.0.0.4 90 < foo - c=$(cat sw0-p1-rej-icmp.pcap | grep \ - "10.0.0.4 > 10.0.0.3: ICMP 10.0.0.4 udp port 90 unreachable" | uniq | wc -l) -- test $c -eq 1 -+ test $c -ge 1 - ]) - - rm -f *.pcap -@@ -4950,7 +4960,7 @@ OVS_WAIT_UNTIL([ - ip netns exec sw0-p1-rej nc -u 10.0.0.4 94 < foo - c=$(cat sw0-p1-rej-icmp.pcap | grep \ - "10.0.0.4 > 10.0.0.3: ICMP 10.0.0.4 udp port 94 unreachable" | uniq | wc -l) -- test $c -eq 1 -+ test $c -ge 1 - ]) - - # Now test for IPv6 UDP. -@@ -4962,7 +4972,7 @@ OVS_WAIT_UNTIL([ - c=$(cat sw0-p2-rej-icmp6.pcap | grep \ - "IP6 aef0::3 > aef0::4: ICMP6, destination unreachable, unreachable port, \ - aef0::3 udp port 90" | uniq | wc -l) -- test $c -eq 1 -+ test $c -ge 1 - ]) - - rm -f *.pcap -@@ -4975,7 +4985,7 @@ OVS_WAIT_UNTIL([ - c=$(cat sw0-p2-rej-icmp6.pcap | grep \ - "IP6 aef0::3 > aef0::4: ICMP6, destination unreachable, unreachable port, \ - aef0::3 udp port 94" | uniq | wc -l) -- test $c -eq 1 -+ test $c -ge 1 - ]) - - # Delete all the ACLs of pg0 and add the ACL with a generic match with reject action. -@@ -5000,7 +5010,7 @@ OVS_WAIT_UNTIL([ - ip netns exec sw0-p1-rej nc -u 10.0.0.4 90 < foo - c=$(cat sw0-p1-rej-icmp.pcap | grep \ - "10.0.0.4 > 10.0.0.3: ICMP 10.0.0.4 udp port 90 unreachable" | uniq | wc -l) -- test $c -eq 1 -+ test $c -ge 1 - ]) - - rm -f *.pcap -@@ -5012,7 +5022,7 @@ OVS_WAIT_UNTIL([ - c=$(cat sw0-p2-rej-icmp6.pcap | grep \ - "IP6 aef0::3 > aef0::4: ICMP6, destination unreachable, unreachable port, \ - aef0::3 udp port 90" | uniq | wc -l) -- test $c -eq 1 -+ test $c -ge 1 - ]) - - -@@ -5179,7 +5189,7 @@ OVS_WAIT_UNTIL([ - ip netns exec sw0-p1-rej nc -u 10.0.0.4 90 < foo - c=$(cat sw0-p1-rej-icmp.pcap | grep \ - "10.0.0.4 > 10.0.0.3: ICMP 10.0.0.4 udp port 90 unreachable" | uniq | wc -l) -- test $c -eq 1 -+ test $c -ge 1 - ]) - - rm -f *.pcap -@@ -5191,7 +5201,7 @@ OVS_WAIT_UNTIL([ - ip netns exec sw0-p1-rej nc -u 10.0.0.4 94 < foo - c=$(cat sw0-p1-rej-icmp.pcap | grep \ - "10.0.0.4 > 10.0.0.3: ICMP 10.0.0.4 udp port 94 unreachable" | uniq | wc -l) -- test $c -eq 1 -+ test $c -ge 1 - ]) - - # Now test for IPv6 UDP. -@@ -5203,7 +5213,7 @@ OVS_WAIT_UNTIL([ - c=$(cat sw0-p2-rej-icmp6.pcap | grep \ - "IP6 aef0::3 > aef0::4: ICMP6, destination unreachable, unreachable port, \ - aef0::3 udp port 90" | uniq | wc -l) -- test $c -eq 1 -+ test $c -ge 1 - ]) - - rm -f *.pcap -@@ -5216,7 +5226,7 @@ OVS_WAIT_UNTIL([ - c=$(cat sw0-p2-rej-icmp6.pcap | grep \ - "IP6 aef0::3 > aef0::4: ICMP6, destination unreachable, unreachable port, \ - aef0::3 udp port 94" | uniq | wc -l) -- test $c -eq 1 -+ test $c -ge 1 - ]) - - # Delete all the ACLs of pg0 and add the ACL with a generic match with reject action. -@@ -5241,7 +5251,7 @@ OVS_WAIT_UNTIL([ - ip netns exec sw0-p1-rej nc -u 10.0.0.4 90 < foo - c=$(cat sw0-p1-rej-icmp.pcap | grep \ - "10.0.0.4 > 10.0.0.3: ICMP 10.0.0.4 udp port 90 unreachable" | uniq | wc -l) -- test $c -eq 1 -+ test $c -ge 1 - ]) - - rm -f *.pcap -@@ -5253,7 +5263,7 @@ OVS_WAIT_UNTIL([ - c=$(cat sw0-p2-rej-icmp6.pcap | grep \ - "IP6 aef0::3 > aef0::4: ICMP6, destination unreachable, unreachable port, \ - aef0::3 udp port 90" | uniq | wc -l) -- test $c -eq 1 -+ test $c -ge 1 - ]) - - -@@ -9277,13 +9287,15 @@ test_related_traffic() { - - check ovs-appctl dpctl/flush-conntrack - -- NETNS_DAEMONIZE([client], [tcpdump -U -i client -w client.pcap], [tcpdump0.pid]) -- NETNS_DAEMONIZE([server], [tcpdump -U -i server -w server.pcap], [tcpdump1.pid]) -+ NETNS_DAEMONIZE([client], [tcpdump -l -U -i client -w client.pcap 2>client_err], [tcpdump0.pid]) -+ NETNS_DAEMONIZE([server], [tcpdump -l -U -i server -w server.pcap 2>server_err], [tcpdump1.pid]) - - # Setup a dummy UDP listeners so we don't get "port unreachable". - NETNS_DAEMONIZE([client], [nc -l -u 1], [nc0.pid]) - NETNS_DAEMONIZE([server], [nc -l -u 2], [nc1.pid]) -- sleep 1 -+ -+ OVS_WAIT_UNTIL([grep "listening" client_err]) -+ OVS_WAIT_UNTIL([grep "listening" server_err]) - - # Send UDP client -> server - check ovs-ofctl packet-out br-int "in_port=ovs-client,packet=$client_udp,actions=resubmit(,0)" -@@ -9479,7 +9491,8 @@ name: 'vport' value: '666' - # Start IPv4 TCP server on vm1. - NETNS_DAEMONIZE([vm1], [nc -k -l 42.42.42.2 4242], [nc-vm1.pid]) - --# Make sure connecting to the VIP works. -+# Make sure connecting to the VIP works (hairpin, via ls and via lr). -+NS_CHECK_EXEC([vm1], [nc 66.66.66.66 666 -z], [0], [ignore], [ignore]) - NS_CHECK_EXEC([vm2], [nc 66.66.66.66 666 -z], [0], [ignore], [ignore]) - NS_CHECK_EXEC([vm3], [nc 66.66.66.66 666 -z], [0], [ignore], [ignore]) - -@@ -9572,9 +9585,263 @@ name: 'vport' value: '666' - # Start IPv6 TCP server on vm1. - NETNS_DAEMONIZE([vm1], [nc -k -l 4242::2 4242], [nc-vm1.pid]) - --# Make sure connecting to the VIP works. -+# Make sure connecting to the VIP works (hairpin, via ls and via lr). -+NS_CHECK_EXEC([vm1], [nc 6666::1 666 -z], [0], [ignore], [ignore]) - NS_CHECK_EXEC([vm2], [nc 6666::1 666 -z], [0], [ignore], [ignore]) - NS_CHECK_EXEC([vm3], [nc 6666::1 666 -z], [0], [ignore], [ignore]) - - AT_CLEANUP - ]) -+ -+########################################################### -+## ls1 -- cluster-router -- join - gr1 -- public1 -- ln1 ## -+########################################################### -+OVN_FOR_EACH_NORTHD([ -+AT_SETUP([Gateway router with dynamic_neigh_routers]) -+ -+CHECK_CONNTRACK() -+CHECK_CONNTRACK_NAT() -+ovn_start -+OVS_TRAFFIC_VSWITCHD_START() -+ADD_BR([br-int]) -+ADD_BR([br-ex], [set Bridge br-ex fail-mode=standalone]) -+ -+check ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=provider:br-ex -+ -+# 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 -+ -+# Add routers -+check ovn-nbctl lr-add gr1 -+check ovn-nbctl lr-add cluster-router -+ -+# Add switches -+check ovn-nbctl ls-add join -+check ovn-nbctl ls-add public1 -+check ovn-nbctl ls-add ls1 -+ -+# Add ls1 ports -+check ovn-nbctl lsp-add ls1 ls1p1 \ -+ -- lsp-set-addresses ls1p1 "00:00:00:00:01:11 10.244.2.11" -+ -+check ovn-nbctl lsp-add ls1 ls1-to-cluster-router \ -+ -- lsp-set-type ls1-to-cluster-router router \ -+ -- lsp-set-options ls1-to-cluster-router router-port=cluster-router-to-ls1 \ -+ -- lsp-set-addresses ls1-to-cluster-router router -+ -+# Add cluster-router ports -+check ovn-nbctl lrp-add cluster-router cluster-router-to-ls1 "00:00:00:0f:01:01" 10.244.2.1/24 \ -+ -- lrp-add cluster-router cluster-router-to-join "00:00:00:0f:02:01" 100.64.0.1/16 \ -+ -- lrp-set-gateway-chassis cluster-router-to-ls1 hv1 10 \ -+ -- --policy=src-ip lr-route-add cluster-router 10.244.2.0/24 100.64.0.3 -+ -+# Add join ports -+check ovn-nbctl lsp-add join join-to-cluster-router \ -+ -- lsp-set-type join-to-cluster-router router \ -+ -- lsp-set-options join-to-cluster-router router-port=cluster-router-to-join \ -+ -- lsp-set-addresses join-to-cluster-router router \ -+ -- lsp-add join join-to-gr1 \ -+ -- lsp-set-type join-to-gr1 router \ -+ -- lsp-set-options join-to-gr1 router-port=gr1-to-join \ -+ -- lsp-set-addresses join-to-gr1 router -+ -+check ovn-nbctl set logical_router gr1 options:lb_force_snat_ip=router_ip \ -+ -- set logical_router gr1 options:snat-ct-zone=0 \ -+ -- set logical_router gr1 options:dynamic_neigh_routers=true -+ -+# Add gr1 ports and set natting -+check ovn-nbctl lrp-add gr1 gr1-to-join "00:00:00:0f:02:03" 100.64.0.3/16 \ -+ -- lr-route-add gr1 10.244.0.0/16 100.64.0.1 \ -+ -- lr-nat-add gr1 snat 10.89.189.12 10.244.0.0/16 \ -+ -- lrp-add gr1 gr1-to-public1 "0a:0a:b6:fc:03:12" 10.89.189.12/24 \ -+ -- set logical_router gr1 options:chassis=hv1 -+ -+# Add public1 ports -+check ovn-nbctl lsp-add public1 public1-to-gr1 \ -+ -- lsp-set-type public1-to-gr1 router \ -+ -- lsp-set-options public1-to-gr1 router-port=gr1-to-public1 \ -+ -- lsp-set-addresses public1-to-gr1 router \ -+ -- lsp-add public1 ln1 \ -+ -- lsp-set-type ln1 localnet \ -+ -- lsp-set-options ln1 network_name=provider \ -+ -- lsp-set-addresses ln1 unknown -+ -+check ovn-nbctl --wait=hv sync -+ -+ADD_NAMESPACES(ns_ls1p1) -+ADD_VETH(ls1p1, ns_ls1p1, br-int, "10.244.2.11/24", "00:00:00:00:01:11", "10.244.2.1") -+ -+ADD_NAMESPACES(ns_ext1) -+ADD_VETH(ln1, ns_ext1, br-ex, "10.89.189.1/24", "0a:0a:b6:fc:03:01") -+ -+NS_CHECK_EXEC([ns_ls1p1], [ping -q -c 3 -i 0.3 -w 2 10.89.189.1 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+OVS_APP_EXIT_AND_WAIT([ovn-controller]) -+ -+as ovn-sb -+OVS_APP_EXIT_AND_WAIT([ovsdb-server]) -+ -+as ovn-nb -+OVS_APP_EXIT_AND_WAIT([ovsdb-server]) -+ -+as northd -+OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE]) -+ -+as -+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d -+/connection dropped.*/d"]) -+AT_CLEANUP -+]) -+ -+OVN_FOR_EACH_NORTHD([ -+AT_SETUP([ACL default_acl_drop]) -+AT_KEYWORDS([acl default_acl_drop]) -+ -+CHECK_CONNTRACK() -+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 -+ -+ovn-nbctl ls-add sw -+ -+# Logical port 'vm1' in switch 'sw'. -+ADD_NAMESPACES(vm1) -+ADD_VETH(vm1, vm1, br-int, "10.0.0.1/24", "f0:00:00:01:02:03", \ -+ "10.0.0.254") -+check ovn-nbctl lsp-add sw vm1 \ -+-- lsp-set-addresses vm1 "f0:00:00:01:02:03 10.0.0.1" -+ -+# Logical port 'vm2' in switch 'sw'. -+ADD_NAMESPACES(vm2) -+ADD_VETH(vm2, vm2, br-int, "10.0.0.2/24", "f0:00:00:01:02:05", \ -+"10.0.0.254") -+check ovn-nbctl lsp-add sw vm2 \ -+-- lsp-set-addresses vm2 "f0:00:00:01:02:05 10.0.0.2" -+ -+# Wait for ovn-controller to catch up. -+wait_for_ports_up -+check ovn-nbctl --wait=hv sync -+ -+AS_BOX([from-lport acl, default_acl_drop false]) -+check ovn-nbctl acl-del sw -+check ovn-nbctl set NB_Global . options:default_acl_drop=false \ -+ -- acl-add sw from-lport 20 "ip4 && icmp" allow-related \ -+ -- acl-add sw from-lport 10 "ip4" drop -+check ovn-nbctl --wait=hv sync -+ -+# 'vm1' should be able to ping 'vm2' directly. -+NS_CHECK_EXEC([vm1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.2 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+AS_BOX([from-lport acl, default_acl_drop true]) -+check ovn-nbctl acl-del sw -+check ovn-nbctl set NB_Global . options:default_acl_drop=true \ -+ -- acl-add sw from-lport 20 "ip4 && icmp" allow-related \ -+ -- acl-add sw from-lport 10 "arp" allow \ -+ -- --apply-after-lb acl-add sw from-lport 1 1 allow \ -+ -- acl-add sw to-lport 1 1 allow -+check ovn-nbctl --wait=hv sync -+ -+# 'vm1' should be able to ping 'vm2' directly. -+NS_CHECK_EXEC([vm1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.2 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+AS_BOX([from-lport acl, after LB, default_acl_drop false]) -+check ovn-nbctl acl-del sw -+check ovn-nbctl set NB_Global . options:default_acl_drop=false \ -+ -- --apply-after-lb acl-add sw from-lport 20 "ip4 && icmp" allow-related \ -+ -- --apply-after-lb acl-add sw from-lport 10 "ip4" drop -+check ovn-nbctl --wait=hv sync -+ -+# 'vm1' should be able to ping 'vm2' directly. -+NS_CHECK_EXEC([vm1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.2 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+AS_BOX([from-lport acl, after LB, default_acl_drop true]) -+check ovn-nbctl acl-del sw -+check ovn-nbctl set NB_Global . options:default_acl_drop=true \ -+ -- acl-add sw from-lport 1 1 allow \ -+ -- --apply-after-lb acl-add sw from-lport 20 "ip4 && icmp" allow-related \ -+ -- --apply-after-lb acl-add sw from-lport 20 "arp" allow-related \ -+ -- acl-add sw to-lport 1 1 allow -+check ovn-nbctl --wait=hv sync -+ -+# 'vm1' should be able to ping 'vm2' directly. -+NS_CHECK_EXEC([vm1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.2 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+AS_BOX([to-lport acl, default_acl_drop false]) -+check ovn-nbctl acl-del sw -+check ovn-nbctl set NB_Global . options:default_acl_drop=false \ -+ -- acl-add sw to-lport 20 "ip4 && icmp" allow-related \ -+ -- acl-add sw to-lport 10 "ip4" drop -+check ovn-nbctl --wait=hv sync -+ -+# 'vm1' should be able to ping 'vm2' directly. -+NS_CHECK_EXEC([vm1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.2 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+AS_BOX([to-lport acl, default_acl_drop true]) -+check ovn-nbctl acl-del sw -+check ovn-nbctl set NB_Global . options:default_acl_drop=true \ -+ -- acl-add sw from-lport 1 1 allow \ -+ -- --apply-after-lb acl-add sw from-lport 1 1 allow \ -+ -- acl-add sw to-lport 20 "ip4 && icmp" allow-related \ -+ -- acl-add sw to-lport 20 "arp" allow -+check ovn-nbctl --wait=hv sync -+ -+# 'vm1' should be able to ping 'vm2' directly. -+NS_CHECK_EXEC([vm1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.2 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+OVS_APP_EXIT_AND_WAIT([ovn-controller]) -+ -+as ovn-sb -+OVS_APP_EXIT_AND_WAIT([ovsdb-server]) -+ -+as ovn-nb -+OVS_APP_EXIT_AND_WAIT([ovsdb-server]) -+ -+as northd -+OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE]) -+ -+as -+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d -+/connection dropped.*/d"]) -+AT_CLEANUP -+]) -diff --git a/utilities/ovn-dbctl.c b/utilities/ovn-dbctl.c -index a850c2f31..5edb82e7f 100644 ---- a/utilities/ovn-dbctl.c -+++ b/utilities/ovn-dbctl.c -@@ -109,6 +109,15 @@ static void server_loop(const struct ovn_dbctl_options *dbctl_options, - struct ovsdb_idl *idl, int argc, char *argv[]); - static void ovn_dbctl_exit(int status); - -+static void -+destroy_argv(int argc, char **argv) -+{ -+ for (int i = 0; i < argc; i++) { -+ free(argv[i]); -+ } -+ free(argv); -+} -+ - int - ovn_dbctl_main(int argc, char *argv[], - const struct ovn_dbctl_options *dbctl_options) -@@ -151,6 +160,7 @@ ovn_dbctl_main(int argc, char *argv[], - char *error_s = ovs_cmdl_parse_all(argc, argv_, get_all_options(), - &parsed_options, &n_parsed_options); - if (error_s) { -+ destroy_argv(argc, argv_); - ctl_fatal("%s", error_s); - } - -@@ -179,6 +189,7 @@ ovn_dbctl_main(int argc, char *argv[], - bool daemon_mode = false; - if (get_detach()) { - if (argc != optind) { -+ destroy_argv(argc, argv_); - ctl_fatal("non-option arguments not supported with --detach " - "(use --help for help)"); - } -@@ -204,11 +215,8 @@ ovn_dbctl_main(int argc, char *argv[], - if (error) { - ovsdb_idl_destroy(idl); - idl = the_idl = NULL; -+ destroy_argv(argc, argv_); - -- for (int i = 0; i < argc; i++) { -- free(argv_[i]); -- } -- free(argv_); - ctl_fatal("%s", error); - } - -@@ -237,21 +245,15 @@ cleanup: - } - free(commands); - if (error) { -- for (int i = 0; i < argc; i++) { -- free(argv_[i]); -- } -- free(argv_); -+ destroy_argv(argc, argv_); - ctl_fatal("%s", error); - } - } - - ovsdb_idl_destroy(idl); - idl = the_idl = NULL; -+ destroy_argv(argc, argv_); - -- for (int i = 0; i < argc; i++) { -- free(argv_[i]); -- } -- free(argv_); - exit(EXIT_SUCCESS); - } - -@@ -1238,40 +1240,53 @@ dbctl_client(const struct ovn_dbctl_options *dbctl_options, - - ctl_timeout_setup(timeout); - -+ char *cmd_result = NULL; -+ char *cmd_error = NULL; - struct jsonrpc *client; -+ int exit_status; -+ char *error_str; -+ - int error = unixctl_client_create(socket_name, &client); - if (error) { -- ctl_fatal("%s: could not connect to %s daemon (%s); " -- "unset %s to avoid using daemon", -- socket_name, program_name, ovs_strerror(error), -- dbctl_options->daemon_env_var_name); -+ error_str = xasprintf("%s: could not connect to %s daemon (%s); " -+ "unset %s to avoid using daemon", -+ socket_name, program_name, ovs_strerror(error), -+ dbctl_options->daemon_env_var_name); -+ goto log_error; - } - -- char *cmd_result; -- char *cmd_error; - error = unixctl_client_transact(client, "run", - args.n, args.names, - &cmd_result, &cmd_error); - if (error) { -- ctl_fatal("%s: transaction error (%s)", -- socket_name, ovs_strerror(error)); -+ error_str = xasprintf("%s: transaction error (%s)", -+ socket_name, ovs_strerror(error)); -+ goto log_error; - } -- svec_destroy(&args); - -- int exit_status; - if (cmd_error) { -- exit_status = EXIT_FAILURE; - fprintf(stderr, "%s: %s", program_name, cmd_error); -- } else { -- exit_status = EXIT_SUCCESS; -- fputs(cmd_result, stdout); -+ goto error; - } -+ -+ exit_status = EXIT_SUCCESS; -+ fputs(cmd_result, stdout); -+ goto cleanup; -+ -+log_error: -+ VLOG_ERR("%s", error_str); -+ ovs_error(0, "%s", error_str); -+ free(error_str); -+ -+error: -+ exit_status = EXIT_FAILURE; -+ -+cleanup: - free(cmd_result); - free(cmd_error); - jsonrpc_close(client); -- for (int i = 0; i < argc; i++) { -- free(argv[i]); -- } -- free(argv); -+ svec_destroy(&args); -+ destroy_argv(argc, argv); -+ - exit(exit_status); - } -diff --git a/utilities/ovn-nbctl.8.xml b/utilities/ovn-nbctl.8.xml -index 92e10c012..72d4088f0 100644 ---- a/utilities/ovn-nbctl.8.xml -+++ b/utilities/ovn-nbctl.8.xml -@@ -814,7 +814,7 @@ - Attaches the mirror m to the logical port port. - - --
    lsp-dettach-mirror port m
    -+
    lsp-detach-mirror port m
    -
    - Detaches the mirror m from the logical port port. -
    -diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c -index 07ebac5e5..e5766ed67 100644 ---- a/utilities/ovn-trace.c -+++ b/utilities/ovn-trace.c -@@ -1486,9 +1486,8 @@ ovntrace_node_prune_hard(struct ovs_list *nodes) - } - - static void --execute_load(const struct ovnact_load *load, -- const struct ovntrace_datapath *dp, struct flow *uflow, -- struct ovs_list *super OVS_UNUSED) -+execute_load(const struct ovnact *ovnact, const struct ovntrace_datapath *dp, -+ struct flow *uflow, struct ovs_list *super OVS_UNUSED) - { - const struct ovnact_encode_params ep = { - .lookup_port = ovntrace_lookup_port, -@@ -1498,7 +1497,7 @@ execute_load(const struct ovnact_load *load, - uint64_t stub[512 / 8]; - struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(stub); - -- ovnacts_encode(&load->ovnact, sizeof *load, &ep, &ofpacts); -+ ovnacts_encode(ovnact, OVNACT_ALIGN(ovnact->len), &ep, &ofpacts); - - struct ofpact *a; - OFPACT_FOR_EACH (a, ofpacts.data, ofpacts.size) { -@@ -1506,12 +1505,11 @@ execute_load(const struct ovnact_load *load, - - if (!mf_is_register(sf->field->id)) { - struct ds s = DS_EMPTY_INITIALIZER; -- ovnacts_format(&load->ovnact, OVNACT_LOAD_SIZE, &s); -- ds_chomp(&s, ';'); - -- char *friendly = ovntrace_make_names_friendly(ds_cstr(&s)); -- ovntrace_node_append(super, OVNTRACE_NODE_MODIFY, "%s", friendly); -- free(friendly); -+ ovnacts_format(ovnact, OVNACT_ALIGN(ovnact->len), &s); -+ ds_chomp(&s, ';'); -+ ovntrace_node_append(super, OVNTRACE_NODE_MODIFY, "%s", -+ ds_cstr(&s)); - - ds_destroy(&s); - } -@@ -3057,7 +3055,7 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len, - const struct ovnact *a; - OVNACT_FOR_EACH (a, ovnacts, ovnacts_len) { - ds_clear(&s); -- ovnacts_format(a, sizeof *a * (ovnact_next(a) - a), &s); -+ ovnacts_format(a, OVNACT_ALIGN(a->len), &s); - char *friendly = ovntrace_make_names_friendly(ds_cstr(&s)); - ovntrace_node_append(super, OVNTRACE_NODE_ACTION, "%s", friendly); - free(friendly); -@@ -3072,7 +3070,7 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len, - break; - - case OVNACT_LOAD: -- execute_load(ovnact_get_LOAD(a), dp, uflow, super); -+ execute_load(a, dp, uflow, super); - break; - - case OVNACT_MOVE: diff --git a/SOURCES/ovn23.03.patch b/SOURCES/ovn23.03.patch new file mode 100644 index 0000000..c66abc6 --- /dev/null +++ b/SOURCES/ovn23.03.patch @@ -0,0 +1,7003 @@ +diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml +index 0f8d9d193..edf4fb2fd 100644 +--- a/.github/workflows/test.yml ++++ b/.github/workflows/test.yml +@@ -17,7 +17,8 @@ jobs: + dependencies: | + automake libtool gcc bc libjemalloc2 libjemalloc-dev \ + libssl-dev llvm-dev libelf-dev libnuma-dev libpcap-dev \ +- selinux-policy-dev ncat python3-scapy isc-dhcp-server ++ selinux-policy-dev ncat python3-scapy isc-dhcp-server \ ++ iputils-arping + m32_dependecies: gcc-multilib + ARCH: ${{ matrix.cfg.arch }} + CC: ${{ matrix.cfg.compiler }} +diff --git a/NEWS b/NEWS +index 5e8aed06d..60c460a05 100644 +--- a/NEWS ++++ b/NEWS +@@ -1,3 +1,11 @@ ++OVN v23.03.1 - xx xxx xxxx ++-------------------------- ++ - CT entries are not flushed by default anymore whenever a load balancer ++ backend is removed. A new, per-LB, option 'ct_flush' can be used to ++ restore the previous behavior. Disabled by default. ++ - Always allow IPv6 Router Discovery, Neighbor Discovery, and Multicast ++ Listener Discovery protocols, regardless of ACLs defined. ++ + OVN v23.03.0 - 03 Mar 2023 + -------------------------- + - ovn-controller: Experimental support for co-hosting multiple controller +diff --git a/configure.ac b/configure.ac +index b51d0f01e..0ba9e8d7e 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -13,7 +13,7 @@ + # limitations under the License. + + AC_PREREQ(2.63) +-AC_INIT(ovn, 23.03.0, bugs@openvswitch.org) ++AC_INIT(ovn, 23.03.1, bugs@openvswitch.org) + AC_CONFIG_MACRO_DIR([m4]) + AC_CONFIG_AUX_DIR([build-aux]) + AC_CONFIG_HEADERS([config.h]) +diff --git a/controller/binding.c b/controller/binding.c +index 5df62baef..bd810f669 100644 +--- a/controller/binding.c ++++ b/controller/binding.c +@@ -746,6 +746,19 @@ local_binding_get_lport_ofport(const struct shash *local_bindings, + u16_to_ofp(lbinding->iface->ofport[0]) : 0; + } + ++bool ++local_binding_is_ovn_installed(struct shash *local_bindings, ++ const char *pb_name) ++{ ++ struct local_binding *lbinding = ++ local_binding_find(local_bindings, pb_name); ++ if (lbinding && lbinding->iface) { ++ return smap_get_bool(&lbinding->iface->external_ids, ++ OVN_INSTALLED_EXT_ID, false); ++ } ++ return false; ++} ++ + bool + local_binding_is_up(struct shash *local_bindings, const char *pb_name, + const struct sbrec_chassis *chassis_rec) +@@ -783,6 +796,7 @@ local_binding_is_down(struct shash *local_bindings, const char *pb_name, + } else if (b_lport->pb->chassis) { + VLOG_DBG("lport %s already claimed by other chassis", + b_lport->pb->logical_port); ++ return true; + } + } + +@@ -834,6 +848,38 @@ local_binding_set_up(struct shash *local_bindings, const char *pb_name, + } + } + ++void ++local_binding_remove_ovn_installed( ++ struct shash *local_bindings, ++ const struct ovsrec_interface_table *iface_table, ++ const char *pb_name, bool ovs_readonly) ++{ ++ if (ovs_readonly) { ++ return; ++ } ++ struct local_binding *lbinding = ++ local_binding_find(local_bindings, pb_name); ++ if (lbinding && lbinding->iface) { ++ const struct uuid *iface_uuid = &lbinding->iface->header_.uuid; ++ remove_ovn_installed_for_uuid(iface_table, iface_uuid); ++ } ++} ++ ++void ++remove_ovn_installed_for_uuid(const struct ovsrec_interface_table *iface_table, ++ const struct uuid *iface_uuid) ++{ ++ const struct ovsrec_interface *iface_rec = ++ ovsrec_interface_table_get_for_uuid(iface_table, iface_uuid); ++ if (iface_rec && smap_get_bool(&iface_rec->external_ids, ++ OVN_INSTALLED_EXT_ID, false)) { ++ VLOG_INFO("Removing iface %s ovn-installed in OVS", ++ iface_rec->name); ++ ovsrec_interface_update_external_ids_delkey(iface_rec, ++ OVN_INSTALLED_EXT_ID); ++ } ++} ++ + void + local_binding_set_down(struct shash *local_bindings, const char *pb_name, + const struct sbrec_chassis *chassis_rec, +@@ -853,7 +899,6 @@ local_binding_set_down(struct shash *local_bindings, const char *pb_name, + + if (!sb_readonly && b_lport && b_lport->pb->n_up && b_lport->pb->up[0] && + (!b_lport->pb->chassis || b_lport->pb->chassis == chassis_rec)) { +- VLOG_INFO("Setting lport %s down in Southbound", pb_name); + binding_lport_set_down(b_lport, sb_readonly); + LIST_FOR_EACH (b_lport, list_node, &lbinding->binding_lports) { + binding_lport_set_down(b_lport, sb_readonly); +@@ -1239,7 +1284,9 @@ claim_lport(const struct sbrec_port_binding *pb, + return false; + } + } else { +- if (pb->n_up && !pb->up[0]) { ++ if ((pb->n_up && !pb->up[0]) || ++ !smap_get_bool(&iface_rec->external_ids, ++ OVN_INSTALLED_EXT_ID, false)) { + if_status_mgr_claim_iface(if_mgr, pb, chassis_rec, + sb_readonly); + } +@@ -1464,9 +1511,11 @@ consider_vif_lport_(const struct sbrec_port_binding *pb, + const char *requested_chassis_option = smap_get( + &pb->options, "requested-chassis"); + VLOG_INFO_RL(&rl, +- "Not claiming lport %s, chassis %s requested-chassis %s", ++ "Not claiming lport %s, chassis %s requested-chassis %s " ++ "pb->chassis %s", + pb->logical_port, b_ctx_in->chassis_rec->name, +- requested_chassis_option ? requested_chassis_option : "[]"); ++ requested_chassis_option ? requested_chassis_option : "[]", ++ pb->chassis ? pb->chassis->name: ""); + } + } + +@@ -2288,6 +2337,11 @@ consider_iface_release(const struct ovsrec_interface *iface_rec, + return false; + } + } ++ if (lbinding->iface && lbinding->iface->name) { ++ if_status_mgr_remove_ovn_installed(b_ctx_out->if_mgr, ++ lbinding->iface->name, ++ &lbinding->iface->header_.uuid); ++ } + + } else if (lbinding && b_lport && b_lport->type == LP_LOCALPORT) { + /* lbinding is associated with a localport. Remove it from the +@@ -2558,6 +2612,7 @@ handle_deleted_lport(const struct sbrec_port_binding *pb, + if (ld) { + remove_pb_from_local_datapath(pb, + b_ctx_out, ld); ++ if_status_mgr_release_iface(b_ctx_out->if_mgr, pb->logical_port); + return; + } + +@@ -2581,6 +2636,7 @@ handle_deleted_lport(const struct sbrec_port_binding *pb, + remove_pb_from_local_datapath(pb, b_ctx_out, + ld); + } ++ if_status_mgr_release_iface(b_ctx_out->if_mgr, pb->logical_port); + } + } + +@@ -2627,6 +2683,11 @@ handle_deleted_vif_lport(const struct sbrec_port_binding *pb, + } + + handle_deleted_lport(pb, b_ctx_in, b_ctx_out); ++ if (lbinding && lbinding->iface && lbinding->iface->name) { ++ if_status_mgr_remove_ovn_installed(b_ctx_out->if_mgr, ++ lbinding->iface->name, ++ &lbinding->iface->header_.uuid); ++ } + return true; + } + +@@ -3314,6 +3375,24 @@ binding_lport_delete(struct shash *binding_lports, + binding_lport_destroy(b_lport); + } + ++void ++port_binding_set_down(const struct sbrec_chassis *chassis_rec, ++ const struct sbrec_port_binding_table *pb_table, ++ const char *iface_id, ++ const struct uuid *pb_uuid) ++{ ++ const struct sbrec_port_binding *pb = ++ sbrec_port_binding_table_get_for_uuid(pb_table, pb_uuid); ++ if (!pb) { ++ VLOG_DBG("port_binding already deleted for %s", iface_id); ++ } else if (pb->n_up && pb->up[0]) { ++ bool up = false; ++ sbrec_port_binding_set_up(pb, &up, 1); ++ VLOG_INFO("Setting lport %s down in Southbound", pb->logical_port); ++ set_pb_chassis_in_sbrec(pb, chassis_rec, false); ++ } ++} ++ + static void + binding_lport_set_up(struct binding_lport *b_lport, bool sb_readonly) + { +@@ -3331,6 +3410,7 @@ binding_lport_set_down(struct binding_lport *b_lport, bool sb_readonly) + if (sb_readonly || !b_lport || !b_lport->pb->n_up || !b_lport->pb->up[0]) { + return; + } ++ VLOG_INFO("Setting lport %s down in Southbound", b_lport->name); + + bool up = false; + sbrec_port_binding_set_up(b_lport->pb, &up, 1); +diff --git a/controller/binding.h b/controller/binding.h +index 6c3a98b02..5b73c6a4b 100644 +--- a/controller/binding.h ++++ b/controller/binding.h +@@ -159,6 +159,14 @@ bool local_binding_is_up(struct shash *local_bindings, const char *pb_name, + bool local_binding_is_down(struct shash *local_bindings, const char *pb_name, + const struct sbrec_chassis *); + ++bool local_binding_is_ovn_installed(struct shash *local_bindings, ++ const char *pb_name); ++void local_binding_remove_ovn_installed( ++ struct shash *local_bindings, ++ const struct ovsrec_interface_table *iface_table, ++ const char *pb_name, ++ bool ovs_readonly); ++ + void local_binding_set_up(struct shash *local_bindings, const char *pb_name, + const struct sbrec_chassis *chassis_rec, + const char *ts_now_str, bool sb_readonly, +@@ -195,6 +203,14 @@ void set_pb_chassis_in_sbrec(const struct sbrec_port_binding *pb, + const struct sbrec_chassis *chassis_rec, + bool is_set); + ++void remove_ovn_installed_for_uuid(const struct ovsrec_interface_table *, ++ const struct uuid *); ++ ++void port_binding_set_down(const struct sbrec_chassis *chassis_rec, ++ const struct sbrec_port_binding_table *pb_table, ++ const char *iface_id, ++ const struct uuid *pb_uuid); ++ + /* Corresponds to each Port_Binding.type. */ + enum en_lport_type { + LP_UNKNOWN, +diff --git a/controller/encaps.c b/controller/encaps.c +index 2662eaf98..b69d72584 100644 +--- a/controller/encaps.c ++++ b/controller/encaps.c +@@ -36,6 +36,8 @@ VLOG_DEFINE_THIS_MODULE(encaps); + */ + #define OVN_MVTEP_CHASSISID_DELIM '@' + ++static char *current_br_int_name = NULL; ++ + void + encaps_register_ovs_idl(struct ovsdb_idl *ovs_idl) + { +@@ -386,6 +388,21 @@ chassis_tzones_overlap(const struct sset *transport_zones, + return false; + } + ++static void ++clear_old_tunnels(const struct ovsrec_bridge *old_br_int, const char *prefix, ++ size_t prefix_len) ++{ ++ for (size_t i = 0; i < old_br_int->n_ports; i++) { ++ const struct ovsrec_port *port = old_br_int->ports[i]; ++ const char *id = smap_get(&port->external_ids, "ovn-chassis-id"); ++ if (id && !strncmp(port->name, prefix, prefix_len)) { ++ VLOG_DBG("Clearing old tunnel port \"%s\" (%s) from bridge " ++ "\"%s\".", port->name, id, old_br_int->name); ++ ovsrec_bridge_update_ports_delvalue(old_br_int, port); ++ } ++ } ++} ++ + void + encaps_run(struct ovsdb_idl_txn *ovs_idl_txn, + const struct ovsrec_bridge *br_int, +@@ -393,12 +410,42 @@ encaps_run(struct ovsdb_idl_txn *ovs_idl_txn, + const struct sbrec_chassis *this_chassis, + const struct sbrec_sb_global *sbg, + const struct ovsrec_open_vswitch_table *ovs_table, +- const struct sset *transport_zones) ++ const struct sset *transport_zones, ++ const struct ovsrec_bridge_table *bridge_table) + { + if (!ovs_idl_txn || !br_int) { + return; + } + ++ if (!current_br_int_name) { ++ /* The controller has just started, we need to look through all ++ * bridges for old tunnel ports. */ ++ char *tunnel_prefix = xasprintf("ovn%s-", get_chassis_idx(ovs_table)); ++ size_t prefix_len = strlen(tunnel_prefix); ++ ++ const struct ovsrec_bridge *br; ++ OVSREC_BRIDGE_TABLE_FOR_EACH (br, bridge_table) { ++ if (!strcmp(br->name, br_int->name)) { ++ continue; ++ } ++ clear_old_tunnels(br, tunnel_prefix, prefix_len); ++ } ++ ++ free(tunnel_prefix); ++ current_br_int_name = xstrdup(br_int->name); ++ } else if (strcmp(current_br_int_name, br_int->name)) { ++ /* The integration bridge was changed, clear tunnel ports from ++ * the old one. */ ++ const struct ovsrec_bridge *old_br_int = ++ get_bridge(bridge_table, current_br_int_name); ++ if (old_br_int) { ++ clear_old_tunnels(old_br_int, "", 0); ++ } ++ ++ free(current_br_int_name); ++ current_br_int_name = xstrdup(br_int->name); ++ } ++ + const struct sbrec_chassis *chassis_rec; + + struct tunnel_ctx tc = { +@@ -511,3 +558,9 @@ encaps_cleanup(struct ovsdb_idl_txn *ovs_idl_txn, + + return !any_changes; + } ++ ++void ++encaps_destroy(void) ++{ ++ free(current_br_int_name); ++} +diff --git a/controller/encaps.h b/controller/encaps.h +index 867c6f28c..3e58b3c82 100644 +--- a/controller/encaps.h ++++ b/controller/encaps.h +@@ -35,7 +35,8 @@ void encaps_run(struct ovsdb_idl_txn *ovs_idl_txn, + const struct sbrec_chassis *, + const struct sbrec_sb_global *, + const struct ovsrec_open_vswitch_table *, +- const struct sset *transport_zones); ++ const struct sset *transport_zones, ++ const struct ovsrec_bridge_table *bridge_table); + + bool encaps_cleanup(struct ovsdb_idl_txn *ovs_idl_txn, + const struct ovsrec_bridge *br_int); +@@ -46,4 +47,6 @@ bool encaps_tunnel_id_parse(const char *tunnel_id, char **chassis_id, + bool encaps_tunnel_id_match(const char *tunnel_id, const char *chassis_id, + const char *encap_ip); + ++void encaps_destroy(void); ++ + #endif /* controller/encaps.h */ +diff --git a/controller/if-status.c b/controller/if-status.c +index d1c14ac30..8503e5daa 100644 +--- a/controller/if-status.c ++++ b/controller/if-status.c +@@ -54,44 +54,54 @@ VLOG_DEFINE_THIS_MODULE(if_status); + */ + + enum if_state { +- OIF_CLAIMED, /* Newly claimed interface. pb->chassis update not yet +- initiated. */ +- OIF_INSTALL_FLOWS, /* Claimed interface with pb->chassis update sent to +- * SB (but update notification not confirmed, so the +- * update may be resent in any of the following states) +- * and for which flows are still being installed. +- */ +- OIF_MARK_UP, /* Interface with flows successfully installed in OVS +- * but not yet marked "up" in the binding module (in +- * SB and OVS databases). +- */ +- OIF_MARK_DOWN, /* Released interface but not yet marked "down" in the +- * binding module (in SB and/or OVS databases). +- */ +- OIF_INSTALLED, /* Interface flows programmed in OVS and binding marked +- * "up" in the binding module. +- */ ++ OIF_CLAIMED, /* Newly claimed interface. pb->chassis update not ++ yet initiated. */ ++ OIF_INSTALL_FLOWS, /* Claimed interface with pb->chassis update sent to ++ * SB (but update notification not confirmed, so the ++ * update may be resent in any of the following ++ * states and for which flows are still being ++ * installed. ++ */ ++ OIF_REM_OLD_OVN_INST, /* Interface with flows successfully installed in OVS ++ * but with ovn-installed still in OVSDB. ++ */ ++ OIF_MARK_UP, /* Interface with flows successfully installed in OVS ++ * but not yet marked "up" in the binding module (in ++ * SB and OVS databases). ++ */ ++ OIF_MARK_DOWN, /* Released interface but not yet marked "down" in ++ * the binding module (in SB and/or OVS databases). ++ */ ++ OIF_INSTALLED, /* Interface flows programmed in OVS and binding ++ * marked "up" in the binding module. ++ */ ++ OIF_UPDATE_PORT, /* Logical ports need to be set down, and pb->chassis ++ * removed. ++ */ + OIF_MAX, + }; + + static const char *if_state_names[] = { +- [OIF_CLAIMED] = "CLAIMED", +- [OIF_INSTALL_FLOWS] = "INSTALL_FLOWS", +- [OIF_MARK_UP] = "MARK_UP", +- [OIF_MARK_DOWN] = "MARK_DOWN", +- [OIF_INSTALLED] = "INSTALLED", ++ [OIF_CLAIMED] = "CLAIMED", ++ [OIF_INSTALL_FLOWS] = "INSTALL_FLOWS", ++ [OIF_REM_OLD_OVN_INST] = "REM_OLD_OVN_INST", ++ [OIF_MARK_UP] = "MARK_UP", ++ [OIF_MARK_DOWN] = "MARK_DOWN", ++ [OIF_INSTALLED] = "INSTALLED", ++ [OIF_UPDATE_PORT] = "UPDATE_PORT", + }; + + /* + * +----------------------+ + * +---> | | +- * | +-> | NULL | <--------------------------------------+++-+ +- * | | +----------------------+ | +- * | | ^ release_iface | claim_iface() | +- * | | | V - sbrec_update_chassis(if sb is rw) | +- * | | +----------------------+ | +- * | | | | <----------------------------------------+ | +- * | | | CLAIMED | <--------------------------------------+ | | ++ * | +-> | NULL | ++ * | | +----------------------+ ++ * | | ^ release_iface | claim_iface() ++ * | | | V - sbrec_update_chassis(if sb is rw) ++ * | | +----------------------+ ++ * | | | | <------------------------------------------+ ++ * | | | CLAIMED | <----------------------------------------+ | ++ * | | | | <--------------------------------------+ | | + * | | +----------------------+ | | | + * | | | V ^ | | | + * | | | | | handle_claims() | | | +@@ -109,38 +119,63 @@ static const char *if_state_names[] = { + * | | | - remove ovn-installed from ovsdb | | | + * | | | mgr_update() | | | + * | +----------------------+ - sbrec_update_chassis if needed | | | +- * | | | | | +- * | | mgr_run(seqno rcvd) | | | +- * | | - set port up in sb | | | +- * | release_iface | - set ovn-installed in ovs | | | +- * | V | | | ++ * | | | | | | ++ * | | +----------------------------------------+ | | | ++ * | | | | | | ++ * | | mgr_run(seqno rcvd, ovn-installed present) | | | | ++ * | V | | | | ++ * | +--------------------+ | | | | ++ * | | | mgr_run() | | | | ++ * +--- | REM_OLD_OVN_INST | - remove ovn-installed in ovs | | | | ++ * | +--------------------+ | | | | ++ * | | | | | | ++ * | | | | | | ++ * | | mgr_update( ovn_installed not present) | | | | ++ * | | | | | | ++ * | | +-------------------------------------------+ | | | ++ * | | | | | | ++ * | | | mgr_run(seqno rcvd, ovn-installed not present) | | | ++ * | | | - set port up in sb | | | ++ * | | | - set ovn-installed in ovs | | | ++ * |release_iface | | | | | ++ * | V V | | | + * | +----------------------+ | | | + * | | | mgr_run() | | | +- * +-- | MARK_UP | - set port up in sb | | | +- * | | - set ovn-installed in ovs | | | +- * | | mgr_update() | | | +- * +----------------------+ - sbrec_update_chassis if needed | | | +- * | | | | +- * | mgr_update(rcvd port up / ovn_installed & chassis set) | | | +- * V | | | +- * +----------------------+ | | | +- * | INSTALLED | ------------> claim_iface ---------------+ | | +- * +----------------------+ | | +- * | | | +- * | release_iface | | +- * V | | +- * +----------------------+ | | +- * | | ------------> claim_iface -----------------+ | +- * | MARK_DOWN | ------> mgr_update(rcvd port down) ----------+ +- * | | mgr_run() +- * | | - set port down in sb +- * | | mgr_update() ++ * +---| MARK_UP | - set port up in sb | | | ++ * | | | - set ovn-installed in ovs | | | ++ * | | | mgr_update() | | | ++ * | +----------------------+ - sbrec_update_chassis if needed | | | ++ * | | | | | ++ * | | mgr_update(rcvd port up / ovn_installed & chassis set) | | | ++ * | V | | | ++ * | +----------------------+ | | | ++ * | | INSTALLED | ------------> claim_iface ---------------+ | | ++ * | +----------------------+ | | ++ * | | | | ++ * | | release_iface | | ++ * |mgr_update( | | | ++ * | rcvd port down) | | | ++ * | V | | ++ * | +----------------------+ | | ++ * | | | ------------> claim_iface -----------------+ | ++ * +---+ MARK_DOWN | mgr_run() | ++ * | | | - set port down in sb | ++ * | | | mgr_update(sb is rw) | ++ * | +----------------------+ - sbrec_update_chassis(NULL) | ++ * | | | ++ * | | mgr_update(local binding not found) | ++ * | | | ++ * | V | ++ * | +----------------------+ | ++ * | | | ------------> claim_iface -------------------+ ++ * +---+ UPDATE_PORT | mgr_run() + * +----------------------+ - sbrec_update_chassis(NULL) + */ + + + struct ovs_iface { + char *id; /* Extracted from OVS external_ids.iface_id. */ ++ struct uuid pb_uuid; /* Port_binding uuid */ + enum if_state state; /* State of the interface in the state machine. */ + uint32_t install_seqno; /* Seqno at which this interface is expected to + * be fully programmed in OVS. Only used in state +@@ -155,6 +190,9 @@ struct if_status_mgr { + /* All local interfaces, mapping from 'iface-id' to 'struct ovs_iface'. */ + struct shash ifaces; + ++ /* local interfaces which need ovn-install removal */ ++ struct shash ovn_uninstall_hash; ++ + /* All local interfaces, stored per state. */ + struct hmapx ifaces_per_state[OIF_MAX]; + +@@ -170,15 +208,20 @@ struct if_status_mgr { + static struct ovs_iface *ovs_iface_create(struct if_status_mgr *, + const char *iface_id, + enum if_state ); ++static void add_to_ovn_uninstall_hash(struct if_status_mgr *, const char *, ++ const struct uuid *); + static void ovs_iface_destroy(struct if_status_mgr *, struct ovs_iface *); ++static void ovn_uninstall_hash_destroy(struct if_status_mgr *mgr, char *name); + static void ovs_iface_set_state(struct if_status_mgr *, struct ovs_iface *, + enum if_state); + + static void if_status_mgr_update_bindings( + struct if_status_mgr *mgr, struct local_binding_data *binding_data, + const struct sbrec_chassis *, ++ const struct ovsrec_interface_table *iface_table, + bool sb_readonly, bool ovs_readonly); + ++static void ovn_uninstall_hash_account_mem(const char *name, bool erase); + struct if_status_mgr * + if_status_mgr_create(void) + { +@@ -189,6 +232,7 @@ if_status_mgr_create(void) + hmapx_init(&mgr->ifaces_per_state[i]); + } + shash_init(&mgr->ifaces); ++ shash_init(&mgr->ovn_uninstall_hash); + return mgr; + } + +@@ -202,6 +246,11 @@ if_status_mgr_clear(struct if_status_mgr *mgr) + } + ovs_assert(shash_is_empty(&mgr->ifaces)); + ++ SHASH_FOR_EACH_SAFE (node, &mgr->ovn_uninstall_hash) { ++ ovn_uninstall_hash_destroy(mgr, node->data); ++ } ++ ovs_assert(shash_is_empty(&mgr->ovn_uninstall_hash)); ++ + for (size_t i = 0; i < ARRAY_SIZE(mgr->ifaces_per_state); i++) { + ovs_assert(hmapx_is_empty(&mgr->ifaces_per_state[i])); + } +@@ -212,6 +261,7 @@ if_status_mgr_destroy(struct if_status_mgr *mgr) + { + if_status_mgr_clear(mgr); + shash_destroy(&mgr->ifaces); ++ shash_destroy(&mgr->ovn_uninstall_hash); + for (size_t i = 0; i < ARRAY_SIZE(mgr->ifaces_per_state); i++) { + hmapx_destroy(&mgr->ifaces_per_state[i]); + } +@@ -231,6 +281,7 @@ if_status_mgr_claim_iface(struct if_status_mgr *mgr, + iface = ovs_iface_create(mgr, iface_id, OIF_CLAIMED); + } + ++ memcpy(&iface->pb_uuid, &pb->header_.uuid, sizeof(iface->pb_uuid)); + if (!sb_readonly) { + set_pb_chassis_in_sbrec(pb, chassis_rec, true); + } +@@ -238,11 +289,13 @@ if_status_mgr_claim_iface(struct if_status_mgr *mgr, + switch (iface->state) { + case OIF_CLAIMED: + case OIF_INSTALL_FLOWS: ++ case OIF_REM_OLD_OVN_INST: + case OIF_MARK_UP: + /* Nothing to do here. */ + break; + case OIF_INSTALLED: + case OIF_MARK_DOWN: ++ case OIF_UPDATE_PORT: + ovs_iface_set_state(mgr, iface, OIF_CLAIMED); + break; + case OIF_MAX: +@@ -271,9 +324,10 @@ if_status_mgr_release_iface(struct if_status_mgr *mgr, const char *iface_id) + switch (iface->state) { + case OIF_CLAIMED: + case OIF_INSTALL_FLOWS: +- /* Not yet fully installed interfaces can be safely deleted. */ +- ovs_iface_destroy(mgr, iface); +- break; ++ /* Not yet fully installed interfaces: ++ * pb->chassis still need to be deleted. ++ */ ++ case OIF_REM_OLD_OVN_INST: + case OIF_MARK_UP: + case OIF_INSTALLED: + /* Properly mark interfaces "down" if their flows were already +@@ -282,6 +336,7 @@ if_status_mgr_release_iface(struct if_status_mgr *mgr, const char *iface_id) + ovs_iface_set_state(mgr, iface, OIF_MARK_DOWN); + break; + case OIF_MARK_DOWN: ++ case OIF_UPDATE_PORT: + /* Nothing to do here. */ + break; + case OIF_MAX: +@@ -302,9 +357,10 @@ if_status_mgr_delete_iface(struct if_status_mgr *mgr, const char *iface_id) + switch (iface->state) { + case OIF_CLAIMED: + case OIF_INSTALL_FLOWS: +- /* Not yet fully installed interfaces can be safely deleted. */ +- ovs_iface_destroy(mgr, iface); +- break; ++ /* Not yet fully installed interfaces: ++ * pb->chassis still need to be deleted. ++ */ ++ case OIF_REM_OLD_OVN_INST: + case OIF_MARK_UP: + case OIF_INSTALLED: + /* Properly mark interfaces "down" if their flows were already +@@ -313,6 +369,7 @@ if_status_mgr_delete_iface(struct if_status_mgr *mgr, const char *iface_id) + ovs_iface_set_state(mgr, iface, OIF_MARK_DOWN); + break; + case OIF_MARK_DOWN: ++ case OIF_UPDATE_PORT: + /* Nothing to do here. */ + break; + case OIF_MAX: +@@ -346,12 +403,34 @@ if_status_handle_claims(struct if_status_mgr *mgr, + return rc; + } + ++static void ++clean_ovn_installed(struct if_status_mgr *mgr, ++ const struct ovsrec_interface_table *iface_table) ++{ ++ struct shash_node *node; ++ ++ SHASH_FOR_EACH_SAFE (node, &mgr->ovn_uninstall_hash) { ++ const struct uuid *iface_uuid = node->data; ++ remove_ovn_installed_for_uuid(iface_table, iface_uuid); ++ free(node->data); ++ char *node_name = shash_steal(&mgr->ovn_uninstall_hash, node); ++ ovn_uninstall_hash_account_mem(node_name, true); ++ free(node_name); ++ } ++} ++ + void + if_status_mgr_update(struct if_status_mgr *mgr, + struct local_binding_data *binding_data, + const struct sbrec_chassis *chassis_rec, ++ const struct ovsrec_interface_table *iface_table, ++ const struct sbrec_port_binding_table *pb_table, ++ bool ovs_readonly, + bool sb_readonly) + { ++ if (!ovs_readonly) { ++ clean_ovn_installed(mgr, iface_table); ++ } + if (!binding_data) { + return; + } +@@ -359,6 +438,17 @@ if_status_mgr_update(struct if_status_mgr *mgr, + struct shash *bindings = &binding_data->bindings; + struct hmapx_node *node; + ++ /* Move all interfaces that have been confirmed without ovn-installed, ++ * from OIF_REM_OLD_OVN_INST to OIF_MARK_UP. ++ */ ++ HMAPX_FOR_EACH_SAFE (node, &mgr->ifaces_per_state[OIF_REM_OLD_OVN_INST]) { ++ struct ovs_iface *iface = node->data; ++ ++ if (!local_binding_is_ovn_installed(bindings, iface->id)) { ++ ovs_iface_set_state(mgr, iface, OIF_MARK_UP); ++ } ++ } ++ + /* Interfaces in OIF_MARK_UP/INSTALL_FLOWS state have already set their + * pb->chassis. However, the update might still be in fly (confirmation + * not received yet) or pb->chassis was overwitten by another chassis. +@@ -390,6 +480,10 @@ if_status_mgr_update(struct if_status_mgr *mgr, + HMAPX_FOR_EACH_SAFE (node, &mgr->ifaces_per_state[OIF_MARK_DOWN]) { + struct ovs_iface *iface = node->data; + ++ if (!local_binding_find(bindings, iface->id)) { ++ ovs_iface_set_state(mgr, iface, OIF_UPDATE_PORT); ++ continue; ++ } + if (!sb_readonly) { + local_binding_set_pb(bindings, iface->id, chassis_rec, + NULL, false); +@@ -437,6 +531,21 @@ if_status_mgr_update(struct if_status_mgr *mgr, + } + } + ++ if (!sb_readonly) { ++ HMAPX_FOR_EACH_SAFE (node, &mgr->ifaces_per_state[OIF_UPDATE_PORT]) { ++ struct ovs_iface *iface = node->data; ++ port_binding_set_down(chassis_rec, pb_table, iface->id, ++ &iface->pb_uuid); ++ ovs_iface_destroy(mgr, node->data); ++ } ++ } else { ++ HMAPX_FOR_EACH_SAFE (node, &mgr->ifaces_per_state[OIF_UPDATE_PORT]) { ++ struct ovs_iface *iface = node->data; ++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); ++ VLOG_INFO_RL(&rl, "Not setting lport %s down as sb is readonly", ++ iface->id); ++ } ++ } + /* Register for a notification about flows being installed in OVS for all + * newly claimed interfaces for which pb->chassis has been updated. + * Request a seqno update when the flows for new interfaces have been +@@ -450,10 +559,23 @@ if_status_mgr_update(struct if_status_mgr *mgr, + } + } + ++void ++if_status_mgr_remove_ovn_installed(struct if_status_mgr *mgr, ++ const char *name, ++ const struct uuid *uuid) ++{ ++ VLOG_DBG("Adding %s to list of interfaces for which to remove " ++ "ovn-installed", name); ++ if (!shash_find_data(&mgr->ovn_uninstall_hash, name)) { ++ add_to_ovn_uninstall_hash(mgr, name, uuid); ++ } ++} ++ + void + if_status_mgr_run(struct if_status_mgr *mgr, + struct local_binding_data *binding_data, + const struct sbrec_chassis *chassis_rec, ++ const struct ovsrec_interface_table *iface_table, + bool sb_readonly, bool ovs_readonly) + { + struct ofctrl_acked_seqnos *acked_seqnos = +@@ -471,12 +593,25 @@ if_status_mgr_run(struct if_status_mgr *mgr, + iface->install_seqno)) { + continue; + } +- ovs_iface_set_state(mgr, iface, OIF_MARK_UP); ++ /* Wait for ovn-installed to be absent before moving to MARK_UP state. ++ * Most of the times ovn-installed is already absent and hence we will ++ * not have to wait. ++ * If there is no binding_data, we can't determine if ovn-installed is ++ * present or not; hence also go to the OIF_REM_OLD_OVN_INST state. ++ */ ++ if (!binding_data || ++ local_binding_is_ovn_installed(&binding_data->bindings, ++ iface->id)) { ++ ovs_iface_set_state(mgr, iface, OIF_REM_OLD_OVN_INST); ++ } else { ++ ovs_iface_set_state(mgr, iface, OIF_MARK_UP); ++ } + } + ofctrl_acked_seqnos_destroy(acked_seqnos); + + /* Update binding states. */ + if_status_mgr_update_bindings(mgr, binding_data, chassis_rec, ++ iface_table, + sb_readonly, ovs_readonly); + } + +@@ -492,6 +627,18 @@ ovs_iface_account_mem(const char *iface_id, bool erase) + } + } + ++static void ++ovn_uninstall_hash_account_mem(const char *name, bool erase) ++{ ++ uint32_t size = (strlen(name) + sizeof(struct uuid) + ++ sizeof(struct shash_node)); ++ if (erase) { ++ ifaces_usage -= size; ++ } else { ++ ifaces_usage += size; ++ } ++} ++ + static struct ovs_iface * + ovs_iface_create(struct if_status_mgr *mgr, const char *iface_id, + enum if_state state) +@@ -506,6 +653,16 @@ ovs_iface_create(struct if_status_mgr *mgr, const char *iface_id, + return iface; + } + ++static void ++add_to_ovn_uninstall_hash(struct if_status_mgr *mgr, const char *name, ++ const struct uuid *uuid) ++{ ++ struct uuid *new_uuid = xzalloc(sizeof *new_uuid); ++ memcpy(new_uuid, uuid, sizeof(*new_uuid)); ++ shash_add(&mgr->ovn_uninstall_hash, name, new_uuid); ++ ovn_uninstall_hash_account_mem(name, false); ++} ++ + static void + ovs_iface_destroy(struct if_status_mgr *mgr, struct ovs_iface *iface) + { +@@ -521,6 +678,23 @@ ovs_iface_destroy(struct if_status_mgr *mgr, struct ovs_iface *iface) + free(iface); + } + ++static void ++ovn_uninstall_hash_destroy(struct if_status_mgr *mgr, char *name) ++{ ++ struct shash_node *node = shash_find(&mgr->ovn_uninstall_hash, name); ++ char *node_name = NULL; ++ if (node) { ++ free(node->data); ++ VLOG_DBG("Interface name %s destroy", name); ++ node_name = shash_steal(&mgr->ovn_uninstall_hash, node); ++ ovn_uninstall_hash_account_mem(name, true); ++ free(node_name); ++ } else { ++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); ++ VLOG_WARN_RL(&rl, "Interface name %s not found", name); ++ } ++} ++ + static void + ovs_iface_set_state(struct if_status_mgr *mgr, struct ovs_iface *iface, + enum if_state state) +@@ -539,6 +713,7 @@ static void + if_status_mgr_update_bindings(struct if_status_mgr *mgr, + struct local_binding_data *binding_data, + const struct sbrec_chassis *chassis_rec, ++ const struct ovsrec_interface_table *iface_table, + bool sb_readonly, bool ovs_readonly) + { + if (!binding_data) { +@@ -558,7 +733,17 @@ if_status_mgr_update_bindings(struct if_status_mgr *mgr, + sb_readonly, ovs_readonly); + } + +- /* Notifiy the binding module to set "up" all bindings that have had ++ /* Notify the binding module to remove "ovn-installed" for all bindings ++ * in the OIF_REM_OLD_OVN_INST state. ++ */ ++ HMAPX_FOR_EACH (node, &mgr->ifaces_per_state[OIF_REM_OLD_OVN_INST]) { ++ struct ovs_iface *iface = node->data; ++ ++ local_binding_remove_ovn_installed(bindings, iface_table, iface->id, ++ ovs_readonly); ++ } ++ ++ /* Notify the binding module to set "up" all bindings that have had + * their flows installed but are not yet marked "up" in the binding + * module. + */ +diff --git a/controller/if-status.h b/controller/if-status.h +index 5bd187a25..8ba80acd9 100644 +--- a/controller/if-status.h ++++ b/controller/if-status.h +@@ -17,6 +17,7 @@ + #define IF_STATUS_H 1 + + #include "openvswitch/shash.h" ++#include "lib/vswitch-idl.h" + + #include "binding.h" + +@@ -35,9 +36,13 @@ void if_status_mgr_delete_iface(struct if_status_mgr *, const char *iface_id); + + void if_status_mgr_update(struct if_status_mgr *, struct local_binding_data *, + const struct sbrec_chassis *chassis, ++ const struct ovsrec_interface_table *iface_table, ++ const struct sbrec_port_binding_table *pb_table, ++ bool ovs_readonly, + bool sb_readonly); + void if_status_mgr_run(struct if_status_mgr *mgr, struct local_binding_data *, + const struct sbrec_chassis *, ++ const struct ovsrec_interface_table *iface_table, + bool sb_readonly, bool ovs_readonly); + void if_status_mgr_get_memory_usage(struct if_status_mgr *mgr, + struct simap *usage); +@@ -48,5 +53,8 @@ bool if_status_handle_claims(struct if_status_mgr *mgr, + const struct sbrec_chassis *chassis_rec, + struct hmap *tracked_datapath, + bool sb_readonly); ++void if_status_mgr_remove_ovn_installed(struct if_status_mgr *mgr, ++ const char *name, ++ const struct uuid *uuid); + + # endif /* controller/if-status.h */ +diff --git a/controller/lflow.c b/controller/lflow.c +index 6a98b19e1..0b071138d 100644 +--- a/controller/lflow.c ++++ b/controller/lflow.c +@@ -1729,6 +1729,7 @@ add_lb_vip_hairpin_flows(const struct ovn_controller_lb *lb, + + static void + add_lb_ct_snat_hairpin_for_dp(const struct ovn_controller_lb *lb, ++ bool has_vip_port, + const struct sbrec_datapath_binding *datapath, + const struct hmap *local_datapaths, + struct match *dp_match, +@@ -1742,15 +1743,21 @@ add_lb_ct_snat_hairpin_for_dp(const struct ovn_controller_lb *lb, + match_set_metadata(dp_match, htonll(datapath->tunnel_key)); + } + ++ uint16_t priority = datapath ? 200 : 100; ++ if (!has_vip_port) { ++ /* If L4 ports are not specified for the current LB, we will decrease ++ * the flow priority in order to not collide with other LBs with more ++ * fine-grained configuration. ++ */ ++ priority -= 10; ++ } + /* A flow added for the "hairpin_snat_ip" case will have an extra + * datapath match, but it will also match on the less restrictive + * general case. Therefore, we set the priority in the + * "hairpin_snat_ip" case to be higher than the general case. */ +- ofctrl_add_or_append_flow(flow_table, OFTABLE_CT_SNAT_HAIRPIN, +- datapath ? 200 : 100, +- lb->slb->header_.uuid.parts[0], +- dp_match, dp_acts, &lb->slb->header_.uuid, +- NX_CTLR_NO_METER, NULL); ++ ofctrl_add_flow(flow_table, OFTABLE_CT_SNAT_HAIRPIN, ++ priority, lb->slb->header_.uuid.parts[0], ++ dp_match, dp_acts, &lb->slb->header_.uuid); + } + + /* Add a ct_snat flow for each VIP of the LB. If this LB does not use +@@ -1836,8 +1843,8 @@ add_lb_ct_snat_hairpin_vip_flow(const struct ovn_controller_lb *lb, + } + } + +- match_set_nw_proto(&match, lb->proto); + if (lb_vip->vip_port) { ++ match_set_nw_proto(&match, lb->proto); + if (!lb->hairpin_orig_tuple) { + match_set_ct_nw_proto(&match, lb->proto); + match_set_ct_tp_dst(&match, htons(lb_vip->vip_port)); +@@ -1854,18 +1861,20 @@ add_lb_ct_snat_hairpin_vip_flow(const struct ovn_controller_lb *lb, + } + + if (!use_hairpin_snat_ip) { +- add_lb_ct_snat_hairpin_for_dp(lb, NULL, NULL, ++ add_lb_ct_snat_hairpin_for_dp(lb, !!lb_vip->vip_port, NULL, NULL, + &match, &ofpacts, flow_table); + } else { + for (size_t i = 0; i < lb->slb->n_datapaths; i++) { +- add_lb_ct_snat_hairpin_for_dp(lb, lb->slb->datapaths[i], +- local_datapaths, +- &match, &ofpacts, flow_table); ++ add_lb_ct_snat_hairpin_for_dp(lb, !!lb_vip->vip_port, ++ lb->slb->datapaths[i], ++ local_datapaths, &match, ++ &ofpacts, flow_table); + } + if (lb->slb->datapath_group) { + for (size_t i = 0; i < lb->slb->datapath_group->n_datapaths; i++) { + add_lb_ct_snat_hairpin_for_dp( +- lb, lb->slb->datapath_group->datapaths[i], ++ lb, !!lb_vip->vip_port, ++ lb->slb->datapath_group->datapaths[i], + local_datapaths, &match, &ofpacts, flow_table); + } + } +diff --git a/controller/mirror.c b/controller/mirror.c +index 665736966..0e5885e9b 100644 +--- a/controller/mirror.c ++++ b/controller/mirror.c +@@ -22,6 +22,7 @@ + + /* OVS includes. */ + #include "lib/vswitch-idl.h" ++#include "lib/socket-util.h" + #include "include/openvswitch/shash.h" + #include "openvswitch/vlog.h" + +@@ -69,6 +70,7 @@ static void set_mirror_iface_options(struct ovsrec_interface *, + static const struct ovsrec_port *get_iface_port( + const struct ovsrec_interface *, const struct ovsrec_bridge *); + ++char *get_mirror_tunnel_type(const struct sbrec_mirror *); + + void + mirror_register_ovs_idl(struct ovsdb_idl *ovs_idl) +@@ -244,24 +246,26 @@ set_mirror_iface_options(struct ovsrec_interface *iface, + smap_destroy(&options); + } + ++char * ++get_mirror_tunnel_type(const struct sbrec_mirror *sb_mirror) ++{ ++ bool is_ipv6 = addr_is_ipv6(sb_mirror->sink); ++ ++ return xasprintf(is_ipv6 ? "ip6%s" : "%s", sb_mirror->type); ++} ++ + static void + check_and_update_interface_table(const struct sbrec_mirror *sb_mirror, + const struct ovsrec_mirror *ovs_mirror) + { +- char *type; +- struct ovsrec_interface *iface = +- ovs_mirror->output_port->interfaces[0]; +- struct smap *opts = &iface->options; +- const char *erspan_ver = smap_get(opts, "erspan_ver"); +- if (erspan_ver) { +- type = "erspan"; +- } else { +- type = "gre"; +- } +- if (strcmp(type, sb_mirror->type)) { +- ovsrec_interface_set_type(iface, sb_mirror->type); ++ struct ovsrec_interface *iface = ovs_mirror->output_port->interfaces[0]; ++ char *type = get_mirror_tunnel_type(sb_mirror); ++ ++ if (strcmp(type, iface->type)) { ++ ovsrec_interface_set_type(iface, type); + } + set_mirror_iface_options(iface, sb_mirror); ++ free(type); + } + + static void +@@ -327,8 +331,11 @@ create_ovs_mirror(struct ovn_mirror *m, struct ovsdb_idl_txn *ovs_idl_txn, + char *port_name = xasprintf("ovn-%s", m->name); + + ovsrec_interface_set_name(iface, port_name); +- ovsrec_interface_set_type(iface, m->sb_mirror->type); ++ ++ char *type = get_mirror_tunnel_type(m->sb_mirror); ++ ovsrec_interface_set_type(iface, type); + set_mirror_iface_options(iface, m->sb_mirror); ++ free(type); + + struct ovsrec_port *port = ovsrec_port_insert(ovs_idl_txn); + ovsrec_port_set_name(port, port_name); +diff --git a/controller/ovn-controller.8.xml b/controller/ovn-controller.8.xml +index ab52e2d34..f61f43008 100644 +--- a/controller/ovn-controller.8.xml ++++ b/controller/ovn-controller.8.xml +@@ -121,11 +121,11 @@ + that is needed in the current chassis. +

    +

    +- It is more optimal to set it to true in use cases when +- the chassis would anyway need to monitor most of the records in +- ovs-database, which would save the overhead of conditions +- processing, especially for server side. Typically, set it to +- true for environments that all workloads need to be ++ It is more efficient to set it to true in use cases ++ where the chassis would anyway need to monitor most of the records in ++ OVN Southbound database, which would save the overhead of ++ conditions processing, especially for server side. Typically, set it ++ to true for environments that all workloads need to be + reachable from each other. +

    +

    +@@ -171,16 +171,14 @@ +

    + +

    +- Supported tunnel types for connecting hypervisors +- are geneve and stt. Gateways may +- use geneve, vxlan, or +- stt. ++ Supported tunnel types for connecting hypervisors and gateways ++ are geneve, vxlan, and stt. +

    + +

    + Due to the limited amount of metadata in vxlan, +- the capabilities and performance of connected gateways will be +- reduced versus other tunnel formats. ++ the capabilities and performance of connected gateways and ++ hypervisors will be reduced versus other tunnel formats. +

    + + +diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c +index 2d18bbfca..44a4518b9 100644 +--- a/controller/ovn-controller.c ++++ b/controller/ovn-controller.c +@@ -712,7 +712,7 @@ get_snat_ct_zone(const struct sbrec_datapath_binding *dp) + } + + static void +-update_ct_zones(const struct shash *binding_lports, ++update_ct_zones(const struct sset *local_lports, + const struct hmap *local_datapaths, + struct simap *ct_zones, unsigned long *ct_zone_bitmap, + struct shash *pending_ct_zones) +@@ -725,9 +725,9 @@ update_ct_zones(const struct shash *binding_lports, + unsigned long unreq_snat_zones_map[BITMAP_N_LONGS(MAX_CT_ZONES)]; + struct simap unreq_snat_zones = SIMAP_INITIALIZER(&unreq_snat_zones); + +- struct shash_node *shash_node; +- SHASH_FOR_EACH (shash_node, binding_lports) { +- sset_add(&all_users, shash_node->name); ++ const char *local_lport; ++ SSET_FOR_EACH (local_lport, local_lports) { ++ sset_add(&all_users, local_lport); + } + + /* Local patched datapath (gateway routers) need zones assigned. */ +@@ -2010,7 +2010,11 @@ addr_sets_update(const struct sbrec_address_set_table *address_set_table, + if (sbrec_address_set_is_deleted(as)) { + expr_const_sets_remove(addr_sets, as->name); + sset_add(deleted, as->name); +- } else { ++ } ++ } ++ ++ SBREC_ADDRESS_SET_TABLE_FOR_EACH_TRACKED (as, address_set_table) { ++ if (!sbrec_address_set_is_deleted(as)) { + struct expr_constant_set *cs_old = shash_find_data(addr_sets, + as->name); + if (!cs_old) { +@@ -2381,7 +2385,7 @@ en_ct_zones_run(struct engine_node *node, void *data) + EN_OVSDB_GET(engine_get_input("OVS_bridge", node)); + + restore_ct_zones(bridge_table, ovs_table, ct_zones_data); +- update_ct_zones(&rt_data->lbinding_data.lports, &rt_data->local_datapaths, ++ update_ct_zones(&rt_data->local_lports, &rt_data->local_datapaths, + &ct_zones_data->current, ct_zones_data->bitmap, + &ct_zones_data->pending); + +@@ -2471,8 +2475,10 @@ ct_zones_runtime_data_handler(struct engine_node *node, void *data) + SHASH_FOR_EACH (shash_node, &tdp->lports) { + struct tracked_lport *t_lport = shash_node->data; + if (strcmp(t_lport->pb->type, "") +- && strcmp(t_lport->pb->type, "localport")) { +- /* We allocate zone-id's only to VIF and localport lports. */ ++ && strcmp(t_lport->pb->type, "localport") ++ && strcmp(t_lport->pb->type, "localnet")) { ++ /* We allocate zone-id's only to VIF, localport, and localnet ++ * lports. */ + continue; + } + +@@ -2697,7 +2703,8 @@ static void + lb_data_removed_five_tuples_add(struct ed_type_lb_data *lb_data, + const struct ovn_controller_lb *lb) + { +- if (!ovs_feature_is_supported(OVS_CT_TUPLE_FLUSH_SUPPORT)) { ++ if (!ovs_feature_is_supported(OVS_CT_TUPLE_FLUSH_SUPPORT) || ++ !lb->ct_flush) { + return; + } + +@@ -2716,7 +2723,8 @@ static void + lb_data_removed_five_tuples_remove(struct ed_type_lb_data *lb_data, + const struct ovn_controller_lb *lb) + { +- if (!ovs_feature_is_supported(OVS_CT_TUPLE_FLUSH_SUPPORT)) { ++ if (!ovs_feature_is_supported(OVS_CT_TUPLE_FLUSH_SUPPORT) || ++ !lb->ct_flush) { + return; + } + +@@ -5071,7 +5079,8 @@ main(int argc, char *argv[]) + chassis, + sbrec_sb_global_first(ovnsb_idl_loop.idl), + ovs_table, +- &transport_zones); ++ &transport_zones, ++ bridge_table); + + stopwatch_start(CONTROLLER_LOOP_STOPWATCH_NAME, + time_msec()); +@@ -5225,6 +5234,11 @@ main(int argc, char *argv[]) + stopwatch_start(IF_STATUS_MGR_UPDATE_STOPWATCH_NAME, + time_msec()); + if_status_mgr_update(if_mgr, binding_data, chassis, ++ ovsrec_interface_table_get( ++ ovs_idl_loop.idl), ++ sbrec_port_binding_table_get( ++ ovnsb_idl_loop.idl), ++ !ovs_idl_txn, + !ovnsb_idl_txn); + stopwatch_stop(IF_STATUS_MGR_UPDATE_STOPWATCH_NAME, + time_msec()); +@@ -5254,11 +5268,12 @@ main(int argc, char *argv[]) + stopwatch_start(IF_STATUS_MGR_RUN_STOPWATCH_NAME, + time_msec()); + if_status_mgr_run(if_mgr, binding_data, chassis, ++ ovsrec_interface_table_get( ++ ovs_idl_loop.idl), + !ovnsb_idl_txn, !ovs_idl_txn); + stopwatch_stop(IF_STATUS_MGR_RUN_STOPWATCH_NAME, + time_msec()); + } +- + } + + if (!engine_has_run()) { +@@ -5449,6 +5464,7 @@ loop_done: + binding_destroy(); + patch_destroy(); + mirror_destroy(); ++ encaps_destroy(); + if_status_mgr_destroy(if_mgr); + shash_destroy(&vif_plug_deleted_iface_ids); + shash_destroy(&vif_plug_changed_iface_ids); +diff --git a/controller/pinctrl.c b/controller/pinctrl.c +index 795847729..761783562 100644 +--- a/controller/pinctrl.c ++++ b/controller/pinctrl.c +@@ -2444,19 +2444,19 @@ compose_out_dhcpv6_opts(struct ofpbuf *userdata, + struct ofpbuf *out_dhcpv6_opts, ovs_be32 iaid) + { + while (userdata->size) { +- struct dhcp_opt6_header *userdata_opt = ofpbuf_try_pull( ++ struct dhcpv6_opt_header *userdata_opt = ofpbuf_try_pull( + userdata, sizeof *userdata_opt); + if (!userdata_opt) { + return false; + } + +- size_t size = ntohs(userdata_opt->size); ++ size_t size = ntohs(userdata_opt->len); + uint8_t *userdata_opt_data = ofpbuf_try_pull(userdata, size); + if (!userdata_opt_data) { + return false; + } + +- switch (ntohs(userdata_opt->opt_code)) { ++ switch (ntohs(userdata_opt->code)) { + case DHCPV6_OPT_SERVER_ID_CODE: + { + /* The Server Identifier option carries a DUID +@@ -7190,7 +7190,9 @@ bfd_monitor_send_msg(struct rconn *swconn, long long int *bfd_time) + pinctrl_send_bfd_tx_msg(swconn, entry, false); + + tx_timeout = MAX(entry->local_min_tx, entry->remote_min_rx); +- tx_timeout -= random_range((tx_timeout * 25) / 100); ++ if (tx_timeout >= 4) { ++ tx_timeout -= random_range(tx_timeout / 4); ++ } + entry->next_tx = cur_time + tx_timeout; + next: + if (*bfd_time > entry->next_tx) { +diff --git a/debian/changelog b/debian/changelog +index 11a07dd38..02a9953ba 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,9 @@ ++OVN (23.03.1-1) unstable; urgency=low ++ [ OVN team ] ++ * New upstream version ++ ++ -- OVN team Fri, 03 Mar 2023 10:40:37 -0500 ++ + ovn (23.03.0-1) unstable; urgency=low + + * New upstream version +diff --git a/lib/actions.c b/lib/actions.c +index 781549d75..2b566c85e 100644 +--- a/lib/actions.c ++++ b/lib/actions.c +@@ -2882,26 +2882,26 @@ static void + encode_put_dhcpv6_option(const struct ovnact_gen_option *o, + struct ofpbuf *ofpacts) + { +- struct dhcp_opt6_header *opt = ofpbuf_put_uninit(ofpacts, sizeof *opt); ++ struct dhcpv6_opt_header *opt = ofpbuf_put_uninit(ofpacts, sizeof *opt); + const union expr_constant *c = o->value.values; + size_t n_values = o->value.n_values; + size_t size; + +- opt->opt_code = htons(o->option->code); ++ opt->code = htons(o->option->code); + + if (!strcmp(o->option->type, "ipv6")) { + size = n_values * sizeof(struct in6_addr); +- opt->size = htons(size); ++ opt->len = htons(size); + for (size_t i = 0; i < n_values; i++) { + ofpbuf_put(ofpacts, &c[i].value.ipv6, sizeof(struct in6_addr)); + } + } else if (!strcmp(o->option->type, "mac")) { + size = sizeof(struct eth_addr); +- opt->size = htons(size); ++ opt->len = htons(size); + ofpbuf_put(ofpacts, &c->value.mac, size); + } else if (!strcmp(o->option->type, "str")) { + size = strlen(c->string); +- opt->size = htons(size); ++ opt->len = htons(size); + ofpbuf_put(ofpacts, c->string, size); + } + } +diff --git a/lib/lb.c b/lib/lb.c +index e941434c4..f88c1855b 100644 +--- a/lib/lb.c ++++ b/lib/lb.c +@@ -38,6 +38,7 @@ static const char *lb_neighbor_responder_mode_names[] = { + static struct nbrec_load_balancer_health_check * + ovn_lb_get_health_check(const struct nbrec_load_balancer *nbrec_lb, + const char *vip_port_str, bool template); ++static void ovn_lb_backends_clear(struct ovn_lb_vip *vip); + + struct ovn_lb_ip_set * + ovn_lb_ip_set_create(void) +@@ -238,6 +239,8 @@ ovn_lb_backends_init_template(struct ovn_lb_vip *lb_vip, const char *value_) + ds_put_format(&errors, "%s: should be a template of the form: " + "'^backendip_variable1[:^port_variable1|:port]', ", + atom); ++ free(backend_port); ++ free(backend_ip); + } + free(atom); + } +@@ -285,8 +288,27 @@ ovn_lb_vip_init_template(struct ovn_lb_vip *lb_vip, const char *lb_key_, + lb_key_); + } + ++ /* Backends can either be templates or explicit IPs and ports. */ + lb_vip->address_family = address_family; +- return ovn_lb_backends_init_template(lb_vip, lb_value); ++ lb_vip->template_backends = true; ++ char *template_error = ovn_lb_backends_init_template(lb_vip, lb_value); ++ ++ if (template_error) { ++ lb_vip->template_backends = false; ++ ovn_lb_backends_clear(lb_vip); ++ ++ char *explicit_error = ovn_lb_backends_init_explicit(lb_vip, lb_value); ++ if (explicit_error) { ++ char *error = ++ xasprintf("invalid backend: template (%s) OR explicit (%s)", ++ template_error, explicit_error); ++ free(explicit_error); ++ free(template_error); ++ return error; ++ } ++ free(template_error); ++ } ++ return NULL; + } + + /* Returns NULL on success, an error string on failure. The caller is +@@ -304,15 +326,29 @@ ovn_lb_vip_init(struct ovn_lb_vip *lb_vip, const char *lb_key, + address_family); + } + +-void +-ovn_lb_vip_destroy(struct ovn_lb_vip *vip) ++static void ++ovn_lb_backends_destroy(struct ovn_lb_vip *vip) + { +- free(vip->vip_str); +- free(vip->port_str); + for (size_t i = 0; i < vip->n_backends; i++) { + free(vip->backends[i].ip_str); + free(vip->backends[i].port_str); + } ++} ++ ++static void ++ovn_lb_backends_clear(struct ovn_lb_vip *vip) ++{ ++ ovn_lb_backends_destroy(vip); ++ vip->backends = NULL; ++ vip->n_backends = 0; ++} ++ ++void ++ovn_lb_vip_destroy(struct ovn_lb_vip *vip) ++{ ++ free(vip->vip_str); ++ free(vip->port_str); ++ ovn_lb_backends_destroy(vip); + free(vip->backends); + } + +@@ -357,11 +393,10 @@ ovn_lb_vip_format(const struct ovn_lb_vip *vip, struct ds *s, bool template) + } + + void +-ovn_lb_vip_backends_format(const struct ovn_lb_vip *vip, struct ds *s, +- bool template) ++ovn_lb_vip_backends_format(const struct ovn_lb_vip *vip, struct ds *s) + { + bool needs_brackets = vip->address_family == AF_INET6 && vip->port_str +- && !template; ++ && !vip->template_backends; + for (size_t i = 0; i < vip->n_backends; i++) { + struct ovn_lb_backend *backend = &vip->backends[i]; + +@@ -798,6 +833,7 @@ ovn_controller_lb_create(const struct sbrec_load_balancer *sbrec_lb, + lb->hairpin_orig_tuple = smap_get_bool(&sbrec_lb->options, + "hairpin_orig_tuple", + false); ++ lb->ct_flush = smap_get_bool(&sbrec_lb->options, "ct_flush", false); + ovn_lb_get_hairpin_snat_ip(&sbrec_lb->header_.uuid, &sbrec_lb->options, + &lb->hairpin_snat_ips); + return lb; +diff --git a/lib/lb.h b/lib/lb.h +index 7a67b7426..e24f519db 100644 +--- a/lib/lb.h ++++ b/lib/lb.h +@@ -96,6 +96,9 @@ struct ovn_lb_vip { + */ + struct ovn_lb_backend *backends; + size_t n_backends; ++ bool template_backends; /* True if the backends are templates. False if ++ * they're explicitly specified. ++ */ + bool empty_backend_rej; + int address_family; + }; +@@ -188,6 +191,7 @@ struct ovn_controller_lb { + bool hairpin_orig_tuple; /* True if ovn-northd stores the original + * destination tuple in registers. + */ ++ bool ct_flush; /* True if we should flush CT after backend removal. */ + + struct lport_addresses hairpin_snat_ips; /* IP (v4 and/or v6) to be used + * as source for hairpinned +@@ -210,8 +214,7 @@ char *ovn_lb_vip_init(struct ovn_lb_vip *lb_vip, const char *lb_key, + void ovn_lb_vip_destroy(struct ovn_lb_vip *vip); + void ovn_lb_vip_format(const struct ovn_lb_vip *vip, struct ds *s, + bool template); +-void ovn_lb_vip_backends_format(const struct ovn_lb_vip *vip, struct ds *s, +- bool template); ++void ovn_lb_vip_backends_format(const struct ovn_lb_vip *vip, struct ds *s); + + struct ovn_lb_5tuple { + struct hmap_node hmap_node; +diff --git a/lib/ovn-l7.h b/lib/ovn-l7.h +index 2b20bc380..d718ed39a 100644 +--- a/lib/ovn-l7.h ++++ b/lib/ovn-l7.h +@@ -240,12 +240,6 @@ struct dhcp_opt_header { + #define DHCP_OPT_PAYLOAD(hdr) \ + (void *)((char *)hdr + sizeof(struct dhcp_opt_header)) + +-/* Used in the OpenFlow PACKET_IN userdata */ +-struct dhcp_opt6_header { +- ovs_be16 opt_code; +- ovs_be16 size; +-}; +- + /* These are not defined in ovs/lib/dhcp.h, hence defining here. */ + #define OVN_DHCP_MSG_DECLINE 4 + #define OVN_DHCP_MSG_RELEASE 7 +diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c +index d23993a55..fd025c92b 100644 +--- a/northd/inc-proc-northd.c ++++ b/northd/inc-proc-northd.c +@@ -34,10 +34,13 @@ + #include "en-lflow.h" + #include "en-northd-output.h" + #include "en-sync-sb.h" ++#include "unixctl.h" + #include "util.h" + + VLOG_DEFINE_THIS_MODULE(inc_proc_northd); + ++static unixctl_cb_func chassis_features_list; ++ + #define NB_NODES \ + NB_NODE(nb_global, "nb_global") \ + NB_NODE(copp, "copp") \ +@@ -306,6 +309,12 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, + engine_ovsdb_node_add_index(&en_sb_address_set, + "sbrec_address_set_by_name", + sbrec_address_set_by_name); ++ ++ struct northd_data *northd_data = ++ engine_get_internal_data(&en_northd); ++ unixctl_command_register("debug/chassis-features-list", "", 0, 0, ++ chassis_features_list, ++ &northd_data->features); + } + + /* Returns true if the incremental processing ended up updating nodes. */ +@@ -356,3 +365,20 @@ void inc_proc_northd_cleanup(void) + engine_cleanup(); + engine_set_context(NULL); + } ++ ++static void ++chassis_features_list(struct unixctl_conn *conn, int argc OVS_UNUSED, ++ const char *argv[] OVS_UNUSED, void *features_) ++{ ++ struct chassis_features *features = features_; ++ struct ds ds = DS_EMPTY_INITIALIZER; ++ ++ ds_put_format(&ds, "ct_no_masked_label: %s\n", ++ features->ct_no_masked_label ? "true" : "false"); ++ ds_put_format(&ds, "ct_lb_related: %s\n", ++ features->ct_lb_related ? "true" : "false"); ++ ds_put_format(&ds, "mac_binding_timestamp: %s\n", ++ features->mac_binding_timestamp ? "true" : "false"); ++ unixctl_command_reply(conn, ds_cstr(&ds)); ++ ds_destroy(&ds); ++} +diff --git a/northd/northd.c b/northd/northd.c +index 7ad4cdfad..045282fac 100644 +--- a/northd/northd.c ++++ b/northd/northd.c +@@ -432,6 +432,13 @@ build_chassis_features(const struct northd_input *input_data, + const struct sbrec_chassis *chassis; + + SBREC_CHASSIS_TABLE_FOR_EACH (chassis, input_data->sbrec_chassis) { ++ /* Only consider local AZ chassis. Remote ones don't install ++ * flows generated by the local northd. ++ */ ++ if (smap_get_bool(&chassis->other_config, "is-remote", false)) { ++ continue; ++ } ++ + bool ct_no_masked_label = + smap_get_bool(&chassis->other_config, + OVN_FEATURE_CT_NO_MASKED_LABEL, +@@ -552,7 +559,7 @@ free_chassis_queueid(struct hmap *set, const struct uuid *uuid, + static inline bool + port_has_qos_params(const struct smap *opts) + { +- return (smap_get(opts, "qos_max_rate") || ++ return (smap_get(opts, "qos_max_rate") || smap_get(opts, "qos_min_rate") || + smap_get(opts, "qos_burst")); + } + +@@ -1641,6 +1648,10 @@ ovn_port_destroy(struct hmap *ports, struct ovn_port *port) + * use it. */ + hmap_remove(ports, &port->key_node); + ++ if (port->peer) { ++ port->peer->peer = NULL; ++ } ++ + for (int i = 0; i < port->n_lsp_addrs; i++) { + destroy_lport_addresses(&port->lsp_addrs[i]); + } +@@ -3881,7 +3892,7 @@ build_lb_vip_actions(struct ovn_lb_vip *lb_vip, + const char *ct_lb_action = + features->ct_no_masked_label ? "ct_lb_mark" : "ct_lb"; + bool reject = !lb_vip->n_backends && lb_vip->empty_backend_rej; +- bool drop = false; ++ bool drop = !lb_vip->n_backends && !lb_vip->empty_backend_rej; + + if (lb_vip_nb->lb_health_check) { + ds_put_format(action, "%s(backends=", ct_lb_action); +@@ -5779,20 +5790,24 @@ skip_port_from_conntrack(struct ovn_datapath *od, struct ovn_port *op, + * know about the connection, as the icmp request went through the logical + * router on hostA, not hostB. This would only work with distributed + * conntrack state across all chassis. */ +- struct ds match_in = DS_EMPTY_INITIALIZER; +- struct ds match_out = DS_EMPTY_INITIALIZER; + +- ds_put_format(&match_in, "ip && inport == %s", op->json_key); +- ds_put_format(&match_out, "ip && outport == %s", op->json_key); ++ const char *ingress_action = "next;"; ++ const char *egress_action = od->has_stateful_acl ++ ? "next;" ++ : "ct_clear; next;"; ++ ++ char *ingress_match = xasprintf("ip && inport == %s", op->json_key); ++ char *egress_match = xasprintf("ip && outport == %s", op->json_key); ++ + ovn_lflow_add_with_lport_and_hint(lflows, od, in_stage, priority, +- ds_cstr(&match_in), "next;", op->key, +- &op->nbsp->header_); ++ ingress_match, ingress_action, ++ op->key, &op->nbsp->header_); + ovn_lflow_add_with_lport_and_hint(lflows, od, out_stage, priority, +- ds_cstr(&match_out), "next;", op->key, +- &op->nbsp->header_); ++ egress_match, egress_action, ++ op->key, &op->nbsp->header_); + +- ds_destroy(&match_in); +- ds_destroy(&match_out); ++ free(ingress_match); ++ free(egress_match); + } + + static void +@@ -5867,7 +5882,8 @@ build_pre_acls(struct ovn_datapath *od, const struct hmap *port_groups, + } + for (size_t i = 0; i < od->n_localnet_ports; i++) { + skip_port_from_conntrack(od, od->localnet_ports[i], +- S_SWITCH_IN_PRE_ACL, S_SWITCH_OUT_PRE_ACL, ++ S_SWITCH_IN_PRE_ACL, ++ S_SWITCH_OUT_PRE_ACL, + 110, lflows); + } + +@@ -6036,10 +6052,17 @@ build_pre_lb(struct ovn_datapath *od, const struct shash *meter_groups, + S_SWITCH_IN_PRE_LB, S_SWITCH_OUT_PRE_LB, + 110, lflows); + } +- for (size_t i = 0; i < od->n_localnet_ports; i++) { +- skip_port_from_conntrack(od, od->localnet_ports[i], +- S_SWITCH_IN_PRE_LB, S_SWITCH_OUT_PRE_LB, +- 110, lflows); ++ /* Localnet ports have no need for going through conntrack, unless ++ * the logical switch has a load balancer. Then, conntrack is necessary ++ * so that traffic arriving via the localnet port can be load ++ * balanced. ++ */ ++ if (!od->has_lb_vip) { ++ for (size_t i = 0; i < od->n_localnet_ports; i++) { ++ skip_port_from_conntrack(od, od->localnet_ports[i], ++ S_SWITCH_IN_PRE_LB, S_SWITCH_OUT_PRE_LB, ++ 110, lflows); ++ } + } + + /* Do not sent statless flows via conntrack */ +@@ -6700,6 +6723,8 @@ build_port_group_lswitches(struct northd_input *input_data, + } + } + ++#define IPV6_CT_OMIT_MATCH "nd || nd_ra || nd_rs || mldv1 || mldv2" ++ + static void + build_acls(struct ovn_datapath *od, const struct chassis_features *features, + struct hmap *lflows, const struct hmap *port_groups, +@@ -6847,20 +6872,26 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features, + ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3, + ds_cstr(&match), ct_out_acl_action); + +- /* Ingress and Egress ACL Table (Priority 65532). +- * +- * Not to do conntrack on ND packets. */ +- ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3, +- "nd || nd_ra || nd_rs || mldv1 || mldv2", "next;"); +- ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3, +- "nd || nd_ra || nd_rs || mldv1 || mldv2", "next;"); +- + /* Reply and related traffic matched by an "allow-related" ACL + * should be allowed in the ls_in_acl_after_lb stage too. */ + ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, UINT16_MAX - 3, + REGBIT_ACL_HINT_ALLOW_REL" == 1", "next;"); + } + ++ /* Ingress and Egress ACL Table (Priority 65532). ++ * ++ * Always allow service IPv6 protocols regardless of other ACLs defined. ++ * ++ * Also, don't send them to conntrack because session tracking ++ * for these protocols is not working properly: ++ * https://bugzilla.kernel.org/show_bug.cgi?id=11797. */ ++ ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3, ++ IPV6_CT_OMIT_MATCH, "next;"); ++ ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3, ++ IPV6_CT_OMIT_MATCH, "next;"); ++ ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, UINT16_MAX - 3, ++ IPV6_CT_OMIT_MATCH, "next;"); ++ + /* Ingress or Egress ACL Table (Various priorities). */ + for (size_t i = 0; i < od->nbs->n_acls; i++) { + struct nbrec_acl *acl = od->nbs->acls[i]; +@@ -7089,7 +7120,9 @@ build_lb_rules_pre_stateful(struct hmap *lflows, struct ovn_northd_lb *lb, + * - load balancing affinity check: + * table=lr_in_lb_aff_check, priority=100 + * match=(new_lb_match) +- * action=(REGBIT_KNOWN_LB_SESSION = chk_lb_aff(); next;) ++ * action=(REG_NEXT_HOP_IPV4 = ip4.dst; ++ * REG_ORIG_TP_DPORT_ROUTER = tcp.dst; ++ * REGBIT_KNOWN_LB_SESSION = chk_lb_aff(); next;) + * + * - load balancing: + * table=lr_in_dnat, priority=150 +@@ -7130,16 +7163,11 @@ build_lb_affinity_lr_flows(struct hmap *lflows, struct ovn_northd_lb *lb, + return; + } + +- static char *aff_check = REGBIT_KNOWN_LB_SESSION" = chk_lb_aff(); next;"; +- +- ovn_lflow_add_with_dp_group( +- lflows, dp_bitmap, S_ROUTER_IN_LB_AFF_CHECK, 100, +- new_lb_match, aff_check, &lb->nlb->header_); +- + struct ds aff_action = DS_EMPTY_INITIALIZER; + struct ds aff_action_learn = DS_EMPTY_INITIALIZER; + struct ds aff_match = DS_EMPTY_INITIALIZER; + struct ds aff_match_learn = DS_EMPTY_INITIALIZER; ++ struct ds aff_check_action = DS_EMPTY_INITIALIZER; + + bool ipv6 = !IN6_IS_ADDR_V4MAPPED(&lb_vip->vip); + const char *ip_match = ipv6 ? "ip6" : "ip4"; +@@ -7155,6 +7183,20 @@ build_lb_affinity_lr_flows(struct hmap *lflows, struct ovn_northd_lb *lb, + ct_flag = "; force_snat"; + } + ++ /* Create affinity check flow. */ ++ ds_put_format(&aff_check_action, "%s = %s.dst; ", reg_vip, ip_match); ++ ++ if (lb_vip->port_str) { ++ ds_put_format(&aff_check_action, REG_ORIG_TP_DPORT_ROUTER" = %s.dst; ", ++ lb->proto); ++ } ++ ds_put_cstr(&aff_check_action, REGBIT_KNOWN_LB_SESSION ++ " = chk_lb_aff(); next;"); ++ ++ ovn_lflow_add_with_dp_group( ++ lflows, dp_bitmap, S_ROUTER_IN_LB_AFF_CHECK, 100, ++ new_lb_match, ds_cstr(&aff_check_action), &lb->nlb->header_); ++ + /* Prepare common part of affinity LB and affinity learn action. */ + ds_put_format(&aff_action, "%s = %s; ", reg_vip, lb_vip->vip_str); + ds_put_cstr(&aff_action_learn, "commit_lb_aff(vip = \""); +@@ -7252,6 +7294,7 @@ build_lb_affinity_lr_flows(struct hmap *lflows, struct ovn_northd_lb *lb, + ds_destroy(&aff_action_learn); + ds_destroy(&aff_match); + ds_destroy(&aff_match_learn); ++ ds_destroy(&aff_check_action); + } + + /* Builds the logical switch flows related to load balancer affinity. +@@ -10450,10 +10493,8 @@ enum lrouter_nat_lb_flow_type { + + struct lrouter_nat_lb_flows_ctx { + const char *new_action[LROUTER_NAT_LB_FLOW_MAX]; +- const char *est_action[LROUTER_NAT_LB_FLOW_MAX]; + + struct ds *new_match; +- struct ds *est_match; + struct ds *undnat_match; + + struct ovn_lb_vip *lb_vip; +@@ -10471,10 +10512,22 @@ build_distr_lrouter_nat_flows_for_lb(struct lrouter_nat_lb_flows_ctx *ctx, + enum lrouter_nat_lb_flow_type type, + struct ovn_datapath *od) + { +- char *gw_action = od->is_gw_router ? "ct_dnat;" : "ct_dnat_in_czone;"; ++ const char *undnat_action; ++ ++ switch (type) { ++ case LROUTER_NAT_LB_FLOW_FORCE_SNAT: ++ undnat_action = "flags.force_snat_for_lb = 1; next;"; ++ break; ++ case LROUTER_NAT_LB_FLOW_SKIP_SNAT: ++ undnat_action = "flags.skip_snat_for_lb = 1; next;"; ++ break; ++ case LROUTER_NAT_LB_FLOW_NORMAL: ++ case LROUTER_NAT_LB_FLOW_MAX: ++ undnat_action = od->is_gw_router ? "ct_dnat;" : "ct_dnat_in_czone;"; ++ break; ++ } + /* Store the match lengths, so we can reuse the ds buffer. */ + size_t new_match_len = ctx->new_match->length; +- size_t est_match_len = ctx->est_match->length; + size_t undnat_match_len = ctx->undnat_match->length; + + +@@ -10487,33 +10540,24 @@ build_distr_lrouter_nat_flows_for_lb(struct lrouter_nat_lb_flows_ctx *ctx, + if (ctx->lb_vip->n_backends || !ctx->lb_vip->empty_backend_rej) { + ds_put_format(ctx->new_match, " && is_chassis_resident(%s)", + od->l3dgw_ports[0]->cr_port->json_key); +- ds_put_format(ctx->est_match, " && is_chassis_resident(%s)", +- od->l3dgw_ports[0]->cr_port->json_key); + } + + ovn_lflow_add_with_hint__(ctx->lflows, od, S_ROUTER_IN_DNAT, ctx->prio, + ds_cstr(ctx->new_match), ctx->new_action[type], + NULL, meter, &ctx->lb->nlb->header_); +- ovn_lflow_add_with_hint(ctx->lflows, od, S_ROUTER_IN_DNAT, ctx->prio, +- ds_cstr(ctx->est_match), ctx->est_action[type], +- &ctx->lb->nlb->header_); + + ds_truncate(ctx->new_match, new_match_len); +- ds_truncate(ctx->est_match, est_match_len); + + if (!ctx->lb_vip->n_backends) { + return; + } + +- const char *action = (type == LROUTER_NAT_LB_FLOW_NORMAL) +- ? gw_action : ctx->est_action[type]; +- + ds_put_format(ctx->undnat_match, + ") && outport == %s && is_chassis_resident(%s)", + od->l3dgw_ports[0]->json_key, + od->l3dgw_ports[0]->cr_port->json_key); + ovn_lflow_add_with_hint(ctx->lflows, od, S_ROUTER_OUT_UNDNAT, 120, +- ds_cstr(ctx->undnat_match), action, ++ ds_cstr(ctx->undnat_match), undnat_action, + &ctx->lb->nlb->header_); + ds_truncate(ctx->undnat_match, undnat_match_len); + } +@@ -10556,11 +10600,6 @@ build_gw_lrouter_nat_flows_for_lb(struct lrouter_nat_lb_flows_ctx *ctx, + ctx->new_action[type], &ctx->lb->nlb->header_); + } + bitmap_free(dp_non_meter); +- +- ovn_lflow_add_with_dp_group( +- ctx->lflows, dp_bitmap, S_ROUTER_IN_DNAT, ctx->prio, +- ds_cstr(ctx->est_match), ctx->est_action[type], +- &ctx->lb->nlb->header_); + } + + static void +@@ -10572,19 +10611,13 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, + const struct shash *meter_groups, + const struct chassis_features *features) + { +- const char *ct_natted = features->ct_no_masked_label +- ? "ct_mark.natted" +- : "ct_label.natted"; +- + bool ipv4 = lb_vip->address_family == AF_INET; + const char *ip_match = ipv4 ? "ip4" : "ip6"; +- const char *ip_reg = ipv4 ? REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6; + + int prio = 110; + + struct ds skip_snat_act = DS_EMPTY_INITIALIZER; + struct ds force_snat_act = DS_EMPTY_INITIALIZER; +- struct ds est_match = DS_EMPTY_INITIALIZER; + struct ds undnat_match = DS_EMPTY_INITIALIZER; + struct ds unsnat_match = DS_EMPTY_INITIALIZER; + +@@ -10601,19 +10634,14 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, + * of "ct_lb_mark($targets);". The other flow is for ct.est with + * an action of "next;". + */ +- ds_put_format(match, "ct.new && !ct.rel && %s && %s == %s", +- ip_match, ip_reg, lb_vip->vip_str); ++ ds_put_format(match, "ct.new && !ct.rel && %s && %s.dst == %s", ++ ip_match, ip_match, lb_vip->vip_str); + if (lb_vip->port_str) { + prio = 120; +- ds_put_format(match, " && %s && "REG_ORIG_TP_DPORT_ROUTER" == %s", +- lb->proto, lb_vip->port_str); ++ ds_put_format(match, " && %s && %s.dst == %s", ++ lb->proto, lb->proto, lb_vip->port_str); + } + +- ds_put_cstr(&est_match, "ct.est"); +- /* Clone the match after initial "ct.new" (6 bytes). */ +- ds_put_cstr(&est_match, ds_cstr(match) + 6); +- ds_put_format(&est_match, " && %s == 1", ct_natted); +- + /* Add logical flows to UNDNAT the load balanced reverse traffic in + * the router egress pipleine stage - S_ROUTER_OUT_UNDNAT if the logical + * router has a gateway router port associated. +@@ -10650,20 +10678,12 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, + .lflows = lflows, + .meter_groups = meter_groups, + .new_match = match, +- .est_match = &est_match, + .undnat_match = &undnat_match + }; + + ctx.new_action[LROUTER_NAT_LB_FLOW_NORMAL] = ds_cstr(action); +- ctx.est_action[LROUTER_NAT_LB_FLOW_NORMAL] = "next;"; +- + ctx.new_action[LROUTER_NAT_LB_FLOW_SKIP_SNAT] = ds_cstr(&skip_snat_act); +- ctx.est_action[LROUTER_NAT_LB_FLOW_SKIP_SNAT] = +- "flags.skip_snat_for_lb = 1; next;"; +- + ctx.new_action[LROUTER_NAT_LB_FLOW_FORCE_SNAT] = ds_cstr(&force_snat_act); +- ctx.est_action[LROUTER_NAT_LB_FLOW_FORCE_SNAT] = +- "flags.force_snat_for_lb = 1; next;"; + + enum { + LROUTER_NAT_LB_AFF = LROUTER_NAT_LB_FLOW_MAX, +@@ -10746,7 +10766,6 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, + + ds_destroy(&unsnat_match); + ds_destroy(&undnat_match); +- ds_destroy(&est_match); + ds_destroy(&skip_snat_act); + ds_destroy(&force_snat_act); + +@@ -10820,39 +10839,19 @@ build_lrouter_defrag_flows_for_lb(struct ovn_northd_lb *lb, + return; + } + +- struct ds defrag_actions = DS_EMPTY_INITIALIZER; + for (size_t i = 0; i < lb->n_vips; i++) { + struct ovn_lb_vip *lb_vip = &lb->vips[i]; ++ bool ipv6 = lb_vip->address_family == AF_INET6; + int prio = 100; + +- ds_clear(&defrag_actions); + ds_clear(match); +- +- if (lb_vip->address_family == AF_INET) { +- ds_put_format(match, "ip && ip4.dst == %s", lb_vip->vip_str); +- ds_put_format(&defrag_actions, REG_NEXT_HOP_IPV4" = %s; ", +- lb_vip->vip_str); +- } else { +- ds_put_format(match, "ip && ip6.dst == %s", lb_vip->vip_str); +- ds_put_format(&defrag_actions, REG_NEXT_HOP_IPV6" = %s; ", +- lb_vip->vip_str); +- } +- +- if (lb_vip->port_str) { +- ds_put_format(match, " && %s", lb->proto); +- prio = 110; +- +- ds_put_format(&defrag_actions, REG_ORIG_TP_DPORT_ROUTER +- " = %s.dst; ", lb->proto); +- } +- +- ds_put_format(&defrag_actions, "ct_dnat;"); ++ ds_put_format(match, "ip && ip%c.dst == %s", ipv6 ? '6' : '4', ++ lb_vip->vip_str); + + ovn_lflow_add_with_dp_group( + lflows, lb->nb_lr_map, S_ROUTER_IN_DEFRAG, prio, +- ds_cstr(match), ds_cstr(&defrag_actions), &lb->nlb->header_); ++ ds_cstr(match), "ct_dnat;", &lb->nlb->header_); + } +- ds_destroy(&defrag_actions); + } + + static void +@@ -10991,15 +10990,10 @@ copy_ra_to_sb(struct ovn_port *op, const char *address_mode) + } + + static inline bool +-lrouter_nat_is_stateless(const struct nbrec_nat *nat) ++lrouter_dnat_and_snat_is_stateless(const struct nbrec_nat *nat) + { +- const char *stateless = smap_get(&nat->options, "stateless"); +- +- if (stateless && !strcmp(stateless, "true")) { +- return true; +- } +- +- return false; ++ return smap_get_bool(&nat->options, "stateless", false) && ++ !strcmp(nat->type, "dnat_and_snat"); + } + + /* Handles the match criteria and actions in logical flow +@@ -12814,8 +12808,7 @@ build_gateway_redirect_flows_for_lrouter( + for (int j = 0; j < od->n_nat_entries; j++) { + const struct ovn_nat *nat = &od->nat_entries[j]; + +- if (!lrouter_nat_is_stateless(nat->nb) || +- strcmp(nat->nb->type, "dnat_and_snat") || ++ if (!lrouter_dnat_and_snat_is_stateless(nat->nb) || + (!nat->nb->allowed_ext_ips && !nat->nb->exempted_ext_ips)) { + continue; + } +@@ -13038,9 +13031,27 @@ build_misc_local_traffic_drop_flows_for_lrouter( + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 50, + "eth.bcast", debug_drop_action()); + ++ /* Avoid ICMP time exceeded for multicast, silent drop instead. ++ * See RFC1812 section 5.3.1: ++ * If the TTL is reduced to zero (or less), the packet MUST be ++ * discarded, and if the destination is NOT A MULTICAST address the ++ * router MUST send an ICMP Time Exceeded message ... ++ * ++ * The reason behind is that TTL has special meanings for multicast. ++ * For example, TTL = 1 means restricted to the same subnet, not ++ * forwarded by the router. So it is very common to see multicast ++ * packets with ttl = 1, and generating ICMP for such packets is ++ * harmful from both slowpath performance and functionality point of ++ * view. ++ * ++ * (priority-31 flows will send ICMP time exceeded) */ ++ ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 32, ++ "ip.ttl == {0, 1} && !ip.later_frag && " ++ "(ip4.mcast || ip6.mcast)", debug_drop_action()); ++ + /* TTL discard */ + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 30, +- "ip4 && ip.ttl == {0, 1}", debug_drop_action()); ++ "ip.ttl == {0, 1}", debug_drop_action()); + + /* Pass other traffic not already handled to the next table for + * routing. */ +@@ -13224,7 +13235,7 @@ build_ipv6_input_flows_for_lrouter_port( + "outport = %s; flags.loopback = 1; output; };", + ds_cstr(&ip_ds), op->json_key); + ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, +- 100, ds_cstr(match), ds_cstr(actions), NULL, ++ 31, ds_cstr(match), ds_cstr(actions), NULL, + copp_meter_get(COPP_ICMP6_ERR, op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); +@@ -13352,7 +13363,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, + "outport = %s; flags.loopback = 1; output; };", + ds_cstr(&ip_ds), op->json_key); + ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, +- 100, ds_cstr(match), ds_cstr(actions), NULL, ++ 31, ds_cstr(match), ds_cstr(actions), NULL, + copp_meter_get(COPP_ICMP4_ERR, op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); +@@ -13597,13 +13608,13 @@ build_lrouter_in_unsnat_flow(struct hmap *lflows, struct ovn_datapath *od, + return; + } + +- bool stateless = lrouter_nat_is_stateless(nat); ++ bool stateless = lrouter_dnat_and_snat_is_stateless(nat); + if (od->is_gw_router) { + ds_clear(match); + ds_clear(actions); + ds_put_format(match, "ip && ip%s.dst == %s", + is_v6 ? "6" : "4", nat->external_ip); +- if (!strcmp(nat->type, "dnat_and_snat") && stateless) { ++ if (stateless) { + ds_put_format(actions, "next;"); + } else { + ds_put_cstr(actions, "ct_snat;"); +@@ -13628,7 +13639,7 @@ build_lrouter_in_unsnat_flow(struct hmap *lflows, struct ovn_datapath *od, + l3dgw_port->cr_port->json_key); + } + +- if (!strcmp(nat->type, "dnat_and_snat") && stateless) { ++ if (stateless) { + ds_put_format(actions, "next;"); + } else { + ds_put_cstr(actions, "ct_snat_in_czone;"); +@@ -13670,7 +13681,7 @@ build_lrouter_in_dnat_flow(struct hmap *lflows, struct ovn_datapath *od, + * IP address that needs to be DNATted from a external IP address + * to a logical IP address. */ + if (!strcmp(nat->type, "dnat") || !strcmp(nat->type, "dnat_and_snat")) { +- bool stateless = lrouter_nat_is_stateless(nat); ++ bool stateless = lrouter_dnat_and_snat_is_stateless(nat); + + if (od->is_gw_router) { + /* Packet when it goes from the initiator to destination. +@@ -13692,7 +13703,7 @@ build_lrouter_in_dnat_flow(struct hmap *lflows, struct ovn_datapath *od, + ds_put_format(actions, "flags.force_snat_for_dnat = 1; "); + } + +- if (!strcmp(nat->type, "dnat_and_snat") && stateless) { ++ if (stateless) { + ds_put_format(actions, "flags.loopback = 1; " + "ip%s.dst=%s; next;", + is_v6 ? "6" : "4", nat->logical_ip); +@@ -13782,8 +13793,7 @@ build_lrouter_out_undnat_flow(struct hmap *lflows, struct ovn_datapath *od, + ETH_ADDR_ARGS(mac)); + } + +- if (!strcmp(nat->type, "dnat_and_snat") && +- lrouter_nat_is_stateless(nat)) { ++ if (lrouter_dnat_and_snat_is_stateless(nat)) { + ds_put_format(actions, "next;"); + } else { + ds_put_format(actions, +@@ -13839,7 +13849,7 @@ build_lrouter_out_snat_flow(struct hmap *lflows, struct ovn_datapath *od, + return; + } + +- bool stateless = lrouter_nat_is_stateless(nat); ++ bool stateless = lrouter_dnat_and_snat_is_stateless(nat); + if (od->is_gw_router) { + ds_clear(match); + ds_put_format(match, "ip && ip%s.src == %s", +@@ -13905,7 +13915,7 @@ build_lrouter_out_snat_flow(struct hmap *lflows, struct ovn_datapath *od, + ETH_ADDR_ARGS(mac)); + } + +- if (!strcmp(nat->type, "dnat_and_snat") && stateless) { ++ if (stateless) { + ds_put_format(actions, "ip%s.src=%s; next;", + is_v6 ? "6" : "4", nat->external_ip); + } else { +@@ -14217,10 +14227,10 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, + ovn_lflow_add(lflows, od, S_ROUTER_OUT_EGR_LOOP, 0, "1", "next;"); + ovn_lflow_add(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 0, "1", "next;"); + +- /* Ingress DNAT and DEFRAG Table (Priority 50/70). +- * +- * The defrag stage needs to have flows for ICMP in order to get +- * the correct ct_state that can be used by DNAT stage. ++ const char *ct_flag_reg = features->ct_no_masked_label ++ ? "ct_mark" ++ : "ct_label"; ++ /* Ingress DNAT (Priority 50/70). + * + * Allow traffic that is related to an existing conntrack entry. + * At the same time apply NAT for this traffic. +@@ -14231,16 +14241,10 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, + * that's generated from a non-listening UDP port. */ + if (od->has_lb_vip && features->ct_lb_related) { + ds_clear(match); +- const char *ct_flag_reg = features->ct_no_masked_label +- ? "ct_mark" +- : "ct_label"; + + ds_put_cstr(match, "ct.rel && !ct.est && !ct.new"); + size_t match_len = match->length; + +- ovn_lflow_add(lflows, od, S_ROUTER_IN_DEFRAG, 50, "icmp || icmp6", +- "ct_dnat;"); +- + ds_put_format(match, " && %s.skip_snat == 1", ct_flag_reg); + ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 70, ds_cstr(match), + "flags.skip_snat_for_lb = 1; ct_commit_nat;"); +@@ -14251,10 +14255,34 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, + "flags.force_snat_for_lb = 1; ct_commit_nat;"); + + ds_truncate(match, match_len); +- ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 50, +- "ct.rel && !ct.est && !ct.new", "ct_commit_nat;"); ++ ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 50, ds_cstr(match), ++ "ct_commit_nat;"); ++ } + ++ /* Ingress DNAT (Priority 50/70). ++ * ++ * Pass the traffic that is already established to the next table with ++ * proper flags set. ++ */ ++ if (od->has_lb_vip) { + ds_clear(match); ++ ++ ds_put_format(match, "ct.est && !ct.rel && !ct.new && %s.natted", ++ ct_flag_reg); ++ size_t match_len = match->length; ++ ++ ds_put_format(match, " && %s.skip_snat == 1", ct_flag_reg); ++ ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 70, ds_cstr(match), ++ "flags.skip_snat_for_lb = 1; next;"); ++ ++ ds_truncate(match, match_len); ++ ds_put_format(match, " && %s.force_snat == 1", ct_flag_reg); ++ ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 70, ds_cstr(match), ++ "flags.force_snat_for_lb = 1; next;"); ++ ++ ds_truncate(match, match_len); ++ ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 50, ds_cstr(match), ++ "next;"); + } + + /* If the router has load balancer or DNAT rules, re-circulate every packet +@@ -14267,6 +14295,9 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, + * flag set. Some NICs are unable to offload these flows. + */ + if (od->is_gw_router && (od->nbr->n_nat || od->has_lb_vip)) { ++ /* Do not send ND or ICMP packets to connection tracking. */ ++ ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 100, ++ "nd || nd_rs || nd_ra", "next;"); + ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 50, + "ip", "flags.loopback = 1; ct_dnat;"); + ovn_lflow_add(lflows, od, S_ROUTER_OUT_POST_UNDNAT, 50, +diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml +index 2eab2c4ae..e16d7d080 100644 +--- a/northd/ovn-northd.8.xml ++++ b/northd/ovn-northd.8.xml +@@ -748,6 +748,12 @@ + drop behavior. +

    + ++

    ++ A priority-65532 flow is added to allow IPv6 Neighbor solicitation, ++ Neighbor discover, Router solicitation, Router advertisement and MLD ++ packets regardless of other ACLs defined. ++

    ++ +

    + If the logical datapath has a stateful ACL or a load balancer with VIP + configured, the following flows will also be added: +@@ -824,12 +830,6 @@ + in the request direction are skipped here to let a newly created + ACL re-allow this connection. +

  • +- +-
  • +- A priority-65532 flow that allows IPv6 Neighbor solicitation, +- Neighbor discover, Router solicitation, Router advertisement and MLD +- packets. +-
  • + + +

    +@@ -2056,6 +2056,16 @@ output; + db="OVN_Northbound"/> table. +

    + ++

    ++ This table also has a priority-110 flow with the match ++ outport == I for all logical switch ++ datapaths to move traffic to the next table, and, if there are no ++ stateful_acl, clear the ct_state. Where I ++ is the peer of a logical router port. This flow is added to ++ skip the connection tracking of packets which will be entering ++ logical router datapath from logical switch datapath for routing. ++

    ++ +

    Egress Table 2: Pre-stateful

    + +

    +@@ -2098,6 +2108,12 @@ output; + to-lport ACLs. +

    + ++

    ++ Similar to ingress table, a priority-65532 flow is added to allow IPv6 ++ Neighbor solicitation, Neighbor discover, Router solicitation, Router ++ advertisement and MLD packets regardless of other ACLs defined. ++

    ++ +

    + In addition, the following flows are added. +

    +@@ -3066,10 +3082,18 @@ nd.tll = external_mac; + broadcast address. By definition this traffic should not be forwarded. + + ++
  • ++ Avoid ICMP time exceeded for multicast. A priority-32 flow with match ++ ip.ttl == {0, 1} && !ip.later_frag && ++ (ip4.mcast || ip6.mcast) and actions drop; drops ++ multicast packets whose TTL has expired without sending ICMP time ++ exceeded. ++
  • ++ +
  • +

    + ICMP time exceeded. For each router port P, whose IP +- address is A, a priority-100 flow with match inport ++ address is A, a priority-31 flow with match inport + == P && ip.ttl == {0, 1} && + !ip.later_frag matches packets whose TTL has expired, with the + following actions to send an ICMP time exceeded reply for IPv4 and +@@ -3282,35 +3306,16 @@ icmp6 { +

    + +

    +- If load balancing rules with only virtual IP addresses are configured in ++ For all load balancing rules that are configured in + OVN_Northbound database for a Gateway router, + a priority-100 flow is added for each configured virtual IP address + VIP. For IPv4 VIPs the flow matches + ip && ip4.dst == VIP. For IPv6 + VIPs, the flow matches ip && ip6.dst == +- VIP. The flow applies the action reg0 = +- VIP; ct_dnat; (or xxreg0 for IPv6) to +- send IP packets to the connection tracker for packet de-fragmentation and +- to dnat the destination IP for the committed connection before sending it +- to the next table. +-

    +- +-

    +- If load balancing rules with virtual IP addresses and ports are +- configured in OVN_Northbound database for a Gateway router, +- a priority-110 flow is added for each configured virtual IP address +- VIP, protocol PROTO and port PORT. +- For IPv4 VIPs the flow matches +- ip && ip4.dst == VIP && +- PROTO && PROTO.dst == +- PORT. For IPv6 VIPs, the flow matches +- ip && ip6.dst == VIP && +- PROTO && PROTO.dst == +- PORT. The flow applies the action reg0 = +- VIP; reg9[16..31] = PROTO.dst; ct_dnat; +- (or xxreg0 for IPv6) to send IP packets to the connection +- tracker for packet de-fragmentation and to dnat the destination IP for +- the committed connection before sending it to the next table. ++ VIP. The flow applies the action ct_dnat; ++ to send IP packets to the connection tracker for packet de-fragmentation ++ and to dnat the destination IP for the committed connection before ++ sending it to the next table. +

    + +

    +@@ -3349,10 +3354,11 @@ icmp6 { + column, that includes a L4 port PORT of protocol + P and IPv4 or IPv6 address VIP, a priority-100 + flow that matches on ct.new && ip && +- reg0 == VIP && P && reg9[16..31] ++ ip.dst == VIP && P && P.dst + == PORT (xxreg0 == VIP +- in the IPv6 case) with an action of reg9[6] = +- chk_lb_aff(); next; ++ in the IPv6 case) with an action of reg0 = ip.dst; ++ reg9[16..31] = P.dst; reg9[6] = chk_lb_aff(); next; ++ (xxreg0 == ip6.dst in the IPv6 case) +

  • + +
  • +@@ -3385,9 +3391,8 @@ icmp6 { + column, that includes a L4 port PORT of protocol + P and IPv4 or IPv6 address VIP, a priority-150 + flow that matches on reg9[6] == 1 && ct.new && +- ip && reg0 == VIP && P && +- reg9[16..31] == PORT (xxreg0 +- == VIP in the IPv6 case) with an action of ++ ip && ip.dst == VIP && P && ++ P.dst == PORT with an action of + ct_lb_mark(args) , where args + contains comma separated IP addresses (and optional port numbers) + to load balance to. The address family of the IP addresses of +@@ -3410,56 +3415,25 @@ icmp6 { + Router with gateway port in OVN_Northbound database that + includes a L4 port PORT of protocol P and IPv4 + or IPv6 address VIP, a priority-120 flow that matches on +- ct.new && !ct.rel && ip && reg0 == +- VIP && P && reg9[16..31] == +- PORT (xxreg0 == VIP +- in the IPv6 case) with an action of ++ ct.new && !ct.rel && ip && ip.dst == ++ VIP && P && P.dst == ++ PORT with an action of + ct_lb_mark(args), where args contains + comma separated IPv4 or IPv6 addresses (and optional port numbers) to + load balance to. If the router is configured to force SNAT any + load-balanced packets, the above action will be replaced by +- flags.force_snat_for_lb = 1; ct_lb_mark(args);. ++ flags.force_snat_for_lb = 1; ct_lb_mark(args; ++ force_snat);. + If the load balancing rule is configured with skip_snat + set to true, the above action will be replaced by +- flags.skip_snat_for_lb = 1; ct_lb_mark(args);. ++ flags.skip_snat_for_lb = 1; ct_lb_mark(args; ++ skip_snat);. + If health check is enabled, then + args will only contain those endpoints whose service + monitor status entry in OVN_Southbound db is + either online or empty. +

    + +-

    +- The previous table lr_in_defrag sets the register +- reg0 (or xxreg0 for IPv6) and does +- ct_dnat. Hence for established traffic, this +- table just advances the packet to the next stage. +-

    +-
  • +- +-
  • +-

    +- For all the configured load balancing rules for a router in +- OVN_Northbound database that includes a L4 port +- PORT of protocol P and IPv4 or IPv6 address +- VIP, a priority-120 flow that matches on +- ct.est && !ct.rel && ip4 && reg0 == +- VIP && P && reg9[16..31] == +- PORT (ip6 and +- xxreg0 == VIP in the IPv6 case) with an +- action of next;. If the router is configured to force +- SNAT any load-balanced packets, the above action will be replaced by +- flags.force_snat_for_lb = 1; next;. If the load +- balancing rule is configured with skip_snat set to true, +- the above action will be replaced by +- flags.skip_snat_for_lb = 1; next;. +-

    +- +-

    +- The previous table lr_in_defrag sets the register +- reg0 (or xxreg0 for IPv6) and does +- ct_dnat. Hence for established traffic, this +- table just advances the packet to the next stage. +-

    +
  • + +
  • +@@ -3467,42 +3441,17 @@ icmp6 { + For all the configured load balancing rules for a router in + OVN_Northbound database that includes just an IP address + VIP to match on, a priority-110 flow that matches on +- ct.new && !ct.rel && ip4 && reg0 == +- VIP (ip6 and xxreg0 == +- VIP in the IPv6 case) with an action of ++ ct.new && !ct.rel && ip4 && ip.dst == ++ VIP with an action of + ct_lb_mark(args), where args contains + comma separated IPv4 or IPv6 addresses. If the router is configured + to force SNAT any load-balanced packets, the above action will be + replaced by flags.force_snat_for_lb = 1; +- ct_lb_mark(args);. +- If the load balancing rule is configured with skip_snat +- set to true, the above action will be replaced by +- flags.skip_snat_for_lb = 1; ct_lb_mark(args);. +-

    +- +-

    +- The previous table lr_in_defrag sets the register +- reg0 (or xxreg0 for IPv6) and does +- ct_dnat. Hence for established traffic, this +- table just advances the packet to the next stage. +-

    +-
  • +- +- +-
  • +-

    +- For all the configured load balancing rules for a router in +- OVN_Northbound database that includes just an IP address +- VIP to match on, a priority-110 flow that matches on +- ct.est && !ct.rel && ip4 && reg0 == +- VIP (or ip6 and +- xxreg0 == VIP) with an action of +- next;. If the router is configured to force SNAT any +- load-balanced packets, the above action will be replaced by +- flags.force_snat_for_lb = 1; next;. ++ ct_lb_mark(args; force_snat);. + If the load balancing rule is configured with skip_snat + set to true, the above action will be replaced by +- flags.skip_snat_for_lb = 1; next;. ++ flags.skip_snat_for_lb = 1; ct_lb_mark(args; ++ skip_snat);. +

    + +

    +@@ -3529,7 +3478,20 @@ icmp6 { + with an action of ct_commit_nat;, if the router + has load balancer assigned to it. Along with two priority 70 flows + that match skip_snat and force_snat +- flags. ++ flags, setting the flags.force_snat_for_lb = 1 or ++ flags.skip_snat_for_lb = 1 accordingly. ++

    ++
  • ++
  • ++

    ++ For the established traffic, a priority 50 flow that matches ++ ct.est && !ct.rel && !ct.new && ++ ct_mark.natted with an action of next;, ++ if the router has load balancer assigned to it. Along with two ++ priority 70 flows that match skip_snat and ++ force_snat flags, setting the ++ flags.force_snat_for_lb = 1 or ++ flags.skip_snat_for_lb = 1 accordingly. +

    +
  • + +@@ -4721,6 +4683,11 @@ nd_ns { +

    Egress Table 1: UNDNAT on Gateway Routers

    + +
      ++
    • ++ For IPv6 Neighbor Discovery or Router Solicitation/Advertisement ++ traffic, a priority-100 flow with action next;. ++
    • ++ +
    • + For all IP packets, a priority-50 flow with an action + flags.loopback = 1; ct_dnat;. +@@ -4998,7 +4965,19 @@ nd_ns { +
    • +
    + +-

    Egress Table 4: Egress Loopback

    ++

    Egress Table 4: Post SNAT

    ++ ++

    ++ Packets reaching this table are processed according to the flows below: ++

      ++
    • ++ A priority-0 logical flow that matches all packets not already ++ handled (match 1) and action next;. ++
    • ++
    ++

    ++ ++

    Egress Table 5: Egress Loopback

    + +

    + For distributed logical routers where one of the logical router +@@ -5070,7 +5049,7 @@ clone { + + + +-

    Egress Table 5: Delivery

    ++

    Egress Table 6: Delivery

    + +

    + Packets that reach this table are ready for delivery. It contains: +diff --git a/ovn-architecture.7.xml b/ovn-architecture.7.xml +index cb1064f71..86c6258e0 100644 +--- a/ovn-architecture.7.xml ++++ b/ovn-architecture.7.xml +@@ -1318,7 +1318,7 @@ + output port is known. These pieces of information are obtained + from the tunnel encapsulation metadata (see Tunnel + Encapsulations for encoding details). Then the actions resubmit +- to table 33 to enter the logical egress pipeline. ++ to table 38 to enter the logical egress pipeline. +

    + + +diff --git a/ovn-nb.xml b/ovn-nb.xml +index 8d56d0c6e..35acda107 100644 +--- a/ovn-nb.xml ++++ b/ovn-nb.xml +@@ -2036,6 +2036,14 @@ or + the affinity timeslot. Max supported affinity_timeout is 65535 + seconds. + ++ ++ ++ The value indicates whether ovn-controller should flush CT entries ++ that are related to this LB. The flush happens if the LB is removed, ++ any of the backends is updated/removed or the LB is not considered ++ local anymore by the ovn-controller. This option is set to ++ false by default. ++ + + + +diff --git a/ovn-sb.xml b/ovn-sb.xml +index a77f8f4ef..8ca206109 100644 +--- a/ovn-sb.xml ++++ b/ovn-sb.xml +@@ -472,9 +472,8 @@ + + + The encapsulation to use to transmit packets to this chassis. +- Hypervisors must use either geneve or +- stt. Gateways may use vxlan, +- geneve, or stt. ++ Hypervisors and gateways must use one of: geneve, ++ vxlan, or stt. + + + +diff --git a/rhel/usr_lib_systemd_system_ovn-db@.service b/rhel/usr_lib_systemd_system_ovn-db@.service +index 98556a673..c835e4967 100644 +--- a/rhel/usr_lib_systemd_system_ovn-db@.service ++++ b/rhel/usr_lib_systemd_system_ovn-db@.service +@@ -33,7 +33,7 @@ EnvironmentFile=-/etc/sysconfig/ovn-%i + ExecStartPre=-/usr/bin/chown -R ${OVN_USER_ID} ${OVN_DBDIR} + ExecStart=/usr/share/ovn/scripts/ovn-ctl \ + --ovn-user=${OVN_USER_ID} start_%i_ovsdb $OPTIONS $ovn_%i_opts +-ExecStop=/usr/share/ovn/scripts/ovn-ctl stop_%i_ovsdb ++ExecStop=/usr/share/ovn/scripts/ovn-ctl stop_%i_ovsdb $OPTIONS $ovn_%i_opts + + [Install] + WantedBy=multi-user.target +diff --git a/rhel/usr_lib_systemd_system_ovn-northd.service b/rhel/usr_lib_systemd_system_ovn-northd.service +index d281f861c..6c4c6621c 100644 +--- a/rhel/usr_lib_systemd_system_ovn-northd.service ++++ b/rhel/usr_lib_systemd_system_ovn-northd.service +@@ -26,7 +26,7 @@ EnvironmentFile=-/etc/sysconfig/ovn-northd + ExecStartPre=-/usr/bin/chown -R ${OVN_USER_ID} ${OVN_DBDIR} + ExecStart=/usr/share/ovn/scripts/ovn-ctl \ + --ovn-user=${OVN_USER_ID} start_northd $OVN_NORTHD_OPTS +-ExecStop=/usr/share/ovn/scripts/ovn-ctl stop_northd ++ExecStop=/usr/share/ovn/scripts/ovn-ctl stop_northd $OVN_NORTHD_OPTS + + [Install] + WantedBy=multi-user.target +diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at +index bbe142ae3..27fc44232 100644 +--- a/tests/ovn-controller.at ++++ b/tests/ovn-controller.at +@@ -493,7 +493,8 @@ check ovn-nbctl --wait=hv sync + + # And check that it gets propagated to br-int external_ids. + as hv1 +-OVS_WAIT_UNTIL([ovs-vsctl get Bridge br-int external_ids:ovn-nb-cfg], [0], [1]) ++OVS_WAIT_FOR_OUTPUT([ovs-vsctl get Bridge br-int external_ids:ovn-nb-cfg], [0], ["1" ++]) + + nb_cfg_ts=$(fetch_column Chassis_Private nb_cfg_timestamp name=hv1) + as hv1 +@@ -672,22 +673,26 @@ check ovs-vsctl del-ssl + start_daemon ovn-controller -p $key -c $cert -C $cacert + + # SSL should not connect because of key and cert mismatch +-OVS_WAIT_UNTIL([ovn-appctl -t ovn-controller connection-status], [0], [not connected]) ++OVS_WAIT_FOR_OUTPUT([ovn-appctl -t ovn-controller connection-status], [0], [not connected ++]) + + # Modify the files with the correct key and cert, and reconnect should succeed + cp $PKIDIR/$key $key + cp $PKIDIR/$cert $cert + +-OVS_WAIT_UNTIL([ovn-appctl -t ovn-controller connection-status], [0], [connected]) ++OVS_WAIT_FOR_OUTPUT([ovn-appctl -t ovn-controller connection-status], [0], [connected ++]) + + # Remove the files and expect the connection to drop + rm $key $cert +-OVS_WAIT_UNTIL([ovn-appctl -t ovn-controller connection-status], [0], [not connected]) ++OVS_WAIT_FOR_OUTPUT([ovn-appctl -t ovn-controller connection-status], [0], [not connected ++]) + + # Restore the files again and expect the connection to recover + cp $PKIDIR/$key $key + cp $PKIDIR/$cert $cert +-OVS_WAIT_UNTIL([ovn-appctl -t ovn-controller connection-status], [0], [connected]) ++OVS_WAIT_FOR_OUTPUT([ovn-appctl -t ovn-controller connection-status], [0], [connected ++]) + + cat hv1/ovn-controller.log + +@@ -2060,6 +2065,57 @@ AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))], [0], [2 + OVN_CLEANUP([hv1]) + AT_CLEANUP + ++AT_SETUP([ovn-controller - address set del-and-add]) ++ ++ovn_start ++ ++net_add n1 ++sim_add hv1 ++as hv1 ++check ovs-vsctl add-br br-phys ++ovn_attach n1 br-phys 192.168.0.1 ++check ovs-vsctl -- add-port br-int hv1-vif1 -- \ ++ set interface hv1-vif1 external-ids:iface-id=ls1-lp1 ++ ++check ovn-nbctl ls-add ls1 ++ ++check ovn-nbctl lsp-add ls1 ls1-lp1 \ ++-- lsp-set-addresses ls1-lp1 "f0:00:00:00:00:01" ++ ++wait_for_ports_up ++ovn-appctl -t ovn-controller vlog/set file:dbg ++ ++ovn-nbctl create address_set name=as1 addresses=8.8.8.8 ++check ovn-nbctl acl-add ls1 to-lport 100 'outport == "ls1-lp1" && ip4.src == $as1' drop ++check ovn-nbctl --wait=hv sync ++AT_CHECK([ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100"], [0], [1 ++]) ++ ++# pause ovn-northd ++check as northd ovn-appctl -t ovn-northd pause ++check as northd-backup ovn-appctl -t ovn-northd pause ++ ++# Simulate a SB address set "del and add" notification to ovn-controller in the ++# same IDL iteration. The flows programmed by ovn-controller should reflect the ++# newly added address set. In reality it can happen when CMS deletes an ++# address-set and immediately creates a new address-set with the same name ++# (with same or different content). The notification of the changes can come to ++# ovn-controller in one shot and the order of the "del" and "add" in the IDL is ++# undefined. This test runs the scenario ten times to make sure different ++# orders are covered and handled properly. ++ ++flow_count=$(ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100") ++for i in $(seq 10); do ++ # Delete and recreate the SB address set with same name and an extra IP. ++ addrs_=$(fetch_column address_set addresses name=as1) ++ addrs=${addrs_// /,} ++ AT_CHECK([ovn-sbctl destroy address_set as1 -- create address_set name=as1 addresses=$addrs,1.1.1.$i], [0], [ignore]) ++ OVS_WAIT_UNTIL([test $(as hv1 ovs-ofctl dump-flows br-int table=44 | grep -c "priority=1100") = "$(($i + 1))"]) ++done ++ ++OVN_CLEANUP([hv1]) ++AT_CLEANUP ++ + AT_SETUP([ovn-controller - I-P handle lb_hairpin_use_ct_mark change]) + + ovn_start --backup-northd=none +@@ -2161,7 +2217,7 @@ AT_CHECK([ovs-ofctl dump-flows br-int | grep 10.1.2.3], [0], [ignore]) + sleep 5 + + # Check after the wait +-OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep 10.1.2.4], [0], [ignore]) ++OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep 10.1.2.4]) + lflow_run_2=$(ovn-appctl -t ovn-controller coverage/read-counter lflow_run) + + # Verify that the flow compute completed during the wait (after the wait it +@@ -2172,7 +2228,7 @@ AT_CHECK_UNQUOTED([echo $lflow_run_1], [0], [$lflow_run_2 + # Restart OVS this time, and wait until flows are reinstalled + OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) + start_daemon ovs-vswitchd --enable-dummy=system -vvconn -vofproto_dpif -vunixctl +-OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep 10.1.2.4], [0], [ignore]) ++OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep 10.1.2.4]) + + check ovn-nbctl --wait=hv lb-add lb3 2.2.2.2 10.1.2.5 \ + -- ls-lb-add ls1 lb3 +diff --git a/tests/ovn-macros.at b/tests/ovn-macros.at +index ee942e8a6..6f2d085ae 100644 +--- a/tests/ovn-macros.at ++++ b/tests/ovn-macros.at +@@ -817,6 +817,29 @@ ovn_trace_client() { + ovs-appctl -t $target trace "$@" | tee trace | sed '/^# /d' + } + ++# Receives a string with scapy python code that represents a packet. ++# Returns a hex-string that contains bytes that reflect the packet symbolic ++# description. ++# ++# Scapy docs: https://scapy.readthedocs.io/en/latest/usage.html ++# ++# Example of usage: ++# ++# packet=$(fmt_pkt " ++# Ether(dst='ff:ff:ff:ff:ff:ff', src='50:64:00:00:00:01') / ++# IPv6(src='abed::1', dst='ff02::1:ff00:2') / ++# ICMPv6ND_NS(tgt='abed::2') ++# ") ++# ++# ovs-appctl netdev-dummy/receive $vif $packet ++# ++fmt_pkt() { ++ echo "from scapy.all import *; \ ++ import binascii; \ ++ out = binascii.hexlify(raw($1)); \ ++ print(out.decode())" | $PYTHON3 ++} ++ + OVS_END_SHELL_HELPERS + + m4_define([OVN_POPULATE_ARP], [AT_CHECK(ovn_populate_arp__, [0], [ignore])]) +diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at +index 2fffe1850..478a32f5a 100644 +--- a/tests/ovn-nbctl.at ++++ b/tests/ovn-nbctl.at +@@ -1482,6 +1482,32 @@ UUID LB PROTO VIP + + dnl --------------------------------------------------------------------- + ++OVN_NBCTL_TEST([ovn_nbctl_template_lbs], [Template LBs], [ ++check ovn-nbctl --template lb-add lb0 ^vip ^backend ++check ovn-nbctl --template lb-add lb1 ^vip:^vport ^backend udp ++check ovn-nbctl --template lb-add lb2 ^vip:^vport ^backend udp ipv4 ++check ovn-nbctl --template lb-add lb3 ^vip:^vport ^backend udp ipv6 ++check ovn-nbctl --template lb-add lb4 ^vip:^vport ^backend:^bport udp ipv4 ++check ovn-nbctl --template lb-add lb5 ^vip:^vport ^backend:^bport udp ipv6 ++check ovn-nbctl --template lb-add lb6 ^vip:^vport 1.1.1.1:111 udp ipv4 ++check ovn-nbctl --template lb-add lb7 ^vip:^vport [[1::1]]:111 udp ipv6 ++ ++AT_CHECK([ovn-nbctl lb-list | uuidfilt], [0], [dnl ++UUID LB PROTO VIP IPs ++<0> lb0 tcp ^vip ^backend ++<1> lb1 udp ^vip:^vport ^backend ++<2> lb2 udp ^vip:^vport ^backend ++<3> lb3 udp ^vip:^vport ^backend ++<4> lb4 udp ^vip:^vport ^backend:^bport ++<5> lb5 udp ^vip:^vport ^backend:^bport ++<6> lb6 udp ^vip:^vport 1.1.1.1:111 ++<7> lb7 udp ^vip:^vport [[1::1]]:111 ++]) ++ ++]) ++ ++dnl --------------------------------------------------------------------- ++ + OVN_NBCTL_TEST([ovn_nbctl_basic_lr], [basic logical router commands], [ + AT_CHECK([ovn-nbctl lr-add lr0]) + AT_CHECK([ovn-nbctl lr-list | uuidfilt], [0], [dnl +@@ -2599,6 +2625,7 @@ OVN_NBCTL_TEST_STOP "/terminating with signal 15/d" + AT_CLEANUP + + AT_SETUP([ovn-nbctl - daemon ssl files change]) ++AT_SKIP_IF([test "$HAVE_OPENSSL" = no]) + dnl Create ovn-nb database. + AT_CHECK([ovsdb-tool create ovn-nb.db $abs_top_srcdir/ovn-nb.ovsschema]) + +diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at +index 3fa02d2b3..846f10e88 100644 +--- a/tests/ovn-northd.at ++++ b/tests/ovn-northd.at +@@ -2486,6 +2486,7 @@ check ovn-nbctl --wait=sb \ + + AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e ls_in_acl -e ls_out_acl | sort], [0], [dnl + table=17(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) ++ table=17(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=17(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;) + table=3 (ls_out_acl_hint ), priority=0 , match=(1), action=(next;) + table=3 (ls_out_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) +@@ -2530,9 +2531,12 @@ ovn-nbctl --wait=sb clear logical_switch ls load_balancer + + AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint -e ls_in_acl -e ls_out_acl | sort], [0], [dnl + table=17(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) ++ table=17(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=3 (ls_out_acl_hint ), priority=65535, match=(1), action=(next;) ++ table=4 (ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=4 (ls_out_acl ), priority=65535, match=(1), action=(next;) + table=7 (ls_in_acl_hint ), priority=65535, match=(1), action=(next;) ++ table=8 (ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=8 (ls_in_acl ), priority=65535, match=(1), action=(next;) + ]) + +@@ -3757,18 +3761,18 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl + + AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl + table=5 (lr_in_defrag ), priority=0 , match=(1), action=(next;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.10 && tcp), action=(reg0 = 10.0.0.10; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.100 && tcp), action=(reg0 = 10.0.0.100; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.100), action=(ct_dnat;) + ]) + + AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl + table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(ct_lb_mark(backends=10.0.0.4:8080);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(ct_lb_mark(backends=10.0.0.40:8080);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.4:8080);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.100 && tcp && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.40:8080);) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) + table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) + ]) +@@ -3788,18 +3792,18 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl + + AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl + table=5 (lr_in_defrag ), priority=0 , match=(1), action=(next;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.10 && tcp), action=(reg0 = 10.0.0.10; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.100 && tcp), action=(reg0 = 10.0.0.100; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.100), action=(ct_dnat;) + ]) + + AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl + table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080; force_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.100 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080; force_snat);) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) + table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) + ]) +@@ -3813,6 +3817,7 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [ + + AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl + table=? (lr_out_undnat ), priority=0 , match=(1), action=(next;) ++ table=? (lr_out_undnat ), priority=100 , match=(nd || nd_rs || nd_ra), action=(next;) + table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;) + ]) + +@@ -3838,18 +3843,18 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl + + AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl + table=5 (lr_in_defrag ), priority=0 , match=(1), action=(next;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.10 && tcp), action=(reg0 = 10.0.0.10; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.100 && tcp), action=(reg0 = 10.0.0.100; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.100), action=(ct_dnat;) + ]) + + AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl + table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080; force_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.100 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080; force_snat);) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) + table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) + ]) +@@ -3864,6 +3869,7 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [ + + AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl + table=? (lr_out_undnat ), priority=0 , match=(1), action=(next;) ++ table=? (lr_out_undnat ), priority=100 , match=(nd || nd_rs || nd_ra), action=(next;) + table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;) + ]) + +@@ -3902,18 +3908,18 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl + + AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl + table=5 (lr_in_defrag ), priority=0 , match=(1), action=(next;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.10 && tcp), action=(reg0 = 10.0.0.10; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.100 && tcp), action=(reg0 = 10.0.0.100; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.100), action=(ct_dnat;) + ]) + + AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl + table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.100 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080; force_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.100 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080; force_snat);) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) + table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) + ]) +@@ -3929,6 +3935,7 @@ AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [ + + AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl + table=? (lr_out_undnat ), priority=0 , match=(1), action=(next;) ++ table=? (lr_out_undnat ), priority=100 , match=(nd || nd_rs || nd_ra), action=(next;) + table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;) + ]) + +@@ -3953,14 +3960,13 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl + + AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl + table=5 (lr_in_defrag ), priority=0 , match=(1), action=(next;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.100 && tcp), action=(reg0 = 10.0.0.100; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.20 && tcp), action=(reg0 = 10.0.0.20; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.100), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.20), action=(ct_dnat;) + ]) + + AT_CHECK([grep "lr_in_dnat" lr0flows | grep skip_snat_for_lb | sort], [0], [dnl +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.20 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.skip_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.20 && tcp && reg9[[16..31]] == 80), action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080; skip_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.20 && tcp && tcp.dst == 80), action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.40:8080; skip_snat);) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) + ]) + +@@ -3970,6 +3976,7 @@ AT_CHECK([grep "lr_out_snat" lr0flows | grep skip_snat_for_lb | sed 's/table=./t + + AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl + table=? (lr_out_undnat ), priority=0 , match=(1), action=(next;) ++ table=? (lr_out_undnat ), priority=100 , match=(nd || nd_rs || nd_ra), action=(next;) + table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;) + ]) + +@@ -4111,6 +4118,7 @@ check ovn-nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0 + check ovn-nbctl --wait=sb sync + + check_stateful_flows() { ++ action=$1 + ovn-sbctl dump-flows sw0 > sw0flows + AT_CAPTURE_FILE([sw0flows]) + +@@ -4144,12 +4152,12 @@ check_stateful_flows() { + table=??(ls_in_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;) + ]) + +- AT_CHECK([grep "ls_out_pre_lb" sw0flows | sort], [0], [dnl ++ AT_CHECK_UNQUOTED([grep "ls_out_pre_lb" sw0flows | sort], [0], [dnl + table=1 (ls_out_pre_lb ), priority=0 , match=(1), action=(next;) + table=1 (ls_out_pre_lb ), priority=100 , match=(ip), action=(reg0[[2]] = 1; next;) + table=1 (ls_out_pre_lb ), priority=110 , match=(eth.mcast), action=(next;) +- table=1 (ls_out_pre_lb ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;) +- table=1 (ls_out_pre_lb ), priority=110 , match=(ip && outport == "sw0-lr0"), action=(next;) ++ table=1 (ls_out_pre_lb ), priority=110 , match=(eth.src == \$svc_monitor_mac), action=(next;) ++ table=1 (ls_out_pre_lb ), priority=110 , match=(ip && outport == "sw0-lr0"), action=($action) + table=1 (ls_out_pre_lb ), priority=110 , match=(nd || nd_rs || nd_ra || mldv1 || mldv2), action=(next;) + table=1 (ls_out_pre_lb ), priority=110 , match=(reg0[[16]] == 1), action=(next;) + ]) +@@ -4169,13 +4177,13 @@ check_stateful_flows() { + ]) + } + +-check_stateful_flows ++check_stateful_flows "ct_clear; next;" + + # Add few ACLs + check ovn-nbctl --wait=sb acl-add sw0 from-lport 1002 "ip4 && tcp && tcp.dst == 80" allow-related + check ovn-nbctl --wait=sb acl-add sw0 to-lport 1002 "ip4 && tcp && tcp.src == 80" drop + +-check_stateful_flows ++check_stateful_flows "next;" + + # Remove load balancers from sw0 + check ovn-nbctl ls-lb-del sw0 lb0 +@@ -4231,6 +4239,15 @@ AT_CHECK([grep "ls_out_stateful" sw0flows | sort], [0], [dnl + table=7 (ls_out_stateful ), priority=100 , match=(reg0[[1]] == 1 && reg0[[13]] == 1), action=(ct_commit { ct_mark.blocked = 0; ct_label.label = reg3; }; next;) + ]) + ++# LB with event=false and reject=false ++AT_CHECK([ovn-nbctl create load_balancer name=lb1 options:reject=false options:event=false vips:\"10.0.0.20\"=\"\" protocol=tcp], [0], [ignore]) ++check ovn-nbctl --wait=sb ls-lb-add sw0 lb1 ++ ++AT_CHECK([ovn-sbctl dump-flows sw0 | grep "ls_in_lb " | sort ], [0], [dnl ++ table=12(ls_in_lb ), priority=0 , match=(1), action=(next;) ++ table=12(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 10.0.0.20), action=(drop;) ++]) ++ + AT_CLEANUP + ]) + +@@ -5211,25 +5228,23 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl + + AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl + table=5 (lr_in_defrag ), priority=0 , match=(1), action=(next;) +- table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.200), action=(reg0 = 172.168.0.200; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.10 && tcp), action=(reg0 = 10.0.0.10; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.100 && tcp), action=(reg0 = 172.168.0.100; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.210 && udp), action=(reg0 = 172.168.0.210; reg9[[16..31]] = udp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.100), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.200), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.210), action=(ct_dnat;) + ]) + + AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl + table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) + table=7 (lr_in_dnat ), priority=100 , match=(ip && ip4.dst == 172.168.0.20 && inport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_dnat_in_czone(10.0.0.3);) +- table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.200 && ct_mark.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;) +- table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.200 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.80,10.0.0.81);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_mark.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.4:8080);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062);) ++ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.200 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.80,10.0.0.81);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.4:8080);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.100 && tcp && tcp.dst == 8082 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.210 && udp && udp.dst == 60 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062);) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) + table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) + ]) +@@ -5284,25 +5299,23 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl + + AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl + table=5 (lr_in_defrag ), priority=0 , match=(1), action=(next;) +- table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.200), action=(reg0 = 172.168.0.200; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.10 && tcp), action=(reg0 = 10.0.0.10; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.100 && tcp), action=(reg0 = 172.168.0.100; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.210 && udp), action=(reg0 = 172.168.0.210; reg9[[16..31]] = udp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.100), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.200), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.210), action=(ct_dnat;) + ]) + + AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl + table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) + table=7 (lr_in_dnat ), priority=100 , match=(ip && ip4.dst == 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);) +- table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.200 && ct_mark.natted == 1), action=(next;) +- table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.200), action=(ct_lb_mark(backends=10.0.0.80,10.0.0.81);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_mark.natted == 1), action=(next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(ct_lb_mark(backends=10.0.0.4:8080);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062);) ++ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.200), action=(ct_lb_mark(backends=10.0.0.80,10.0.0.81);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.4:8080);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.100 && tcp && tcp.dst == 8082), action=(ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.210 && udp && udp.dst == 60), action=(ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062);) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) + table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) + ]) +@@ -5314,6 +5327,7 @@ AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sor + + AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl + table=? (lr_out_undnat ), priority=0 , match=(1), action=(next;) ++ table=? (lr_out_undnat ), priority=100 , match=(nd || nd_rs || nd_ra), action=(next;) + table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;) + ]) + +@@ -5349,25 +5363,23 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl + + AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl + table=5 (lr_in_defrag ), priority=0 , match=(1), action=(next;) +- table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.200), action=(reg0 = 172.168.0.200; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.10 && tcp), action=(reg0 = 10.0.0.10; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.100 && tcp), action=(reg0 = 172.168.0.100; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.210 && udp), action=(reg0 = 172.168.0.210; reg9[[16..31]] = udp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.100), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.200), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.210), action=(ct_dnat;) + ]) + + AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl + table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) + table=7 (lr_in_dnat ), priority=100 , match=(ip && ip4.dst == 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);) +- table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.200 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.80,10.0.0.81; force_snat);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82; force_snat);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062; force_snat);) ++ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.80,10.0.0.81; force_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.100 && tcp && tcp.dst == 8082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82; force_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.210 && udp && udp.dst == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062; force_snat);) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) + table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) + ]) +@@ -5379,6 +5391,7 @@ AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sor + + AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl + table=? (lr_out_undnat ), priority=0 , match=(1), action=(next;) ++ table=? (lr_out_undnat ), priority=100 , match=(nd || nd_rs || nd_ra), action=(next;) + table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;) + ]) + +@@ -5416,28 +5429,25 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl + + AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl + table=5 (lr_in_defrag ), priority=0 , match=(1), action=(next;) +- table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.200), action=(reg0 = 172.168.0.200; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.10 && tcp), action=(reg0 = 10.0.0.10; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.10 && tcp), action=(reg0 = 172.168.0.10; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.100 && tcp), action=(reg0 = 172.168.0.100; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.210 && udp), action=(reg0 = 172.168.0.210; reg9[[16..31]] = udp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.10), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.100), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.200), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.210), action=(ct_dnat;) + ]) + + AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl + table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) + table=7 (lr_in_dnat ), priority=100 , match=(ip && ip4.dst == 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);) +- table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.200 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.80,10.0.0.81; force_snat);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82; force_snat);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82; force_snat);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062; force_snat);) ++ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.80,10.0.0.81; force_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.10 && tcp && tcp.dst == 9082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82; force_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.100 && tcp && tcp.dst == 8082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82; force_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.210 && udp && udp.dst == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062; force_snat);) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) + table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) + ]) +@@ -5449,6 +5459,7 @@ AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sor + + AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl + table=? (lr_out_undnat ), priority=0 , match=(1), action=(next;) ++ table=? (lr_out_undnat ), priority=100 , match=(nd || nd_rs || nd_ra), action=(next;) + table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;) + ]) + +@@ -5496,31 +5507,27 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl + + AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl + table=5 (lr_in_defrag ), priority=0 , match=(1), action=(next;) +- table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.200), action=(reg0 = 172.168.0.200; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 10.0.0.10 && tcp), action=(reg0 = 10.0.0.10; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.10 && tcp), action=(reg0 = 172.168.0.10; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.100 && tcp), action=(reg0 = 172.168.0.100; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.210 && udp), action=(reg0 = 172.168.0.210; reg9[[16..31]] = udp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip6.dst == def0::2 && tcp), action=(xxreg0 = def0::2; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 10.0.0.10), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.10), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.100), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.200), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.210), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip6.dst == def0::2), action=(ct_dnat;) + ]) + + AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl + table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) + table=7 (lr_in_dnat ), priority=100 , match=(ip && ip4.dst == 172.168.0.20), action=(flags.loopback = 1; ct_dnat(10.0.0.3);) +- table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.200 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.80,10.0.0.81; force_snat);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip6 && xxreg0 == def0::2 && tcp && reg9[[16..31]] == 8000 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.10 && tcp && reg9[[16..31]] == 9082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82; force_snat);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.100 && tcp && reg9[[16..31]] == 8082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82; force_snat);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062; force_snat);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip6 && xxreg0 == def0::2 && tcp && reg9[[16..31]] == 8000), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=[[aef0::2]]:80,[[aef0::3]]:80; force_snat);) ++ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.200), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.80,10.0.0.81; force_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.4:8080; force_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.10 && tcp && tcp.dst == 9082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82; force_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.100 && tcp && tcp.dst == 8082), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:82,10.0.0.60:82; force_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.210 && udp && udp.dst == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062; force_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip6 && ip6.dst == def0::2 && tcp && tcp.dst == 8000), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=[[aef0::2]]:80,[[aef0::3]]:80; force_snat);) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) + table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) + ]) +@@ -5532,6 +5539,7 @@ AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sor + + AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl + table=? (lr_out_undnat ), priority=0 , match=(1), action=(next;) ++ table=? (lr_out_undnat ), priority=100 , match=(nd || nd_rs || nd_ra), action=(next;) + table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;) + ]) + +@@ -5572,18 +5580,17 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl + + AT_CHECK([grep "lr_in_defrag" lr0flows | sort], [0], [dnl + table=5 (lr_in_defrag ), priority=0 , match=(1), action=(next;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.210 && tcp), action=(reg0 = 172.168.0.210; reg9[[16..31]] = tcp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=110 , match=(ip && ip4.dst == 172.168.0.210 && udp), action=(reg0 = 172.168.0.210; reg9[[16..31]] = udp.dst; ct_dnat;) +- table=5 (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;) ++ table=5 (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 172.168.0.210), action=(ct_dnat;) + ]) + + AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl + table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.210 && tcp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.210 && tcp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062; force_snat);) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.0.210 && udp && reg9[[16..31]] == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062; force_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.210 && tcp && tcp.dst == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062; force_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.0.210 && udp && udp.dst == 60), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.50:6062,10.0.0.60:6062; force_snat);) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) + table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) + ]) +@@ -5594,6 +5601,7 @@ AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sor + + AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl + table=? (lr_out_undnat ), priority=0 , match=(1), action=(next;) ++ table=? (lr_out_undnat ), priority=100 , match=(nd || nd_rs || nd_ra), action=(next;) + table=? (lr_out_undnat ), priority=50 , match=(ip), action=(flags.loopback = 1; ct_dnat;) + ]) + +@@ -5634,9 +5642,11 @@ ovn-sbctl set service_monitor $sm_vip2 status=offline + + AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" | sort], [0], [dnl + table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) +- table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.10.10 && ct_mark.natted == 1), action=(next;) +- table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.10.10), action=(reg0 = 0; reject { outport <-> inport; next(pipeline=egress,table=3);};) ++ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.10.10), action=(reg0 = 0; reject { outport <-> inport; next(pipeline=egress,table=3);};) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) + table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) + ]) +@@ -5646,9 +5656,11 @@ check ovn-nbctl --wait=sb set load_balancer lb5 options:skip_snat=true + + AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" | sort], [0], [dnl + table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) +- table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.10.10 && ct_mark.natted == 1), action=(flags.skip_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.10.10), action=(flags.skip_snat_for_lb = 1; reg0 = 0; reject { outport <-> inport; next(pipeline=egress,table=3);};) ++ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.10.10), action=(flags.skip_snat_for_lb = 1; reg0 = 0; reject { outport <-> inport; next(pipeline=egress,table=3);};) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) + table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) + ]) +@@ -5660,9 +5672,58 @@ check ovn-nbctl --wait=sb set logical_router lr0 options:lb_force_snat_ip="route + + AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" | sort], [0], [dnl + table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) +- table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.168.10.10 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.168.10.10), action=(flags.force_snat_for_lb = 1; reg0 = 0; reject { outport <-> inport; next(pipeline=egress,table=3);};) ++ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.10.10), action=(flags.force_snat_for_lb = 1; reg0 = 0; reject { outport <-> inport; next(pipeline=egress,table=3);};) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) ++]) ++ ++# LB with event=false and reject=false ++check ovn-nbctl lr-lb-del lr0 ++check ovn-nbctl remove logical_router lr0 options lb_force_snat_ip ++AT_CHECK([ovn-nbctl create load_balancer name=lb6 options:reject=false options:event=false vips:\"172.168.10.30\"=\"\" protocol=tcp], [0], [ignore]) ++check ovn-nbctl --wait=sb lr-lb-add lr0 lb6 ++ ++AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" | sort], [0], [dnl ++ table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) ++ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.10.30), action=(drop;) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) ++]) ++ ++# LB with event=false, reject=false and skip_snat ++check ovn-nbctl --wait=sb set load_balancer lb6 options:skip_snat=true ++ ++AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" | sort], [0], [dnl ++ table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) ++ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.10.30), action=(flags.skip_snat_for_lb = 1; drop;) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) ++]) ++ ++check ovn-nbctl remove load_balancer lb6 options skip_snat ++ ++# LB with event=false, reject=false and force_snat ++check ovn-nbctl --wait=sb set logical_router lr0 options:lb_force_snat_ip="router_ip" ++ ++AT_CHECK([ovn-sbctl dump-flows lr0 | grep "lr_in_dnat" | sort], [0], [dnl ++ table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) ++ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.168.10.30), action=(flags.force_snat_for_lb = 1; drop;) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) + table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) + ]) +@@ -6692,11 +6753,12 @@ dnl Flows to skip TTL == {0, 1} check for IGMP and MLD packets. + AT_CHECK([grep -e 'lr_in_ip_input ' lrflows | grep -e 'igmp' -e 'mld' -e 'ip.ttl == {0, 1}' | sed 's/table=../table=??/'], [0], [dnl + table=??(lr_in_ip_input ), priority=120 , match=((mldv1 || mldv2) && ip.ttl == 1), action=(next;) + table=??(lr_in_ip_input ), priority=120 , match=(igmp && ip.ttl == 1), action=(next;) +- table=??(lr_in_ip_input ), priority=100 , match=(inport == "lrp1" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 10.10.10.1 ; ip.ttl = 254; outport = "lrp1"; flags.loopback = 1; output; };) +- table=??(lr_in_ip_input ), priority=100 , match=(inport == "lrp1" && ip6 && ip6.src == 1010::/64 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst <-> eth.src; ip6.dst = ip6.src; ip6.src = 1010::1 ; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = "lrp1"; flags.loopback = 1; output; };) +- table=??(lr_in_ip_input ), priority=100 , match=(inport == "lrp2" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 20.20.20.1 ; ip.ttl = 254; outport = "lrp2"; flags.loopback = 1; output; };) +- table=??(lr_in_ip_input ), priority=100 , match=(inport == "lrp2" && ip6 && ip6.src == 2020::/64 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst <-> eth.src; ip6.dst = ip6.src; ip6.src = 2020::1 ; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = "lrp2"; flags.loopback = 1; output; };) +- table=??(lr_in_ip_input ), priority=30 , match=(ip4 && ip.ttl == {0, 1}), action=(drop;) ++ table=??(lr_in_ip_input ), priority=32 , match=(ip.ttl == {0, 1} && !ip.later_frag && (ip4.mcast || ip6.mcast)), action=(drop;) ++ table=??(lr_in_ip_input ), priority=31 , match=(inport == "lrp1" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 10.10.10.1 ; ip.ttl = 254; outport = "lrp1"; flags.loopback = 1; output; };) ++ table=??(lr_in_ip_input ), priority=31 , match=(inport == "lrp1" && ip6 && ip6.src == 1010::/64 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst <-> eth.src; ip6.dst = ip6.src; ip6.src = 1010::1 ; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = "lrp1"; flags.loopback = 1; output; };) ++ table=??(lr_in_ip_input ), priority=31 , match=(inport == "lrp2" && ip4 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp4 {eth.dst <-> eth.src; icmp4.type = 11; /* Time exceeded */ icmp4.code = 0; /* TTL exceeded in transit */ ip4.dst = ip4.src; ip4.src = 20.20.20.1 ; ip.ttl = 254; outport = "lrp2"; flags.loopback = 1; output; };) ++ table=??(lr_in_ip_input ), priority=31 , match=(inport == "lrp2" && ip6 && ip6.src == 2020::/64 && ip.ttl == {0, 1} && !ip.later_frag), action=(icmp6 {eth.dst <-> eth.src; ip6.dst = ip6.src; ip6.src = 2020::1 ; ip.ttl = 254; icmp6.type = 3; /* Time exceeded */ icmp6.code = 0; /* TTL exceeded in transit */ outport = "lrp2"; flags.loopback = 1; output; };) ++ table=??(lr_in_ip_input ), priority=30 , match=(ip.ttl == {0, 1}), action=(drop;) + ]) + + dnl Flows to "route" (statically forward) without decrementing TTL for +@@ -6755,6 +6817,7 @@ AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], + table=??(ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) + table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) ++ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) +@@ -6809,6 +6872,7 @@ AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], + table=??(ls_in_acl_after_lb ), priority=2003 , match=(reg0[[8]] == 1 && (ip4 && icmp)), action=(next;) + table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */) + table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(/* drop */) ++ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) +@@ -6863,6 +6927,7 @@ AT_CHECK([grep -e "ls_in_acl" lsflows | sed 's/table=../table=??/' | sort], [0], + table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[9]] == 1 && (ip4)), action=(/* drop */) + table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[10]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_mark.blocked = 1; }; /* drop */) + table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[9]] == 1 && (ip4 && ip4.dst == 10.0.0.2)), action=(/* drop */) ++ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) +@@ -7154,11 +7219,14 @@ flow="inport == \"lsp1\" && eth.src == 00:00:00:00:00:01 && eth.dst == 00:00:00: + AS_BOX([No ACL, default_acl_drop not set]) + check ovn-nbctl --wait=sb sync + AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl ++ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl ), priority=65535, match=(1), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) ++ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_hint ), priority=65535, match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) ++ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_out_acl ), priority=65535, match=(1), action=(next;) + table=??(ls_out_acl_hint ), priority=65535, match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) +@@ -7173,11 +7241,14 @@ output("lsp2"); + AS_BOX([No ACL, default_acl_drop false]) + check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=false + AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl ++ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl ), priority=65535, match=(1), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) ++ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_hint ), priority=65535, match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) ++ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_out_acl ), priority=65535, match=(1), action=(next;) + table=??(ls_out_acl_hint ), priority=65535, match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) +@@ -7192,11 +7263,14 @@ output("lsp2"); + AS_BOX([No ACL, default_acl_drop true]) + check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=true + AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl ++ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl ), priority=65535, match=(1), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) ++ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_hint ), priority=65535, match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) ++ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_out_acl ), priority=65535, match=(1), action=(next;) + table=??(ls_out_acl_hint ), priority=65535, match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) +@@ -7218,12 +7292,15 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/ + table=??(ls_in_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl ), priority=1001 , match=(ip4 && tcp), action=(next;) + table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) ++ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) ++ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;) ++ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;) +@@ -7240,12 +7317,15 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/ + table=??(ls_in_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl ), priority=1001 , match=(ip4 && tcp), action=(next;) + table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) ++ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) ++ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;) ++ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;) +@@ -7262,12 +7342,15 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/ + table=??(ls_in_acl ), priority=0 , match=(1), action=(drop;) + table=??(ls_in_acl ), priority=1001 , match=(ip4 && tcp), action=(next;) + table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) ++ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(drop;) ++ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl ), priority=0 , match=(1), action=(drop;) + table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;) ++ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;) +@@ -7292,6 +7375,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/ + table=??(ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) + table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(drop;) ++ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) +@@ -7343,13 +7427,16 @@ check ovn-nbctl --wait=sb remove NB_Global . options default_acl_drop + AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) ++ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl_after_lb ), priority=1001 , match=(ip4 && tcp), action=(next;) ++ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;) ++ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;) +@@ -7365,13 +7452,16 @@ check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=false + AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) ++ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl_after_lb ), priority=1001 , match=(ip4 && tcp), action=(next;) ++ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;) ++ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;) +@@ -7387,13 +7477,16 @@ check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=true + AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_acl ), priority=0 , match=(1), action=(drop;) + table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) ++ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(drop;) + table=??(ls_in_acl_after_lb ), priority=1001 , match=(ip4 && tcp), action=(next;) ++ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl ), priority=0 , match=(1), action=(drop;) + table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;) ++ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;) +@@ -7418,6 +7511,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/ + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(drop;) + table=??(ls_in_acl_after_lb ), priority=1001 , match=(reg0[[7]] == 1 && (ip4 && tcp)), action=(reg0[[1]] = 1; next;) + table=??(ls_in_acl_after_lb ), priority=1001 , match=(reg0[[8]] == 1 && (ip4 && tcp)), action=(next;) ++ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) +@@ -7469,13 +7563,16 @@ check ovn-nbctl --wait=sb remove NB_Global . options default_acl_drop + AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) ++ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) ++ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_acl ), priority=1001 , match=(ip4 && tcp), action=(next;) + table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;) ++ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;) +@@ -7491,13 +7588,16 @@ check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=false + AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) ++ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(next;) ++ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_acl ), priority=1001 , match=(ip4 && tcp), action=(next;) + table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;) ++ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;) +@@ -7513,13 +7613,16 @@ check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=true + AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/' | sort], [0], [dnl + table=??(ls_in_acl ), priority=0 , match=(1), action=(drop;) + table=??(ls_in_acl ), priority=34000, match=(eth.dst == $svc_monitor_mac), action=(next;) ++ table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(drop;) ++ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_in_pre_acl ), priority=110 , match=(eth.dst == $svc_monitor_mac), action=(next;) + table=??(ls_out_acl ), priority=0 , match=(1), action=(drop;) + table=??(ls_out_acl ), priority=1001 , match=(ip4 && tcp), action=(next;) + table=??(ls_out_acl ), priority=34000, match=(eth.src == $svc_monitor_mac), action=(next;) ++ table=??(ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_out_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=0 , match=(1), action=(next;) + table=??(ls_out_pre_acl ), priority=110 , match=(eth.src == $svc_monitor_mac), action=(next;) +@@ -7542,6 +7645,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 's/table=../table=??/ + table=??(ls_in_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) + table=??(ls_in_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_after_lb ), priority=0 , match=(1), action=(drop;) ++ table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;) + table=??(ls_in_acl_hint ), priority=0 , match=(1), action=(next;) + table=??(ls_in_acl_hint ), priority=1 , match=(ct.est && ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;) +@@ -7886,8 +7990,10 @@ check ovn-nbctl \ + AS_BOX([No chassis registered - use ct_lb_mark and ct_mark.natted]) + check ovn-nbctl --wait=sb sync + AT_CHECK([ovn-sbctl lflow-list | grep -e natted -e ct_lb], [0], [dnl +- table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 66.66.66.66 && ct_mark.natted == 1), action=(next;) +- table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 66.66.66.66), action=(ct_lb_mark(backends=42.42.42.2);) ++ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 66.66.66.66), action=(ct_lb_mark(backends=42.42.42.2);) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) + table=6 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4.dst == 66.66.66.66), action=(reg1 = 66.66.66.66; ct_lb_mark;) + table=6 (ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb_mark;) + table=12(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 66.66.66.66), action=(reg0[[1]] = 0; ct_lb_mark(backends=42.42.42.2);) +@@ -7898,8 +8004,10 @@ AS_BOX([Chassis registered that doesn't support ct_lb_mark - use ct_lb and ct_la + check ovn-sbctl chassis-add hv geneve 127.0.0.1 + check ovn-nbctl --wait=sb sync + AT_CHECK([ovn-sbctl lflow-list | grep -e natted -e ct_lb], [0], [dnl +- table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 66.66.66.66 && ct_label.natted == 1), action=(next;) +- table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 66.66.66.66), action=(ct_lb(backends=42.42.42.2);) ++ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 66.66.66.66), action=(ct_lb(backends=42.42.42.2);) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_label.natted && ct_label.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_label.natted && ct_label.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_label.natted), action=(next;) + table=6 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4.dst == 66.66.66.66), action=(reg1 = 66.66.66.66; ct_lb;) + table=6 (ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb;) + table=12(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 66.66.66.66), action=(reg0[[1]] = 0; ct_lb(backends=42.42.42.2);) +@@ -7910,8 +8018,10 @@ AS_BOX([Chassis upgrades and supports ct_lb_mark - use ct_lb_mark and ct_mark.na + check ovn-sbctl set chassis hv other_config:ct-no-masked-label=true + check ovn-nbctl --wait=sb sync + AT_CHECK([ovn-sbctl lflow-list | grep -e natted -e ct_lb], [0], [dnl +- table=7 (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 66.66.66.66 && ct_mark.natted == 1), action=(next;) +- table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 66.66.66.66), action=(ct_lb_mark(backends=42.42.42.2);) ++ table=7 (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 66.66.66.66), action=(ct_lb_mark(backends=42.42.42.2);) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) + table=6 (ls_in_pre_stateful ), priority=120 , match=(reg0[[2]] == 1 && ip4.dst == 66.66.66.66), action=(reg1 = 66.66.66.66; ct_lb_mark;) + table=6 (ls_in_pre_stateful ), priority=110 , match=(reg0[[2]] == 1), action=(ct_lb_mark;) + table=12(ls_in_lb ), priority=110 , match=(ct.new && ip4.dst == 66.66.66.66), action=(reg0[[1]] = 0; ct_lb_mark(backends=42.42.42.2);) +@@ -8244,15 +8354,17 @@ AT_CAPTURE_FILE([R1flows]) + + AT_CHECK([grep "lr_in_lb_aff_check" R1flows | sort], [0], [dnl + table=6 (lr_in_lb_aff_check ), priority=0 , match=(1), action=(next;) +- table=6 (lr_in_lb_aff_check ), priority=100 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.16.0.10 && tcp && reg9[[16..31]] == 80), action=(reg9[[6]] = chk_lb_aff(); next;) ++ table=6 (lr_in_lb_aff_check ), priority=100 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(reg0 = ip4.dst; reg9[[16..31]] = tcp.dst; reg9[[6]] = chk_lb_aff(); next;) + ]) + AT_CHECK([grep "lr_in_dnat " R1flows | sort], [0], [dnl + table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.16.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.16.0.10 && tcp && reg9[[16..31]] == 80), action=(ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80);) + table=7 (lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; ct_lb_mark(backends=10.0.0.2:80);) + table=7 (lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; ct_lb_mark(backends=20.0.0.2:80);) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) + table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) + ]) +@@ -8270,11 +8382,13 @@ AT_CAPTURE_FILE([R1flows_skip_snat]) + + AT_CHECK([grep "lr_in_dnat " R1flows_skip_snat | sort], [0], [dnl + table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.16.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.skip_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.16.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; skip_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; skip_snat);) + table=7 (lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; skip_snat);) + table=7 (lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; skip_snat);) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) + table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) + ]) +@@ -8289,11 +8403,13 @@ AT_CAPTURE_FILE([R1flows_force_snat]) + + AT_CHECK([grep "lr_in_dnat " R1flows_force_snat | sort], [0], [dnl + table=7 (lr_in_dnat ), priority=0 , match=(1), action=(next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 172.16.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1), action=(flags.force_snat_for_lb = 1; next;) +- table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 172.16.0.10 && tcp && reg9[[16..31]] == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; force_snat);) ++ table=7 (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; force_snat);) + table=7 (lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; force_snat);) + table=7 (lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.force_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; force_snat);) ++ table=7 (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) + table=7 (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=7 (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) + table=7 (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) + ]) +@@ -8569,12 +8685,13 @@ ovn-sbctl dump-flows | DUMP_FLOWS_SORTED > lflows0 + + AT_CHECK([grep -e "lr_in_defrag" -e "lr_in_dnat" lflows0], [0], [dnl + table=? (lr_in_defrag ), priority=0 , match=(1), action=(next;) +- table=? (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 192.168.0.1), action=(reg0 = 192.168.0.1; ct_dnat;) +- table=? (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;) ++ table=? (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 192.168.0.1), action=(ct_dnat;) + table=? (lr_in_dnat ), priority=0 , match=(1), action=(next;) +- table=? (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 192.168.0.1 && ct_mark.natted == 1), action=(next;) +- table=? (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 192.168.0.1), action=(ct_lb_mark(backends=192.168.1.10);) ++ table=? (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 192.168.0.1), action=(ct_lb_mark(backends=192.168.1.10);) ++ table=? (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) + table=? (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) ++ table=? (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=? (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) + table=? (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) + table=? (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) + ]) +@@ -8588,6 +8705,7 @@ AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows0 | grep "priority=65532"], + table=? (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(next;) + table=? (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) + table=? (ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) ++ table=?(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=?(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;) + ]) + +@@ -8599,10 +8717,12 @@ ovn-sbctl dump-flows | DUMP_FLOWS_SORTED > lflows1 + + AT_CHECK([grep -e "lr_in_defrag" -e "lr_in_dnat" lflows1], [0], [dnl + table=? (lr_in_defrag ), priority=0 , match=(1), action=(next;) +- table=? (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 192.168.0.1), action=(reg0 = 192.168.0.1; ct_dnat;) ++ table=? (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 192.168.0.1), action=(ct_dnat;) + table=? (lr_in_dnat ), priority=0 , match=(1), action=(next;) +- table=? (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 192.168.0.1 && ct_label.natted == 1), action=(next;) +- table=? (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 192.168.0.1), action=(ct_lb(backends=192.168.1.10);) ++ table=? (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 192.168.0.1), action=(ct_lb(backends=192.168.1.10);) ++ table=? (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_label.natted), action=(next;) ++ table=? (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_label.natted && ct_label.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=? (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_label.natted && ct_label.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) + ]) + + AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows1 | grep "priority=65532"], [0], [dnl +@@ -8614,6 +8734,7 @@ AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows1 | grep "priority=65532"], + table=? (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;) + table=? (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)), action=(drop;) + table=? (ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) ++ table=?(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=?(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;) + ]) + +@@ -8625,12 +8746,13 @@ ovn-sbctl dump-flows | DUMP_FLOWS_SORTED > lflows2 + + AT_CHECK([grep -e "lr_in_defrag" -e "lr_in_dnat" lflows2], [0], [dnl + table=? (lr_in_defrag ), priority=0 , match=(1), action=(next;) +- table=? (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 192.168.0.1), action=(reg0 = 192.168.0.1; ct_dnat;) +- table=? (lr_in_defrag ), priority=50 , match=(icmp || icmp6), action=(ct_dnat;) ++ table=? (lr_in_defrag ), priority=100 , match=(ip && ip4.dst == 192.168.0.1), action=(ct_dnat;) + table=? (lr_in_dnat ), priority=0 , match=(1), action=(next;) +- table=? (lr_in_dnat ), priority=110 , match=(ct.est && !ct.rel && ip4 && reg0 == 192.168.0.1 && ct_mark.natted == 1), action=(next;) +- table=? (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && reg0 == 192.168.0.1), action=(ct_lb_mark(backends=192.168.1.10);) ++ table=? (lr_in_dnat ), priority=110 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 192.168.0.1), action=(ct_lb_mark(backends=192.168.1.10);) ++ table=? (lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) + table=? (lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) ++ table=? (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) ++ table=? (lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) + table=? (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) + table=? (lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) + ]) +@@ -8644,8 +8766,104 @@ AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows2 | grep "priority=65532"], + table=? (ls_out_acl ), priority=65532, match=(ct.est && !ct.rel && !ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(next;) + table=? (ls_out_acl ), priority=65532, match=(ct.inv || (ct.est && ct.rpl && ct_mark.blocked == 1)), action=(drop;) + table=? (ls_out_acl ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) ++ table=?(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || mldv1 || mldv2), action=(next;) + table=?(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), action=(next;) + ]) + + AT_CLEANUP + ]) ++ ++OVN_FOR_EACH_NORTHD_NO_HV([ ++AT_SETUP([Chassis-feature compatibitility - remote chassis]) ++ovn_start ++ ++AS_BOX([Local chassis]) ++check ovn-sbctl chassis-add hv1 geneve 127.0.0.1 \ ++ -- set chassis hv1 other_config:ct-no-masked-label=true \ ++ -- set chassis hv1 other_config:ovn-ct-lb-related=true \ ++ -- set chassis hv1 other_config:mac-binding-timestamp=true ++ ++check ovn-nbctl --wait=sb sync ++ ++AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE debug/chassis-features-list], [0], [dnl ++ct_no_masked_label: true ++ct_lb_related: true ++mac_binding_timestamp: true ++]) ++ ++AS_BOX([Remote chassis]) ++check ovn-sbctl chassis-add hv2 geneve 127.0.0.2 \ ++ -- set chassis hv2 other_config:is-remote=true \ ++ -- set chassis hv2 other_config:ct-no-masked-label=false \ ++ -- set chassis hv2 other_config:ovn-ct-lb-related=false \ ++ -- set chassis hv2 other_config:mac-binding-timestamp=false ++ ++check ovn-nbctl --wait=sb sync ++ ++AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE debug/chassis-features-list], [0], [dnl ++ct_no_masked_label: true ++ct_lb_related: true ++mac_binding_timestamp: true ++]) ++ ++AT_CLEANUP ++]) ++ ++AT_SETUP([Localnet ports on LS with LB]) ++ovn_start ++# In the past, traffic arriving on localnet ports has skipped conntrack. ++# This test ensures that we still skip conntrack for localnet ports, ++# *except* for the case where the logical switch has a load balancer ++# configured. In this case, the localnet port will not skip conntrack, ++# allowing for traffic to be load balanced on the localnet port. ++ ++check ovn-nbctl ls-add sw ++check ovn-nbctl lsp-add sw sw-ln ++check ovn-nbctl lsp-set-type sw-ln localnet ++check ovn-nbctl lsp-set-addresses sw-ln unknown ++check ovn-nbctl --wait=sb sync ++ ++# Since this test is only concerned with logical flows, we don't need to ++# configure anything else that we normally would with regards to localnet ++# ports ++ ++ ++# First, ensure that conntrack is skipped for the localnet port since there ++# isn't a load balancer configured. ++ ++AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_pre_lb | grep priority=110 | grep sw-ln | sed 's/table=../table=??/'], [0], [dnl ++ table=??(ls_in_pre_lb ), priority=110 , match=(ip && inport == "sw-ln"), action=(next;) ++]) ++ ++AT_CHECK([ovn-sbctl lflow-list sw | grep ls_out_pre_lb | grep priority=110 | grep sw-ln | sed 's/table=../table=??/'], [0], [dnl ++ table=??(ls_out_pre_lb ), priority=110 , match=(ip && outport == "sw-ln"), action=(ct_clear; next;) ++]) ++ ++# Now add a load balancer and ensure that we no longer are skipping conntrack ++# for the localnet port ++ ++check ovn-nbctl lb-add lb 10.0.0.1:80 10.0.0.100:8080 tcp ++check ovn-nbctl ls-lb-add sw lb ++check ovn-nbctl --wait=sb sync ++ ++AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_pre_lb | grep priority=110 | grep sw-ln | sed 's/table=../table=??/'], [0], [dnl ++]) ++ ++AT_CHECK([ovn-sbctl lflow-list sw | grep ls_out_pre_lb | grep priority=110 | grep sw-ln | sed 's/table=../table=??/'], [0], [dnl ++]) ++ ++# And ensure that removing the load balancer from the switch results in skipping ++# conntrack again ++check ovn-nbctl ls-lb-del sw lb ++check ovn-nbctl --wait=sb sync ++ ++AT_CHECK([ovn-sbctl lflow-list sw | grep ls_in_pre_lb | grep priority=110 | grep sw-ln | sed 's/table=../table=??/'], [0], [dnl ++ table=??(ls_in_pre_lb ), priority=110 , match=(ip && inport == "sw-ln"), action=(next;) ++]) ++ ++AT_CHECK([ovn-sbctl lflow-list sw | grep ls_out_pre_lb | grep priority=110 | grep sw-ln | sed 's/table=../table=??/'], [0], [dnl ++ table=??(ls_out_pre_lb ), priority=110 , match=(ip && outport == "sw-ln"), action=(ct_clear; next;) ++]) ++ ++AT_CLEANUP ++]) +diff --git a/tests/ovn.at b/tests/ovn.at +index 55de7c85b..3515a1e3c 100644 +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -5753,7 +5753,7 @@ check ovn-nbctl --wait=hv sync + packet="inport==\"ls1-lp1\" && eth.src==$ls1_lp1_mac && eth.dst==$rp_ls1_mac && + ip4 && ip.ttl==64 && ip4.src==$ls1_lp1_ip && ip4.dst==$ls2_lp1_ip && + udp && udp.src==53 && udp.dst==4369" +-AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) ++OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + + echo "---------NB dump-----" +@@ -5803,7 +5803,7 @@ packet="inport==\"ls1-lp1\" && eth.src==$ls1_lp1_mac && eth.dst==$rp_ls1_mac && + ip4 && ip.ttl==64 && ip4.src==$ls1_lp1_ip && ip4.dst==$ls2_lp1_ip && + udp && udp.src==53 && udp.dst==4369" + +-as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) + # The 2nd packet sent shound not be received. + OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) + +@@ -7741,7 +7741,6 @@ ls3_p1_mac=00:00:00:01:02:05 + check ovn-nbctl --wait=hv lr-policy-add R1 10 "ip4.src==192.168.1.0/24 && ip4.dst==172.16.1.0/24" drop + + # Check logical flow +-ovn-sbctl dump-flows > sbflows + AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | grep "192.168.1.0" | wc -l], [0], [dnl + 1 + ]) +@@ -7751,15 +7750,12 @@ packet="inport==\"ls1-lp1\" && eth.src==$ls1_p1_mac && eth.dst==$ls1_ro_mac && + ip4 && ip.ttl==64 && ip4.src==$ls1_p1_ip && ip4.dst==$ls2_p1_ip && + udp && udp.src==53 && udp.dst==4369" + +-as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Check if packet hit the drop policy +-AT_CHECK([ovs-ofctl dump-flows br-int | \ ++OVS_WAIT_UNTIL([test "1" = "$(ovs-ofctl dump-flows br-int | \ + grep "nw_src=192.168.1.0/24,nw_dst=172.16.1.0/24 actions=drop" | \ +- grep "priority=10" | \ +- grep "n_packets=1" | wc -l], [0], [dnl +-1 +-]) ++ grep "priority=10" | grep "n_packets=1" -c)"]) + + # Expected to drop the packet. + $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" pbr-hv/vif2-tx.pcap > vif2.packets +@@ -7770,7 +7766,7 @@ AT_FAIL_IF([test "$rcvd_packet" != ""]) + check ovn-nbctl --wait=hv lr-policy-add R1 20 "ip4.src==192.168.1.0/24 && ip4.dst==172.16.1.0/24" allow + + # Check logical flow +-AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | grep "192.168.1.0" | wc -l], [0], [dnl ++AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | grep "192.168.1.0" -c], [0], [dnl + 2 + ]) + +@@ -7778,15 +7774,12 @@ AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | grep "192.168.1.0" | wc -l] + packet="inport==\"ls1-lp1\" && eth.src==$ls1_p1_mac && eth.dst==$ls1_ro_mac && + ip4 && ip.ttl==64 && ip4.src==$ls1_p1_ip && ip4.dst==$ls2_p1_ip && + udp && udp.src==53 && udp.dst==4369" +-as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Check if packet hit the allow policy +-sleep 1 +-AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | \ +- grep "192.168.1.0" | \ +- grep "priority=20" | wc -l], [0], [dnl +-1 +-]) ++OVS_WAIT_UNTIL([test "1" = "$(ovs-ofctl dump-flows br-int | \ ++ grep "nw_src=192.168.1.0/24,nw_dst=172.16.1.0/24" | \ ++ grep "priority=20" | grep "n_packets=1" -c)"]) + + # Expected packet has TTL decreased by 1 + expected="eth.src==$ls2_ro_mac && eth.dst==$ls2_p1_mac && +@@ -7802,7 +7795,7 @@ check ovn-nbctl --wait=hv lr-policy-add R1 30 "ip4.src==192.168.1.0/24 && ip4.ds + # Check logical flow + AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | \ + grep "192.168.1.0" | \ +- grep "priority=30" | wc -l], [0], [dnl ++ grep "priority=30" -c], [0], [dnl + 1 + ]) + +@@ -7810,21 +7803,12 @@ AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | \ + packet="inport==\"ls1-lp1\" && eth.src==$ls1_p1_mac && eth.dst==$ls1_ro_mac && + ip4 && ip.ttl==64 && ip4.src==$ls1_p1_ip && ip4.dst==$ls2_p1_ip && + udp && udp.src==53 && udp.dst==4369" +-as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet" +-sleep 1 ++OVS_WAIT_UNTIL([as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet"]) + +-echo "southbound flows" +-ovn-sbctl --ovs dump-flows > sbflows +-AT_CAPTURE_FILE([sbflows]) +-echo "ovs flows" +-ovs-ofctl dump-flows br-int > brflows +-AT_CAPTURE_FILE([brflows]) + # Check if packet hit the allow policy +-AT_CHECK([grep "nw_src=192.168.1.0/24,nw_dst=172.16.1.0/24" brflows | \ +- grep "priority=30" | \ +- grep "n_packets=1" | wc -l], [0], [dnl +-1 +-]) ++OVS_WAIT_UNTIL([test "1" = "$(ovs-ofctl dump-flows br-int | \ ++ grep "nw_src=192.168.1.0/24,nw_dst=172.16.1.0/24" | \ ++ grep "priority=30" | grep "n_packets=1" -c)"]) + echo "packet hit reroute policy" + + # Expected packet has TTL decreased by 1 +@@ -7927,9 +7911,7 @@ ls3_p1_mac=00:00:00:01:02:05 + check ovn-nbctl --wait=sb lr-policy-add R1 10 "ip6.src==2001::/64 && ip6.dst==2002::/64" drop + + # Check logical flow +-ovn-sbctl dump-flows > sbflows +-AT_CAPTURE_FILE([sbflows]) +-AT_CHECK([grep lr_in_policy sbflows | grep "2001" | wc -l], [0], [dnl ++AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | grep "2001" -c], [0], [dnl + 1 + ]) + +@@ -7938,15 +7920,12 @@ packet="inport==\"ls1-lp1\" && eth.src==$ls1_p1_mac && eth.dst==$ls1_ro_mac && + ip6 && ip.ttl==64 && ip6.src==$ls1_p1_ip && ip6.dst==$ls2_p1_ip && + udp && udp.src==53 && udp.dst==4369" + +-as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Check if packet hit the drop policy +-AT_CHECK([ovs-ofctl dump-flows br-int | \ ++OVS_WAIT_UNTIL([test "1" = "$(ovs-ofctl dump-flows br-int | \ + grep "ipv6_src=2001::/64,ipv6_dst=2002::/64 actions=drop" | \ +- grep "priority=10" | \ +- grep "n_packets=1" | wc -l], [0], [dnl +-1 +-]) ++ grep "priority=10" | grep "n_packets=1" -c)"]) + + # Expected to drop the packet. + $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" pbr-hv/vif2-tx.pcap > vif2.packets +@@ -7956,9 +7935,7 @@ AT_FAIL_IF([test -s vif2.packets]) + check ovn-nbctl --wait=sb lr-policy-add R1 20 "ip6.src==2001::/64 && ip6.dst==2002::/64" allow + + # Check logical flow +-ovn-sbctl dump-flows > sbflows2 +-AT_CAPTURE_FILE([sbflows2]) +-AT_CHECK([grep lr_in_policy sbflows2 | grep "2001" | wc -l], [0], [dnl ++AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | grep "2001" -c], [0], [dnl + 2 + ]) + +@@ -7966,16 +7943,12 @@ AT_CHECK([grep lr_in_policy sbflows2 | grep "2001" | wc -l], [0], [dnl + packet="inport==\"ls1-lp1\" && eth.src==$ls1_p1_mac && eth.dst==$ls1_ro_mac && + ip6 && ip.ttl==64 && ip6.src==$ls1_p1_ip && ip6.dst==$ls2_p1_ip && + udp && udp.src==53 && udp.dst==4369" +-as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Check if packet hit the allow policy +-ovn-sbctl dump-flows > sbflows3 +-AT_CAPTURE_FILE([sbflows3]) +-AT_CHECK([grep lr_in_policy sbflows3 | \ +- grep "2001" | \ +- grep "priority=20" | wc -l], [0], [dnl +-1 +-]) ++OVS_WAIT_UNTIL([test "1" = "$(ovs-ofctl dump-flows br-int | \ ++ grep "ipv6_src=2001::/64,ipv6_dst=2002::/64" | \ ++ grep "priority=20" | grep "n_packets=1" -c)"]) + + # Expected packet has TTL decreased by 1 + expected="eth.src==$ls2_ro_mac && eth.dst==$ls2_p1_mac && +@@ -7989,11 +7962,9 @@ OVN_CHECK_PACKETS([pbr-hv/vif2-tx.pcap], [expected]) + check ovn-nbctl --wait=sb lr-policy-add R1 30 "ip6.src==2001::/64 && ip6.dst==2002::/64" reroute 2003::2 + + # Check logical flow +-ovn-sbctl dump-flows > sbflows4 +-AT_CAPTURE_FILE([sbflows4]) +-AT_CHECK([grep lr_in_policy sbflows4 | \ ++AT_CHECK([ovn-sbctl dump-flows | grep lr_in_policy | \ + grep "2001" | \ +- grep "priority=30" | wc -l], [0], [dnl ++ grep "priority=30" -c], [0], [dnl + 1 + ]) + +@@ -8001,19 +7972,12 @@ AT_CHECK([grep lr_in_policy sbflows4 | \ + packet="inport==\"ls1-lp1\" && eth.src==$ls1_p1_mac && eth.dst==$ls1_ro_mac && + ip6 && ip.ttl==64 && ip6.src==$ls1_p1_ip && ip6.dst==$ls2_p1_ip && + udp && udp.src==53 && udp.dst==4369" +-as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet" +-sleep 1 ++OVS_WAIT_UNTIL([as pbr-hv ovs-appctl -t ovn-controller inject-pkt "$packet"]) + +-ovn-sbctl dump-flows > sbflows5 +-ovs-ofctl dump-flows br-int > offlows5 +-AT_CAPTURE_FILE([sbflows5]) +-AT_CAPTURE_FILE([offlows5]) + # Check if packet hit the allow policy +-AT_CHECK([grep "ipv6_src=2001::/64,ipv6_dst=2002::/64" offlows5 | \ +- grep "priority=30" | \ +- grep "n_packets=1" | wc -l], [0], [dnl +-1 +-]) ++OVS_WAIT_UNTIL([test "1" = "$(ovs-ofctl dump-flows br-int | \ ++ grep "ipv6_src=2001::/64,ipv6_dst=2002::/64" | \ ++ grep "priority=30" | grep "n_packets=1" -c)"]) + + # Expected packet has TTL decreased by 1 + expected="eth.src==$ls3_ro_mac && eth.dst==$ls3_p1_mac && +@@ -9531,73 +9495,73 @@ AT_CAPTURE_FILE([sbflows]) + packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac && + ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip && + tcp && tcp.flags==2 && tcp.src==4360 && tcp.dst==80" +-as hv ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Send packet that should be dropped with logging in the ingress pipeline. + packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac && + ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip && + tcp && tcp.flags==2 && tcp.src==4361 && tcp.dst==81" +-as hv ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Send packet that should be dropped without logging in the eggress pipeline. + packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac && + ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip && + tcp && tcp.flags==2 && tcp.src==4360 && tcp.dst==180" +-as hv ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Send packet that should be dropped with logging in the egress pipeline. + packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac && + ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip && + tcp && tcp.flags==2 && tcp.src==4361 && tcp.dst==181" +-as hv ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Send packet that should be allowed without logging. + packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac && + ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip && + tcp && tcp.flags==2 && tcp.src==4362 && tcp.dst==82" +-as hv ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Send packet that should be allowed with logging. + packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac && + ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip && + tcp && tcp.flags==2 && tcp.src==4363 && tcp.dst==83" +-as hv ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Send packet that should allow related flows without logging. + packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac && + ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip && + tcp && tcp.flags==2 && tcp.src==4364 && tcp.dst==84" +-as hv ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Send packet that should allow related flows with logging. + packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac && + ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip && + tcp && tcp.flags==2 && tcp.src==4365 && tcp.dst==85" +-as hv ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Send packet that should be rejected without logging in the ingress pipeline. + packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac && + ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip && + tcp && tcp.flags==2 && tcp.src==4366 && tcp.dst==86" +-as hv ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Send packet that should be rejected with logging in the ingress pipeline. + packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac && + ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip && + tcp && tcp.flags==2 && tcp.src==4367 && tcp.dst==87" +-as hv ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Send packet that should be rejected without logging in the egress pipeline. + packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac && + ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip && + tcp && tcp.flags==2 && tcp.src==4366 && tcp.dst==186" +-as hv ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Send packet that should be rejected with logging in the egress pipeline. + packet="inport==\"lp1\" && eth.src==$lp1_mac && eth.dst==$lp2_mac && + ip4 && ip.ttl==64 && ip4.src==$lp1_ip && ip4.dst==$lp2_ip && + tcp && tcp.flags==2 && tcp.src==4367 && tcp.dst==187" +-as hv ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as hv ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + OVS_WAIT_UNTIL([ test 8 = $(grep -c 'acl_log' hv/ovn-controller.log) ]) + +@@ -12254,7 +12218,7 @@ nexthop_mac="f00000010204" + AS_BOX([Send ip packet from foo1 to 8.8.8.8]) + src_mac="f00000010203" + dst_mac="000001010203" +-packet=${foo_mac}${foo1_mac}08004500001c0000000040110000${foo1_ip}${dst_ip}0035111100080000 ++packet=${foo_mac}${foo1_mac}080045000028000000004006a916${foo1_ip}${dst_ip}0035111112345678000000005002faf069450000 + + AS_BOX([Wait for GARPs announcing gw IP to arrive]) + OVS_WAIT_UNTIL([ +@@ -12265,15 +12229,12 @@ grep actions=mod_dl_dst:f0:00:00:01:02:04 | wc -l` -eq 1 + AS_BOX([Verify VLAN tagged packet on bridge connecting hv1 and hv2]) + # VLAN tagged packet with router port(192.168.1.1) MAC as destination MAC + # is expected on bridge connecting hv1 and hv2 +-expected=${foo_mac}${foo1_mac}8100000208004500001c0000000040110000${foo1_ip}${dst_ip}0035111100080000 ++expected=${foo_mac}${foo1_mac}81000002080045000028000000004006a916${foo1_ip}${dst_ip}0035111112345678000000005002faf069450000 + echo $expected > hv1-br-ex_n2.expected + + AS_BOX([Verify packet at outside1 i.e nexthop(172.16.1.1) port]) + # Packet to Expect at outside1 i.e nexthop(172.16.1.1) port. +-# As connection tracking not enabled for this test, snat can't be done on the packet. +-# We still see foo1 as the source ip address. But source mac(gateway MAC) and +-# dest mac(nexthop mac) are properly configured. +-expected=${nexthop_mac}${gw_mac}08004500001c000000003f110100${foo1_ip}${dst_ip}0035111100080000 ++expected=${nexthop_mac}${gw_mac}080045000028000000003f06beaa${gw_ip}${dst_ip}0035111112345678000000005002faf07dd90000 + echo $expected > hv3-vif1.expected + + check as hv1 ovs-appctl dpctl/del-flows +@@ -12304,7 +12265,7 @@ cat hv1-br-ex_n2.expected > expout + AT_CHECK([sort hv1-br-ex_n2], [0], [expout]) + + AS_BOX([Check expected packet on nexthop interface]) +-$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv3/vif1-tx.pcap | grep ${foo1_ip}${dst_ip} | uniq > hv3-vif1 ++$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv3/vif1-tx.pcap | grep ${gw_ip}${dst_ip} | uniq > hv3-vif1 + cat hv3-vif1.expected > expout + AT_CHECK([sort hv3-vif1], [0], [expout]) + +@@ -13268,30 +13229,27 @@ as hv2 ovs-ofctl dump-flows br-int table=37 + gw1_chassis=$(fetch_column Chassis _uuid name=gw1) + gw2_chassis=$(fetch_column Chassis _uuid name=gw2) + +-OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int table=37 | \ +-grep active_backup | grep slaves:$hv1_gw1_ofport,$hv1_gw2_ofport \ ++OVS_WAIT_FOR_OUTPUT([as hv1 ovs-ofctl dump-flows br-int table=37 | \ ++grep active_backup | grep members:$hv1_gw1_ofport,$hv1_gw2_ofport \ + | wc -l], [0], [1 + ]) + +-OVS_WAIT_UNTIL([as hv2 ovs-ofctl dump-flows br-int table=37 | \ +-grep active_backup | grep slaves:$hv2_gw1_ofport,$hv2_gw2_ofport \ ++OVS_WAIT_FOR_OUTPUT([as hv2 ovs-ofctl dump-flows br-int table=37 | \ ++grep active_backup | grep members:$hv2_gw1_ofport,$hv2_gw2_ofport \ + | wc -l], [0], [1 + ]) + +-# make sure that flows for handling the outside router port reside on gw1 +-OVS_WAIT_UNTIL([as gw1 ovs-ofctl dump-flows br-int table=25 | \ +-grep 00:00:02:01:02:04 | wc -l], [0], [[1 ++# make sure that flows for handling the outside router port reside on gw1 through ls_in_l2_lkup table ++OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \ ++grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1 + ]]) +-OVS_WAIT_UNTIL([as gw2 ovs-ofctl dump-flows br-int table=25 | \ +-grep 00:00:02:01:02:04 | wc -l], [0], [[0 ++OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \ ++grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[0 + ]]) + +-# make sure ARP responder flows for outside router port reside on gw1 too +-OVS_WAIT_UNTIL([as gw1 ovs-ofctl dump-flows br-int table=9 | \ +-grep arp_tpa=192.168.0.101 | wc -l], [0], [[1 +-]]) +-OVS_WAIT_UNTIL([as gw2 ovs-ofctl dump-flows br-int table=9 | grep arp_tpa=192.168.0.101 | wc -l], [0], [[0 +-]]) ++# make sure ARP responder flows for outside router port reside on gw1 too through ls_in_arp_rsp table ++OVS_WAIT_UNTIL([test `as gw1 ovs-ofctl dump-flows br-int table=27 | \ ++grep arp_tpa=192.168.0.101 | wc -l` -ge 1]) + + # check that the chassis redirect port has been claimed by the gw1 chassis + wait_row_count Port_Binding 1 logical_port=cr-outside chassis=$gw1_chassis +@@ -13314,13 +13272,13 @@ wait_for_ports_up + check ovn-nbctl --wait=hv sync + + # we make sure that the hypervisors noticed, and inverted the slave ports +-OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int table=37 | \ +-grep active_backup | grep slaves:$hv1_gw2_ofport,$hv1_gw1_ofport \ ++OVS_WAIT_FOR_OUTPUT([as hv1 ovs-ofctl dump-flows br-int table=37 | \ ++grep active_backup | grep members:$hv1_gw2_ofport,$hv1_gw1_ofport \ + | wc -l], [0], [1 + ]) + +-OVS_WAIT_UNTIL([as hv2 ovs-ofctl dump-flows br-int table=37 | \ +-grep active_backup | grep slaves:$hv2_gw2_ofport,$hv2_gw1_ofport \ ++OVS_WAIT_FOR_OUTPUT([as hv2 ovs-ofctl dump-flows br-int table=37 | \ ++grep active_backup | grep members:$hv2_gw2_ofport,$hv2_gw1_ofport \ + | wc -l], [0], [1 + ]) + +@@ -13372,11 +13330,11 @@ AT_CHECK([ovs-vsctl --bare --columns bfd find Interface name=ovn-hv1-0],[0], + ]]) + + # make sure that flows for handling the outside router port reside on gw2 now +-OVS_WAIT_UNTIL([as gw2 ovs-ofctl dump-flows br-int table=25 | \ +-grep 00:00:02:01:02:04 | wc -l], [0], [[1 ++OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \ ++grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1 + ]]) +-OVS_WAIT_UNTIL([as gw1 ovs-ofctl dump-flows br-int table=25 | \ +-grep 00:00:02:01:02:04 | wc -l], [0], [[0 ++OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \ ++grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[0 + ]]) + + # disconnect GW2 from the network, GW1 should take over +@@ -13386,12 +13344,12 @@ as main ovs-vsctl del-port n1 $port + + bfd_dump + +-# make sure that flows for handling the outside router port reside on gw2 now +-OVS_WAIT_UNTIL([as gw1 ovs-ofctl dump-flows br-int table=25 | \ +-grep 00:00:02:01:02:04 | wc -l], [0], [[1 ++# make sure that flows for handling the outside router port reside on gw1 now ++OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \ ++grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1 + ]]) +-OVS_WAIT_UNTIL([as gw2 ovs-ofctl dump-flows br-int table=25 | \ +-grep 00:00:02:01:02:04 | wc -l], [0], [[0 ++OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \ ++grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[0 + ]]) + + # check that the chassis redirect port has been reclaimed by the gw1 chassis +@@ -13470,45 +13428,16 @@ ovn-nbctl set Logical_Router_Port outside ha_chassis_group=$hagrp1_uuid + wait_row_count HA_Chassis_Group 1 + wait_row_count HA_Chassis 2 + +-OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int table=37 | \ +-grep active_backup | grep slaves:$hv1_gw1_ofport,$hv1_gw2_ofport \ +-| wc -l], [0], [1 ++OVS_WAIT_FOR_OUTPUT([as hv1 ovs-ofctl dump-flows br-int table=37 | \ ++grep active_backup | grep members:$hv1_gw1_ofport,$hv1_gw2_ofport \ ++| wc -l], [0], [0 + ]) + +-OVS_WAIT_UNTIL([as hv2 ovs-ofctl dump-flows br-int table=37 | \ +-grep active_backup | grep slaves:$hv2_gw1_ofport,$hv2_gw2_ofport \ +-| wc -l], [0], [1 ++OVS_WAIT_FOR_OUTPUT([as hv2 ovs-ofctl dump-flows br-int table=37 | \ ++grep active_backup | grep members:$hv2_gw1_ofport,$hv2_gw2_ofport \ ++| wc -l], [0], [0 + ]) + +-# make sure that flows for handling the outside router port reside on gw1 +-OVS_WAIT_UNTIL([as gw1 ovs-ofctl dump-flows br-int table=24 | \ +-grep 00:00:02:01:02:04 | wc -l], [0], [[1 +-]]) +-OVS_WAIT_UNTIL([as gw2 ovs-ofctl dump-flows br-int table=24 | \ +-grep 00:00:02:01:02:04 | wc -l], [0], [[0 +-]]) +- +-# make sure ARP responder flows for outside router port reside on gw1 too +-OVS_WAIT_UNTIL([as gw1 ovs-ofctl dump-flows br-int table=9 | \ +-grep arp_tpa=192.168.0.101 | wc -l], [0], [[1 +-]]) +-OVS_WAIT_UNTIL([as gw2 ovs-ofctl dump-flows br-int table=9 | grep arp_tpa=192.168.0.101 | wc -l], [0], [[0 +-]]) +- +-# check that the chassis redirect port has been claimed by the gw1 chassis +-# +-# XXX actually it doesn't happen, the test has always been wrong here +-# because the following just checks that "wc -l" succeeds (and it always +-# does): +-# +-# OVS_WAIT_UNTIL([ovn-sbctl --columns chassis --bare find Port_Binding \ +-# logical_port=cr-outside | grep $gw1_chassis | wc -l], [0],[[1 +-# ]]) +-# +-# If it were correct, then the following would be a good substitute: +-# +-# wait_row_count Port_Binding 1 logical_port=cr-outside chassis=$gw1_chassis +- + # Re add the ovs ports. + for i in 1 2; do + as hv$i +@@ -13519,6 +13448,34 @@ for i in 1 2; do + ofport-request=1 + done + ++# Re-add gw2 ++as gw2 ovn_attach n1 br-phys 192.168.0.1 ++ ++OVS_WAIT_FOR_OUTPUT([as hv1 ovs-ofctl dump-flows br-int table=37 | \ ++grep active_backup | grep members:$hv1_gw1_ofport,$hv1_gw2_ofport \ ++| wc -l], [0], [1 ++]) ++ ++OVS_WAIT_FOR_OUTPUT([as hv2 ovs-ofctl dump-flows br-int table=37 | \ ++grep active_backup | grep members:$hv2_gw1_ofport,$hv2_gw2_ofport \ ++| wc -l], [0], [1 ++]) ++ ++# make sure that flows for handling the outside router port reside on gw1 ++OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \ ++grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1 ++]]) ++OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \ ++grep "dl_dst:00:00:02:01:02:04" | wc -l], [0], [[0 ++]]) ++ ++# make sure ARP responder flows for outside router port reside on gw1 too ++OVS_WAIT_UNTIL([test `as gw1 ovs-ofctl dump-flows br-int table=27 | \ ++grep arp_tpa=192.168.0.101 | wc -l` -ge 1 ]) ++ ++# check that the chassis redirect port has been claimed by the gw1 chassis ++wait_row_count Port_Binding 1 logical_port=cr-outside chassis=$gw1_chassis ++ + hv1_ch_uuid=$(fetch_column Chassis _uuid name=hv1) + hv2_ch_uuid=$(fetch_column Chassis _uuid name=hv2) + exp_ref_ch_list="$hv1_ch_uuid $hv2_ch_uuid" +@@ -13527,29 +13484,18 @@ wait_column "$exp_ref_ch_list" HA_Chassis_Group ref_chassis + # Increase the priority of gw2 + ovn-nbctl --wait=sb ha-chassis-group-add-chassis hagrp1 gw2 40 + +-OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int table=37 | \ +-grep active_backup | grep slaves:$hv1_gw2_ofport,$hv1_gw1_ofport \ ++OVS_WAIT_FOR_OUTPUT([as hv1 ovs-ofctl dump-flows br-int table=37 | \ ++grep active_backup | grep members:$hv1_gw2_ofport,$hv1_gw1_ofport \ + | wc -l], [0], [1 + ]) + +-OVS_WAIT_UNTIL([as hv2 ovs-ofctl dump-flows br-int table=37 | \ +-grep active_backup | grep slaves:$hv2_gw2_ofport,$hv2_gw1_ofport \ ++OVS_WAIT_FOR_OUTPUT([as hv2 ovs-ofctl dump-flows br-int table=37 | \ ++grep active_backup | grep members:$hv2_gw2_ofport,$hv2_gw1_ofport \ + | wc -l], [0], [1 + ]) + + # check that the chassis redirect port has been reclaimed by the gw2 chassis +-# +-# XXX actually it doesn't happen, the test has always been wrong here +-# because the following just checks that "wc -l" succeeds (and it always +-# does): +-# +-# OVS_WAIT_UNTIL([ovn-sbctl --columns chassis --bare find Port_Binding \ +-# logical_port=cr-outside | grep $gw2_chassis | wc -l], [0],[[1 +-# ]]) +-# +-# If it were correct, then the following would be a good substitute: +-# +-# wait_row_count Port_Binding 1 logical_port=cr-outside chassis=$gw2_chassis ++wait_row_count Port_Binding 1 logical_port=cr-outside chassis=$gw2_chassis + + # check BFD enablement on tunnel ports from gw1 ######### + as gw1 +@@ -13588,11 +13534,11 @@ AT_CHECK([ovs-vsctl --bare --columns bfd find Interface name=ovn-hv1-0],[0], + ]]) + + # make sure that flows for handling the outside router port reside on gw2 now +-OVS_WAIT_UNTIL([as gw2 ovs-ofctl dump-flows br-int table=24 | \ +-grep 00:00:02:01:02:04 | wc -l], [0], [[1 ++OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \ ++grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1 + ]]) +-OVS_WAIT_UNTIL([as gw1 ovs-ofctl dump-flows br-int table=24 | \ +-grep 00:00:02:01:02:04 | wc -l], [0], [[0 ++OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \ ++grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[0 + ]]) + + # disconnect GW2 from the network, GW1 should take over +@@ -13603,11 +13549,11 @@ as main ovs-vsctl del-port n1 $port + bfd_dump + + # make sure that flows for handling the outside router port reside on gw2 now +-OVS_WAIT_UNTIL([as gw1 ovs-ofctl dump-flows br-int table=24 | \ +-grep 00:00:02:01:02:04 | wc -l], [0], [[1 ++OVS_WAIT_FOR_OUTPUT([as gw1 ovs-ofctl dump-flows br-int table=33 | \ ++grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[1 + ]]) +-OVS_WAIT_UNTIL([as gw2 ovs-ofctl dump-flows br-int table=24 | \ +-grep 00:00:02:01:02:04 | wc -l], [0], [[0 ++OVS_WAIT_FOR_OUTPUT([as gw2 ovs-ofctl dump-flows br-int table=33 | \ ++grep "dl_dst=00:00:02:01:02:04" | wc -l], [0], [[0 + ]]) + + # check that the chassis redirect port has been reclaimed by the gw1 chassis +@@ -13889,6 +13835,133 @@ OVN_CLEANUP([gw1],[gw2],[hv1]) + AT_CLEANUP + ]) + ++OVN_FOR_EACH_NORTHD([ ++AT_SETUP([allow IPv6 RA / NA / MLD by default]) ++AT_SKIP_IF([test $HAVE_SCAPY = no]) ++ovn_start ++net_add n1 ++sim_add hv1 ++as hv1 ++ovs-vsctl add-br br-phys ++ovn_attach n1 br-phys 192.168.0.1 ++ ++lsp_mac_prefix=50:64:00:00:00:0 ++lsp_ip_prefix=10.0.0. ++lsp_ip6_prefix=aef0::5264:00ff:fe00:000 ++ ++check ovn-nbctl ls-add ls0 ++for i in 1 2; do ++ check ovn-nbctl lsp-add ls0 lsp$i ++ check ovn-nbctl lsp-set-addresses lsp$i \ ++ "${lsp_mac_prefix}$i ${lsp_ip_prefix}$i ${lsp_ip6_prefix}$i" ++ ++ # forbid all traffic for the ports ++ check ovn-nbctl acl-add ls0 \ ++ from-lport 1000 "inport == \"lsp$i\"" drop ++ check ovn-nbctl --apply-after-lb acl-add ls0\ ++ from-lport 1000 "inport == \"lsp$i\"" drop ++ check ovn-nbctl acl-add ls0 \ ++ to-lport 1000 "outport == \"lsp$i\"" drop ++ ++ check ovs-vsctl -- add-port br-int vif$i -- \ ++ set interface vif$i external-ids:iface-id=lsp$i \ ++ options:tx_pcap=hv1/vif$i-tx.pcap \ ++ options:rxq_pcap=hv1/vif$i-rx.pcap ++ : > $i.expected ++done ++ ++router_mac=fa:16:3e:00:00:01 ++router_prefix=fdad:1234:5678:: ++router_ip=${router_prefix}1 ++check ovn-nbctl lr-add lr0 ++check ovn-nbctl lrp-add lr0 lrp0 ${router_mac} ${router_ip}/64 ++check ovn-nbctl set Logical_Router_Port lrp0 ipv6_ra_configs:address_mode="slaac" ++check ovn-nbctl \ ++ -- lsp-add ls0 rp0 \ ++ -- set Logical_Switch_Port rp0 type=router \ ++ options:router-port=lrp0 \ ++ addresses='"${router_mac} ${router_ip}"' ++ ++wait_for_ports_up ++ ++test_ns_na() { ++ local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5 ++ ++ packet=$(fmt_pkt " ++ Ether(dst='ff:ff:ff:ff:ff:ff', src='${src_mac}') / ++ IPv6(src='${src_ip}', dst='ff02::1:ff00:2') / ++ ICMPv6ND_NS(tgt='${dst_ip}') ++ ") ++ as hv1 ovs-appctl netdev-dummy/receive vif${inport} $packet ++ ++ expected_packet=$(fmt_pkt " ++ Ether(dst='${src_mac}', src='${dst_mac}') / ++ IPv6(src='${dst_ip}', dst='${src_ip}') / ++ ICMPv6ND_NA(tgt='${dst_ip}', R=0, S=1) / ++ ICMPv6NDOptDstLLAddr(lladdr='${dst_mac}') ++ ") ++ echo $expected_packet >> $inport.expected ++} ++ ++test_rs_ra() { ++ local inport=$1 src_mac=$2 src_ip=$3 ++ local router_mac=$4 router_prefix=$5 router_ip=$6 ++ ++ packet=$(fmt_pkt " ++ Ether(dst='ff:ff:ff:ff:ff:ff', src='${src_mac}') / ++ IPv6(src='${src_ip}', dst='ff02::2') / ++ ICMPv6ND_RS() ++ ") ++ as hv1 ovs-appctl netdev-dummy/receive vif${inport} $packet ++ ++ expected_packet=$(fmt_pkt " ++ Ether(dst='${src_mac}', src='${router_mac}') / ++ IPv6(src='${router_ip}', dst='${src_ip}') / ++ ICMPv6ND_RA(chlim=255, prf=0, routerlifetime=65535) / ++ ICMPv6NDOptSrcLLAddr(lladdr='${router_mac}') / ++ ICMPv6NDOptPrefixInfo(prefix='${router_prefix}') ++ ") ++ echo $expected_packet >> $inport.expected ++} ++ ++test_mldv2() { ++ local inport=$1 outport=$2 src_mac=$3 src_ip=$4 ++ ++ packet=$(fmt_pkt " ++ Ether(dst='ff:ff:ff:ff:ff:ff', src='${src_mac}') / ++ IPv6(src='${src_ip}', dst='ff02::2') / ++ ICMPv6MLQuery2() ++ ") ++ as hv1 ovs-appctl netdev-dummy/receive vif${inport} $packet ++ ++ expected_packet=$packet ++ echo $expected_packet >> $outport.expected ++} ++ ++src_mac=${lsp_mac_prefix}1 ++dst_mac=${lsp_mac_prefix}2 ++src_ip=${lsp_ip6_prefix}1 ++dst_ip=${lsp_ip6_prefix}2 ++ ++as hv1 ++test_ns_na 1 $src_mac $dst_mac $src_ip $dst_ip ++ ++as hv1 ++router_local_ip=fe80::f816:3eff:fe00:1 ++test_rs_ra 1 $src_mac $src_ip $router_mac $router_prefix $router_local_ip ++ ++as hv1 ++src_ip=fe80::1 ++test_mldv2 1 2 $src_mac $src_ip ++ ++OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [1.expected]) ++OVN_CHECK_PACKETS([hv1/vif2-tx.pcap], [2.expected]) ++ ++OVN_CLEANUP([hv1]) ++ ++AT_CLEANUP ++]) ++ + OVN_FOR_EACH_NORTHD([ + AT_SETUP([IPv6 Neighbor Solicitation for unknown MAC]) + AT_KEYWORDS([ovn-nd_ns for unknown mac]) +@@ -17210,7 +17283,7 @@ test_icmp() { + icmp4.code==0" + shift; shift; shift; shift; shift; shift + hv=hv`vif_to_hv $inport` +- as $hv ovs-appctl -t ovn-controller inject-pkt "$packet" ++ OVS_WAIT_UNTIL([as $hv ovs-appctl -t ovn-controller inject-pkt "$packet"]) + in_ls=`vif_to_ls $inport` + in_lrp=`vif_to_lrp $inport` + for outport; do +@@ -18276,7 +18349,7 @@ AT_SETUP([TTL exceeded]) + AT_KEYWORDS([ttl-exceeded]) + ovn_start + +-# test_ip_packet INPORT HV ETH_SRC ETH_DST IPV4_SRC IPV4_DST IPV4_ROUTER IP_CHKSUM EXP_IP_CHKSUM EXP_ICMP_CHKSUM ++# test_ip_packet INPORT HV ETH_SRC ETH_DST IPV4_SRC IPV4_DST IPV4_ROUTER IP_CHKSUM EXP_IP_CHKSUM EXP_ICMP_CHKSUM SHOULD_REPLY + # + # Causes a packet to be received on INPORT of the hypervisor HV. The packet is an IPv4 packet with + # ETH_SRC, ETH_DST, IPV4_SRC, IPV4_DST, IP_CHKSUM as specified and TTL set to 1. +@@ -18292,6 +18365,7 @@ test_ip_packet() { + local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ipv4_src=$5 ipv4_dst=$6 ip_router=$7 ip_chksum=$8 + local exp_ip_chksum=$9 exp_icmp_chksum=${10} + shift 10 ++ local should_reply=$1 + + local ip_ttl=01 + local packet=${eth_dst}${eth_src}08004500001400004000${ip_ttl}01${ip_chksum}${ipv4_src}${ipv4_dst} +@@ -18300,27 +18374,31 @@ test_ip_packet() { + local icmp_type_code_response=0b00 + local icmp_data=00000000 + local reply_icmp_payload=${icmp_type_code_response}${exp_icmp_chksum}${icmp_data} +- local reply=${eth_src}${eth_dst}08004500003000004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload} +- echo $reply$orig_pkt_in_reply >> vif$inport.expected ++ if test $should_reply == yes; then ++ local reply=${eth_src}${eth_dst}08004500003000004000${reply_icmp_ttl}01${exp_ip_chksum}${ip_router}${ipv4_src}${reply_icmp_payload} ++ echo $reply$orig_pkt_in_reply >> vif$inport.expected ++ fi + + as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet + } + +-# test_ip6_packet INPORT HV ETH_SRC ETH_DST IPV6_SRC IPV6_DST IPV6_ROUTER EXP_ICMP_CHKSUM ++# test_ip6_packet INPORT HV ETH_SRC ETH_DST IPV6_SRC IPV6_DST IPV6_ROUTER EXP_ICMP_CHKSUM SHOULD_REPLY + # + # Causes a packet to be received on INPORT of the hypervisor HV. The packet is an IPv6 + # packet with ETH_SRC, ETH_DST, IPV6_SRC and IPV6_DST as specified. + # IPV6_ROUTER and EXP_ICMP_CHKSUM are the source IP and checksum of the icmpv6 ttl exceeded + # packet sent by OVN logical router + test_ip6_packet() { +- local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ipv6_src=$5 ipv6_dst=$6 ipv6_router=$7 exp_icmp_chksum=$8 ++ local inport=$1 hv=$2 eth_src=$3 eth_dst=$4 ipv6_src=$5 ipv6_dst=$6 ipv6_router=$7 exp_icmp_chksum=$8 should_reply=$9 + shift 8 + + local ip6_hdr=6000000000151101${ipv6_src}${ipv6_dst} + local packet=${eth_dst}${eth_src}86dd${ip6_hdr}dbb8303900155bac6b646f65206676676e6d66720a + +- local reply=${eth_src}${eth_dst}86dd6000000000453afe${ipv6_router}${ipv6_src}0300${exp_icmp_chksum}00000000${ip6_hdr}dbb8303900155bac6b646f65206676676e6d66720a +- echo $reply >> vif$inport.expected ++ if test $should_reply == yes; then ++ local reply=${eth_src}${eth_dst}86dd6000000000453afe${ipv6_router}${ipv6_src}0300${exp_icmp_chksum}00000000${ip6_hdr}dbb8303900155bac6b646f65206676676e6d66720a ++ echo $reply >> vif$inport.expected ++ fi + + as hv$hv ovs-appctl netdev-dummy/receive vif$inport $packet + } +@@ -18343,6 +18421,8 @@ for i in 1 2; do + options:tx_pcap=hv$i/vif$i-tx.pcap \ + options:rxq_pcap=hv$i/vif$i-rx.pcap \ + ofport-request=$i ++ ++ ovs-appctl -t ovn-controller vlog/set file:dbg:pinctrl + done + + ovn-nbctl lr-add lr0 +@@ -18358,10 +18438,22 @@ OVN_POPULATE_ARP + wait_for_ports_up + ovn-nbctl --wait=hv sync + +-test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 2 1) $(ip_to_hex 192 168 1 254) 0000 f87c ea96 +-test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011 20010db8000200000000000000000011 20010db8000100000000000000000001 1c22 ++test_ip_packet 1 1 000000000001 00000000ff01 $(ip_to_hex 192 168 1 1) $(ip_to_hex 192 168 2 1) $(ip_to_hex 192 168 1 254) 0000 f87c ea96 yes ++test_ip6_packet 1 1 000000000001 00000000ff01 20010db8000100000000000000000011 20010db8000200000000000000000011 20010db8000100000000000000000001 1c22 yes ++ ++# Should not send ICMP for multicast ++test_ip_packet 1 1 000000000001 01005e7f0001 $(ip_to_hex 192 168 1 1) $(ip_to_hex 239 255 0 1) $(ip_to_hex 192 168 1 254) 0000 000000000 no ++test_ip6_packet 1 1 000000000001 333300000001 20010db8000100000000000000000011 ff020000000000000000000000000001 20010db8000100000000000000000001 0000 no ++ + OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [vif1.expected]) + ++# Confirm from debug log that we only see 2 packet-ins (no packet-ins for ++# multicasts). This is necessary because not seeing ICMP messages doesn't ++# necessarily mean the packet-in didn't happen. It is possible that packet-in ++# is processed but the ICMP message got dropped. ++AT_CHECK([grep -c packet-in hv1/ovn-controller.log], [0], [2 ++]) ++ + OVN_CLEANUP([hv1], [hv2]) + AT_CLEANUP + ]) +@@ -18656,7 +18748,7 @@ packet="inport==\"sw1-p1\" && eth.src==$sw1_p1_mac && eth.dst==$sw1_ro_mac && + udp && udp.src==53 && udp.dst==4369" + + # Start by Sending the packet and make sure it makes it there as expected +-as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Expected packet has TTL decreased by 1 + expected="eth.src==$sw2_ro_mac && eth.dst==$sw2_p1_mac && +@@ -18670,7 +18762,7 @@ OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) + as hv2 ovs-appctl -t ovn-controller exit + + # Now send the packet again. This time, it should not arrive. +-as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) + +@@ -19552,7 +19644,7 @@ packet="inport==\"sw1-p1\" && eth.src==$sw1_p1_mac && eth.dst==$sw1_ro_mac && + udp && udp.src==53 && udp.dst==4369" + + # Start by Sending the packet and make sure it makes it there as expected +-as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Expected packet has TTL decreased by 1 + expected="eth.src==$sw2_ro_mac && eth.dst==$sw2_p1_mac && +@@ -19566,7 +19658,7 @@ OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) + as hv2 ovs-appctl -t ovn-controller exit --restart + + # Now send the packet again. This time, it should still arrive +-as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + cat expected expected > expected2 + +@@ -19705,7 +19797,7 @@ test_ip_packet_larger() { + # Set the packet length to 114. + pkt_len=0072 + packet=${dst_mac}${src_mac}08004500${pkt_len}000000004001c3dd +- orig_packet_l3=${src_ip}${dst_ip}0304fcfb00000000 ++ orig_packet_l3=${src_ip}${dst_ip}0800f7ff00000000 + orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000 + orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000 + orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000 +@@ -19729,10 +19821,10 @@ test_ip_packet_larger() { + # Packet to expect at br-phys. + src_mac="000020201213" + dst_mac="00000012af11" +- src_ip=`ip_to_hex 10 0 0 3` ++ src_ip=`ip_to_hex 172 168 0 100` + dst_ip=`ip_to_hex 172 168 0 3` +- expected=${dst_mac}${src_mac}08004500${pkt_len}000000003f01c4dd +- expected=${expected}${src_ip}${dst_ip}0304fcfb00000000 ++ expected=${dst_mac}${src_mac}08004500${pkt_len}000000003f0121d4 ++ expected=${expected}${src_ip}${dst_ip}0800f7ff00000000 + expected=${expected}000000000000000000000000000000000000 + expected=${expected}000000000000000000000000000000000000 + expected=${expected}000000000000000000000000000000000000 +@@ -19793,7 +19885,7 @@ test_ip_packet_larger_ext() { + # Set the packet length to 114. + pkt_len=0072 + packet=${dst_mac}${src_mac}08004500${pkt_len}000000004001${checksum} +- orig_packet_l3=${src_ip}${dst_ip}0900000000000000 ++ orig_packet_l3=${src_ip}${dst_ip}0800f7ff00000000 + orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000 + orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000 + orig_packet_l3=${orig_packet_l3}000000000000000000000000000000000000 +@@ -19810,7 +19902,7 @@ test_ip_packet_larger_ext() { + dst_ip=`ip_to_hex 172 168 0 4` + # pkt len should be 146 (28 (icmp packet) + 118 (orig ip + payload)) + reply_pkt_len=008e +- ip_csum=f39b ++ ip_csum=$7 + icmp_reply=${src_mac}${dst_mac}08004500${reply_pkt_len}00004000fe01${reply_checksum} + icmp_reply=${icmp_reply}${src_ip}${dst_ip}0304${ip_csum}0000$(printf "%04x" $mtu) + icmp_reply=${icmp_reply}4500${pkt_len}000000004001${checksum} +@@ -19985,10 +20077,10 @@ OVS_WAIT_FOR_OUTPUT([ + ]) + + AS_BOX([testing ingress traffic mtu 100 - IPv4]) +-test_ip_packet_larger_ext 1 000020201213 $(ip_to_hex 172 168 0 100) 20cf 100 22b6 ++test_ip_packet_larger_ext 1 000020201213 $(ip_to_hex 172 168 0 100) 20d3 100 22b6 fc97 + + AS_BOX([testing ingress traffic mtu 100 - IPv4 FIP]) +-test_ip_packet_larger_ext 2 f00000010204 $(ip_to_hex 172 168 0 110) 20c5 100 22ac ++test_ip_packet_larger_ext 2 f00000010204 $(ip_to_hex 172 168 0 110) 20c5 100 22ac fc9b + + AS_BOX([testing ingress traffic mtu 100 - IPv6]) + test_ip6_packet_larger_ext 1 000020201213 20000000000000000000000000000001 100 cc7a +@@ -20055,10 +20147,10 @@ OVS_WAIT_FOR_OUTPUT([ + ]) + + AS_BOX([testing ingress traffic mtu 100 for gw router - IPv4]) +-test_ip_packet_larger_ext 1 000020201213 $(ip_to_hex 172 168 0 100) 20cf 100 22b6 ++test_ip_packet_larger_ext 1 000020201213 $(ip_to_hex 172 168 0 100) 20d3 100 22b6 fc97 + + AS_BOX([testing ingress traffic mtu 100 for gw router - IPv6]) +-test_ip6_packet_larger_ext 1 000020201213 20000000000000000000000000000001 100 cc7a ++test_ip6_packet_larger_ext 1 000020201213 20000000000000000000000000000001 100 cc7a fc9b + + OVN_CLEANUP([hv1]) + AT_CLEANUP +@@ -21116,7 +21208,7 @@ check_virtual_offlows_not_present hv2 + send_garp 1 1 $eth_src $eth_dst $spa $tpa + + OVS_WAIT_UNTIL([test x$(ovn-sbctl --bare --columns chassis find port_binding \ +-logical_port=sw0-vir) = x$hv1_ch_uuid], [0], []) ++logical_port=sw0-vir) = x$hv1_ch_uuid]) + + AT_CHECK([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \ + logical_port=sw0-vir) = xsw0-p1]) +@@ -21184,7 +21276,7 @@ tpa=$(ip_to_hex 10 0 0 10) + send_garp 1 2 $eth_src $eth_dst $spa $tpa + + OVS_WAIT_UNTIL([test x$(ovn-sbctl --bare --columns chassis find port_binding \ +-logical_port=sw0-vir) = x$hv1_ch_uuid], [0], []) ++logical_port=sw0-vir) = x$hv1_ch_uuid]) + + OVS_WAIT_UNTIL([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \ + logical_port=sw0-vir) = xsw0-p3]) +@@ -21217,7 +21309,7 @@ tpa=$(ip_to_hex 10 0 0 10) + send_garp 2 1 $eth_src $eth_dst $spa $tpa + + OVS_WAIT_UNTIL([test x$(ovn-sbctl --bare --columns chassis find port_binding \ +-logical_port=sw0-vir) = x$hv2_ch_uuid], [0], []) ++logical_port=sw0-vir) = x$hv2_ch_uuid]) + + AT_CHECK([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \ + logical_port=sw0-vir) = xsw0-p2]) +@@ -21249,7 +21341,7 @@ tpa=$(ip_to_hex 10 0 0 4) + send_arp_reply 1 1 $eth_src $eth_dst $spa $tpa + + OVS_WAIT_UNTIL([test x$(ovn-sbctl --bare --columns chassis find port_binding \ +-logical_port=sw0-vir) = x$hv1_ch_uuid], [0], []) ++logical_port=sw0-vir) = x$hv1_ch_uuid]) + sleep 1 + + AT_CHECK([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \ +@@ -21275,7 +21367,7 @@ check_virtual_offlows_not_present hv2 + as hv1 ovs-vsctl del-port hv1-vif1 + + OVS_WAIT_UNTIL([test x$(ovn-sbctl --bare --columns chassis find port_binding \ +-logical_port=sw0-vir) = x], [0], []) ++logical_port=sw0-vir) = x]) + sleep 1 + + AT_CHECK([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \ +@@ -21310,7 +21402,7 @@ send_arp_reply 2 1 $eth_src $eth_dst $spa $tpa + sleep 1 + + OVS_WAIT_UNTIL([test x$(ovn-sbctl --bare --columns chassis find port_binding \ +-logical_port=sw0-vir) = x$hv2_ch_uuid], [0], []) ++logical_port=sw0-vir) = x$hv2_ch_uuid]) + sleep 1 + AT_CHECK([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \ + logical_port=sw0-vir) = xsw0-p2]) +@@ -21335,7 +21427,7 @@ check_virtual_offlows_not_present hv1 + ovn-nbctl lsp-del sw0-p2 + + OVS_WAIT_UNTIL([test x$(ovn-sbctl --bare --columns chassis find port_binding \ +-logical_port=sw0-vir) = x], [0], []) ++logical_port=sw0-vir) = x]) + AT_CHECK([test x$(ovn-sbctl --bare --columns virtual_parent find port_binding \ + logical_port=sw0-vir) = x]) + +@@ -21516,7 +21608,7 @@ AT_CAPTURE_FILE([offlows]) + packet0="inport==\"sw0-p11\" && eth.src==00:00:00:00:00:11 && eth.dst==00:00:00:00:00:21 && + ip4 && ip.ttl==64 && ip4.src==192.168.1.11 && ip4.dst==192.168.1.100 && + tcp && tcp.src==10000 && tcp.dst==80" +-as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet0" ++OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet0"]) + ovn-nbctl --wait=hv + + ovn-sbctl list controller_event > events +@@ -21545,7 +21637,7 @@ packet1="inport==\"sw1-p0\" && eth.src==00:00:00:00:00:33 && eth.dst==00:00:00:0 + ip4 && ip.ttl==64 && ip4.src==192.168.2.11 && ip4.dst==192.168.2.100 && + tcp && tcp.src==10000 && tcp.dst==80" + +-as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet1" ++OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet1"]) + ovn-nbctl --wait=hv + ovn-sbctl list controller_event + uuid=$(ovn-sbctl list controller_event | awk '/_uuid/{print $3}') +@@ -21561,7 +21653,7 @@ packet2="inport==\"sw0-p11\" && eth.src==00:00:00:00:00:11 && eth.dst==00:00:00: + ip6 && ip.ttl==64 && ip6.src==2001::11 && ip6.dst==2001::10 && + tcp && tcp.src==10000 && tcp.dst==50051" + +-as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet2" ++OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet2"]) + ovn-nbctl --wait=hv + ovn-sbctl list controller_event + uuid=$(ovn-sbctl list controller_event | awk '/_uuid/{print $3}') +@@ -23744,7 +23836,7 @@ send_garp 1 1 $eth_src $eth_dst $spa $tpa + + wait_row_count MAC_Binding 1 + +-OVS_WAIT_UNTIL([ovn-sbctl --format=csv --bare --columns logical_port,ip,mac \ ++OVS_WAIT_FOR_OUTPUT([ovn-sbctl --format=csv --bare --columns logical_port,ip,mac \ + list mac_binding], [0], [lr0-sw0 + 10.0.0.30 + 50:54:00:00:00:03 +@@ -23791,7 +23883,7 @@ grep table_id=10 | wc -l`]) + + check_row_count MAC_Binding 1 + +-OVS_WAIT_UNTIL([ovn-sbctl --format=csv --bare --columns logical_port,ip,mac \ ++OVS_WAIT_FOR_OUTPUT([ovn-sbctl --format=csv --bare --columns logical_port,ip,mac \ + list mac_binding], [0], [lr0-sw0 + 10.0.0.30 + 50:54:00:00:00:13 +@@ -23820,7 +23912,7 @@ OVS_WAIT_UNTIL( + | wc -l`] + ) + +-OVS_WAIT_UNTIL([ovn-sbctl --format=csv --bare --columns logical_port,ip,mac \ ++OVS_WAIT_FOR_OUTPUT([ovn-sbctl --format=csv --bare --columns logical_port,ip,mac \ + find mac_binding ip=10.0.0.50], [0], [lr0-sw0 + 10.0.0.50 + 50:54:00:00:00:33 +@@ -24377,7 +24469,7 @@ AT_CAPTURE_FILE([sbflows2]) + OVS_WAIT_FOR_OUTPUT( + [ovn-sbctl dump-flows > sbflows2 + ovn-sbctl dump-flows lr0 | grep ct_lb_mark | grep priority=120 | sed 's/table=..//'], 0, +- [ (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80; hash_fields="ip_dst,ip_src,tcp_dst,tcp_src");) ++ [ (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=10.0.0.3:80,20.0.0.3:80; hash_fields="ip_dst,ip_src,tcp_dst,tcp_src");) + ]) + + # get the svc monitor mac. +@@ -24419,8 +24511,7 @@ AT_CHECK( + AT_CAPTURE_FILE([sbflows4]) + ovn-sbctl dump-flows lr0 > sbflows4 + AT_CHECK([grep lr_in_dnat sbflows4 | grep priority=120 | sed 's/table=..//' | sort], [0], [dnl +- (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;) +- (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && reg0 == 10.0.0.10 && tcp && reg9[[16..31]] == 80 && is_chassis_resident("cr-lr0-public")), action=(drop;) ++ (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80 && is_chassis_resident("cr-lr0-public")), action=(drop;) + ]) + + # Delete sw0-p1 +@@ -24576,7 +24667,7 @@ AT_CAPTURE_FILE([sbflows2]) + OVS_WAIT_FOR_OUTPUT( + [ovn-sbctl dump-flows > sbflows2 + ovn-sbctl dump-flows lr0 | grep ct_lb_mark | grep priority=120 | sed 's/table=..//'], 0, +- [ (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip6 && xxreg0 == 2001::a && tcp && reg9[[16..31]] == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=[[2001::3]]:80,[[2002::3]]:80; hash_fields="ip_dst,ip_src,tcp_dst,tcp_src");) ++ [ (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip6 && ip6.dst == 2001::a && tcp && tcp.dst == 80 && is_chassis_resident("cr-lr0-public")), action=(ct_lb_mark(backends=[[2001::3]]:80,[[2002::3]]:80; hash_fields="ip_dst,ip_src,tcp_dst,tcp_src");) + ]) + + # get the svc monitor mac. +@@ -24618,8 +24709,7 @@ AT_CHECK( + AT_CAPTURE_FILE([sbflows4]) + ovn-sbctl dump-flows lr0 > sbflows4 + AT_CHECK([grep lr_in_dnat sbflows4 | grep priority=120 | sed 's/table=..//' | sort], [0], [dnl +- (lr_in_dnat ), priority=120 , match=(ct.est && !ct.rel && ip6 && xxreg0 == 2001::a && tcp && reg9[[16..31]] == 80 && ct_mark.natted == 1 && is_chassis_resident("cr-lr0-public")), action=(next;) +- (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip6 && xxreg0 == 2001::a && tcp && reg9[[16..31]] == 80 && is_chassis_resident("cr-lr0-public")), action=(drop;) ++ (lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip6 && ip6.dst == 2001::a && tcp && tcp.dst == 80 && is_chassis_resident("cr-lr0-public")), action=(drop;) + ]) + + # Delete sw0-p1 +@@ -25447,7 +25537,7 @@ for s_az in $(seq 1 $n_az); do + udp && udp.src==53 && udp.dst==4369" + echo "sending: $packet" + AT_CHECK([ovn_trace --ovs "$packet" > ${s_az}-${d_az}-$i.ovn-trace]) +- AT_CHECK([ovs-appctl -t ovn-controller inject-pkt "$packet"]) ++ OVS_WAIT_UNTIL([ovs-appctl -t ovn-controller inject-pkt "$packet"]) + ovs_inport=$(ovs-vsctl --bare --columns=ofport find Interface external-ids:iface-id="$ovn_inport") + + ovs_packet=$(echo $packet | ovstest test-ovn expr-to-packets) +@@ -26002,7 +26092,7 @@ for i in $(seq 5001 5010); do + packet="inport==\"lsp11\" && eth.src==f0:00:00:00:01:11 && eth.dst==00:00:00:01:01:01 && + ip4 && ip.ttl==64 && ip4.src==192.168.1.11 && ip4.dst==10.0.0.123 && + tcp && tcp.src==$i && tcp.dst==80" +- AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) ++ OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + for j in 1 2; do + # Assume all packets go to lsp2${j}. +@@ -26121,7 +26211,7 @@ wait_for_ports_up + # Test 1 + packet="inport==\"lsp11\" && eth.src==f0:00:00:00:01:11 && eth.dst==00:00:00:01:01:01 && + ip4 && ip.ttl==64 && ip4.src==192.168.1.11 && ip4.dst==2.2.2.2 && icmp" +-AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) ++OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Assume no packets go neither to lsp21 nor to lsp22. + > expected_lsp21 +@@ -26151,7 +26241,7 @@ done + # Test 2 + packet="inport==\"lsp11\" && eth.src==f0:00:00:00:01:11 && eth.dst==00:00:00:01:01:01 && + ip4 && ip.ttl==64 && ip4.src==192.168.1.11 && ip4.dst==1.1.1.1 && icmp" +-AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) ++OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Assume all packets go to lsp22. + exp_packet="eth.src==00:00:00:01:02:01 && eth.dst==f0:00:00:00:02:22 && +@@ -26181,7 +26271,7 @@ done + # Test 3 + packet="inport==\"lsp21\" && eth.src==f0:00:00:00:02:21 && eth.dst==00:00:00:01:02:01 && + ip4 && ip.ttl==64 && ip4.src==192.168.2.21 && ip4.dst==2.2.2.2 && icmp" +-AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) ++OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Assume all packets go to lsp21. + exp_packet="eth.src==00:00:00:01:02:01 && eth.dst==f0:00:00:00:02:21 && +@@ -26278,7 +26368,7 @@ wait_for_ports_up + # test 1 + packet="inport==\"lsp11\" && eth.src==f0:00:00:00:01:11 && eth.dst==00:00:00:01:01:01 && + ip4 && ip.ttl==64 && ip4.src==192.168.1.11 && ip4.dst==192.168.2.21 && icmp" +-AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) ++OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Assume all packets go to lsp21. + exp_packet="eth.src==00:00:00:01:02:01 && eth.dst==f0:00:00:00:02:21 && ip4 && +@@ -26312,7 +26402,7 @@ ovs-vsctl set interface hv1-vif2 options:tx_pcap=hv1/vif2-tx.pcap + # test 2 + packet="inport==\"lsp11\" && eth.src==f0:00:00:00:01:11 && eth.dst==00:00:00:01:01:01 && + ip4 && ip.ttl==64 && ip4.src==192.168.1.11 && ip4.dst==192.168.2.200 && icmp" +-AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) ++OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Assume all packets go to lsp11. + exp_packet="eth.src==00:00:00:01:01:01 && eth.dst==f0:00:00:00:01:11 && ip4 && +@@ -26417,7 +26507,7 @@ for i in $(seq 1 2); do + packet="inport==\"lsp${i}1\" && eth.src==f0:00:00:00:0${i}:1${i} && + eth.dst==00:00:00:01:0${i}:01 && ip4 && ip.ttl==64 && + ip4.src==192.168.${i}.${i}1 && ip4.dst==10.0.0.1 && icmp" +- AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) ++ OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Assume all packets go to lsp${di}1. + exp_packet="eth.src==00:00:00:01:0${di}:01 && eth.dst==f0:00:00:00:0${di}:1${di} && +@@ -26530,7 +26620,7 @@ for i in $(seq 1 2); do + packet="inport==\"lsp${i}1\" && eth.src==f0:00:00:00:0${i}:1${i} && + eth.dst==00:00:00:01:0${i}:01 && ip6 && ip.ttl==64 && + ip6.src==2001:db8:${i}::${i}1 && ip6.dst==2001:db8:2000::1 && icmp6" +- AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) ++ OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Assume all packets go to lsp${di}1. + exp_packet="eth.src==00:00:00:01:0${di}:01 && eth.dst==f0:00:00:00:0${di}:1${di} && ip6 && +@@ -26650,7 +26740,7 @@ dst_ip=172.16.1.11 + packet="inport==\"lsp11\" && eth.src==$src_mac && eth.dst==$dst_mac && + ip4 && ip.ttl==64 && ip4.src==$src_ip && ip4.dst==$dst_ip && + udp && udp.src==53 && udp.dst==4369" +-check as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Check if the packet hit the forwarding group policy + AT_CAPTURE_FILE([offlows2]) +@@ -27173,7 +27263,7 @@ ovn_attach n1 br-phys 192.168.0.1 + + # Chassis hv1 should add flows for the ls1 datapath in table 8 (ls_in_port_sec_l2). + dp_key=$(ovn-sbctl --bare --columns tunnel_key list Datapath_Binding ls1) +-OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int | grep -E "table=8.*metadata=0x${dp_key}"], [0], [ignore]) ++OVS_WAIT_UNTIL([as hv1 ovs-ofctl dump-flows br-int | grep -E "table=8.*metadata=0x${dp_key}"]) + + OVN_CLEANUP([hv1]) + AT_CLEANUP +@@ -27199,7 +27289,7 @@ ovs-vsctl add-br br-phys + ovn_attach n1 br-phys 192.168.0.1 + + # Port_Binding should be released. +-OVS_WAIT_UNTIL([test 0 = $(ovn-sbctl show | grep Port_Binding -c)], [0]) ++OVS_WAIT_UNTIL([test 0 = $(ovn-sbctl show | grep Port_Binding -c)]) + + OVN_CLEANUP([hv1]) + AT_CLEANUP +@@ -27332,22 +27422,24 @@ sleep 5 + send_ipv4_pkt() { + local hv=$1 inport=$2 eth_src=$3 eth_dst=$4 + local ip_src=$5 ip_dst=$6 +- packet=${eth_dst}${eth_src}08004500001c0000000040110000${ip_src}${ip_dst}0035111100080000 ++ local ip_cksum=$7 tcp_cksum=$8 ++ packet=${eth_dst}${eth_src}080045000028000000004006${ip_cksum}${ip_src}${ip_dst}0035111112345678000000005002faf0${tcp_cksum}0000 + tcpdump_hex $packet + as $hv ovs-appctl netdev-dummy/receive ${inport} ${packet} + } + + send_icmp6_packet() { +- local hv=$1 inport=$2 eth_src=$3 eth_dst=$4 ipv6_src=$5 ipv6_dst=$6 ++ local hv=$1 inport=$2 eth_src=$3 eth_dst=$4 ipv6_src=$5 ipv6_dst=$6 tcp_cksum=$7 + +- local ip6_hdr=6000000000083aff${ipv6_src}${ipv6_dst} +- local packet=${eth_dst}${eth_src}86dd${ip6_hdr}8000dcb662f00001 ++ local ip6_hdr=60000000001406ff${ipv6_src}${ipv6_dst} ++ local packet=${eth_dst}${eth_src}86dd${ip6_hdr}0035111112345678000000005002faf0${tcp_cksum}0000 + + as $hv ovs-appctl netdev-dummy/receive ${inport} ${packet} + } + + send_ipv4_pkt hv1 hv1-vif1 505400000003 00000000ff01 \ +- $(ip_to_hex 10 0 0 3) $(ip_to_hex 172 168 0 120) ++ $(ip_to_hex 10 0 0 3) $(ip_to_hex 172 168 0 120) \ ++ c3ad 83dc + + AT_CAPTURE_FILE([offlows2]) + OVS_WAIT_UNTIL([ +@@ -27364,7 +27456,8 @@ AT_CHECK([ + + # Send the pkt from sw0-port2. Packet should not be marked. + send_ipv4_pkt hv1 hv1-vif2 505400000004 00000000ff01 \ +- $(ip_to_hex 10 0 0 4) $(ip_to_hex 172 168 0 120) ++ $(ip_to_hex 10 0 0 4) $(ip_to_hex 172 168 0 120) \ ++ c3ac 83db + + AT_CHECK([ + test 1 -eq $(as hv1 ovs-ofctl dump-flows br-phys table=0 | \ +@@ -27398,7 +27491,8 @@ AT_CHECK([ + + ovn-nbctl set logical_router_policy $pol1 options:pkt_mark=2 + send_ipv4_pkt hv1 hv1-vif1 505400000003 00000000ff01 \ +- $(ip_to_hex 10 0 0 3) $(ip_to_hex 172 168 0 120) ++ $(ip_to_hex 10 0 0 3) $(ip_to_hex 172 168 0 120) \ ++ c3ad 83dc + + OVS_WAIT_UNTIL([ + test 1 -eq $(as hv1 ovs-ofctl dump-flows br-int table=23 | \ +@@ -27431,7 +27525,8 @@ AT_CHECK([ + # Send with src ip 10.0.0.5. The reroute policy should be hit + # and the packet should be marked with 5. + send_ipv4_pkt hv1 hv1-vif1 505400000003 00000000ff01 \ +- $(ip_to_hex 10 0 0 5) $(ip_to_hex 172 168 0 120) ++ $(ip_to_hex 10 0 0 5) $(ip_to_hex 172 168 0 120) \ ++ c3ab 83da + + OVS_WAIT_UNTIL([ + test 1 -eq $(as hv1 ovs-ofctl dump-flows br-phys table=0 | \ +@@ -27443,7 +27538,7 @@ OVS_WAIT_UNTIL([ + src_ip6=aef00000000000000000000000000004 + dst_ip6=bef00000000000000000000000000004 + +-send_icmp6_packet hv1 hv1-vif2 505400000004 00000000ff01 ${src_ip6} ${dst_ip6} ++send_icmp6_packet hv1 hv1-vif2 505400000004 00000000ff01 ${src_ip6} ${dst_ip6} cd16 + + OVS_WAIT_UNTIL([ + test 1 -eq $(as hv1 ovs-ofctl dump-flows br-phys table=0 | \ +@@ -27463,7 +27558,7 @@ AT_CHECK([ + src_ip6=aef00000000000000000000000000004 + dst_ip6=bef00000000000000000000000000005 + +-send_icmp6_packet hv1 hv1-vif2 505400000004 00000000ff01 ${src_ip6} ${dst_ip6} ++send_icmp6_packet hv1 hv1-vif2 505400000004 00000000ff01 ${src_ip6} ${dst_ip6} cd15 + + OVS_WAIT_UNTIL([ + test 1 -eq $(as hv1 ovs-ofctl dump-flows br-phys table=0 | \ +@@ -28737,7 +28832,7 @@ src_mac="f00000000102" + dst_mac="000000000101" + src_ip=`ip_to_hex 10 0 1 2` + dst_ip=`ip_to_hex 10 0 1 1` +-packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000 ++packet=${dst_mac}${src_mac}08004500001c00000000401164cf${src_ip}${dst_ip}0035111100080000 + as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet + + # Even after configuring a router owned IP for SNAT, no packet-ins should +@@ -28763,7 +28858,7 @@ src_mac="f00000000202" + dst_mac="000000000201" + src_ip=`ip_to_hex 10 0 2 2` + dst_ip=`ip_to_hex 10 0 1 1` +-packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000 ++packet=${dst_mac}${src_mac}08004500001c00000000401163cf${src_ip}${dst_ip}0035111100080000 + as hv1 ovs-appctl netdev-dummy/receive hv1-vif2 $packet + + # Still no packet-ins should reach ovn-controller. +@@ -29548,7 +29643,9 @@ OVS_WAIT_UNTIL([test x$(ovn-nbctl lsp-get-up sw1-p1) = xup]) + + check ovn-nbctl lb-add lb-ipv4-tcp 88.88.88.88:8080 42.42.42.1:4041 tcp + check ovn-nbctl lb-add lb-ipv4-udp 88.88.88.88:4040 42.42.42.1:2021 udp ++check ovn-nbctl lb-add lb-ipv4 88.88.88.89 42.42.42.2 + check ovn-nbctl lb-add lb-ipv6-tcp [[8800::0088]]:8080 [[4200::1]]:4041 tcp ++check ovn-nbctl lb-add lb-ipv6 8800::0089 4200::2 + check ovn-nbctl --wait=hv lb-add lb-ipv6-udp [[8800::0088]]:4040 [[4200::1]]:2021 udp + + AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=68 | grep -v NXST], [1], [dnl +@@ -29839,6 +29936,119 @@ AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=70 | ofctl_strip_all | grep - + table=70, priority=100,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=8800::88)) + ]) + ++check ovn-nbctl --wait=hv ls-lb-add sw0 lb-ipv4 ++OVS_WAIT_UNTIL( ++ [test $(as hv1 ovs-ofctl dump-flows br-int table=68 | grep -c -v NXST) -eq 7] ++) ++ ++OVS_WAIT_UNTIL( ++ [test $(as hv2 ovs-ofctl dump-flows br-int table=68 | grep -c -v NXST) -eq 7] ++) ++ ++AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=68 | ofctl_strip_all | grep -v NXST], [0], [dnl ++ table=68, priority=100,ct_mark=0x2/0x2,ip,reg1=0x58585859,nw_src=42.42.42.2,nw_dst=42.42.42.2 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.89,NXM_OF_IP_PROTO[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++]) ++ ++AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=69 | grep -v NXST], [1], [dnl ++]) ++ ++AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=70 | ofctl_strip_all | grep -v NXST], [0], [dnl ++ table=70, priority=100,tcp,reg1=0x58585858,reg2=0x1f90/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.88)) ++ table=70, priority=100,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.90)) ++ table=70, priority=100,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=8800::88)) ++ table=70, priority=100,udp,reg1=0x58585858,reg2=0xfc8/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.88)) ++ table=70, priority=100,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=8800::88)) ++ table=70, priority=90,ip,reg1=0x58585859 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.89)) ++]) ++ ++AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=68 | ofctl_strip_all | grep -v NXST], [0], [dnl ++ table=68, priority=100,ct_mark=0x2/0x2,ip,reg1=0x58585859,nw_src=42.42.42.2,nw_dst=42.42.42.2 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.89,NXM_OF_IP_PROTO[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++]) ++ ++AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=69 | grep -v NXST], [1], [dnl ++]) ++ ++AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=70 | ofctl_strip_all | grep -v NXST], [0], [dnl ++ table=70, priority=100,tcp,reg1=0x58585858,reg2=0x1f90/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.88)) ++ table=70, priority=100,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.90)) ++ table=70, priority=100,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=8800::88)) ++ table=70, priority=100,udp,reg1=0x58585858,reg2=0xfc8/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.88)) ++ table=70, priority=100,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=8800::88)) ++ table=70, priority=90,ip,reg1=0x58585859 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.89)) ++]) ++ ++check ovn-nbctl --wait=hv ls-lb-add sw0 lb-ipv6 ++OVS_WAIT_UNTIL( ++ [test $(as hv1 ovs-ofctl dump-flows br-int table=68 | grep -c -v NXST) -eq 8] ++) ++ ++OVS_WAIT_UNTIL( ++ [test $(as hv2 ovs-ofctl dump-flows br-int table=68 | grep -c -v NXST) -eq 8] ++) ++ ++AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=68 | ofctl_strip_all | grep -v NXST], [0], [dnl ++ table=68, priority=100,ct_mark=0x2/0x2,ip,reg1=0x58585859,nw_src=42.42.42.2,nw_dst=42.42.42.2 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.89,NXM_OF_IP_PROTO[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,ipv6,reg4=0x88000000,reg5=0,reg6=0,reg7=0x89,ipv6_src=4200::2,ipv6_dst=4200::2 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::89,NXM_OF_IP_PROTO[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++]) ++ ++AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=69 | grep -v NXST], [1], [dnl ++]) ++ ++AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=70 | ofctl_strip_all | grep -v NXST], [0], [dnl ++ table=70, priority=100,tcp,reg1=0x58585858,reg2=0x1f90/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.88)) ++ table=70, priority=100,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.90)) ++ table=70, priority=100,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=8800::88)) ++ table=70, priority=100,udp,reg1=0x58585858,reg2=0xfc8/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.88)) ++ table=70, priority=100,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=8800::88)) ++ table=70, priority=90,ip,reg1=0x58585859 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.89)) ++ table=70, priority=90,ipv6,reg4=0x88000000,reg5=0,reg6=0,reg7=0x89 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=8800::89)) ++]) ++ ++AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=68 | ofctl_strip_all | grep -v NXST], [0], [dnl ++ table=68, priority=100,ct_mark=0x2/0x2,ip,reg1=0x58585859,nw_src=42.42.42.2,nw_dst=42.42.42.2 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.89,NXM_OF_IP_PROTO[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,ipv6,reg4=0x88000000,reg5=0,reg6=0,reg7=0x89,ipv6_src=4200::2,ipv6_dst=4200::2 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::89,NXM_OF_IP_PROTO[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x58585858,reg2=0x1f90/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=42.42.42.42,nw_dst=42.42.42.42,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff,nw_src=52.52.52.52,nw_dst=52.52.52.52,tp_dst=4042 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.90,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=4041 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=6,NXM_OF_TCP_SRC[[]]=NXM_OF_TCP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,udp,reg1=0x58585858,reg2=0xfc8/0xffff,nw_src=42.42.42.1,nw_dst=42.42.42.1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x800,NXM_OF_IP_SRC[[]],ip_dst=88.88.88.88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++ table=68, priority=100,ct_mark=0x2/0x2,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88,ipv6_src=4200::1,ipv6_dst=4200::1,tp_dst=2021 actions=load:0x1->NXM_NX_REG10[[7]],learn(table=69,delete_learned,OXM_OF_METADATA[[]],eth_type=0x86dd,NXM_NX_IPV6_SRC[[]],ipv6_dst=8800::88,nw_proto=17,NXM_OF_UDP_SRC[[]]=NXM_OF_UDP_DST[[]],load:0x1->NXM_NX_REG10[[7]]) ++]) ++ ++AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=69 | grep -v NXST], [1], [dnl ++]) ++ ++AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=70 | ofctl_strip_all | grep -v NXST], [0], [dnl ++ table=70, priority=100,tcp,reg1=0x58585858,reg2=0x1f90/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.88)) ++ table=70, priority=100,tcp,reg1=0x5858585a,reg2=0x1f90/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.90)) ++ table=70, priority=100,tcp6,reg2=0x1f90/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=8800::88)) ++ table=70, priority=100,udp,reg1=0x58585858,reg2=0xfc8/0xffff actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.88)) ++ table=70, priority=100,udp6,reg2=0xfc8/0xffff,reg4=0x88000000,reg5=0,reg6=0,reg7=0x88 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=8800::88)) ++ table=70, priority=90,ip,reg1=0x58585859 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=88.88.88.89)) ++ table=70, priority=90,ipv6,reg4=0x88000000,reg5=0,reg6=0,reg7=0x89 actions=ct(commit,zone=NXM_NX_REG12[[0..15]],nat(src=8800::89)) ++]) ++ ++check ovn-nbctl --wait=hv ls-lb-del sw0 lb-ipv4 ++check ovn-nbctl --wait=hv ls-lb-del sw0 lb-ipv6 ++ + # Check backwards compatibility with ovn-northd versions that don't store the + # original destination tuple. + # +@@ -31743,7 +31953,7 @@ packet="inport==\"sw1-lp1\" && eth.src==00:00:04:01:02:03 && + ip4.src==10.0.0.100 && ip4.dst==20.0.0.200 && + udp && udp.src==53 && udp.dst==4369" + +-as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Check if packet hit the drop rule + AT_CHECK([ovs-ofctl dump-flows br-int | grep "nw_dst=20.0.0.0/24" | \ +@@ -31770,7 +31980,7 @@ packet="inport==\"sw1-lp1\" && eth.src==00:00:04:01:02:03 && + ip4.src==10.0.0.100 && ip4.dst==20.0.0.200 && + udp && udp.src==53 && udp.dst==4369" + +-as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) + + # Check if packet hit the drop rule + AT_CHECK([ovs-ofctl dump-flows br-int "nw_src=10.0.0.0/24" | \ +@@ -31857,7 +32067,7 @@ packet="inport==\"ls1-lp1\" && eth.src==$ls1_p1_mac && eth.dst==$bcast_mac && + arp.op==1 && arp.sha==$ls1_p1_mac && arp.spa==$ls1_p1_ip && + arp.tha==$bcast_mac && arp.tpa==$proxy_ip1" + +-as hv1 ovn-appctl -t ovn-controller inject-pkt "$packet" ++OVS_WAIT_UNTIL([as hv1 ovn-appctl -t ovn-controller inject-pkt "$packet"]) + + as hv1 ovs-ofctl dump-flows br-int| grep 169.254.239.254 | grep priority=50 > debug1 + AT_CAPTURE_FILE([debug1]) +@@ -32108,7 +32318,6 @@ ovn-nbctl lrp-set-gateway-chassis DR-S3 hv4 + + ovn-nbctl --wait=sb sync + OVN_POPULATE_ARP +- + vif_to_ls () { + case ${1} in dnl ( + vif?[[11]]) echo ls ;; dnl ( +@@ -32222,6 +32431,9 @@ echo "Send Dummy ARP" + sip=`ip_to_hex 172 16 1 10` + tip=`ip_to_hex 172 16 1 50` + test_arp vif-north1 f0f000000011 $sip $tip ++OVS_WAIT_UNTIL( ++ [test 1 = `as hv1 ovs-ofctl dump-flows br-int table=67 | grep dl_src=f0:f0:00:00:00:11 | wc -l`] ++) + + echo "Send traffic North to South" + sip=`ip_to_hex 172 16 1 10` +@@ -32242,6 +32454,9 @@ echo "Send Dummy ARP" + sip=`ip_to_hex 10 0 0 10` + tip=`ip_to_hex 10 0 0 50` + test_arp vif-north2 f0f000000022 $sip $tip ++OVS_WAIT_UNTIL( ++ [test 1 = `as hv1 ovs-ofctl dump-flows br-int table=67 | grep dl_src=f0:f0:00:00:00:22 | wc -l`] ++) + + echo "Send traffic South to North2" + sip=`ip_to_hex 20 0 0 10` +@@ -32255,6 +32470,9 @@ echo "Send Dummy ARP" + sip=`ip_to_hex 192 168 0 10` + tip=`ip_to_hex 192 168 0 50` + test_arp vif-north3 f0f000000033 $sip $tip ++OVS_WAIT_UNTIL( ++ [test 1 = `as hv1 ovs-ofctl dump-flows br-int table=67 | grep dl_src=f0:f0:00:00:00:33 | wc -l`] ++) + + echo "Send traffic South to North3" + sip=`ip_to_hex 20 0 0 10` +@@ -34926,7 +35144,8 @@ check ovs-vsctl add-port br-int p1 -- set interface p1 external_ids:iface-id=lsp + wait_for_ports_up + ovn-nbctl --wait=hv sync + +-check ovn-nbctl lb-add lb1 "192.168.0.10" "192.168.10.10,192.168.10.20" ++check ovn-nbctl lb-add lb1 "192.168.0.10" "192.168.10.10,192.168.10.20" \ ++ -- set load_balancer lb1 options:ct_flush="true" + check ovn-nbctl ls-lb-add sw lb1 + + # Remove a single backend +@@ -34949,7 +35168,8 @@ AT_CHECK([grep -q "Flushing CT for 5-tuple: vip=192.168.0.10:0, backend=192.168. + AT_CHECK([grep -q "Flushing CT for 5-tuple: vip=192.168.0.10:0, backend=192.168.10.30:0, protocol=0" hv1/ovn-controller.log], [0]) + + # Check flush for LB with port and protocol +-check ovn-nbctl lb-add lb1 "192.168.30.10:80" "192.168.40.10:8080,192.168.40.20:8090" udp ++check ovn-nbctl lb-add lb1 "192.168.30.10:80" "192.168.40.10:8080,192.168.40.20:8090" udp \ ++ -- set load_balancer lb1 options:ct_flush="true" + check ovn-nbctl ls-lb-add sw lb1 + check ovn-nbctl lb-del lb1 + check ovn-nbctl --wait=hv sync +@@ -34958,7 +35178,8 @@ AT_CHECK([grep -q "Flushing CT for 5-tuple: vip=192.168.30.10:80, backend=192.16 + AT_CHECK([grep -q "Flushing CT for 5-tuple: vip=192.168.30.10:80, backend=192.168.40.20:8090, protocol=17" hv1/ovn-controller.log], [0]) + + # Check recompute when LB is no longer local +-check ovn-nbctl lb-add lb1 "192.168.50.10:80" "192.168.60.10:8080" ++check ovn-nbctl lb-add lb1 "192.168.50.10:80" "192.168.60.10:8080" \ ++ -- set load_balancer lb1 options:ct_flush="true" + check ovn-nbctl ls-lb-add sw lb1 + check ovs-vsctl remove interface p1 external_ids iface-id + check ovn-appctl inc-engine/recompute +@@ -34968,6 +35189,193 @@ AT_CHECK([grep -q "Flushing CT for 5-tuple: vip=192.168.50.10:80, backend=192.16 + + AT_CHECK([test "$(grep -c "Flushing CT for 5-tuple" hv1/ovn-controller.log)" = "6"], [0]) + ++# Check if CT flush is disabled by default ++check ovn-nbctl lb-del lb1 ++check ovn-nbctl lb-add lb1 "192.168.70.10:80" "192.168.80.10:8080,192.168.90.10:8080" ++check ovn-nbctl ls-lb-add sw lb1 ++check ovs-vsctl set interface p1 external_ids:iface-id=lsp1 ++check ovn-nbctl --wait=hv sync ++ ++AT_CHECK([test "$(grep -c "Flushing CT for 5-tuple" hv1/ovn-controller.log)" = "6"], [0]) ++ ++# Remove one backend ++check ovn-nbctl --wait=hv set load_balancer lb1 vips='"192.168.70.10:80"="192.168.80.10:8080"' ++ ++AT_CHECK([grep -q "Flushing CT for 5-tuple: vip=192.168.70.10:80, backend=192.168.90.10:8080, protocol=6" hv1/ovn-controller.log], [1]) ++AT_CHECK([test "$(grep -c "Flushing CT for 5-tuple" hv1/ovn-controller.log)" = "6"], [0]) ++ ++check ovn-nbctl --wait=hv lb-del lb1 ++AT_CHECK([grep -q "Flushing CT for 5-tuple: vip=192.168.70.10:80, backend=192.168.80.10:8080, protocol=6" hv1/ovn-controller.log], [1]) ++AT_CHECK([test "$(grep -c "Flushing CT for 5-tuple" hv1/ovn-controller.log)" = "6"], [0]) ++ ++OVN_CLEANUP([hv1]) ++AT_CLEANUP ++]) ++ ++OVN_FOR_EACH_NORTHD([ ++AT_SETUP([Re-create encap tunnels during integration bridge migration]) ++ovn_start ++net_add n1 ++ ++sim_add hv1 ++as hv1 ++ovs-vsctl add-br br-phys ++ovn_attach n1 br-phys 192.168.0.1 ++ ++sim_add hv2 ++as hv2 ++ovs-vsctl add-br br-phys ++ovn_attach n1 br-phys 192.168.0.2 ++ ++check ovn-nbctl --wait=hv sync ++ ++check_tunnel_port() { ++ local hv=$1 ++ local br=$2 ++ local id=$3 ++ ++ as $hv ++ OVS_WAIT_UNTIL([ ++ test "$(ovs-vsctl --format=table --no-headings find port external_ids:ovn-chassis-id="$id" | wc -l)" = "1" ++ ]) ++ local tunnel_id=$(ovs-vsctl --bare --columns _uuid find port external_ids:ovn-chassis-id="$id") ++ AT_CHECK([ovs-vsctl --bare --columns ports find bridge name="$br" | grep -q "$tunnel_id"]) ++} ++ ++# Check that both chassis have tunnel ++check_tunnel_port hv1 br-int hv2@192.168.0.2 ++check_tunnel_port hv2 br-int hv1@192.168.0.1 ++ ++# Stop ovn-controller on hv1 ++check as hv1 ovn-appctl -t ovn-controller exit --restart ++ ++# The tunnel should remain intact ++check_tunnel_port hv1 br-int hv2@192.168.0.2 ++ ++# Change the bridge to br-int1 on hv1 ++as hv1 ++check ovs-vsctl add-br br-int1 ++check ovs-vsctl set open . external_ids:ovn-bridge="br-int1" ++start_daemon ovn-controller --verbose="encaps:dbg" ++check ovn-nbctl --wait=hv sync ++ ++# Check that the tunnel was created on br-int1 instead ++check_tunnel_port hv1 br-int1 hv2@192.168.0.2 ++check grep -q "Clearing old tunnel port \"ovn-hv2-0\" (hv2@192.168.0.2) from bridge \"br-int\"" hv1/ovn-controller.log ++ ++# Change the bridge to br-int1 on hv2 ++as hv2 ++check ovn-appctl vlog/set encaps:dbg ++check ovs-vsctl add-br br-int1 ++check ovs-vsctl set open . external_ids:ovn-bridge="br-int1" ++check ovn-nbctl --wait=hv sync ++ ++ ++# Check that the tunnel was created on br-int1 instead ++check_tunnel_port hv2 br-int1 hv1@192.168.0.1 ++check grep -q "Clearing old tunnel port \"ovn-hv1-0\" (hv1@192.168.0.1) from bridge \"br-int\"" hv2/ovn-controller.log ++ ++# Stop ovn-controller on hv1 ++check as hv1 ovn-appctl -t ovn-controller exit --restart ++ ++# The tunnel should remain intact ++check_tunnel_port hv1 br-int1 hv2@192.168.0.2 ++prev_id=$(ovs-vsctl --bare --columns _uuid find port external_ids:ovn-chassis-id="hv2@192.168.0.2") ++ ++# Start the controller again ++start_daemon ovn-controller --verbose="encaps:dbg" ++check ovn-nbctl --wait=hv sync ++check_tunnel_port hv1 br-int1 hv2@192.168.0.2 ++current_id=$(ovs-vsctl --bare --columns _uuid find port external_ids:ovn-chassis-id="hv2@192.168.0.2") ++ ++# The tunnel should be the same after restart ++check test "$current_id" = "$prev_id" ++ ++OVN_CLEANUP([hv1],[hv2]) ++AT_CLEANUP ++]) ++ ++# NOTE: This test case runs two ovn-controllers inside the same sandbox (hv1). ++# Each controller uses a unique chassis name - hv1 and hv2 - and manage ++# different bridges with different ports. ++OVN_FOR_EACH_NORTHD([ ++AT_SETUP([Encaps tunnel cleanup does not interfere with multiple controller on the same host]) ++ovn_start ++net_add n1 ++ ++sim_add hv1 ++as hv1 ++ovs-vsctl add-br br-phys-1 ++ovn_attach n1 br-phys-1 192.168.0.1 24 ++ ++ ++# now start the second virtual controller ++ovs-vsctl add-br br-phys-2 ++ ++ ++# the file is read once at startup so it's safe to write it ++# here after the first ovn-controller has started ++echo hv2 > ${OVN_SYSCONFDIR}/system-id-override ++ ++# for some reason SSL ovsdb configuration overrides CLI, so ++# delete ssl config from ovsdb to give CLI arguments priority ++ovs-vsctl del-ssl ++ ++start_virtual_controller n1 br-phys-2 br-int-2 192.168.0.2 24 geneve,vxlan hv2 \ ++ --pidfile=${OVS_RUNDIR}/ovn-controller-2.pid \ ++ --log-file=${OVS_RUNDIR}/ovn-controller-2.log \ ++ -p $PKIDIR/testpki-hv2-privkey.pem \ ++ -c $PKIDIR/testpki-hv2-cert.pem \ ++ -C $PKIDIR/testpki-cacert.pem ++pidfile="$OVS_RUNDIR"/ovn-controller-2.pid ++on_exit "test -e \"$pidfile\" && kill \`cat \"$pidfile\"\`" ++ ++ovn-nbctl --wait=hv sync ++ ++check_tunnel_port() { ++ local hv=$1 ++ local br=$2 ++ local id=$3 ++ ++ as $hv ++ OVS_WAIT_UNTIL([ ++ test "$(ovs-vsctl --format=table --no-headings find port external_ids:ovn-chassis-id="$id" | wc -l)" = "1" ++ ]) ++ local tunnel_id=$(ovs-vsctl --bare --columns _uuid find port external_ids:ovn-chassis-id="$id") ++ AT_CHECK([ovs-vsctl --bare --columns ports find bridge name="$br" | grep -q "$tunnel_id"]) ++} ++ ++check_tunnel_port hv1 br-int hv2@192.168.0.2 ++check_tunnel_port hv1 br-int-2 hv1@192.168.0.1 ++prev_id1=$(ovs-vsctl --bare --columns _uuid find port external_ids:ovn-chassis-id="hv1@192.168.0.1") ++prev_id2=$(ovs-vsctl --bare --columns _uuid find port external_ids:ovn-chassis-id="hv2@192.168.0.2") ++ ++# The hv2 is running we can remove the override file ++rm -f ${OVN_SYSCONFDIR}/system-id-override ++ ++check ovn-appctl -t ovn-controller exit --restart ++ ++# for some reason SSL ovsdb configuration overrides CLI, so ++# delete ssl config from ovsdb to give CLI arguments priority ++ovs-vsctl del-ssl ++ ++start_daemon ovn-controller --verbose="encaps:dbg" \ ++ -p $PKIDIR/testpki-hv1-privkey.pem \ ++ -c $PKIDIR/testpki-hv1-cert.pem \ ++ -C $PKIDIR/testpki-cacert.pem ++ ++check ovn-nbctl --wait=hv sync ++ ++check_tunnel_port hv1 br-int hv2@192.168.0.2 ++check_tunnel_port hv1 br-int-2 hv1@192.168.0.1 ++current_id1=$(ovs-vsctl --bare --columns _uuid find port external_ids:ovn-chassis-id="hv1@192.168.0.1") ++current_id2=$(ovs-vsctl --bare --columns _uuid find port external_ids:ovn-chassis-id="hv2@192.168.0.2") ++ ++# Check that restart of hv1 ovn-controller did not interfere with hv2 ++AT_CHECK([grep -q "Clearing old tunnel port \"ovn0-hv1-0\" (hv1@192.168.0.1) from bridge \"br-int-2\"" hv1/ovn-controller.log], [1]) ++check test "$current_id1" = "$prev_id1" ++check test "$current_id2" = "$prev_id2" ++ + OVN_CLEANUP([hv1]) + AT_CLEANUP + ]) +diff --git a/tests/ovs-macros.at b/tests/ovs-macros.at +index 36b58b5ae..cc5f6e3b1 100644 +--- a/tests/ovs-macros.at ++++ b/tests/ovs-macros.at +@@ -256,6 +256,13 @@ ovs_wait () { + ovs_wait_failed + AT_FAIL_IF([:]) + } ++ ++check_ovs_wait_until_args() { ++ AT_FAIL_IF([test $1 -ge 3]) ++ dnl The second argument should not be a number (confused with AT_CHECK ?). ++ AT_FAIL_IF([test $1 -eq 2 && test "$2" -eq "$2" 2>/dev/null]) ++} ++ + OVS_END_SHELL_HELPERS + m4_define([OVS_WAIT], [dnl + ovs_wait_cond () { +@@ -276,7 +283,8 @@ dnl zero code within reasonable time limit, then + dnl the test fails. In that case, runs IF-FAILED + dnl before aborting. + m4_define([OVS_WAIT_UNTIL], +- [OVS_WAIT([$1], [$2], [AT_LINE], [until $1])]) ++ [check_ovs_wait_until_args "$#" "$2" ++ OVS_WAIT([$1], [$2], [AT_LINE], [until $1])]) + + dnl OVS_WAIT_FOR_OUTPUT(COMMAND, EXIT-STATUS, STDOUT, STDERR) + dnl OVS_WAIT_FOR_OUTPUT_UNQUOTED(COMMAND, EXIT-STATUS, STDOUT, STDERR) +diff --git a/tests/system-common-macros.at b/tests/system-common-macros.at +index d65f359a6..b8c5ae9ad 100644 +--- a/tests/system-common-macros.at ++++ b/tests/system-common-macros.at +@@ -44,43 +44,8 @@ m4_define([NS_CHECK_EXEC], + # appropriate type, and allows additional arguments to be passed. + m4_define([ADD_BR], [ovs-vsctl _ADD_BR([$1]) -- $2]) + +-# ADD_INT([port], [namespace], [ovs-br], [ip_addr] [ip6_addr]) +-# +-# Add an internal port to 'ovs-br', then shift it into 'namespace' and +-# configure it with 'ip_addr' (specified in CIDR notation). +-# Optionally add an ipv6 address +-m4_define([ADD_INT], +- [ AT_CHECK([ovs-vsctl add-port $3 $1 -- set int $1 type=internal]) +- AT_CHECK([ip link set $1 netns $2]) +- NS_CHECK_EXEC([$2], [ip addr add $4 dev $1]) +- NS_CHECK_EXEC([$2], [ip link set dev $1 up]) +- if test -n "$5"; then +- NS_CHECK_EXEC([$2], [ip -6 addr add $5 dev $1]) +- fi +- ] +-) +- +-# NS_ADD_INT([port], [namespace], [ovs-br], [ip_addr] [mac_addr] [ip6_addr] [default_gw] [default_ipv6_gw]) +-# Create a namespace +-# Add an internal port to 'ovs-br', then shift it into 'namespace'. +-# Configure it with 'ip_addr' (specified in CIDR notation) and ip6_addr. +-# Set mac_addr +-# Add default gw for ipv4 and ipv6 +-m4_define([NS_ADD_INT], +- [ AT_CHECK([ovs-vsctl add-port $3 $1 -- set int $1 type=internal external_ids:iface-id=$1]) +- ADD_NAMESPACES($2) +- AT_CHECK([ip link set $1 netns $2]) +- NS_CHECK_EXEC([$2], [ip link set $1 address $5]) +- NS_CHECK_EXEC([$2], [ip link set dev $1 up]) +- NS_CHECK_EXEC([$2], [ip addr add $4 dev $1]) +- NS_CHECK_EXEC([$2], [ip addr add $6 dev $1]) +- NS_CHECK_EXEC([$2], [ip route add default via $7 dev $1]) +- NS_CHECK_EXEC([$2], [ip -6 route add default via $8 dev $1]) +- ] +-) +- + # ADD_VETH([port], [namespace], [ovs-br], [ip_addr] [mac_addr], [gateway], +-# [ip_addr_flags]) ++# [ip_addr_flags] [ip6_addr] [gateway6]) + # + # Add a pair of veth ports. 'port' will be added to name space 'namespace', + # and "ovs-'port'" will be added to ovs bridge 'ovs-br'. +@@ -108,6 +73,12 @@ m4_define([ADD_VETH], + if test -n "$6"; then + NS_CHECK_EXEC([$2], [ip route add default via $6]) + fi ++ if test -n "$8"; then ++ NS_CHECK_EXEC([$2], [ip addr add $8 dev $1]) ++ fi ++ if test -n "$9"; then ++ NS_CHECK_EXEC([$2], [ip route add default via $9]) ++ fi + on_exit "ip link del ovs-$1" + ] + ) +@@ -263,7 +234,7 @@ m4_define([STRIP_MONITOR_CSUM], [grep "csum:" | sed 's/csum:.*/csum: /']) + # and limit the output to the rows containing 'ip-addr'. + # + m4_define([FORMAT_CT], +- [[grep -F "dst=$1" | sed -e 's/port=[0-9]*/port=/g' -e 's/id=[0-9]*/id=/g' -e 's/state=[0-9_A-Z]*/state=/g' | sort | uniq]]) ++ [[grep -F "dst=$1," | sed -e 's/port=[0-9]*/port=/g' -e 's/id=[0-9]*/id=/g' -e 's/state=[0-9_A-Z]*/state=/g' | sort | uniq]]) + + # NETNS_DAEMONIZE([namespace], [command], [pidfile]) + # +diff --git a/tests/system-ovn-kmod.at b/tests/system-ovn-kmod.at +index dd4996041..3c3e5bc61 100644 +--- a/tests/system-ovn-kmod.at ++++ b/tests/system-ovn-kmod.at +@@ -215,3 +215,139 @@ as + OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d + /connection dropped.*/d"]) + AT_CLEANUP ++ ++OVN_FOR_EACH_NORTHD([ ++AT_SETUP([LB correctly de-fragments traffic]) ++AT_KEYWORDS([ovnlb]) ++ ++CHECK_CONNTRACK() ++CHECK_CONNTRACK_NAT() ++AT_SKIP_IF([test $HAVE_SCAPY = no]) ++ ++ovn_start ++OVS_TRAFFIC_VSWITCHD_START() ++ADD_BR([br-int]) ++ADD_BR([br-ext]) ++ ++# Logical network: ++# 2 logical switches "public" (192.168.1.0/24) and "internal" (172.16.1.0/24) ++# connected to a router lr. ++# internal has a server. ++# client is connected through localnet. ++# ++# Load balancer for udp 192.168.1.20:4242 172.16.1.2 4242. ++ ++check ovs-ofctl add-flow br-ext action=normal ++# Set external-ids in br-int needed for ovn-controller ++check ovs-vsctl \ ++ -- set Open_vSwitch . external-ids:system-id=hv1 \ ++ -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ ++ -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ ++ -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ ++ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true \ ++ -- set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext ++ ++ ++# Start ovn-controller ++start_daemon ovn-controller ++ ++check ovn-nbctl lr-add lr ++check ovn-nbctl ls-add internal ++check ovn-nbctl ls-add public ++ ++check ovn-nbctl lrp-add lr lr-pub 00:00:01:01:02:03 192.168.1.1/24 ++check ovn-nbctl lsp-add public pub-lr -- set Logical_Switch_Port pub-lr \ ++ type=router options:router-port=lr-pub addresses=\"00:00:01:01:02:03\" ++ ++check ovn-nbctl lrp-add lr lr-internal 00:00:01:01:02:04 172.16.1.1/24 ++check ovn-nbctl lsp-add internal internal-lr -- set Logical_Switch_Port internal-lr \ ++ type=router options:router-port=lr-internal addresses=\"00:00:01:01:02:04\" ++ ++ovn-nbctl lsp-add public ln_port \ ++ -- lsp-set-addresses ln_port unknown \ ++ -- lsp-set-type ln_port localnet \ ++ -- lsp-set-options ln_port network_name=phynet ++ ++ADD_NAMESPACES(client) ++ADD_VETH(client, client, br-ext, "192.168.1.2/24", "f0:00:00:01:02:03", \ ++ "192.168.1.1") ++ ++ADD_NAMESPACES(server) ++ADD_VETH(server, server, br-int, "172.16.1.2/24", "f0:00:0f:01:02:03", \ ++ "172.16.1.1") ++check ovn-nbctl lsp-add internal server \ ++-- lsp-set-addresses server "f0:00:0f:01:02:03 172.16.1.2" ++ ++# Config OVN load-balancer with a VIP. ++check ovn-nbctl lb-add lb1 192.168.1.20:4242 172.16.1.2:4242 udp ++check ovn-nbctl lr-lb-add lr lb1 ++check ovn-nbctl set logical_router lr options:chassis=hv1 ++check ovn-nbctl set logical_router_port lr-internal options:gateway_mtu=800 ++ ++ovn-nbctl --wait=hv sync ++ ++NETNS_DAEMONIZE([server], [nc -l -u 172.16.1.2 4242 > /dev/null], [server.pid]) ++ ++# Collect ICMP packets on client side ++NETNS_DAEMONIZE([client], [tcpdump -l -U -i client -vnne \ ++icmp > client.pcap 2>client_err], [tcpdump0.pid]) ++OVS_WAIT_UNTIL([grep "listening" client_err]) ++ ++# Collect UDP packets on server side ++NETNS_DAEMONIZE([server], [tcpdump -l -U -i server -vnne \ ++'udp and ip[[6:2]] > 0 and not ip[[6]] = 64' > server.pcap 2>server_err], [tcpdump1.pid]) ++OVS_WAIT_UNTIL([grep "listening" server_err]) ++ ++check ip netns exec client python3 << EOF ++import os ++import socket ++import sys ++import time ++ ++FILE="client.pcap" ++ ++ ++def contains_string(file, str): ++ file = open(file, "r") ++ for line in file.readlines(): ++ if str in line: ++ return True ++ return False ++ ++ ++def need_frag_received(): ++ for _ in range(20): ++ if os.path.getsize(FILE) and contains_string(FILE, "need to frag"): ++ return True ++ time.sleep(0.5) ++ return False ++ ++ ++sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) ++sock.sendto(b"x" * 1000, ("192.168.1.20", 4242)) ++if need_frag_received(): ++ sock.sendto(b"x" * 1000, ("192.168.1.20", 4242)) ++else: ++ print("Missing need frag") ++ sys.exit(1) ++EOF ++ ++OVS_WAIT_UNTIL([test "$(cat server.pcap | wc -l)" = "4"]) ++ ++ ++OVS_APP_EXIT_AND_WAIT([ovn-controller]) ++ ++as ovn-sb ++OVS_APP_EXIT_AND_WAIT([ovsdb-server]) ++ ++as ovn-nb ++OVS_APP_EXIT_AND_WAIT([ovsdb-server]) ++ ++as northd ++OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE]) ++ ++as ++OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d ++/connection dropped.*/d"]) ++AT_CLEANUP ++]) +diff --git a/tests/system-ovn.at b/tests/system-ovn.at +index 84a459d6a..40f808515 100644 +--- a/tests/system-ovn.at ++++ b/tests/system-ovn.at +@@ -1569,7 +1569,6 @@ bar3_ct=$(ovs-appctl dpctl/dump-conntrack | grep 30.0.0.2 | grep 172.16.1.4 -c) + AT_CHECK([test $(ovs-appctl dpctl/dump-conntrack | grep 30.0.0.2 | grep 172.16.1 -c) -ne 0]) + + if [[ "$bar1_ct" == "20" ]]; then +- AT_CHECK([test $bar1_ct -eq 20]) + AT_CHECK([test $bar2_ct -eq 0]) + AT_CHECK([test $bar3_ct -eq 0]) + else +@@ -1577,17 +1576,15 @@ else + fi + + if [[ "$bar2_ct" == "20" ]]; then +- AT_CHECK([test $bar1_ct -eq 20]) +- AT_CHECK([test $bar2_ct -eq 0]) ++ AT_CHECK([test $bar1_ct -eq 0]) + AT_CHECK([test $bar3_ct -eq 0]) + else + AT_CHECK([test $bar2_ct -eq 0]) + fi + + if [[ "$bar3_ct" == "20" ]]; then +- AT_CHECK([test $bar1_ct -eq 20]) ++ AT_CHECK([test $bar1_ct -eq 0]) + AT_CHECK([test $bar2_ct -eq 0]) +- AT_CHECK([test $bar3_ct -eq 0]) + else + AT_CHECK([test $bar3_ct -eq 0]) + fi +@@ -4850,9 +4847,9 @@ NS_CHECK_EXEC([lsp], [tcpdump -l -nn -c 3 -i lsp ${filter} > lsp.pcap 2>tcpdump_ + OVS_WAIT_UNTIL([grep "listening" tcpdump_err]) + + # Generate IPv4 UDP hairpin traffic. +-NS_CHECK_EXEC([lsp], [echo a | nc -u 88.88.88.88 4040 &], [0]) +-NS_CHECK_EXEC([lsp], [echo a | nc -u 88.88.88.89 4040 &], [0]) +-NS_CHECK_EXEC([lsp], [echo a | nc -u 88.88.88.90 2021 &], [0]) ++NS_CHECK_EXEC([lsp], [echo a | nc -u 88.88.88.88 4040], [ignore], [ignore], [ignore]) ++NS_CHECK_EXEC([lsp], [echo a | nc -u 88.88.88.89 4040], [ignore], [ignore], [ignore]) ++NS_CHECK_EXEC([lsp], [echo a | nc -u 88.88.88.90 2021], [ignore], [ignore], [ignore]) + + # Check hairpin traffic. + OVS_WAIT_UNTIL([ +@@ -4949,9 +4946,9 @@ NS_CHECK_EXEC([lsp], [tcpdump -l -nn -c 3 -i lsp $filter > lsp.pcap 2>tcpdump_er + OVS_WAIT_UNTIL([grep "listening" tcpdump_err]) + + # Generate IPv6 UDP hairpin traffic. +-NS_CHECK_EXEC([lsp], [echo a | nc -u 8800::0088 4040 &], [0]) +-NS_CHECK_EXEC([lsp], [echo a | nc -u 8800::0089 4040 &], [0]) +-NS_CHECK_EXEC([lsp], [echo a | nc -u 8800::0090 2021 &], [0]) ++NS_CHECK_EXEC([lsp], [echo a | nc -u 8800::0088 4040], [ignore], [ignore], [ignore]) ++NS_CHECK_EXEC([lsp], [echo a | nc -u 8800::0089 4040], [ignore], [ignore], [ignore]) ++NS_CHECK_EXEC([lsp], [echo a | nc -u 8800::0090 2021], [ignore], [ignore], [ignore]) + + # Check hairpin traffic. + OVS_WAIT_UNTIL([ +@@ -7190,7 +7187,7 @@ NS_EXEC([sw01], [tcpdump -l -n -i sw01 icmp -Q in > reject.pcap &]) + check ovn-nbctl --may-exist meter-add acl-meter drop 10 pktps 0 + ip netns exec sw01 scapy -H <<-EOF + p = IP(src="192.168.1.2", dst="192.168.1.1") / UDP(dport = 12345) / Raw(b"X"*64) +-send (p, iface='sw01', loop = 0, verbose = 0, count = 100) ++send (p, iface='sw01', loop = 0, verbose = 0, count = 40) + EOF + + # 10pps +@@ -8482,11 +8479,18 @@ check ovn-nbctl lsp-set-addresses ln unknown + check ovn-nbctl lr-nat-add lr1 snat 172.16.1.10 192.168.1.0/24 + check ovn-nbctl lr-nat-add lr1 snat 1711::10 2001::/64 + +-NS_ADD_INT(ls1p1, ls1p1, br-int, "192.168.1.1/24", "00:00:00:01:01:01", "2001::1/64", "192.168.1.254", "2001::a" ) +-NS_ADD_INT(ls1p2, ls1p2, br-int, "192.168.1.2/24", "00:00:00:01:01:02", "2001::2/64", "192.168.1.254", "2001::a" ) ++ADD_NAMESPACES(ls1p1) ++ADD_VETH(ls1p1, ls1p1, br-int, "192.168.1.1/24", "00:00:00:01:01:01", \ ++ "192.168.1.254", , "2001::1/64", "2001::a") ++ ++ADD_NAMESPACES(ls1p2) ++ADD_VETH(ls1p2, ls1p2, br-int, "192.168.1.2/24", "00:00:00:01:01:02", \ ++ "192.168.1.254", , "2001::2/64", "2001::a") + + ADD_NAMESPACES(ext1) +-ADD_INT(ext1, ext1, br0, 172.16.1.1/24, 1711::1/64) ++ADD_VETH(ext1, ext1, br0, "172.16.1.1/24", "00:ee:00:01:01:01", \ ++ "172.16.1.254", , "1711::1/64", "1711::a") ++ + check ovn-nbctl --wait=hv sync + wait_for_ports_up + OVS_WAIT_UNTIL([test "$(ip netns exec ls1p1 ip a | grep 2001::1 | grep tentative)" = ""]) +@@ -8548,25 +8552,17 @@ wait_igmp_flows_installed() + } + + ADD_NAMESPACES(vm1) +-ADD_INT([vm1], [vm1], [br-int], [42.42.42.1/24]) +-NS_CHECK_EXEC([vm1], [ip link set vm1 address 00:00:00:00:00:01], [0]) +-NS_CHECK_EXEC([vm1], [ip route add default via 42.42.42.5], [0]) +-check ovs-vsctl set Interface vm1 external_ids:iface-id=vm1 ++ADD_VETH(vm1, vm1, br-int, "42.42.42.1/24", "00:00:00:00:00:01", \ ++ "42.42.42.5") + + ADD_NAMESPACES(vm2) +-ADD_INT([vm2], [vm2], [br-int], [42.42.42.2/24]) +-NS_CHECK_EXEC([vm2], [ip link set vm2 address 00:00:00:00:00:02], [0]) +-NS_CHECK_EXEC([vm2], [ip link set lo up], [0]) +-check ovs-vsctl set Interface vm2 external_ids:iface-id=vm2 ++ADD_VETH(vm2, vm2, br-int, "42.42.42.2/24", "00:00:00:00:00:02") + + ADD_NAMESPACES(vm3) + NETNS_DAEMONIZE([vm3], [tcpdump -n -i any -nnleX > vm3.pcap 2>/dev/null], [tcpdump3.pid]) + +-ADD_INT([vm3], [vm3], [br-int], [42.42.42.3/24]) +-NS_CHECK_EXEC([vm3], [ip link set vm3 address 00:00:00:00:00:03], [0]) +-NS_CHECK_EXEC([vm3], [ip link set lo up], [0]) +-NS_CHECK_EXEC([vm3], [ip route add default via 42.42.42.5], [0]) +-check ovs-vsctl set Interface vm3 external_ids:iface-id=vm3 ++ADD_VETH(vm3, vm3, br-int, "42.42.42.3/24", "00:00:00:00:00:03", \ ++ "42.42.42.5") + + NS_CHECK_EXEC([vm2], [sysctl -w net.ipv4.igmp_max_memberships=100], [ignore], [ignore]) + NS_CHECK_EXEC([vm3], [sysctl -w net.ipv4.igmp_max_memberships=100], [ignore], [ignore]) +@@ -9639,7 +9635,7 @@ start_daemon ovn-controller + # | + # VM2 ----+ + # +-# Two templated load balancer applied on LS1 and GW-Router with ++# Four templated load balancer applied on LS1 and GW-Router with + # VM1 as backend. The VIPs should be accessible from both VM2 and VM3. + + check ovn-nbctl \ +@@ -9667,7 +9663,7 @@ check ovn-nbctl \ + # VIP=66.66.66.66:777 backends=42.42.42.2:4343 proto=udp + + AT_CHECK([ovn-nbctl -- create chassis_template_var chassis="hv1" \ +- variables="{vip=66.66.66.66,vport1=666,backends1=\"42.42.42.2:4242\",vport2=777,backends2=\"42.42.42.2:4343\"}"], ++ variables="{vip=66.66.66.66,vport1=666,backends1=\"42.42.42.2:4242\",vport2=777,backends2=\"42.42.42.2:4343\",vport3=888,vport4=999}"], + [0], [ignore]) + + check ovn-nbctl --template lb-add lb-test-tcp "^vip:^vport1" "^backends1" tcp \ +@@ -9678,6 +9674,18 @@ check ovn-nbctl --template lb-add lb-test-udp "^vip:^vport2" "^backends2" udp \ + -- ls-lb-add ls1 lb-test-udp \ + -- lr-lb-add rtr lb-test-udp + ++# Add a TCP template LB with explicit backends that eventually expands to: ++# VIP=66.66.66.66:888 backends=42.42.42.2:4242 proto=tcp ++# And a UDP template LB that eventually expands to: ++# VIP=66.66.66.66:999 backends=42.42.42.2:4343 proto=udp ++check ovn-nbctl --template lb-add lb-test-tcp2 "^vip:^vport3" "42.42.42.2:4242" tcp ipv4 \ ++ -- ls-lb-add ls1 lb-test-tcp2 \ ++ -- lr-lb-add rtr lb-test-tcp2 ++ ++check ovn-nbctl --template lb-add lb-test-udp2 "^vip:^vport4" "42.42.42.2:4343" udp ipv4 \ ++ -- ls-lb-add ls1 lb-test-udp2 \ ++ -- lr-lb-add rtr lb-test-udp2 ++ + ADD_NAMESPACES(vm1) + ADD_VETH(vm1, vm1, br-int, "42.42.42.2/24", "00:00:00:00:00:01", "42.42.42.1") + +@@ -9698,13 +9706,15 @@ name: 'backends2' value: '42.42.42.2:4343' + name: 'vip' value: '66.66.66.66' + name: 'vport1' value: '666' + name: 'vport2' value: '777' ++name: 'vport3' value: '888' ++name: 'vport4' value: '999' + ]) + + # Start IPv4 TCP server on vm1. + NETNS_DAEMONIZE([vm1], [nc -k -l 42.42.42.2 4242], [nc-vm1.pid]) + + NETNS_DAEMONIZE([vm1], +- [tcpdump -n -i vm1 -nnleX -c3 udp and dst 42.42.42.2 and dst port 4343 > vm1.pcap 2>/dev/null], ++ [tcpdump -n -i vm1 -nnleX -c6 udp and dst 42.42.42.2 and dst port 4343 > vm1.pcap 2>/dev/null], + [tcpdump1.pid]) + + # Make sure connecting to the VIP works (hairpin, via ls and via lr). +@@ -9712,13 +9722,21 @@ NS_CHECK_EXEC([vm1], [nc 66.66.66.66 666 -z], [0], [ignore], [ignore]) + NS_CHECK_EXEC([vm2], [nc 66.66.66.66 666 -z], [0], [ignore], [ignore]) + NS_CHECK_EXEC([vm3], [nc 66.66.66.66 666 -z], [0], [ignore], [ignore]) + +-NS_CHECK_EXEC([vm1], [echo a | nc -u 66.66.66.66 777 &], [0]) +-NS_CHECK_EXEC([vm2], [echo a | nc -u 66.66.66.66 777 &], [0]) +-NS_CHECK_EXEC([vm3], [echo a | nc -u 66.66.66.66 777 &], [0]) ++NS_CHECK_EXEC([vm1], [echo a | nc -u 66.66.66.66 777], [ignore], [ignore], [ignore]) ++NS_CHECK_EXEC([vm2], [echo a | nc -u 66.66.66.66 777], [ignore], [ignore], [ignore]) ++NS_CHECK_EXEC([vm3], [echo a | nc -u 66.66.66.66 777], [ignore], [ignore], [ignore]) ++ ++NS_CHECK_EXEC([vm1], [nc 66.66.66.66 888 -z], [0], [ignore], [ignore]) ++NS_CHECK_EXEC([vm2], [nc 66.66.66.66 888 -z], [0], [ignore], [ignore]) ++NS_CHECK_EXEC([vm3], [nc 66.66.66.66 888 -z], [0], [ignore], [ignore]) ++ ++NS_CHECK_EXEC([vm1], [echo a | nc -u 66.66.66.66 999], [ignore], [ignore], [ignore]) ++NS_CHECK_EXEC([vm2], [echo a | nc -u 66.66.66.66 999], [ignore], [ignore], [ignore]) ++NS_CHECK_EXEC([vm3], [echo a | nc -u 66.66.66.66 999], [ignore], [ignore], [ignore]) + + OVS_WAIT_UNTIL([ + requests=`grep "UDP" -c vm1.pcap` +- test "${requests}" -ge "3" ++ test "${requests}" -ge "6" + ]) + + AT_CLEANUP +@@ -9753,7 +9771,7 @@ start_daemon ovn-controller + # | + # VM2 ----+ + # +-# Two templated load balancer applied on LS1 and GW-Router with ++# Four templated load balancer applied on LS1 and GW-Router with + # VM1 as backend. The VIPs should be accessible from both VM2 and VM3. + + check ovn-nbctl \ +@@ -9781,7 +9799,7 @@ check ovn-nbctl \ + # VIP=[6666::1]:777 backends=[4242::2]:4343 proto=udp + + AT_CHECK([ovn-nbctl -- create chassis_template_var chassis="hv1" \ +- variables="{vip=\"6666::1\",vport1=666,backends1=\"[[4242::2]]:4242\",vport2=777,backends2=\"[[4242::2]]:4343\"}"], ++ variables="{vip=\"6666::1\",vport1=666,backends1=\"[[4242::2]]:4242\",vport2=777,backends2=\"[[4242::2]]:4343\",vport3=888,vport4=999}"], + [0], [ignore]) + + check ovn-nbctl --template lb-add lb-test-tcp "^vip:^vport1" "^backends1" tcp ipv6 \ +@@ -9792,6 +9810,18 @@ check ovn-nbctl --template lb-add lb-test-udp "^vip:^vport2" "^backends2" udp ip + -- ls-lb-add ls1 lb-test-udp \ + -- lr-lb-add rtr lb-test-udp + ++# Add a TCP template LB with explicit backends that eventually expands to: ++# VIP=[6666::1]:888 backends=[4242::2]:4242 proto=tcp ++# And a UDP template LB that eventually expands to: ++# VIP=[6666::1]:999 backends=[4242::2]:4343 proto=udp ++check ovn-nbctl --template lb-add lb-test-tcp2 "^vip:^vport3" "[[4242::2]]:4242" tcp ipv6 \ ++ -- ls-lb-add ls1 lb-test-tcp2 \ ++ -- lr-lb-add rtr lb-test-tcp2 ++ ++check ovn-nbctl --template lb-add lb-test-udp2 "^vip:^vport4" "[[4242::2]]:4343" udp ipv6 \ ++ -- ls-lb-add ls1 lb-test-udp2 \ ++ -- lr-lb-add rtr lb-test-udp2 ++ + ADD_NAMESPACES(vm1) + ADD_VETH(vm1, vm1, br-int, "4242::2/64", "00:00:00:00:00:01", "4242::1") + OVS_WAIT_UNTIL([test "$(ip netns exec vm1 ip a | grep 4242::2 | grep tentative)" = ""]) +@@ -9815,13 +9845,15 @@ name: 'backends2' value: '[[4242::2]]:4343' + name: 'vip' value: '6666::1' + name: 'vport1' value: '666' + name: 'vport2' value: '777' ++name: 'vport3' value: '888' ++name: 'vport4' value: '999' + ]) + + # Start IPv6 TCP server on vm1. + NETNS_DAEMONIZE([vm1], [nc -k -l 4242::2 4242], [nc-vm1.pid]) + + NETNS_DAEMONIZE([vm1], +- [tcpdump -n -i vm1 -nnleX -c3 udp and dst 4242::2 and dst port 4343 > vm1.pcap 2>/dev/null], ++ [tcpdump -n -i vm1 -nnleX -c6 udp and dst 4242::2 and dst port 4343 > vm1.pcap 2>/dev/null], + [tcpdump1.pid]) + + # Make sure connecting to the VIP works (hairpin, via ls and via lr). +@@ -9829,13 +9861,21 @@ NS_CHECK_EXEC([vm1], [nc 6666::1 666 -z], [0], [ignore], [ignore]) + NS_CHECK_EXEC([vm2], [nc 6666::1 666 -z], [0], [ignore], [ignore]) + NS_CHECK_EXEC([vm3], [nc 6666::1 666 -z], [0], [ignore], [ignore]) + +-NS_CHECK_EXEC([vm1], [echo a | nc -u 6666::1 777 &], [0]) +-NS_CHECK_EXEC([vm2], [echo a | nc -u 6666::1 777 &], [0]) +-NS_CHECK_EXEC([vm3], [echo a | nc -u 6666::1 777 &], [0]) ++NS_CHECK_EXEC([vm1], [echo a | nc -u 6666::1 777], [ignore], [ignore], [ignore]) ++NS_CHECK_EXEC([vm2], [echo a | nc -u 6666::1 777], [ignore], [ignore], [ignore]) ++NS_CHECK_EXEC([vm3], [echo a | nc -u 6666::1 777], [ignore], [ignore], [ignore]) ++ ++NS_CHECK_EXEC([vm1], [nc 6666::1 888 -z], [0], [ignore], [ignore]) ++NS_CHECK_EXEC([vm2], [nc 6666::1 888 -z], [0], [ignore], [ignore]) ++NS_CHECK_EXEC([vm3], [nc 6666::1 888 -z], [0], [ignore], [ignore]) ++ ++NS_CHECK_EXEC([vm1], [echo a | nc -u 6666::1 999], [ignore], [ignore], [ignore]) ++NS_CHECK_EXEC([vm2], [echo a | nc -u 6666::1 999], [ignore], [ignore], [ignore]) ++NS_CHECK_EXEC([vm3], [echo a | nc -u 6666::1 999], [ignore], [ignore], [ignore]) + + OVS_WAIT_UNTIL([ + requests=`grep "UDP" -c vm1.pcap` +- test "${requests}" -ge "3" ++ test "${requests}" -ge "6" + ]) + + AT_CLEANUP +@@ -10587,11 +10627,13 @@ check ovn-nbctl lsp-add bar bar3 \ + -- lsp-set-addresses bar3 "f0:00:0f:01:02:05 172.16.1.4" + + # Config OVN load-balancer with a VIP. +-check ovn-nbctl lb-add lb1 30.0.0.1 "172.16.1.2,172.16.1.3,172.16.1.4" ++check ovn-nbctl lb-add lb1 30.0.0.1 "172.16.1.2,172.16.1.3,172.16.1.4" \ ++ -- set load_balancer lb1 options:ct_flush="true" + check ovn-nbctl ls-lb-add foo lb1 + + # Create another load-balancer with another VIP. + lb2_uuid=`ovn-nbctl create load_balancer name=lb2 vips:30.0.0.3="172.16.1.2,172.16.1.3,172.16.1.4"` ++check ovn-nbctl set load_balancer lb2 options:ct_flush="true" + check ovn-nbctl ls-lb-add foo lb2 + + # Config OVN load-balancer with another VIP (this time with ports). +@@ -10607,16 +10649,18 @@ OVS_START_L7([bar1], [http]) + OVS_START_L7([bar2], [http]) + OVS_START_L7([bar3], [http]) + +-OVS_WAIT_FOR_OUTPUT([ +- for i in `seq 1 20`; do +- ip netns exec foo1 wget 30.0.0.1 -t 5 -T 1 --retry-connrefused -v -o wget$i.log; +- done +- ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl ++m4_define([LB1_CT_ENTRIES], [dnl + tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=172.16.1.2,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=172.16.1.3,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + tcp,orig=(src=192.168.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=172.16.1.4,dst=192.168.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) + ]) + ++OVS_WAIT_FOR_OUTPUT([ ++ for i in `seq 1 20`; do ++ ip netns exec foo1 wget 30.0.0.1 -t 5 -T 1 --retry-connrefused -v -o wget$i.log; ++ done ++ ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | sed -e 's/zone=[[0-9]]*/zone=/'], [0], [LB1_CT_ENTRIES]) ++ + OVS_WAIT_FOR_OUTPUT([ + for i in `seq 1 20`; do + ip netns exec foo1 wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log; +@@ -10690,6 +10734,191 @@ check ovn-nbctl lb-del lb2 + + OVS_WAIT_UNTIL([test "$(ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.3) | wc -l)" = "0"]) + ++# Check that LB has CT flush disabled by default ++check ovn-nbctl lb-add lb1 30.0.0.1 "172.16.1.2,172.16.1.3,172.16.1.4" ++check ovn-nbctl ls-lb-add foo lb1 ++ ++OVS_WAIT_FOR_OUTPUT([ ++ for i in `seq 1 20`; do ++ ip netns exec foo1 wget 30.0.0.1 -t 5 -T 1 --retry-connrefused -v -o wget$i.log; ++ done ++ ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | sed -e 's/zone=[[0-9]]*/zone=/'], [0], [LB1_CT_ENTRIES]) ++ ++# Remove one backend ++check ovn-nbctl --wait=hv set load_balancer lb1 vips='"30.0.0.1"="172.16.1.2,172.16.1.3"' ++ ++AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | sed -e 's/zone=[[0-9]]*/zone=/'], [0], [LB1_CT_ENTRIES]) ++ ++# Remove whole LB ++check ovn-nbctl --wait=hv lb-del lb1 ++ ++AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | sed -e 's/zone=[[0-9]]*/zone=/'], [0], [LB1_CT_ENTRIES]) ++ ++OVS_APP_EXIT_AND_WAIT([ovn-controller]) ++ ++as ovn-sb ++OVS_APP_EXIT_AND_WAIT([ovsdb-server]) ++ ++as ovn-nb ++OVS_APP_EXIT_AND_WAIT([ovsdb-server]) ++ ++as northd ++OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE]) ++ ++as ++OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d ++/connection dropped.*/d"]) ++AT_CLEANUP ++]) ++ ++OVN_FOR_EACH_NORTHD([ ++AT_SETUP([ACL and committing to conntrack]) ++AT_KEYWORDS([acl]) ++ ++CHECK_CONNTRACK() ++CHECK_CONNTRACK_NAT() ++ovn_start ++OVS_TRAFFIC_VSWITCHD_START() ++ADD_BR([br-int]) ++# Set external-ids in br-int needed for ovn-controller ++ovs-vsctl \ ++ -- set Open_vSwitch . external-ids:system-id=hv1 \ ++ -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ ++ -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ ++ -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ ++ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true ++ ++start_daemon ovn-controller ++ ++check ovn-nbctl lr-add r1 ++check ovn-nbctl lrp-add r1 r1_s1 00:de:ad:fe:00:01 173.0.1.1/24 ++check ovn-nbctl lrp-add r1 r1_s2 00:de:ad:fe:00:02 173.0.2.1/24 ++ ++check ovn-nbctl ls-add s1 ++check ovn-nbctl lsp-add s1 s1_r1 ++check ovn-nbctl lsp-set-type s1_r1 router ++check ovn-nbctl lsp-set-addresses s1_r1 router ++check ovn-nbctl lsp-set-options s1_r1 router-port=r1_s1 ++ ++check ovn-nbctl ls-add s2 ++check ovn-nbctl lsp-add s2 s2_r1 ++check ovn-nbctl lsp-set-type s2_r1 router ++check ovn-nbctl lsp-set-addresses s2_r1 router ++check ovn-nbctl lsp-set-options s2_r1 router-port=r1_s2 ++ ++check ovn-nbctl lsp-add s1 vm1 ++check ovn-nbctl lsp-set-addresses vm1 "00:de:ad:01:00:01 173.0.1.2" ++ ++check ovn-nbctl lsp-add s2 vm2 ++check ovn-nbctl lsp-set-addresses vm2 "00:de:ad:01:00:02 173.0.2.2" ++ ++check ovn-nbctl lsp-add s2 vm3 ++check ovn-nbctl lsp-set-addresses vm3 "00:de:ad:01:00:03 173.0.2.3" ++ ++check ovn-nbctl lb-add lb1 30.0.0.1:80 173.0.2.2:80 udp ++check ovn-nbctl lb-add lb2 20.0.0.1:80 173.0.1.2:80 udp ++check ovn-nbctl lb-add lb1 30.0.0.1 173.0.2.2 ++check ovn-nbctl lb-add lb2 173.0.2.250 173.0.1.3 ++check ovn-nbctl ls-lb-add s1 lb1 ++check ovn-nbctl ls-lb-add s2 lb2 ++ ++ADD_NAMESPACES(vm1) ++ADD_VETH(vm1, vm1, br-int, "173.0.1.2/24", "00:de:ad:01:00:01", \ ++ "173.0.1.1") ++ADD_NAMESPACES(vm2) ++ADD_VETH(vm2, vm2, br-int, "173.0.2.2/24", "00:de:ad:01:00:02", \ ++ "173.0.2.1") ++ADD_NAMESPACES(vm3) ++ADD_VETH(vm3, vm3, br-int, "173.0.2.250/24", "00:de:ad:01:00:03", \ ++ "173.0.2.1") ++ ++check ovn-nbctl acl-add s1 from-lport 1001 "ip" allow ++check ovn-nbctl acl-add s1 to-lport 1002 "ip" allow ++check ovn-nbctl acl-add s2 from-lport 1003 "ip" allow ++check ovn-nbctl acl-add s2 to-lport 1004 "ip" allow ++check ovn-nbctl --wait=hv sync ++AS_BOX([initial ping]) ++# Send ping in background. Same ping, same flow throughout the test ++on_exit 'kill $(pidof ping)' ++NS_EXEC([vm1], [ping -c 10000 -i 0.1 30.0.0.1 > icmp.txt &]) ++ ++# Check for conntrack entries ++OVS_WAIT_FOR_OUTPUT([ ++ ovs-appctl dpctl/dump-conntrack | FORMAT_CT(173.0.1.2) | \ ++ sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl ++icmp,orig=(src=173.0.1.2,dst=173.0.2.2,id=,type=8,code=0),reply=(src=173.0.2.2,dst=173.0.1.2,id=,type=0,code=0),zone= ++icmp,orig=(src=173.0.1.2,dst=30.0.0.1,id=,type=8,code=0),reply=(src=173.0.2.2,dst=173.0.1.2,id=,type=0,code=0),zone=,mark=2 ++]) ++ ++# Now check for multiple ct_commits ++ovs-appctl dpctl/dump-flows > dp_flows ++zone_id=$(ovn-appctl -t ovn-controller ct-zone-list | grep vm1 | cut -d ' ' -f2) ++AT_CHECK([test 1 = `cat dp_flows | grep "commit,zone=$zone_id" | wc -l`]) ++ ++check ovn-nbctl acl-del s1 from-lport 1001 "ip" ++check ovn-nbctl acl-del s1 to-lport 1002 "ip" ++check ovn-nbctl acl-del s2 from-lport 1003 "ip" ++check ovn-nbctl acl-del s2 to-lport 1004 "ip" ++ ++AS_BOX([acl drop echo request]) ++check ovn-nbctl --log --severity=alert --name=drop-flow-s1 acl-add s1 to-lport 2001 icmp4 drop ++# acl-drop to-lport s1 apply to traffic from s1 to vm1 and s1 to r1. ++check ovn-nbctl --wait=hv sync ++ ++# Check that traffic is blocked ++# Wait for some packets to hit the rule to avoid potential race conditions. Then count packets. ++OVS_WAIT_UNTIL([test `cat ovn-controller.log | grep acl_log | grep -c drop-flow-s1` -gt "0"]) ++total_icmp_pkts=$(cat icmp.txt | grep ttl | wc -l) ++ ++# Wait some time and check whether packets went through. In the worse race condition, the sleep is too short ++# and this test will still succeed. ++sleep 1 ++OVS_WAIT_UNTIL([ ++ total_icmp1_pkts=$(cat icmp.txt | grep ttl | wc -l) ++ test "${total_icmp1_pkts}" -eq "${total_icmp_pkts}" ++]) ++ ++AS_BOX([acl allow-related echo request]) ++check ovn-nbctl acl-add s1 to-lport 2002 "icmp4 && ip4.src == 173.0.1.2" allow-related ++# This rule has higher priority than to-lport 2001 icmp4 drop. ++# So traffic from s1 (w/ src=173.0.1.2) to r1 should be accepted ++# (return) traffic from s1 to vm1 should be accepted as return traffic ++check ovn-nbctl --wait=hv sync ++OVS_WAIT_UNTIL([ ++ total_icmp1_pkts=$(cat icmp.txt | grep ttl | wc -l) ++ test "${total_icmp1_pkts}" -gt "${total_icmp_pkts}" ++]) ++ ++# Check we did not break handling acl-drop for existing flows ++AS_BOX([acl drop echo request in s2]) ++check ovn-nbctl acl-del s1 to-lport 2001 icmp4 ++check ovn-nbctl --log --severity=alert --name=drop-flow-s2 acl-add s2 to-lport 2001 icmp4 drop ++check ovn-nbctl --wait=hv sync ++ ++OVS_WAIT_UNTIL([test `cat ovn-controller.log | grep acl_log | grep -c drop-flow-s2` -gt "0"]) ++ ++OVS_WAIT_FOR_OUTPUT([ ++ ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | \ ++ sed -e 's/zone=[[0-9]]*/zone=/' | \ ++ sed -e 's/mark=[[0-9]]*/mark=/'], [0], [dnl ++icmp,orig=(src=173.0.1.2,dst=30.0.0.1,id=,type=8,code=0),reply=(src=173.0.2.2,dst=173.0.1.2,id=,type=0,code=0),zone=,mark= ++]) ++total_icmp_pkts=$(cat icmp.txt | grep ttl | wc -l) ++ ++# Allow ping again ++AS_BOX([acl allow echo request in s2]) ++check ovn-nbctl acl-add s2 to-lport 2005 icmp4 allow ++check ovn-nbctl --wait=hv sync ++OVS_WAIT_FOR_OUTPUT([ ++ ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | \ ++ sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl ++icmp,orig=(src=173.0.1.2,dst=30.0.0.1,id=,type=8,code=0),reply=(src=173.0.2.2,dst=173.0.1.2,id=,type=0,code=0),zone=,mark=2 ++]) ++OVS_WAIT_UNTIL([ ++ total_icmp1_pkts=$(cat icmp.txt | grep ttl | wc -l) ++ test "${total_icmp1_pkts}" -gt "${total_icmp_pkts}" ++]) ++ + OVS_APP_EXIT_AND_WAIT([ovn-controller]) + + as ovn-sb +@@ -10706,3 +10935,605 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d + /connection dropped.*/d"]) + AT_CLEANUP + ]) ++ ++# This tests port->up/down and ovn-installed after adding and removing Ports and Interfaces. ++# 3 Conditions x 3 tests: ++# - 3 Conditions: ++# - In normal conditions ++# - Remove interface while starting and stopping SB and Controller ++# - Remove and add back interface while starting and stopping SB and Controller ++# - 3 tests: ++# - Add/Remove Logical Port ++# - Add/Remove iface-id ++# - Add/Remove Interface ++# Each tests/conditions checks for ++# - Port_binding->chassis ++# - Port up or down ++# - ovn-installed ++OVN_FOR_EACH_NORTHD([ ++AT_SETUP([ovn-install on slow ovsdb]) ++AT_KEYWORDS([ovn-install]) ++ ++OVS_TRAFFIC_VSWITCHD_START() ++# Restart ovsdb-server, this time with tcp ++OVS_APP_EXIT_AND_WAIT([ovsdb-server]) ++start_daemon ovsdb-server --remote=punix:"$OVS_RUNDIR"/db.sock --remote=ptcp:0:127.0.0.1 ++ ++ovn_start ++ADD_BR([br-int]) ++ ++# Set external-ids in br-int needed for ovn-controller ++ovs-vsctl \ ++ -- set Open_vSwitch . external-ids:system-id=hv1 \ ++ -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ ++ -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ ++ -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ ++ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true ++ ++# Start ovn-controller ++PARSE_LISTENING_PORT([$ovs_base/ovsdb-server.log], [TCP_PORT]) ++start_daemon ovn-controller tcp:127.0.0.1:$TCP_PORT ++ ++check ovn-nbctl ls-add ls1 ++check ovn-nbctl set Logical_Switch ls1 other_config:subnet=10.1.0.0/16 ++ ++check ovn-nbctl --wait=hv sync ++ ++add_logical_ports() { ++ echo Adding logical ports ++ check ovn-nbctl lsp-add ls1 lsp1 ++ check ovn-nbctl lsp-add ls1 lsp2 ++} ++ ++remove_logical_ports() { ++ echo Removing logical ports ++ check ovn-nbctl lsp-del lsp1 ++ check ovn-nbctl lsp-del lsp2 ++} ++ ++add_ovs_interface() { ++ echo Adding interface $1 $2 ++ ovs-vsctl --no-wait -- add-port br-int $1 \ ++ -- set Interface $1 external_ids:iface-id=$2 \ ++ -- set Interface $1 type=internal ++} ++add_ovs_interfaces() { ++ add_ovs_interface vif1 lsp1 ++ add_ovs_interface vif2 lsp2 ++} ++remove_ovs_interface() { ++ echo Removing interface $1 ++ check ovs-vsctl --no-wait -- del-port $1 ++} ++remove_ovs_interfaces() { ++ remove_ovs_interface vif1 ++ remove_ovs_interface vif2 ++} ++add_iface_ids() { ++ echo Adding iface-id vif1 lsp1 ++ ovs-vsctl --no-wait -- set Interface vif1 external_ids:iface-id=lsp1 ++ echo Adding iface-id vif2 lsp2 ++ ovs-vsctl --no-wait -- set Interface vif2 external_ids:iface-id=lsp2 ++} ++remove_iface_id() { ++ echo Removing iface-id $1 ++ check ovs-vsctl remove Interface $1 external_ids iface-id ++} ++remove_iface_ids() { ++ remove_iface_id vif1 ++ remove_iface_id vif2 ++} ++wait_for_local_bindings() { ++ OVS_WAIT_UNTIL( ++ [test `ovs-appctl -t ovn-controller debug/dump-local-bindings | grep interface | wc -l` -eq 2], ++ [kill -CONT $(cat ovn-sb/ovsdb-server.pid)] ++ ) ++} ++sleep_sb() { ++ echo SB going to sleep ++ AT_CHECK([kill -STOP $(cat ovn-sb/ovsdb-server.pid)]) ++} ++wake_up_sb() { ++ echo SB waking up ++ AT_CHECK([kill -CONT $(cat ovn-sb/ovsdb-server.pid)]) ++} ++sleep_controller() { ++ echo Controller going to sleep ++ ovn-appctl debug/pause ++ OVS_WAIT_UNTIL([test x$(ovn-appctl -t ovn-controller debug/status) = "xpaused"]) ++} ++ ++stop_ovsdb_controller_updates() { ++ TCP_PORT=$1 ++ echo Stopping updates from ovn-controller to ovsdb using port $TCP_PORT ++ on_exit 'iptables -C INPUT -p tcp --destination-port $TCP_PORT -j DROP 2>/dev/null && iptables -D INPUT -p tcp --destination-port $TCP_PORT -j DROP' ++ iptables -A INPUT -p tcp --destination-port $TCP_PORT -j DROP ++} ++restart_ovsdb_controller_updates() { ++ TCP_PORT=$1 ++ echo Restarting updates from ovn-controller to ovsdb ++ iptables -D INPUT -p tcp --destination-port $TCP_PORT -j DROP ++} ++wake_up_controller() { ++ echo Controller waking up ++ ovn-appctl debug/resume ++} ++ensure_controller_run() { ++# We want to make sure controller could run at least one full loop. ++# We can't use wait=hv as sb might be sleeping. ++# Use 2 ovn-appctl to guarentee that ovn-controller run the full loop, and not just the unixctl handling ++ OVS_WAIT_UNTIL([test x$(ovn-appctl -t ovn-controller debug/status) = "xrunning"]) ++ OVS_WAIT_UNTIL([test x$(ovn-appctl -t ovn-controller debug/status) = "xrunning"]) ++} ++sleep_ovsdb() { ++ echo OVSDB going to sleep ++ AT_CHECK([kill -STOP $(cat ovsdb-server.pid)]) ++} ++wake_up_ovsdb() { ++ echo OVSDB waking up ++ AT_CHECK([kill -CONT $(cat ovsdb-server.pid)]) ++} ++check_ovn_installed() { ++ OVS_WAIT_UNTIL([test `ovs-vsctl get Interface vif1 external_ids:ovn-installed` = '"true"']) ++ OVS_WAIT_UNTIL([test `ovs-vsctl get Interface vif2 external_ids:ovn-installed` = '"true"']) ++} ++check_ovn_uninstalled() { ++ OVS_WAIT_UNTIL([test x`ovs-vsctl get Interface vif2 external_ids:ovn-installed` = x]) ++ OVS_WAIT_UNTIL([test x`ovs-vsctl get Interface vif1 external_ids:ovn-installed` = x]) ++} ++check_ports_up() { ++ OVS_WAIT_UNTIL([test `ovn-sbctl get Port_Binding lsp1 up` = 'true']) ++ OVS_WAIT_UNTIL([test `ovn-sbctl get Port_Binding lsp2 up` = 'true']) ++} ++check_ports_down() { ++ OVS_WAIT_UNTIL([test `ovn-sbctl get Port_Binding lsp1 up` = 'false']) ++ OVS_WAIT_UNTIL([test `ovn-sbctl get Port_Binding lsp2 up` = 'false']) ++} ++ ++check_ports_bound() { ++ ch=$(fetch_column Chassis _uuid name=hv1) ++ wait_row_count Port_Binding 1 logical_port=lsp1 chassis=$ch ++ wait_row_count Port_Binding 1 logical_port=lsp2 chassis=$ch ++} ++check_ports_unbound() { ++ wait_column "" Port_Binding chassis logical_port=lsp1 ++ wait_column "" Port_Binding chassis logical_port=lsp2 ++} ++add_logical_ports ++add_ovs_interfaces ++wait_for_local_bindings ++wait_for_ports_up ++check ovn-nbctl --wait=hv sync ++############################################################ ++########## Remove interface while removing iface-id ######## ++############################################################ ++AS_BOX(["Remove interface while removing iface-id"]) ++stop_ovsdb_controller_updates $TCP_PORT ++remove_iface_id vif1 ++ensure_controller_run ++# OVSDB should be seen as ro now ++remove_iface_id vif2 ++ensure_controller_run ++# Controller delaying ovn-install removal for vif2 as ovsdb ro ++sleep_controller ++restart_ovsdb_controller_updates $TCP_PORT ++remove_ovs_interface vif2 ++# vif2, for which we want to remove ovn-install, is deleted ++wake_up_controller ++check_ovn_uninstalled ++check_ports_down ++check_ports_unbound ++add_ovs_interface vif2 lsp2 ++add_iface_ids ++check_ovn_installed ++check_ports_up ++check_ports_bound ++############################################################ ++################### Add/Remove iface-id #################### ++############################################################ ++AS_BOX(["iface-id removal and added back (no sleeping sb or controller)"]) ++remove_iface_ids ++check_ovn_uninstalled ++check_ports_down ++check_ports_unbound ++add_iface_ids ++check_ovn_installed ++check_ports_up ++check_ports_bound ++ ++AS_BOX(["iface-id removal"]) ++sleep_sb ++remove_iface_ids ++ensure_controller_run ++sleep_controller ++wake_up_sb ++wake_up_controller ++check_ovn_uninstalled ++check_ports_down ++check_ports_unbound ++add_iface_ids ++check ovn-nbctl --wait=hv sync ++ ++AS_BOX(["iface-id removal 2"]) ++# Block IDL from ovn-controller to OVSDB ++stop_ovsdb_controller_updates $TCP_PORT ++remove_iface_id vif2 ++ensure_controller_run ++ ++# OVSDB should now be seen as read-only by ovn-controller ++remove_iface_id vif1 ++ensure_controller_run ++ ++# Restart connection from ovn-controller to OVSDB ++restart_ovsdb_controller_updates $TCP_PORT ++check_ovn_uninstalled ++check_ports_down ++check_ports_unbound ++ ++add_iface_ids ++check ovn-nbctl --wait=hv sync ++ ++AS_BOX(["iface-id removal and added back"]) ++sleep_sb ++remove_iface_ids ++ensure_controller_run ++sleep_controller ++add_iface_ids ++wake_up_sb ++wake_up_controller ++check_ovn_installed ++check_ports_up ++check_ports_bound ++############################################################ ++###################### Add/Remove Interface ################ ++############################################################ ++AS_BOX(["Interface removal and added back (no sleeping sb or controller)"]) ++remove_ovs_interfaces ++check_ovn_uninstalled ++check_ports_down ++check_ports_unbound ++add_ovs_interfaces ++check_ovn_installed ++check_ports_up ++check_ports_bound ++check ovn-nbctl --wait=hv sync ++ ++AS_BOX(["Interface removal"]) ++sleep_sb ++remove_ovs_interfaces ++ensure_controller_run ++sleep_controller ++wake_up_sb ++wake_up_controller ++check_ovn_uninstalled ++check_ports_down ++check_ports_unbound ++add_ovs_interfaces ++check ovn-nbctl --wait=hv sync ++ ++AS_BOX(["Interface removal and added back"]) ++sleep_sb ++remove_ovs_interfaces ++ensure_controller_run ++sleep_controller ++add_ovs_interfaces ++wake_up_sb ++wake_up_controller ++check_ovn_installed ++check_ports_up ++check_ports_bound ++check ovn-nbctl --wait=hv sync ++############################################################ ++###################### Add/Remove Logical Port ############# ++############################################################ ++AS_BOX(["Logical port removal and added back (no sleeping sb or controller)"]) ++remove_logical_ports ++check_ovn_uninstalled ++check_ports_unbound ++sleep_ovsdb ++add_logical_ports ++ensure_controller_run ++wake_up_ovsdb ++check_ovn_installed ++check_ports_up ++check_ports_bound ++check ovn-nbctl --wait=hv sync ++ ++AS_BOX(["Logical port removal"]) ++sleep_sb ++remove_logical_ports ++ensure_controller_run ++sleep_controller ++wake_up_sb ++wake_up_controller ++check_ovn_uninstalled ++check_ports_unbound ++add_logical_ports ++check ovn-nbctl --wait=hv sync ++ ++AS_BOX(["Logical port removal and added back"]) ++sleep_sb ++remove_logical_ports ++ensure_controller_run ++sleep_controller ++add_logical_ports ++wake_up_sb ++wake_up_controller ++check_ovn_installed ++check_ports_up ++check_ports_bound ++ ++OVS_APP_EXIT_AND_WAIT([ovn-controller]) ++ ++as ovn-sb ++OVS_APP_EXIT_AND_WAIT([ovsdb-server]) ++ ++as ovn-nb ++OVS_APP_EXIT_AND_WAIT([ovsdb-server]) ++ ++as northd ++OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE]) ++ ++as ++OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d ++/connection dropped.*/d"]) ++AT_CLEANUP ++]) ++ ++OVN_FOR_EACH_NORTHD([ ++AT_SETUP([ovn mirroring]) ++AT_KEYWORDS([mirror]) ++AT_SKIP_IF([test $HAVE_TCPDUMP = no]) ++ ++CHECK_CONNTRACK() ++CHECK_CONNTRACK_NAT() ++ovn_start ++OVS_TRAFFIC_VSWITCHD_START() ++ADD_BR([br-int]) ++ADD_BR([br-mirror]) ++ ++# Set external-ids in br-int needed for ovn-controller ++ovs-vsctl \ ++ -- set Open_vSwitch . external-ids:system-id=hv1 \ ++ -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ ++ -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ ++ -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ ++ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true ++ ++# Start ovn-controller ++start_daemon ovn-controller ++ ++ovs-ofctl add-flow br-mirror action=normal ++ ++ovn-nbctl create Logical_Router name=R1 options:chassis=hv1 ++ ++ovn-nbctl ls-add foo ++ovn-nbctl ls-add bar ++ ++# Connect foo to R1 ++ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 192.168.1.1/24 2001::1/64 ++ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \ ++ type=router options:router-port=foo addresses=\"00:00:01:01:02:03\" ++ ++# Connect bar to R1 ++ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 192.168.2.1/24 2002::1/64 ++ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \ ++ type=router options:router-port=bar addresses=\"00:00:01:01:02:04\" ++ ++# Logical port 'foo1' in switch 'foo'. ++ADD_NAMESPACES(foo1) ++ADD_VETH(foo1, foo1, br-int, "2001::2/64", "f0:00:00:01:02:03", \ ++ "2001::1", "nodad", "192.168.1.2/24", "192.168.1.1") ++ovn-nbctl lsp-add foo foo1 \ ++-- lsp-set-addresses foo1 "f0:00:00:01:02:03 192.168.1.2 2001::2" ++ ++# Logical port 'bar1' in switch 'bar'. ++ADD_NAMESPACES(bar1) ++ADD_VETH(bar1, bar1, br-int, "2002::2/64", "f0:00:00:01:02:05", \ ++ "2002::1", "nodad", "192.168.2.2/24", "192.168.2.1") ++ovn-nbctl lsp-add bar bar1 \ ++-- lsp-set-addresses bar1 "f0:00:00:01:02:05 192.168.2.2 2002::2" ++ ++ovn-nbctl mirror-add mirror0 gre 1 to-lport 172.16.0.100 ++ovn-nbctl lsp-attach-mirror bar1 mirror0 ++ ++ADD_NAMESPACES(mirror) ++ADD_VETH(mirror, mirror, br-mirror, "2003::b/64", "f0:00:00:01:07:06", \ ++ "2003::1", "nodad", "172.16.0.100/24", "172.16.0.1") ++AT_CHECK([ip addr add 172.16.0.101/24 dev br-mirror]) ++AT_CHECK([ip addr add 2003::a/64 dev br-mirror nodad]) ++AT_CHECK([ip link set dev br-mirror up]) ++ ++NS_CHECK_EXEC([mirror], [tcpdump -l -c 3 -neei mirror proto GRE > gre_mirror4.pcap 2>gre_mirror4_error &]) ++OVS_WAIT_UNTIL([grep "listening" gre_mirror4_error]) ++ ++NS_CHECK_EXEC([foo1], [ping -q -c 3 -i 0.3 -w 2 192.168.2.2 | FORMAT_PING], \ ++[0], [dnl ++3 packets transmitted, 3 received, 0% packet loss, time 0ms ++]) ++OVS_WAIT_UNTIL([ ++ n_packets=$(grep "GRE" -c gre_mirror4.pcap) ++ test "${n_packets}" = "3" ++]) ++ ++killall tcpdump ++ ++ovn-nbctl mirror-del mirror0 ++ovn-nbctl mirror-add mirror1 gre 2 to-lport 2003::b ++ovn-nbctl lsp-attach-mirror bar1 mirror1 ++ ++NS_CHECK_EXEC([mirror], [tcpdump -l -c 3 -neei mirror proto GRE > gre_mirror6.pcap 2>gre_mirror6_error &]) ++OVS_WAIT_UNTIL([grep "listening" gre_mirror6_error]) ++ ++NS_CHECK_EXEC([foo1], [ping6 -q -c 3 -i 0.3 -w 2 2002::2 | FORMAT_PING], \ ++[0], [dnl ++3 packets transmitted, 3 received, 0% packet loss, time 0ms ++]) ++ ++OVS_WAIT_UNTIL([ ++ n_packets=$(grep "GRE" -c gre_mirror6.pcap) ++ test "${n_packets}" = "3" ++]) ++ ++killall tcpdump ++ ++ovn-nbctl mirror-del mirror1 ++ovn-nbctl mirror-add mirror2 erspan 3 to-lport 172.16.0.100 ++ovn-nbctl lsp-attach-mirror bar1 mirror2 ++ ++NS_CHECK_EXEC([mirror], [tcpdump -l -c 3 -neei mirror ip[[22:2]]=0x88be > erspan_mirror4.pcap 2>erspan_mirror4_error &]) ++OVS_WAIT_UNTIL([grep "listening" erspan_mirror4_error]) ++ ++NS_CHECK_EXEC([foo1], [ping -q -c 3 -i 0.3 -w 2 192.168.2.2 | FORMAT_PING], \ ++[0], [dnl ++3 packets transmitted, 3 received, 0% packet loss, time 0ms ++]) ++OVS_WAIT_UNTIL([ ++ n_packets=$(grep "gre-proto-0x88be" -c erspan_mirror4.pcap) ++ test "${n_packets}" = "3" ++]) ++ ++killall tcpdump ++ ++ovn-nbctl mirror-del mirror2 ++ovn-nbctl mirror-add mirror3 erspan 4 to-lport 2003::b ++ovn-nbctl lsp-attach-mirror bar1 mirror3 ++ ++NS_CHECK_EXEC([mirror], [tcpdump -l -c 3 -neei mirror ip6[[42:2]]=0x88be > erspan_mirror6.pcap 2>erspan_mirror6_error &]) ++OVS_WAIT_UNTIL([grep "listening" erspan_mirror6_error]) ++ ++NS_CHECK_EXEC([foo1], [ping6 -q -c 3 -i 0.3 -w 2 2002::2 | FORMAT_PING], \ ++[0], [dnl ++3 packets transmitted, 3 received, 0% packet loss, time 0ms ++]) ++OVS_WAIT_UNTIL([ ++ n_packets=$(grep "gre-proto-0x88be" -c erspan_mirror6.pcap) ++ test "${n_packets}" = "3" ++]) ++ ++killall tcpdump ++ ++uuid=$(fetch_column nb:mirror _uuid name="mirror3") ++ovn-nbctl set mirror $uuid type=gre ++ ++NS_CHECK_EXEC([mirror], [tcpdump -c 3 -l -neei mirror proto GRE > gre_mirror6.pcap 2>gre_mirror6_error &]) ++OVS_WAIT_UNTIL([grep "listening" gre_mirror6_error]) ++ ++NS_CHECK_EXEC([foo1], [ping6 -q -c 3 -i 0.3 -w 2 2002::2 | FORMAT_PING], \ ++[0], [dnl ++3 packets transmitted, 3 received, 0% packet loss, time 0ms ++]) ++ ++OVS_WAIT_UNTIL([ ++ n_packets=$(grep "GRE" -c gre_mirror6.pcap) ++ test "${n_packets}" = "3" ++]) ++ ++killall tcpdump ++ ++OVS_APP_EXIT_AND_WAIT([ovn-controller]) ++ ++as ovn-sb ++OVS_APP_EXIT_AND_WAIT([ovsdb-server]) ++ ++as ovn-nb ++OVS_APP_EXIT_AND_WAIT([ovsdb-server]) ++ ++as northd ++OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE]) ++ ++as ++OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d ++/connection dropped.*/d"]) ++AT_CLEANUP ++]) ++ ++OVN_FOR_EACH_NORTHD([ ++AT_SETUP([load balancer with localnet port]) ++CHECK_CONNTRACK() ++CHECK_CONNTRACK_NAT() ++ovn_start ++OVS_TRAFFIC_VSWITCHD_START() ++ADD_BR([br-int]) ++ADD_BR([br-phys], [set Bridge br-phys fail-mode=standalone]) ++ ++# Set external-ids in br-int needed for ovn-controller ++ovs-vsctl \ ++ -- set Open_vSwitch . external-ids:system-id=hv1 \ ++ -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ ++ -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ ++ -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ ++ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true ++ ++start_daemon ovn-controller ++ ++check ovn-nbctl lr-add ro ++check ovn-nbctl lrp-add ro ro-sw 00:00:00:00:00:01 192.168.0.1/24 ++check ovn-nbctl lrp-add ro ro-pub 00:00:00:00:01:01 10.0.0.1/24 ++ ++check ovn-nbctl ls-add sw ++check ovn-nbctl lsp-add sw sw-vm1 \ ++ -- lsp-set-addresses sw-vm1 "00:00:00:00:00:02 192.168.0.2" ++check ovn-nbctl lsp-add sw sw-ro \ ++ -- lsp-set-type sw-ro router \ ++ -- lsp-set-addresses sw-ro router \ ++ -- lsp-set-options sw-ro router-port=ro-sw ++ ++check ovn-nbctl ls-add pub ++check ovn-nbctl lsp-add pub sw-ln \ ++ -- lsp-set-type sw-ln localnet \ ++ -- lsp-set-addresses sw-ln unknown \ ++ -- lsp-set-options sw-ln network_name=phys ++check ovn-nbctl lsp-add pub pub-ro \ ++ -- lsp-set-type pub-ro router \ ++ -- lsp-set-addresses pub-ro router \ ++ -- lsp-set-options pub-ro router-port=ro-pub ++ ++check ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys ++ ++ADD_NAMESPACES(sw-vm1) ++ADD_VETH(sw-vm1, sw-vm1, br-int, "192.168.0.2/24", "00:00:00:00:00:02", \ ++ "192.168.0.1") ++ ++ADD_NAMESPACES(ln) ++ADD_VETH(ln, ln, br-phys, "10.0.0.2/24", "00:00:00:00:01:02", \ ++ "10.0.0.1") ++ ++# We have the basic network set up. Now let's add a load balancer ++# on the "pub" logical switch. ++ ++check ovn-nbctl lb-add ln-lb 172.16.0.1:80 192.168.0.2:80 tcp ++check ovn-nbctl ls-lb-add pub ln-lb ++check ovn-nbctl --wait=hv sync ++ ++# Add a route so that the localnet port can reach the load balancer ++# VIP. ++NS_CHECK_EXEC([ln], [ip route add 172.16.0.1 via 10.0.0.1]) ++NS_CHECK_EXEC([ln], [ip route add 192.168.0.0/24 via 10.0.0.1]) ++ ++OVS_START_L7([sw-vm1], [http]) ++ ++NS_CHECK_EXEC([ln], [wget 172.16.0.1 -t 5 -T 1 --retry-connrefused -v -o wget.log]) ++ ++AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.0.1) | \ ++sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl ++tcp,orig=(src=10.0.0.2,dst=172.16.0.1,sport=,dport=),reply=(src=192.168.0.2,dst=10.0.0.2,sport=,dport=),zone=,mark=2,protoinfo=(state=) ++]) ++ ++OVS_APP_EXIT_AND_WAIT([ovn-controller]) ++ ++as ovn-sb ++OVS_APP_EXIT_AND_WAIT([ovsdb-server]) ++ ++as ovn-nb ++OVS_APP_EXIT_AND_WAIT([ovsdb-server]) ++ ++as northd ++OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE]) ++ ++as ++OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d ++/connection dropped.*/d"]) ++ ++AT_CLEANUP ++]) +diff --git a/utilities/containers/py-requirements.txt b/utilities/containers/py-requirements.txt +index d7bd21e0d..0d90765c9 100644 +--- a/utilities/containers/py-requirements.txt ++++ b/utilities/containers/py-requirements.txt +@@ -1,5 +1,6 @@ + flake8 + hacking>=3.0 ++scapy + sphinx + setuptools + pyelftools +diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c +index 45572fd30..9399f9462 100644 +--- a/utilities/ovn-nbctl.c ++++ b/utilities/ovn-nbctl.c +@@ -3033,7 +3033,7 @@ nbctl_lb_add(struct ctl_context *ctx) + } + + ovn_lb_vip_format(&lb_vip_parsed, &lb_vip_normalized, template); +- ovn_lb_vip_backends_format(&lb_vip_parsed, &lb_ips_new, template); ++ ovn_lb_vip_backends_format(&lb_vip_parsed, &lb_ips_new); + ovn_lb_vip_destroy(&lb_vip_parsed); + + const struct nbrec_load_balancer *lb = NULL; +@@ -4204,8 +4204,7 @@ print_routing_policy(const struct nbrec_logical_router_policy *policy, + policy->match, policy->action); + for (int i = 0; i < policy->n_nexthops; i++) { + char *next_hop = normalize_prefix_str(policy->nexthops[i]); +- char *fmt = i ? ", %s" : " %25s"; +- ds_put_format(s, fmt, next_hop); ++ ds_put_format(s, i ? ", %s" : " %25s", next_hop ? next_hop : ""); + free(next_hop); + } + } else { +@@ -6586,18 +6585,17 @@ print_route(const struct nbrec_logical_router_static_route *route, + { + + char *prefix = normalize_prefix_str(route->ip_prefix); +- char *next_hop = ""; ++ char *next_hop = NULL; + + if (!strcmp(route->nexthop, "discard")) { + next_hop = xasprintf("discard"); + } else if (route->nexthop[0]) { + next_hop = normalize_prefix_str(route->nexthop); + } +- ds_put_format(s, "%25s %25s", prefix, next_hop); ++ ds_put_format(s, "%25s %25s", prefix ? prefix : "", ++ next_hop ? next_hop : ""); + free(prefix); +- if (next_hop[0]) { +- free(next_hop); +- } ++ free(next_hop); + + if (route->policy) { + ds_put_format(s, " %s", route->policy); diff --git a/SPECS/ovn22.12.spec b/SPECS/ovn22.12.spec deleted file mode 100644 index 3536329..0000000 --- a/SPECS/ovn22.12.spec +++ /dev/null @@ -1,650 +0,0 @@ -# Copyright (C) 2009, 2010, 2013, 2014 Nicira Networks, Inc. -# -# Copying and distribution of this file, with or without modification, -# are permitted in any medium without royalty provided the copyright -# notice and this notice are preserved. This file is offered as-is, -# without warranty of any kind. -# -# If tests have to be skipped while building, specify the '--without check' -# option. For example: -# rpmbuild -bb --without check rhel/openvswitch-fedora.spec - -# This defines the base package name's version. - -%define pkgver 2.13 -%define pkgname ovn22.12 - -# If libcap-ng isn't available and there is no need for running OVS -# as regular user, specify the '--without libcapng' -%bcond_without libcapng - -# Enable PIE, bz#955181 -%global _hardened_build 1 - -# RHEL-7 doesn't define _rundir macro yet -# Fedora 15 onwards uses /run as _rundir -%if 0%{!?_rundir:1} -%define _rundir /run -%endif - -# Build python2 (that provides python) and python3 subpackages on Fedora -# Build only python3 (that provides python) subpackage on RHEL8 -# Build only python subpackage on RHEL7 -%if 0%{?rhel} > 7 || 0%{?fedora} -# On RHEL8 Sphinx is included in buildroot -%global external_sphinx 1 -%else -# Don't use external sphinx (RHV doesn't have optional repositories enabled) -%global external_sphinx 0 -%endif - -# We would see rpmlinit error - E: hardcoded-library-path in '% {_prefix}/lib'. -# But there is no solution to fix this. Using {_lib} macro will solve the -# rpmlink error, but will install the files in /usr/lib64/. -# OVN pacemaker ocf script file is copied in /usr/lib/ocf/resource.d/ovn/ -# and we are not sure if pacemaker looks into this path to find the -# OVN resource agent script. -%global ovnlibdir %{_prefix}/lib - -Name: %{pkgname} -Summary: Open Virtual Network support -Group: System Environment/Daemons -URL: http://www.ovn.org/ -Version: 22.12.0 -Release: 34%{?commit0:.%{date}git%{shortcommit0}}%{?dist} -Provides: openvswitch%{pkgver}-ovn-common = %{?epoch:%{epoch}:}%{version}-%{release} -Obsoletes: openvswitch%{pkgver}-ovn-common < 2.11.0-1 - -# Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the -# lib/sflow*.[ch] files are SISSL -License: ASL 2.0 and LGPLv2+ and SISSL - -# Always pull an upstream release, since this is what we rebase to. -Source: https://github.com/ovn-org/ovn/archive/v%{version}.tar.gz#/ovn-%{version}.tar.gz - -%define ovscommit a787fbbf9dd6a108a53053afb45fb59a0b58b514 -%define ovsshortcommit a787fbb - -Source10: https://github.com/openvswitch/ovs/archive/%{ovscommit}.tar.gz#/openvswitch-%{ovsshortcommit}.tar.gz -%define ovsdir ovs-%{ovscommit} - -%define docutilsver 0.12 -%define pygmentsver 1.4 -%define sphinxver 1.1.3 -Source100: https://pypi.io/packages/source/d/docutils/docutils-%{docutilsver}.tar.gz -Source101: https://pypi.io/packages/source/P/Pygments/Pygments-%{pygmentsver}.tar.gz -Source102: https://pypi.io/packages/source/S/Sphinx/Sphinx-%{sphinxver}.tar.gz - -Source500: configlib.sh -Source501: gen_config_group.sh -Source502: set_config.sh - -# Important: source503 is used as the actual copy file -# @TODO: this causes a warning - fix it? -Source504: arm64-armv8a-linuxapp-gcc-config -Source505: ppc_64-power8-linuxapp-gcc-config -Source506: x86_64-native-linuxapp-gcc-config - -Patch: %{pkgname}.patch - -# FIXME Sphinx is used to generate some manpages, unfortunately, on RHEL, it's -# in the -optional repository and so we can't require it directly since RHV -# doesn't have the -optional repository enabled and so TPS fails -%if %{external_sphinx} -BuildRequires: python3-sphinx -%else -# Sphinx dependencies -BuildRequires: python-devel -BuildRequires: python-setuptools -#BuildRequires: python2-docutils -BuildRequires: python-jinja2 -BuildRequires: python-nose -#BuildRequires: python2-pygments -# docutils dependencies -BuildRequires: python-imaging -# pygments dependencies -BuildRequires: python-nose -%endif - -BuildRequires: gcc gcc-c++ make -BuildRequires: autoconf automake libtool -BuildRequires: systemd-units openssl openssl-devel -BuildRequires: python3-devel python3-setuptools -BuildRequires: desktop-file-utils -BuildRequires: groff-base graphviz -BuildRequires: unbound-devel - -# make check dependencies -BuildRequires: procps-ng -%if 0%{?rhel} == 8 || 0%{?fedora} -BuildRequires: python3-pyOpenSSL -%endif -BuildRequires: tcpdump - -%if %{with libcapng} -BuildRequires: libcap-ng libcap-ng-devel -%endif - -Requires: hostname openssl iproute module-init-tools - -Requires(post): systemd-units -Requires(preun): systemd-units -Requires(postun): systemd-units - -# to skip running checks, pass --without check -%bcond_without check - -%description -OVN, the Open Virtual Network, is a system to support virtual network -abstraction. OVN complements the existing capabilities of OVS to add -native support for virtual network abstractions, such as virtual L2 and L3 -overlays and security groups. - -%package central -Summary: Open Virtual Network support -License: ASL 2.0 -Requires: %{pkgname} -Requires: firewalld-filesystem -Provides: openvswitch%{pkgver}-ovn-central = %{?epoch:%{epoch}:}%{version}-%{release} -Obsoletes: openvswitch%{pkgver}-ovn-central < 2.11.0-1 - -%description central -OVN DB servers and ovn-northd running on a central node. - -%package host -Summary: Open Virtual Network support -License: ASL 2.0 -Requires: %{pkgname} -Requires: firewalld-filesystem -Provides: openvswitch%{pkgver}-ovn-host = %{?epoch:%{epoch}:}%{version}-%{release} -Obsoletes: openvswitch%{pkgver}-ovn-host < 2.11.0-1 - -%description host -OVN controller running on each host. - -%package vtep -Summary: Open Virtual Network support -License: ASL 2.0 -Requires: %{pkgname} -Provides: openvswitch%{pkgver}-ovn-vtep = %{?epoch:%{epoch}:}%{version}-%{release} -Obsoletes: openvswitch%{pkgver}-ovn-vtep < 2.11.0-1 - -%description vtep -OVN vtep controller - -%prep -%autosetup -n ovn-%{version} -a 10 -p 1 - -%build -%if 0%{?commit0:1} -# fix the snapshot unreleased version to be the released one. -sed -i.old -e "s/^AC_INIT(openvswitch,.*,/AC_INIT(openvswitch, %{version},/" configure.ac -%endif -./boot.sh - -# OVN source code is now separate. -# Build openvswitch first. -# XXX Current openvswitch2.13 doesn't -# use "2.13.0" for version. It's a commit hash -pushd %{ovsdir} -./boot.sh -%configure \ -%if %{with libcapng} - --enable-libcapng \ -%else - --disable-libcapng \ -%endif - --enable-ssl \ - --with-pkidir=%{_sharedstatedir}/openvswitch/pki - -make %{?_smp_mflags} -popd - -# Build OVN. -# XXX OVS version needs to be updated when ovs2.13 is updated. -%configure \ - --with-ovs-source=$PWD/%{ovsdir} \ -%if %{with libcapng} - --enable-libcapng \ -%else - --disable-libcapng \ -%endif - --enable-ssl \ - --with-pkidir=%{_sharedstatedir}/openvswitch/pki - -make %{?_smp_mflags} - -%install -%make_install -install -p -D -m 0644 \ - rhel/usr_share_ovn_scripts_systemd_sysconfig.template \ - $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/ovn - -for service in ovn-controller ovn-controller-vtep ovn-northd; do - install -p -D -m 0644 \ - rhel/usr_lib_systemd_system_${service}.service \ - $RPM_BUILD_ROOT%{_unitdir}/${service}.service -done - -install -d -m 0755 $RPM_BUILD_ROOT/%{_sharedstatedir}/ovn - -install -d $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/ -install -p -m 0644 rhel/usr_lib_firewalld_services_ovn-central-firewall-service.xml \ - $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/ovn-central-firewall-service.xml -install -p -m 0644 rhel/usr_lib_firewalld_services_ovn-host-firewall-service.xml \ - $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/ovn-host-firewall-service.xml - -install -d -m 0755 $RPM_BUILD_ROOT%{ovnlibdir}/ocf/resource.d/ovn -ln -s %{_datadir}/ovn/scripts/ovndb-servers.ocf \ - $RPM_BUILD_ROOT%{ovnlibdir}/ocf/resource.d/ovn/ovndb-servers - -install -p -D -m 0644 rhel/etc_logrotate.d_ovn \ - $RPM_BUILD_ROOT/%{_sysconfdir}/logrotate.d/ovn - -# remove unneeded files. -rm -f $RPM_BUILD_ROOT%{_bindir}/ovs* -rm -f $RPM_BUILD_ROOT%{_bindir}/vtep-ctl -rm -f $RPM_BUILD_ROOT%{_sbindir}/ovs* -rm -f $RPM_BUILD_ROOT%{_mandir}/man1/ovs* -rm -f $RPM_BUILD_ROOT%{_mandir}/man5/ovs* -rm -f $RPM_BUILD_ROOT%{_mandir}/man5/vtep* -rm -f $RPM_BUILD_ROOT%{_mandir}/man7/ovs* -rm -f $RPM_BUILD_ROOT%{_mandir}/man8/ovs* -rm -f $RPM_BUILD_ROOT%{_mandir}/man8/vtep* -rm -rf $RPM_BUILD_ROOT%{_datadir}/ovn/python -rm -f $RPM_BUILD_ROOT%{_datadir}/ovn/scripts/ovs* -rm -rf $RPM_BUILD_ROOT%{_datadir}/ovn/bugtool-plugins -rm -f $RPM_BUILD_ROOT%{_libdir}/*.a -rm -f $RPM_BUILD_ROOT%{_libdir}/*.la -rm -f $RPM_BUILD_ROOT%{_libdir}/pkgconfig/*.pc -rm -f $RPM_BUILD_ROOT%{_includedir}/ovn/* -rm -f $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d/ovs-appctl-bashcomp.bash -rm -f $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d/ovs-vsctl-bashcomp.bash -rm -rf $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/openvswitch -rm -f $RPM_BUILD_ROOT%{_datadir}/ovn/scripts/ovn-bugtool* -rm -f $RPM_BUILD_ROOT/%{_bindir}/ovn-docker-overlay-driver \ - $RPM_BUILD_ROOT/%{_bindir}/ovn-docker-underlay-driver - -%check -%if %{with check} - touch resolv.conf - export OVS_RESOLV_CONF=$(pwd)/resolv.conf - if ! make check TESTSUITEFLAGS='%{_smp_mflags}'; then - cat tests/testsuite.log - if ! make check TESTSUITEFLAGS='--recheck'; then - cat tests/testsuite.log - # Presently a test case - "2796: ovn -- ovn-controller incremental processing" - # is failing on aarch64 arch. Let's not exit for this arch - # until we figure out why it is failing. - # Test case 93: ovn.at:12105 ovn -- ACLs on Port Groups is failing - # repeatedly on s390x. This needs to be investigated. - %ifnarch aarch64 - %ifnarch ppc64le - %ifnarch s390x - exit 1 - %endif - %endif - %endif - fi - fi -%endif - -%clean -rm -rf $RPM_BUILD_ROOT - -%pre central -if [ $1 -eq 1 ] ; then - # Package install. - /bin/systemctl status ovn-northd.service >/dev/null - ovn_status=$? - rpm -ql openvswitch-ovn-central > /dev/null - if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then - # ovn-northd service is running which means old openvswitch-ovn-central - # is already installed and it will be cleaned up. So start ovn-northd - # service when posttrans central is called. - touch %{_localstatedir}/lib/rpm-state/ovn-northd - fi -fi - -%pre host -if [ $1 -eq 1 ] ; then - # Package install. - /bin/systemctl status ovn-controller.service >/dev/null - ovn_status=$? - rpm -ql openvswitch-ovn-host > /dev/null - if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then - # ovn-controller service is running which means old - # openvswitch-ovn-host is installed and it will be cleaned up. So - # start ovn-controller service when posttrans host is called. - touch %{_localstatedir}/lib/rpm-state/ovn-controller - fi -fi - -%pre vtep -if [ $1 -eq 1 ] ; then - # Package install. - /bin/systemctl status ovn-controller-vtep.service >/dev/null - ovn_status=$? - rpm -ql openvswitch-ovn-vtep > /dev/null - if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then - # ovn-controller-vtep service is running which means old - # openvswitch-ovn-vtep is installed and it will be cleaned up. So - # start ovn-controller-vtep service when posttrans host is called. - touch %{_localstatedir}/lib/rpm-state/ovn-controller-vtep - fi -fi - -%preun central -%if 0%{?systemd_preun:1} - %systemd_preun ovn-northd.service -%else - if [ $1 -eq 0 ] ; then - # Package removal, not upgrade - /bin/systemctl --no-reload disable ovn-northd.service >/dev/null 2>&1 || : - /bin/systemctl stop ovn-northd.service >/dev/null 2>&1 || : - fi -%endif - -%preun host -%if 0%{?systemd_preun:1} - %systemd_preun ovn-controller.service -%else - if [ $1 -eq 0 ] ; then - # Package removal, not upgrade - /bin/systemctl --no-reload disable ovn-controller.service >/dev/null 2>&1 || : - /bin/systemctl stop ovn-controller.service >/dev/null 2>&1 || : - fi -%endif - -%preun vtep -%if 0%{?systemd_preun:1} - %systemd_preun ovn-controller-vtep.service -%else - if [ $1 -eq 0 ] ; then - # Package removal, not upgrade - /bin/systemctl --no-reload disable ovn-controller-vtep.service >/dev/null 2>&1 || : - /bin/systemctl stop ovn-controller-vtep.service >/dev/null 2>&1 || : - fi -%endif - -%post -%if %{with libcapng} -if [ $1 -eq 1 ]; then - sed -i 's:^#OVN_USER_ID=:OVN_USER_ID=:' %{_sysconfdir}/sysconfig/ovn - sed -i 's:\(.*su\).*:\1 openvswitch openvswitch:' %{_sysconfdir}/logrotate.d/ovn -fi -%endif - -%post central -%if 0%{?systemd_post:1} - %systemd_post ovn-northd.service -%else - # Package install, not upgrade - if [ $1 -eq 1 ]; then - /bin/systemctl daemon-reload >dev/null || : - fi -%endif - -%post host -%if 0%{?systemd_post:1} - %systemd_post ovn-controller.service -%else - # Package install, not upgrade - if [ $1 -eq 1 ]; then - /bin/systemctl daemon-reload >dev/null || : - fi -%endif - -%post vtep -%if 0%{?systemd_post:1} - %systemd_post ovn-controller-vtep.service -%else - # Package install, not upgrade - if [ $1 -eq 1 ]; then - /bin/systemctl daemon-reload >dev/null || : - fi -%endif - -%postun - -%postun central -%if 0%{?systemd_postun_with_restart:1} - %systemd_postun_with_restart ovn-northd.service -%else - /bin/systemctl daemon-reload >/dev/null 2>&1 || : - if [ "$1" -ge "1" ] ; then - # Package upgrade, not uninstall - /bin/systemctl try-restart ovn-northd.service >/dev/null 2>&1 || : - fi -%endif - -%postun host -%if 0%{?systemd_postun_with_restart:1} - %systemd_postun_with_restart ovn-controller.service -%else - /bin/systemctl daemon-reload >/dev/null 2>&1 || : - if [ "$1" -ge "1" ] ; then - # Package upgrade, not uninstall - /bin/systemctl try-restart ovn-controller.service >/dev/null 2>&1 || : - fi -%endif - -%postun vtep -%if 0%{?systemd_postun_with_restart:1} - %systemd_postun_with_restart ovn-controller-vtep.service -%else - /bin/systemctl daemon-reload >/dev/null 2>&1 || : - if [ "$1" -ge "1" ] ; then - # Package upgrade, not uninstall - /bin/systemctl try-restart ovn-controller-vtep.service >/dev/null 2>&1 || : - fi -%endif - -%posttrans central -if [ $1 -eq 1 ]; then - # Package install, not upgrade - if [ -e %{_localstatedir}/lib/rpm-state/ovn-northd ]; then - rm %{_localstatedir}/lib/rpm-state/ovn-northd - /bin/systemctl start ovn-northd.service >/dev/null 2>&1 || : - fi -fi - - -%posttrans host -if [ $1 -eq 1 ]; then - # Package install, not upgrade - if [ -e %{_localstatedir}/lib/rpm-state/ovn-controller ]; then - rm %{_localstatedir}/lib/rpm-state/ovn-controller - /bin/systemctl start ovn-controller.service >/dev/null 2>&1 || : - fi -fi - -%posttrans vtep -if [ $1 -eq 1 ]; then - # Package install, not upgrade - if [ -e %{_localstatedir}/lib/rpm-state/ovn-controller-vtep ]; then - rm %{_localstatedir}/lib/rpm-state/ovn-controller-vtep - /bin/systemctl start ovn-controller-vtep.service >/dev/null 2>&1 || : - fi -fi - -%files -%{_bindir}/ovn-nbctl -%{_bindir}/ovn-sbctl -%{_bindir}/ovn-trace -%{_bindir}/ovn-detrace -%{_bindir}/ovn_detrace.py -%{_bindir}/ovn-appctl -%{_bindir}/ovn-ic-nbctl -%{_bindir}/ovn-ic-sbctl -%dir %{_datadir}/ovn/ -%dir %{_datadir}/ovn/scripts/ -%{_datadir}/ovn/scripts/ovn-ctl -%{_datadir}/ovn/scripts/ovn-lib -%{_datadir}/ovn/scripts/ovndb-servers.ocf -%{_mandir}/man8/ovn-ctl.8* -%{_mandir}/man8/ovn-appctl.8* -%{_mandir}/man8/ovn-nbctl.8* -%{_mandir}/man8/ovn-ic-nbctl.8* -%{_mandir}/man8/ovn-trace.8* -%{_mandir}/man1/ovn-detrace.1* -%{_mandir}/man7/ovn-architecture.7* -%{_mandir}/man8/ovn-sbctl.8* -%{_mandir}/man8/ovn-ic-sbctl.8* -%{_mandir}/man5/ovn-nb.5* -%{_mandir}/man5/ovn-ic-nb.5* -%{_mandir}/man5/ovn-sb.5* -%{_mandir}/man5/ovn-ic-sb.5* -%dir %{ovnlibdir}/ocf/resource.d/ovn/ -%{ovnlibdir}/ocf/resource.d/ovn/ovndb-servers -%config(noreplace) %verify(not md5 size mtime) %{_sysconfdir}/logrotate.d/ovn -%config(noreplace) %verify(not md5 size mtime) %{_sysconfdir}/sysconfig/ovn - -%files central -%{_bindir}/ovn-northd -%{_bindir}/ovn-ic -%{_mandir}/man8/ovn-northd.8* -%{_mandir}/man8/ovn-ic.8* -%{_datadir}/ovn/ovn-nb.ovsschema -%{_datadir}/ovn/ovn-ic-nb.ovsschema -%{_datadir}/ovn/ovn-sb.ovsschema -%{_datadir}/ovn/ovn-ic-sb.ovsschema -%{_unitdir}/ovn-northd.service -%{ovnlibdir}/firewalld/services/ovn-central-firewall-service.xml - -%files host -%{_bindir}/ovn-controller -%{_mandir}/man8/ovn-controller.8* -%{_unitdir}/ovn-controller.service -%{ovnlibdir}/firewalld/services/ovn-host-firewall-service.xml - -%files vtep -%{_bindir}/ovn-controller-vtep -%{_mandir}/man8/ovn-controller-vtep.8* -%{_unitdir}/ovn-controller-vtep.service - -%changelog -* Thu Mar 16 2023 Dumitru Ceara - 22.12.0-34 -- northd: Ignore remote chassis when computing the supported feature set. -[Upstream: 31ffefe9f6cc65192a8158adc41ad7adb02f634b] - -* Thu Mar 09 2023 Ales Musil - 22.12.0-33 -- northd: Fix missig "); " from LB flows -[Upstream: cf205ca0e52c425a14f49145fa74b3fe293b547e] - -* Thu Mar 02 2023 Ilya Maximets - 22.12.0-32 -- ovn-util: Remove unused ovn_parse_internal_version_minor. -[Upstream: 5b9e7a70386ee9863469fbf2ce4b9a4d922716d8] - -* Thu Mar 02 2023 Felix Hüttner - 22.12.0-31 -- northd: fix comments on functions -[Upstream: 79dca2c4d0f3550757b6e3bb0813703348dab541] - -* Thu Mar 02 2023 Ales Musil - 22.12.0-30 -- system-tests: Reduce flakiness of ACL reject tests -[Upstream: b3196d1b140c98b409086ca72880a76da96c6c62] - -* Thu Mar 02 2023 Ales Musil - 22.12.0-29 -- dbctl: Fix a couple of memory leaks -[Upstream: 2733558a2e76ad6db3fc639f1bd8235d6382248b] - -* Thu Mar 02 2023 Dumitru Ceara - 22.12.0-28 -- ci: ovn-kubernetes: Bump libovsdb to a6a173993830. -[Upstream: 81ae7831f8d64a114a1be265782b6aa9ad0c52db] - -* Wed Mar 01 2023 Xavier Simonart - 22.12.0-27 -- tests: Fixed some tests failing on (very) slow systems -[Upstream: 2bd8697b25ac4342af33985899248248557c5481] - -* Mon Feb 27 2023 Ales Musil - 22.12.0-26 -- tests: Decrease the number of zones and switches for interconnection -[Upstream: 2a24ebc3064959c57ded1060a6a31be5397382b3] - -* Thu Feb 16 2023 Dumitru Ceara - 22.12.0-25 -- lb: northd: Properly format IPv6 SB load balancer VIPs. -[Upstream: 7053ae61267ebcb282d5ef18b5bd8f2f6c6c37e0] - -* Wed Feb 15 2023 Ales Musil - 22.12.0-24 -- system-test: Use OVS_WAIT_UNTIL for tcpdump start instead fo sleep -[Upstream: d5273f929513458a569cdfb297bffd9922d44c01] - -* Wed Feb 15 2023 Ihar Hrachyshka - 22.12.0-23 -- docs: fix the max number of ports per network for vxlan -[Upstream: 4dfa4ba431ab634b6068f27e886a4d403d589c87] - -* Wed Feb 15 2023 Ales Musil - 22.12.0-22 -- ovn-nbctl: Fix documentation typo (#2168009) -[Upstream: 0c44d7dbf4a013f08c79d5818e89a8f55ecd09e0] - -* Wed Feb 15 2023 Lorenzo Bianconi - 22.12.0-21 -- northd: do not create flows for reserved multicast IPv6 groups (#2154930) -[Upstream: 61e030ed59c2d2a1029866dce6769428e0abbc0c] - -* Thu Feb 02 2023 Han Zhou - 22.12.0-20 -- northd.c: Validate port type to avoid unexpected behavior. -[Upstream: b67009fdb6312e95367183c65b439fd3b7a288bf] - -* Tue Jan 31 2023 Surya Seetharaman - 22.12.0-19 -- Add the metalLB install flag for CI actions -[Upstream: 65990b8398e8e7ff29c6d7e9903fd0cf7ef64965] - -* Mon Jan 23 2023 Ales Musil - 22.12.0-18 -- ovn-trace: Use the original ovnact for execute_load -[Upstream: 4c78bef966927f4083b601a6a4f5fc76a839fd1a] - -* Mon Jan 23 2023 Dumitru Ceara - 22.12.0-17 -- northd: Add logical flows to allow rpl/rel traffic in acl_after_lb stage. (#1947807) -[Upstream: d6914efd53ac28a6e3da6e65f9e026674f05dc4c] - -* Fri Jan 20 2023 Mark Michelson - 22.12.0-16 -- ovn-controller: Fix initial requested SNAT zone assignment. (#2160403) -[Upstream: 17f1e9e0148e298b6ec525d5d6b149082a864dca] - -* Thu Jan 19 2023 Han Zhou - 22.12.0-15 -- northd: Drop packets destined to router owned NAT IP for DGP. -[Upstream: 481f25b784896eec07fedc77631992a009bcdada] - -* Thu Jan 19 2023 Ales Musil - 22.12.0-14 -- northd: Add flag for CT related (#2126083) -[Upstream: 2619f6a27aca2a5925e25297f75e6a925cf1eb6a] - -* Wed Jan 18 2023 Xavier Simonart - 22.12.0-13 -- tests: Fixed load balancing system-tests -[Upstream: 1791a107debbaa474669a794b4d2a6dff4cb1dcb] - -* Wed Jan 18 2023 Xavier Simonart - 22.12.0-12 -- tests: Fixed flaky ACL fair Meters -[Upstream: f9fb0bb4de4e7cb0a02fcb0794e226e6af8e8f5c] - -* Wed Jan 18 2023 Lorenzo Bianconi - 22.12.0-11 -- northd: move hairpin stages before acl_after_lb (#2103086) -[Upstream: 3723a6d6e39dcffc502e094ccc10a8d638fa5efa] - -* Tue Jan 17 2023 Xavier Simonart - 22.12.0-10 -- controller: Fix missing first ping from pod to external (#2129283) -[Upstream: 7109f02b78f5087b5bae2885f153378e627d90f7] - -* Mon Jan 16 2023 Lorenzo Bianconi - 22.12.0-9 -- controller: use packet proto for hairpin traffic learned action if not specified (#2157846) -[Upstream: 588291528fc0568e7da402c05b596c6c855d2c5f] - -* Fri Jan 13 2023 Dumitru Ceara - 22.12.0-8 -- .ci: ovn-kubernetes: Add a "prepare" stage to allow for custom actions. -[Upstream: 29fb21e6ec0a1203e3f5b2bfff4c3ccea8df4d37] - -* Wed Jan 11 2023 Han Zhou - 22.12.0-7 -- build-aux/sodepends.py: Fix flake8 error. -[Upstream: 1fd28ef34bef9b19ca350f15bd03e10265a911dc] - -* Wed Jan 11 2023 Han Zhou - 22.12.0-6 -- build-aux/sodepends.py: Fix broken build when manpage changes. -[Upstream: 79edad8a1e547f4120ea3d20f08aafe1e40a6f65] - -* Tue Jan 10 2023 Dumitru Ceara - 22.12.0-5 -- ovn-ic: Only monitor useful tables and columns. -[Upstream: fdad33f2348f34b5fb886a5a3143d91f44021811] - -* Fri Dec 16 2022 Mark Michelson - 22.12.0-4 -- Prepare for 22.12.1. -[Upstream: 78af8b76ab30ad3e704211256c313dec67f63cb8] - diff --git a/SPECS/ovn23.03.spec b/SPECS/ovn23.03.spec new file mode 100644 index 0000000..e3ac702 --- /dev/null +++ b/SPECS/ovn23.03.spec @@ -0,0 +1,714 @@ +# Copyright (C) 2009, 2010, 2013, 2014 Nicira Networks, Inc. +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. This file is offered as-is, +# without warranty of any kind. +# +# If tests have to be skipped while building, specify the '--without check' +# option. For example: +# rpmbuild -bb --without check rhel/openvswitch-fedora.spec + +# This defines the base package name's version. + +%define pkgver 2.13 +%define pkgname ovn23.03 + +# If libcap-ng isn't available and there is no need for running OVS +# as regular user, specify the '--without libcapng' +%bcond_without libcapng + +# Enable PIE, bz#955181 +%global _hardened_build 1 + +# RHEL-7 doesn't define _rundir macro yet +# Fedora 15 onwards uses /run as _rundir +%if 0%{!?_rundir:1} +%define _rundir /run +%endif + +# Build python2 (that provides python) and python3 subpackages on Fedora +# Build only python3 (that provides python) subpackage on RHEL8 +# Build only python subpackage on RHEL7 +%if 0%{?rhel} > 7 || 0%{?fedora} +# On RHEL8 Sphinx is included in buildroot +%global external_sphinx 1 +%else +# Don't use external sphinx (RHV doesn't have optional repositories enabled) +%global external_sphinx 0 +%endif + +# We would see rpmlinit error - E: hardcoded-library-path in '% {_prefix}/lib'. +# But there is no solution to fix this. Using {_lib} macro will solve the +# rpmlink error, but will install the files in /usr/lib64/. +# OVN pacemaker ocf script file is copied in /usr/lib/ocf/resource.d/ovn/ +# and we are not sure if pacemaker looks into this path to find the +# OVN resource agent script. +%global ovnlibdir %{_prefix}/lib + +Name: %{pkgname} +Summary: Open Virtual Network support +Group: System Environment/Daemons +URL: http://www.ovn.org/ +Version: 23.03.0 +Release: 50%{?commit0:.%{date}git%{shortcommit0}}%{?dist} +Provides: openvswitch%{pkgver}-ovn-common = %{?epoch:%{epoch}:}%{version}-%{release} +Obsoletes: openvswitch%{pkgver}-ovn-common < 2.11.0-1 + +# Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the +# lib/sflow*.[ch] files are SISSL +License: ASL 2.0 and LGPLv2+ and SISSL + +# Always pull an upstream release, since this is what we rebase to. +Source: https://github.com/ovn-org/ovn/archive/v%{version}.tar.gz#/ovn-%{version}.tar.gz + +%define ovscommit 8986d4d5564401eeef3dea828b51fe8bae2cc8aa +%define ovsshortcommit 8986d4d + +Source10: https://github.com/openvswitch/ovs/archive/%{ovscommit}.tar.gz#/openvswitch-%{ovsshortcommit}.tar.gz +%define ovsdir ovs-%{ovscommit} + +%define docutilsver 0.12 +%define pygmentsver 1.4 +%define sphinxver 1.1.3 +Source100: https://pypi.io/packages/source/d/docutils/docutils-%{docutilsver}.tar.gz +Source101: https://pypi.io/packages/source/P/Pygments/Pygments-%{pygmentsver}.tar.gz +Source102: https://pypi.io/packages/source/S/Sphinx/Sphinx-%{sphinxver}.tar.gz + +Source500: configlib.sh +Source501: gen_config_group.sh +Source502: set_config.sh + +# Important: source503 is used as the actual copy file +# @TODO: this causes a warning - fix it? +Source504: arm64-armv8a-linuxapp-gcc-config +Source505: ppc_64-power8-linuxapp-gcc-config +Source506: x86_64-native-linuxapp-gcc-config + +Patch: %{pkgname}.patch + +# FIXME Sphinx is used to generate some manpages, unfortunately, on RHEL, it's +# in the -optional repository and so we can't require it directly since RHV +# doesn't have the -optional repository enabled and so TPS fails +%if %{external_sphinx} +BuildRequires: python3-sphinx +%else +# Sphinx dependencies +BuildRequires: python-devel +BuildRequires: python-setuptools +#BuildRequires: python2-docutils +BuildRequires: python-jinja2 +BuildRequires: python-nose +#BuildRequires: python2-pygments +# docutils dependencies +BuildRequires: python-imaging +# pygments dependencies +BuildRequires: python-nose +%endif + +BuildRequires: gcc gcc-c++ make +BuildRequires: autoconf automake libtool +BuildRequires: systemd-units openssl openssl-devel +BuildRequires: python3-devel python3-setuptools +BuildRequires: desktop-file-utils +BuildRequires: groff-base graphviz +BuildRequires: unbound-devel + +# make check dependencies +BuildRequires: procps-ng +%if 0%{?rhel} == 8 || 0%{?fedora} +BuildRequires: python3-pyOpenSSL +%endif +BuildRequires: tcpdump + +%if %{with libcapng} +BuildRequires: libcap-ng libcap-ng-devel +%endif + +Requires: hostname openssl iproute module-init-tools + +Requires(post): systemd-units +Requires(preun): systemd-units +Requires(postun): systemd-units + +# to skip running checks, pass --without check +%bcond_without check + +%description +OVN, the Open Virtual Network, is a system to support virtual network +abstraction. OVN complements the existing capabilities of OVS to add +native support for virtual network abstractions, such as virtual L2 and L3 +overlays and security groups. + +%package central +Summary: Open Virtual Network support +License: ASL 2.0 +Requires: %{pkgname} +Requires: firewalld-filesystem +Provides: openvswitch%{pkgver}-ovn-central = %{?epoch:%{epoch}:}%{version}-%{release} +Obsoletes: openvswitch%{pkgver}-ovn-central < 2.11.0-1 + +%description central +OVN DB servers and ovn-northd running on a central node. + +%package host +Summary: Open Virtual Network support +License: ASL 2.0 +Requires: %{pkgname} +Requires: firewalld-filesystem +Provides: openvswitch%{pkgver}-ovn-host = %{?epoch:%{epoch}:}%{version}-%{release} +Obsoletes: openvswitch%{pkgver}-ovn-host < 2.11.0-1 + +%description host +OVN controller running on each host. + +%package vtep +Summary: Open Virtual Network support +License: ASL 2.0 +Requires: %{pkgname} +Provides: openvswitch%{pkgver}-ovn-vtep = %{?epoch:%{epoch}:}%{version}-%{release} +Obsoletes: openvswitch%{pkgver}-ovn-vtep < 2.11.0-1 + +%description vtep +OVN vtep controller + +%prep +%autosetup -n ovn-%{version} -a 10 -p 1 + +%build +%if 0%{?commit0:1} +# fix the snapshot unreleased version to be the released one. +sed -i.old -e "s/^AC_INIT(openvswitch,.*,/AC_INIT(openvswitch, %{version},/" configure.ac +%endif +./boot.sh + +# OVN source code is now separate. +# Build openvswitch first. +# XXX Current openvswitch2.13 doesn't +# use "2.13.0" for version. It's a commit hash +pushd %{ovsdir} +./boot.sh +%configure \ +%if %{with libcapng} + --enable-libcapng \ +%else + --disable-libcapng \ +%endif + --enable-ssl \ + --with-pkidir=%{_sharedstatedir}/openvswitch/pki + +make %{?_smp_mflags} +popd + +# Build OVN. +# XXX OVS version needs to be updated when ovs2.13 is updated. +%configure \ + --with-ovs-source=$PWD/%{ovsdir} \ +%if %{with libcapng} + --enable-libcapng \ +%else + --disable-libcapng \ +%endif + --enable-ssl \ + --with-pkidir=%{_sharedstatedir}/openvswitch/pki + +make %{?_smp_mflags} + +%install +%make_install +install -p -D -m 0644 \ + rhel/usr_share_ovn_scripts_systemd_sysconfig.template \ + $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/ovn + +for service in ovn-controller ovn-controller-vtep ovn-northd; do + install -p -D -m 0644 \ + rhel/usr_lib_systemd_system_${service}.service \ + $RPM_BUILD_ROOT%{_unitdir}/${service}.service +done + +install -d -m 0755 $RPM_BUILD_ROOT/%{_sharedstatedir}/ovn + +install -d $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/ +install -p -m 0644 rhel/usr_lib_firewalld_services_ovn-central-firewall-service.xml \ + $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/ovn-central-firewall-service.xml +install -p -m 0644 rhel/usr_lib_firewalld_services_ovn-host-firewall-service.xml \ + $RPM_BUILD_ROOT%{ovnlibdir}/firewalld/services/ovn-host-firewall-service.xml + +install -d -m 0755 $RPM_BUILD_ROOT%{ovnlibdir}/ocf/resource.d/ovn +ln -s %{_datadir}/ovn/scripts/ovndb-servers.ocf \ + $RPM_BUILD_ROOT%{ovnlibdir}/ocf/resource.d/ovn/ovndb-servers + +install -p -D -m 0644 rhel/etc_logrotate.d_ovn \ + $RPM_BUILD_ROOT/%{_sysconfdir}/logrotate.d/ovn + +# remove unneeded files. +rm -f $RPM_BUILD_ROOT%{_bindir}/ovs* +rm -f $RPM_BUILD_ROOT%{_bindir}/vtep-ctl +rm -f $RPM_BUILD_ROOT%{_sbindir}/ovs* +rm -f $RPM_BUILD_ROOT%{_mandir}/man1/ovs* +rm -f $RPM_BUILD_ROOT%{_mandir}/man5/ovs* +rm -f $RPM_BUILD_ROOT%{_mandir}/man5/vtep* +rm -f $RPM_BUILD_ROOT%{_mandir}/man7/ovs* +rm -f $RPM_BUILD_ROOT%{_mandir}/man8/ovs* +rm -f $RPM_BUILD_ROOT%{_mandir}/man8/vtep* +rm -rf $RPM_BUILD_ROOT%{_datadir}/ovn/python +rm -f $RPM_BUILD_ROOT%{_datadir}/ovn/scripts/ovs* +rm -rf $RPM_BUILD_ROOT%{_datadir}/ovn/bugtool-plugins +rm -f $RPM_BUILD_ROOT%{_libdir}/*.a +rm -f $RPM_BUILD_ROOT%{_libdir}/*.la +rm -f $RPM_BUILD_ROOT%{_libdir}/pkgconfig/*.pc +rm -f $RPM_BUILD_ROOT%{_includedir}/ovn/* +rm -f $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d/ovs-appctl-bashcomp.bash +rm -f $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d/ovs-vsctl-bashcomp.bash +rm -rf $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/openvswitch +rm -f $RPM_BUILD_ROOT%{_datadir}/ovn/scripts/ovn-bugtool* +rm -f $RPM_BUILD_ROOT/%{_bindir}/ovn-docker-overlay-driver \ + $RPM_BUILD_ROOT/%{_bindir}/ovn-docker-underlay-driver + +%check +%if %{with check} + touch resolv.conf + export OVS_RESOLV_CONF=$(pwd)/resolv.conf + if ! make check TESTSUITEFLAGS='%{_smp_mflags}'; then + cat tests/testsuite.log + if ! make check TESTSUITEFLAGS='--recheck'; then + cat tests/testsuite.log + # Presently a test case - "2796: ovn -- ovn-controller incremental processing" + # is failing on aarch64 arch. Let's not exit for this arch + # until we figure out why it is failing. + # Test case 93: ovn.at:12105 ovn -- ACLs on Port Groups is failing + # repeatedly on s390x. This needs to be investigated. + %ifnarch aarch64 + %ifnarch ppc64le + %ifnarch s390x + exit 1 + %endif + %endif + %endif + fi + fi +%endif + +%clean +rm -rf $RPM_BUILD_ROOT + +%pre central +if [ $1 -eq 1 ] ; then + # Package install. + /bin/systemctl status ovn-northd.service >/dev/null + ovn_status=$? + rpm -ql openvswitch-ovn-central > /dev/null + if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then + # ovn-northd service is running which means old openvswitch-ovn-central + # is already installed and it will be cleaned up. So start ovn-northd + # service when posttrans central is called. + touch %{_localstatedir}/lib/rpm-state/ovn-northd + fi +fi + +%pre host +if [ $1 -eq 1 ] ; then + # Package install. + /bin/systemctl status ovn-controller.service >/dev/null + ovn_status=$? + rpm -ql openvswitch-ovn-host > /dev/null + if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then + # ovn-controller service is running which means old + # openvswitch-ovn-host is installed and it will be cleaned up. So + # start ovn-controller service when posttrans host is called. + touch %{_localstatedir}/lib/rpm-state/ovn-controller + fi +fi + +%pre vtep +if [ $1 -eq 1 ] ; then + # Package install. + /bin/systemctl status ovn-controller-vtep.service >/dev/null + ovn_status=$? + rpm -ql openvswitch-ovn-vtep > /dev/null + if [[ "$?" = "0" && "$ovn_status" = "0" ]]; then + # ovn-controller-vtep service is running which means old + # openvswitch-ovn-vtep is installed and it will be cleaned up. So + # start ovn-controller-vtep service when posttrans host is called. + touch %{_localstatedir}/lib/rpm-state/ovn-controller-vtep + fi +fi + +%preun central +%if 0%{?systemd_preun:1} + %systemd_preun ovn-northd.service +%else + if [ $1 -eq 0 ] ; then + # Package removal, not upgrade + /bin/systemctl --no-reload disable ovn-northd.service >/dev/null 2>&1 || : + /bin/systemctl stop ovn-northd.service >/dev/null 2>&1 || : + fi +%endif + +%preun host +%if 0%{?systemd_preun:1} + %systemd_preun ovn-controller.service +%else + if [ $1 -eq 0 ] ; then + # Package removal, not upgrade + /bin/systemctl --no-reload disable ovn-controller.service >/dev/null 2>&1 || : + /bin/systemctl stop ovn-controller.service >/dev/null 2>&1 || : + fi +%endif + +%preun vtep +%if 0%{?systemd_preun:1} + %systemd_preun ovn-controller-vtep.service +%else + if [ $1 -eq 0 ] ; then + # Package removal, not upgrade + /bin/systemctl --no-reload disable ovn-controller-vtep.service >/dev/null 2>&1 || : + /bin/systemctl stop ovn-controller-vtep.service >/dev/null 2>&1 || : + fi +%endif + +%post +%if %{with libcapng} +if [ $1 -eq 1 ]; then + sed -i 's:^#OVN_USER_ID=:OVN_USER_ID=:' %{_sysconfdir}/sysconfig/ovn + sed -i 's:\(.*su\).*:\1 openvswitch openvswitch:' %{_sysconfdir}/logrotate.d/ovn +fi +%endif + +%post central +%if 0%{?systemd_post:1} + %systemd_post ovn-northd.service +%else + # Package install, not upgrade + if [ $1 -eq 1 ]; then + /bin/systemctl daemon-reload >dev/null || : + fi +%endif + +%post host +%if 0%{?systemd_post:1} + %systemd_post ovn-controller.service +%else + # Package install, not upgrade + if [ $1 -eq 1 ]; then + /bin/systemctl daemon-reload >dev/null || : + fi +%endif + +%post vtep +%if 0%{?systemd_post:1} + %systemd_post ovn-controller-vtep.service +%else + # Package install, not upgrade + if [ $1 -eq 1 ]; then + /bin/systemctl daemon-reload >dev/null || : + fi +%endif + +%postun + +%postun central +%if 0%{?systemd_postun_with_restart:1} + %systemd_postun_with_restart ovn-northd.service +%else + /bin/systemctl daemon-reload >/dev/null 2>&1 || : + if [ "$1" -ge "1" ] ; then + # Package upgrade, not uninstall + /bin/systemctl try-restart ovn-northd.service >/dev/null 2>&1 || : + fi +%endif + +%postun host +%if 0%{?systemd_postun_with_restart:1} + %systemd_postun_with_restart ovn-controller.service +%else + /bin/systemctl daemon-reload >/dev/null 2>&1 || : + if [ "$1" -ge "1" ] ; then + # Package upgrade, not uninstall + /bin/systemctl try-restart ovn-controller.service >/dev/null 2>&1 || : + fi +%endif + +%postun vtep +%if 0%{?systemd_postun_with_restart:1} + %systemd_postun_with_restart ovn-controller-vtep.service +%else + /bin/systemctl daemon-reload >/dev/null 2>&1 || : + if [ "$1" -ge "1" ] ; then + # Package upgrade, not uninstall + /bin/systemctl try-restart ovn-controller-vtep.service >/dev/null 2>&1 || : + fi +%endif + +%posttrans central +if [ $1 -eq 1 ]; then + # Package install, not upgrade + if [ -e %{_localstatedir}/lib/rpm-state/ovn-northd ]; then + rm %{_localstatedir}/lib/rpm-state/ovn-northd + /bin/systemctl start ovn-northd.service >/dev/null 2>&1 || : + fi +fi + + +%posttrans host +if [ $1 -eq 1 ]; then + # Package install, not upgrade + if [ -e %{_localstatedir}/lib/rpm-state/ovn-controller ]; then + rm %{_localstatedir}/lib/rpm-state/ovn-controller + /bin/systemctl start ovn-controller.service >/dev/null 2>&1 || : + fi +fi + +%posttrans vtep +if [ $1 -eq 1 ]; then + # Package install, not upgrade + if [ -e %{_localstatedir}/lib/rpm-state/ovn-controller-vtep ]; then + rm %{_localstatedir}/lib/rpm-state/ovn-controller-vtep + /bin/systemctl start ovn-controller-vtep.service >/dev/null 2>&1 || : + fi +fi + +%files +%{_bindir}/ovn-nbctl +%{_bindir}/ovn-sbctl +%{_bindir}/ovn-trace +%{_bindir}/ovn-detrace +%{_bindir}/ovn_detrace.py +%{_bindir}/ovn-appctl +%{_bindir}/ovn-ic-nbctl +%{_bindir}/ovn-ic-sbctl +%dir %{_datadir}/ovn/ +%dir %{_datadir}/ovn/scripts/ +%{_datadir}/ovn/scripts/ovn-ctl +%{_datadir}/ovn/scripts/ovn-lib +%{_datadir}/ovn/scripts/ovndb-servers.ocf +%{_mandir}/man8/ovn-ctl.8* +%{_mandir}/man8/ovn-appctl.8* +%{_mandir}/man8/ovn-nbctl.8* +%{_mandir}/man8/ovn-ic-nbctl.8* +%{_mandir}/man8/ovn-trace.8* +%{_mandir}/man1/ovn-detrace.1* +%{_mandir}/man7/ovn-architecture.7* +%{_mandir}/man8/ovn-sbctl.8* +%{_mandir}/man8/ovn-ic-sbctl.8* +%{_mandir}/man5/ovn-nb.5* +%{_mandir}/man5/ovn-ic-nb.5* +%{_mandir}/man5/ovn-sb.5* +%{_mandir}/man5/ovn-ic-sb.5* +%dir %{ovnlibdir}/ocf/resource.d/ovn/ +%{ovnlibdir}/ocf/resource.d/ovn/ovndb-servers +%config(noreplace) %verify(not md5 size mtime) %{_sysconfdir}/logrotate.d/ovn +%config(noreplace) %verify(not md5 size mtime) %{_sysconfdir}/sysconfig/ovn + +%files central +%{_bindir}/ovn-northd +%{_bindir}/ovn-ic +%{_mandir}/man8/ovn-northd.8* +%{_mandir}/man8/ovn-ic.8* +%{_datadir}/ovn/ovn-nb.ovsschema +%{_datadir}/ovn/ovn-ic-nb.ovsschema +%{_datadir}/ovn/ovn-sb.ovsschema +%{_datadir}/ovn/ovn-ic-sb.ovsschema +%{_unitdir}/ovn-northd.service +%{ovnlibdir}/firewalld/services/ovn-central-firewall-service.xml + +%files host +%{_bindir}/ovn-controller +%{_mandir}/man8/ovn-controller.8* +%{_unitdir}/ovn-controller.service +%{ovnlibdir}/firewalld/services/ovn-host-firewall-service.xml + +%files vtep +%{_bindir}/ovn-controller-vtep +%{_mandir}/man8/ovn-controller-vtep.8* +%{_unitdir}/ovn-controller-vtep.service + +%changelog +* Fri May 26 2023 Han Zhou - 23.03.0-50 +- ovn-controller.c: Fix assertion failure during address set update. +[Upstream: 777786f38a61041898891ccbb3f139b0552e5794] + +* Fri May 19 2023 Mark Michelson - 23.03.0-49 +- Pass localnet traffic through CT when a LB is configured. (#2164652) +[Upstream: 2449608303464d62ff5b1a89e20e476248d1e82b] + +* Fri May 19 2023 Mark Michelson - 23.03.0-48 +- tests: Use stricter IP match for FORMAT_CT. +[Upstream: a1d8ebd306021844646629c42bd638203399c568] + +* Wed May 17 2023 Ales Musil - 23.03.0-47 +- tests: Fix flakiness of policy based routing on slower systems +[Upstream: bb22fe9c4591dc96d98bf2c2c3f629efb5721757] + +* Wed May 17 2023 Vladislav Odintsov - 23.03.0-46 +- ovn-controller docs: fix typo in ovn-monitor-all description +[Upstream: 0ba1609d6426cd779f48cb5a97e63c0a7811dc03] + +* Wed May 10 2023 Ales Musil - 23.03.0-45 +- system-tests: Replace use of ADD_INT with ADD_VETH +[Upstream: c2f36b530613728100b1dbdf7f967c4a87053155] + +* Wed May 10 2023 Lorenzo Bianconi - 23.03.0-44 +- controller: fix possible unaligned accesses in DHCPv6 code +[Upstream: 080cbcd95d3d065524272f5f1d0bed11df35a9d4] + +* Tue May 09 2023 Lorenzo Bianconi - 23.03.0-43 +- mirror: fix ovn mirror support with IPv6 (#2168119) +[Upstream: 5255303229f4da0c1478656597c774510ceda4e9] + +* Mon May 08 2023 Xavier Simonart - 23.03.0-42 +- ovn-controller: fixed port not always set down when unbinding interface (#2150905) +[Upstream: 39930c0254bc8758b5722e0f2c3a7fdc43256888] + +* Mon May 08 2023 Xavier Simonart - 23.03.0-41 +- ovn-controller: fixed ovn-installed not always properly added or removed. +[Upstream: 395eac485b871ef75bb0b5f29b09ebd1cb877ca8] + +* Mon May 08 2023 Wei Li - 23.03.0-40 +- documentation: packets that arrive from other chassis resubmit to table 38 +[Upstream: 4ad402df2870c44234945b462345bfcb0c95b6f6] + +* Mon May 08 2023 Tao Liu - 23.03.0-39 +- northd: fix use-after-free after lrp destroyed +[Upstream: fd0111e59c6a78acf70dd47e10e724210c2e94ea] + +* Mon May 08 2023 Ihar Hrachyshka - 23.03.0-38 +- docs: document that vxlan is supported for encap type +[Upstream: 31bc347255a9206b29dc3f9af14c8af75ea9600e] + +* Mon May 08 2023 Xavier Simonart - 23.03.0-37 +- tests: Fixed flaky lr multiple gw ports +[Upstream: 94dea8bb6bba439de673fa4fa72e3fa3f8c44593] + +* Mon May 08 2023 Xavier Simonart - 23.03.0-36 +- Fix test "load-balancing" +[Upstream: bfdfb9a0565b2f21f59120b360db1aa59b24f96d] + +* Fri May 05 2023 Dumitru Ceara - 23.03.0-35 +- tests: Retry inject-pkt in case ovn-controller is still busy. +[Upstream: d6cad0cc05f752a83f72c82881a76642301125b9] + +* Tue May 02 2023 wangchuanlei - 23.03.0-34 +- pinctrl: fix restart of controller when bfd min_tx is too low. +[Upstream: 77d0ff0dace95ce6c8453c2b95f65d18892133b6] + +* Tue May 02 2023 Ales Musil - 23.03.0-33 +- ovn-nbctl: Fix unhandled NULL return from normalize_prefix_str +[Upstream: 86ceec393a9b776990bb24625bf9ca13ce9dfe05] + +* Mon May 01 2023 Xavier Simonart - 23.03.0-32 +- tests: decrease risk of flaky failures of ovn -- CoPP system test +[Upstream: b81229835436b63a593e0e6a55bb639309101592] + +* Mon May 01 2023 Xavier Simonart - 23.03.0-31 +- tests: check arguments count of OVS_WAIT_UNTIL +[Upstream: 352c584c403ce914b59e3c3c95028949ec3ede05] + +* Mon May 01 2023 Xavier Simonart - 23.03.0-30 +- tests: Fixed wrong usage of OVS_WAIT_UNTIL +[Upstream: b88d8bbba3ba59ee0a3c2d3fb62cab748e1b59dc] + +* Mon May 01 2023 Xavier Simonart - 23.03.0-29 +- tests: Fixed "1 LR with HA distributed router gateway port" +[Upstream: 1758332a51766231e74479302ee8efdfc07bf33c] + +* Fri Apr 21 2023 Mark Michelson - 23.03.0-28 +- tests: Skip "daemon ssl files change" when SSL is disabled. +[Upstream: 3d231640d852bc4c7b49d17de80ba747bebe8817] + +* Wed Apr 19 2023 Ihar Hrachyshka - 23.03.0-27 +- Omit ACLs for nd || nd_ra || nd_rs || mldv1 || mldv2 (#2149731) +[Upstream: 6e6cc27bdb9735a6461b53771b3969a2ca230cab] + +* Wed Apr 19 2023 Ihar Hrachyshka - 23.03.0-26 +- tests: define fmt_pkt function to construct packets with scapy +[Upstream: b797e5dbd955ee61d503bb38dade490957bce563] + +* Wed Apr 19 2023 Ales Musil - 23.03.0-25 +- controller: Prevent race in tunnel cleanup +[Upstream: 40befbb1d508db48f894cb190637ee33cccf0977] + +* Thu Apr 13 2023 Han Zhou - 23.03.0-24 +- northd.c: Avoid sending ICMP time exceeded for multicast packets. +[Upstream: a38a5df4a49ddf678d6a50de39b613b8f0305e26] + +* Thu Apr 13 2023 Han Zhou - 23.03.0-23 +- northd.c: TTL discard flow should support for both ipv4 and ipv6. +[Upstream: d42d070bd2598b72c13d2a67209d368acc8128b8] + +* Tue Apr 11 2023 Ales Musil - 23.03.0-22 +- northd: Update the is_stateless helper for router nat +[Upstream: 99b42566998c9e9b952cdfe3f8435e8bd79eca43] + +* Tue Apr 11 2023 Eelco Chaudron - 23.03.0-21 +- ci: Add arping package to run floating IP tests. +[Upstream: 825164cd4164e9c9bf5c66ebe00e147f1e2ac1fd] + +* Tue Apr 11 2023 Ales Musil - 23.03.0-20 +- controller: Clear tunnels from old integration bridge (#2173635) +[Upstream: 8481abcc04fee5e0ecd881e599be178625ad1522] + +* Tue Apr 11 2023 Lorenzo Bianconi - 23.03.0-19 +- northd: revert ct.inv drop flows +[Upstream: 04d7552479736bd2da84dd5d2be146fa4a51e3e6] + +* Thu Apr 06 2023 Lorenzo Bianconi - 23.03.0-18 +- northd: take into account qos_min_rate in port_has_qos_params +[Upstream: 0bbcfb52f0248d839e413acaf2b116bb7b1c4db6] + +* Thu Mar 30 2023 Ales Musil - 23.03.0-17 +- system-tests: Reduce flakiness of netcat UDP clients +[Upstream: 6c2d80c5bb6a2cd7c353b796a7d46b3962a06c9f] + +* Tue Mar 28 2023 Dumitru Ceara - 23.03.0-16 +- Revert "DOWNSTREAM: Forcefully disable backend conntrack flushing." +[Upstream: 8c98303437610a32faff8c0e7d8eff419b40619e] + +* Tue Mar 28 2023 Xavier Simonart - 23.03.0-15 +- northd: prevents sending packet to conntrack for router ports (#2062431) +[Upstream: 2bab96e899b5da5ae0c3b24bd04ece93d1339824] + +* Tue Mar 28 2023 Dumitru Ceara - 23.03.0-14 +- lb: Allow IPv6 template LBs to use explicit backends. +[Upstream: d01fdfdb2c97222cf326c8ab5579f670ded6e3cb] + +* Tue Mar 28 2023 Lorenzo Bianconi - 23.03.0-13 +- controller: lflow: do not use tcp as default IP protocol for ct_snat_to_vip action (#2157846) +[Upstream: 6a16c741e5a10a817ca8251898f48bf9eeb971f5] + +* Tue Mar 28 2023 Ales Musil - 23.03.0-12 +- northd: Drop packets for LBs with no backends (#2177173) +[Upstream: 77384b7fe3f7d3260fd2f94a3bd75b8ca79f56ae] + +* Mon Mar 27 2023 Ales Musil - 23.03.0-11 +- northd: Use generic ct.est flows for LR LBs (#2172048 2170885) +[Upstream: 81eaa98bbb608bda320abfa0122ba073de6597d7] + +* Thu Mar 23 2023 Lorenzo Bianconi - 23.03.0-10 +- northd: drop ct.inv packets in post snat and lb_aff_learn stages (#2160685) +[Upstream: 0af110c400cc29bb037172cdfd674794716771df] + +* Mon Mar 20 2023 Ales Musil - 23.03.0-9 +- controller: Add config option per LB to enable/disable CT flush (#2178962) +[Upstream: 89fc85fa7f2b00f404ec5aef4ce8f2236474fbab] + +* Thu Mar 16 2023 Dumitru Ceara - 23.03.0-8 +- DOWNSTREAM: Forcefully disable backend conntrack flushing. (#2178962) +[Upstream: b7522be8bf28534cc422234e8d9484b9ef4220d9] + +* Thu Mar 16 2023 Dumitru Ceara - 23.03.0-7 +- northd: Ignore remote chassis when computing the supported feature set. +[Upstream: 80b7e48a877abd337eb54b9bb9c7b4280aa9ff74] + +* Wed Mar 08 2023 Ilya Maximets - 23.03.0-6 +- controller: Use ofctrl_add_flow for CT SNAT hairpin flows. +[Upstream: 888215e2164b476462f12d206a3d734958ef79e2] + +* Wed Mar 08 2023 Vladislav Odintsov - 23.03.0-5 +- rhel: pass options to stop daemon command in systemd units +[Upstream: ed7095613abf3d36cbcf347e1238b84e6843eaf1] + +* Fri Mar 03 2023 Mark Michelson - 23.03.0-4 +- Prepare for 23.03.1. +[Upstream: e98ea52f12de2a7d6a9a7547b6b0a493a78f0fed] +