diff --git a/ovn.patch b/ovn.patch new file mode 100644 index 0000000..725dbdd --- /dev/null +++ b/ovn.patch @@ -0,0 +1,2739 @@ +diff --git a/.ci/ovn-kubernetes/Dockerfile b/.ci/ovn-kubernetes/Dockerfile +index e74b620be..7edf86a13 100644 +--- a/.ci/ovn-kubernetes/Dockerfile ++++ b/.ci/ovn-kubernetes/Dockerfile +@@ -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..8a7815f1d 100644 +--- a/.github/workflows/ovn-kubernetes.yml ++++ b/.github/workflows/ovn-kubernetes.yml +@@ -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.h b/lib/ovn-util.h +index 809ff1d36..4b3d501b2 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); +diff --git a/northd/northd.c b/northd/northd.c +index 841ae9cc5..2cb6e8054 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" +@@ -446,6 +447,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 +4420,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 +4859,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 +6768,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 +6785,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 +6808,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). */ +@@ -8973,9 +8996,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( +@@ -10471,9 +10496,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 +10511,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 +10533,11 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, + } + + if (lb->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), +- drop ? "" : "; skip_snat);"); ++ ds_cstr(action), skip_snat); + skip_snat_est_action = xasprintf("flags.skip_snat_for_lb = 1; " + "next;"); + } +@@ -10641,9 +10670,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); + ++ 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), +- drop ? "" : "; force_snat);"); ++ 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 +10929,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 +14239,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 +14270,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 +14361,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 +14514,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 +14631,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 +16123,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/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..ab06d0406 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;) +@@ -7865,8 +7873,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 +7895,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 +7917,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 +8445,104 @@ 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);) ++]) ++ ++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 ++]) +diff --git a/tests/ovn.at b/tests/ovn.at +index ad2014de6..aa7674b47 100644 +--- a/tests/ovn.at ++++ b/tests/ovn.at +@@ -28416,24 +28416,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 +28462,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 +28478,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 +28500,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 +28518,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..1d54ddb31 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 +@@ -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-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/ovn.spec b/ovn.spec index fff065d..f6718f3 100644 --- a/ovn.spec +++ b/ovn.spec @@ -46,7 +46,7 @@ Name: ovn Summary: Open Virtual Network support URL: http://www.openvswitch.org/ Version: 22.12.0 -Release: 1%{?commit0:.%{date}git%{shortcommit0}}%{?dist} +Release: 25%{?commit0:.%{date}git%{shortcommit0}}%{?dist} Obsoletes: openvswitch-ovn-common < %{?epoch_ovs:%{epoch_ovs}:}2.11.0-8 Provides: openvswitch-ovn-common = %{?epoch:%{epoch}:}%{version}-%{release} @@ -67,7 +67,7 @@ Source10: https://github.com/openvswitch/ovs/archive/%{ovscommit}.tar.gz#/openvs %define ovsdir ovs-%{ovscommit} # ovn-patches -# Patch: ovn.patch +Patch: ovn.patch # OpenvSwitch backports (400-) if required. # Address crpto policy for fedora @@ -438,6 +438,73 @@ fi %{_unitdir}/ovn-controller-vtep.service %changelog +* Thu Feb 16 2023 Numan Siddique - 22.12.0-25 +- Sync to upstream OVN branch-22.12. Below are the commits +since last update (22.12.0-1) + +- lb: northd: Properly format IPv6 SB load balancer VIPs. +[Upstream: 7053ae61267ebcb282d5ef18b5bd8f2f6c6c37e0] + +- system-test: Use OVS_WAIT_UNTIL for tcpdump start instead fo sleep +[Upstream: d5273f929513458a569cdfb297bffd9922d44c01] + +- docs: fix the max number of ports per network for vxlan +[Upstream: 4dfa4ba431ab634b6068f27e886a4d403d589c87] + +- ovn-nbctl: Fix documentation typo (#2168009) +[Upstream: 0c44d7dbf4a013f08c79d5818e89a8f55ecd09e0] + +- northd: do not create flows for reserved multicast IPv6 groups (#2154930) +[Upstream: 61e030ed59c2d2a1029866dce6769428e0abbc0c] + +- northd.c: Validate port type to avoid unexpected behavior. +[Upstream: b67009fdb6312e95367183c65b439fd3b7a288bf] + +- Add the metalLB install flag for CI actions +[Upstream: 65990b8398e8e7ff29c6d7e9903fd0cf7ef64965] + +- ovn-trace: Use the original ovnact for execute_load +[Upstream: 4c78bef966927f4083b601a6a4f5fc76a839fd1a] + +- northd: Add logical flows to allow rpl/rel traffic in acl_after_lb stage. (#1947807) +[Upstream: d6914efd53ac28a6e3da6e65f9e026674f05dc4c] + +- ovn-controller: Fix initial requested SNAT zone assignment. (#2160403) +[Upstream: 17f1e9e0148e298b6ec525d5d6b149082a864dca] + +- northd: Drop packets destined to router owned NAT IP for DGP. +[Upstream: 481f25b784896eec07fedc77631992a009bcdada] + +- northd: Add flag for CT related (#2126083) +[Upstream: 2619f6a27aca2a5925e25297f75e6a925cf1eb6a] + +- tests: Fixed load balancing system-tests +[Upstream: 1791a107debbaa474669a794b4d2a6dff4cb1dcb] + +- tests: Fixed flaky ACL fair Meters +[Upstream: f9fb0bb4de4e7cb0a02fcb0794e226e6af8e8f5c] + +- northd: move hairpin stages before acl_after_lb (#2103086) +[Upstream: 3723a6d6e39dcffc502e094ccc10a8d638fa5efa] + +- controller: Fix missing first ping from pod to external (#2129283) +[Upstream: 7109f02b78f5087b5bae2885f153378e627d90f7] + +- controller: use packet proto for hairpin traffic learned action if not specified (#2157846) +[Upstream: 588291528fc0568e7da402c05b596c6c855d2c5f] + +- .ci: ovn-kubernetes: Add a "prepare" stage to allow for custom actions. +[Upstream: 29fb21e6ec0a1203e3f5b2bfff4c3ccea8df4d37] + +- build-aux/sodepends.py: Fix flake8 error. +[Upstream: 1fd28ef34bef9b19ca350f15bd03e10265a911dc] + +- build-aux/sodepends.py: Fix broken build when manpage changes. +[Upstream: 79edad8a1e547f4120ea3d20f08aafe1e40a6f65] + +- ovn-ic: Only monitor useful tables and columns. +[Upstream: fdad33f2348f34b5fb886a5a3143d91f44021811] + * Thu Jan 19 2023 Fedora Release Engineering - 22.12.0-1 - Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild