61e211
diff --git a/NEWS b/NEWS
61e211
index ef6a99fed..0392d8d23 100644
61e211
--- a/NEWS
61e211
+++ b/NEWS
61e211
@@ -1,3 +1,6 @@
61e211
+OVN v22.09.1 - xx xxx xxxx
61e211
+--------------------------
61e211
+
61e211
 OVN v22.09.0 - 16 Sep 2022
61e211
 --------------------------
61e211
   - ovn-controller: Add configuration knob, through OVS external-id
61e211
diff --git a/configure.ac b/configure.ac
61e211
index 765aacb17..c79d79ffe 100644
61e211
--- a/configure.ac
61e211
+++ b/configure.ac
61e211
@@ -13,7 +13,7 @@
61e211
 # limitations under the License.
61e211
 
61e211
 AC_PREREQ(2.63)
61e211
-AC_INIT(ovn, 22.09.0, bugs@openvswitch.org)
61e211
+AC_INIT(ovn, 22.09.1, bugs@openvswitch.org)
61e211
 AC_CONFIG_MACRO_DIR([m4])
61e211
 AC_CONFIG_AUX_DIR([build-aux])
61e211
 AC_CONFIG_HEADERS([config.h])
61e211
diff --git a/controller/binding.c b/controller/binding.c
61e211
index 8f6b4b19d..c3d2b2e42 100644
61e211
--- a/controller/binding.c
61e211
+++ b/controller/binding.c
61e211
@@ -2666,7 +2666,7 @@ consider_patch_port_for_local_datapaths(const struct sbrec_port_binding *pb,
61e211
                 get_local_datapath(b_ctx_out->local_datapaths,
61e211
                                    peer->datapath->tunnel_key);
61e211
         }
61e211
-        if (peer_ld && need_add_patch_peer_to_local(
61e211
+        if (peer_ld && need_add_peer_to_local(
61e211
                 b_ctx_in->sbrec_port_binding_by_name, peer,
61e211
                 b_ctx_in->chassis_rec)) {
61e211
             add_local_datapath(
61e211
@@ -2681,7 +2681,7 @@ consider_patch_port_for_local_datapaths(const struct sbrec_port_binding *pb,
61e211
         /* Add the peer datapath to the local datapaths if it's
61e211
          * not present yet.
61e211
          */
61e211
-        if (need_add_patch_peer_to_local(
61e211
+        if (need_add_peer_to_local(
61e211
                 b_ctx_in->sbrec_port_binding_by_name, pb,
61e211
                 b_ctx_in->chassis_rec)) {
61e211
             add_local_datapath_peer_port(
61e211
diff --git a/controller/local_data.c b/controller/local_data.c
61e211
index 9eee568d1..035f10fff 100644
61e211
--- a/controller/local_data.c
61e211
+++ b/controller/local_data.c
61e211
@@ -115,14 +115,19 @@ local_datapath_destroy(struct local_datapath *ld)
61e211
     free(ld);
61e211
 }
61e211
 
61e211
-/* Checks if pb is a patch port and the peer datapath should be added to local
61e211
- * datapaths. */
61e211
+/* Checks if pb is running on local gw router or pb is a patch port
61e211
+ * and the peer datapath should be added to local datapaths. */
61e211
 bool
61e211
-need_add_patch_peer_to_local(
61e211
+need_add_peer_to_local(
61e211
     struct ovsdb_idl_index *sbrec_port_binding_by_name,
61e211
     const struct sbrec_port_binding *pb,
61e211
     const struct sbrec_chassis *chassis)
61e211
 {
61e211
+    /* This port is running on local gw router. */
61e211
+    if (!strcmp(pb->type, "l3gateway") && pb->chassis == chassis) {
61e211
+        return true;
61e211
+    }
61e211
+
61e211
     /* If it is not a patch port, no peer to add. */
61e211
     if (strcmp(pb->type, "patch")) {
61e211
         return false;
61e211
@@ -571,7 +576,7 @@ add_local_datapath__(struct ovsdb_idl_index *sbrec_datapath_binding_by_key,
61e211
                                             peer_name);
61e211
 
61e211
                 if (peer && peer->datapath) {
61e211
-                    if (need_add_patch_peer_to_local(
61e211
+                    if (need_add_peer_to_local(
61e211
                             sbrec_port_binding_by_name, pb, chassis)) {
61e211
                         struct local_datapath *peer_ld =
61e211
                             add_local_datapath__(sbrec_datapath_binding_by_key,
61e211
diff --git a/controller/local_data.h b/controller/local_data.h
61e211
index d898c8aa5..b5429eb58 100644
61e211
--- a/controller/local_data.h
61e211
+++ b/controller/local_data.h
61e211
@@ -66,7 +66,7 @@ struct local_datapath *local_datapath_alloc(
61e211
 struct local_datapath *get_local_datapath(const struct hmap *,
61e211
                                           uint32_t tunnel_key);
61e211
 bool
61e211
-need_add_patch_peer_to_local(
61e211
+need_add_peer_to_local(
61e211
     struct ovsdb_idl_index *sbrec_port_binding_by_name,
61e211
     const struct sbrec_port_binding *,
61e211
     const struct sbrec_chassis *);
61e211
diff --git a/controller/physical.c b/controller/physical.c
61e211
index f3c8bddce..705146316 100644
61e211
--- a/controller/physical.c
61e211
+++ b/controller/physical.c
61e211
@@ -803,6 +803,14 @@ put_replace_router_port_mac_flows(struct ovsdb_idl_index
61e211
 
61e211
         ofpact_put_OUTPUT(ofpacts_p)->port = ofport;
61e211
 
61e211
+        /* Replace the MAC back and strip vlan. In case of l2 flooding
61e211
+         * traffic (ARP/ND) we need to restore previous state so other ports
61e211
+         * do not receive the traffic tagged and with wrong MAC. */
61e211
+        ofpact_put_SET_ETH_SRC(ofpacts_p)->mac = router_port_mac;
61e211
+        if (tag) {
61e211
+            ofpact_put_STRIP_VLAN(ofpacts_p);
61e211
+        }
61e211
+
61e211
         ofctrl_add_flow(flow_table, OFTABLE_LOG_TO_PHY, 150,
61e211
                         localnet_port->header_.uuid.parts[0],
61e211
                         &match, ofpacts_p, &localnet_port->header_.uuid);
61e211
diff --git a/controller/pinctrl.c b/controller/pinctrl.c
61e211
index 3f5d0af79..1e4230ed3 100644
61e211
--- a/controller/pinctrl.c
61e211
+++ b/controller/pinctrl.c
61e211
@@ -4378,7 +4378,7 @@ run_buffered_binding(struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
61e211
         const struct sbrec_port_binding *pb;
61e211
         SBREC_PORT_BINDING_FOR_EACH_EQUAL (pb, target,
61e211
                                            sbrec_port_binding_by_datapath) {
61e211
-            if (strcmp(pb->type, "patch")) {
61e211
+            if (strcmp(pb->type, "patch") && strcmp(pb->type, "l3gateway")) {
61e211
                 continue;
61e211
             }
61e211
             struct buffered_packets *cur_qp;
61e211
diff --git a/debian/changelog b/debian/changelog
61e211
index 267e12baa..5ed83900b 100644
61e211
--- a/debian/changelog
61e211
+++ b/debian/changelog
61e211
@@ -1,3 +1,9 @@
61e211
+OVN (22.09.1-1) unstable; urgency=low
61e211
+   [ OVN team ]
61e211
+   * New upstream version
61e211
+
61e211
+ -- OVN team <dev@openvswitch.org>  Fri, 16 Sep 2022 13:54:11 -0400
61e211
+
61e211
 ovn (22.09.0-1) unstable; urgency=low
61e211
 
61e211
    * New upstream version
61e211
diff --git a/northd/northd.c b/northd/northd.c
61e211
index 84440a47f..a7b1c6404 100644
61e211
--- a/northd/northd.c
61e211
+++ b/northd/northd.c
61e211
@@ -1040,7 +1040,16 @@ init_mcast_info_for_switch_datapath(struct ovn_datapath *od)
61e211
     mcast_sw_info->query_max_response =
61e211
         smap_get_ullong(&od->nbs->other_config, "mcast_query_max_response",
61e211
                         OVN_MCAST_DEFAULT_QUERY_MAX_RESPONSE_S);
61e211
+}
61e211
 
61e211
+static void
61e211
+init_mcast_flow_count(struct ovn_datapath *od)
61e211
+{
61e211
+    if (od->nbr) {
61e211
+        return;
61e211
+    }
61e211
+
61e211
+    struct mcast_switch_info *mcast_sw_info = &od->mcast_info.sw;
61e211
     mcast_sw_info->active_v4_flows = ATOMIC_VAR_INIT(0);
61e211
     mcast_sw_info->active_v6_flows = ATOMIC_VAR_INIT(0);
61e211
 }
61e211
@@ -8451,6 +8460,10 @@ build_lswitch_ip_mcast_igmp_mld(struct ovn_igmp_group *igmp_group,
61e211
             if (atomic_compare_exchange_strong(
61e211
                         &mcast_sw_info->active_v4_flows, &table_size,
61e211
                         mcast_sw_info->table_size)) {
61e211
+                static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
61e211
+
61e211
+                VLOG_INFO_RL(&rl, "Too many active mcast flows: %"PRIu64,
61e211
+                             mcast_sw_info->active_v4_flows);
61e211
                 return;
61e211
             }
61e211
             atomic_add(&mcast_sw_info->active_v4_flows, 1, &dummy);
61e211
@@ -13633,7 +13646,8 @@ static void
61e211
 build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows,
61e211
                                 const struct hmap *ports, struct ds *match,
61e211
                                 struct ds *actions,
61e211
-                                const struct shash *meter_groups)
61e211
+                                const struct shash *meter_groups,
61e211
+                                bool ct_lb_mark)
61e211
 {
61e211
     if (!od->nbr) {
61e211
         return;
61e211
@@ -13827,6 +13841,26 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows,
61e211
         }
61e211
     }
61e211
 
61e211
+    if (od->nbr->n_nat) {
61e211
+        ds_clear(match);
61e211
+        const char *ct_natted = ct_lb_mark ?
61e211
+                                "ct_mark.natted" :
61e211
+                                "ct_label.natted";
61e211
+        ds_put_format(match, "ip && %s == 1", ct_natted);
61e211
+        /* This flow is unique since it is in the egress pipeline but checks
61e211
+         * the value of ct_label.natted, which would have been set in the
61e211
+         * ingress pipeline. If a change is ever introduced that clears or
61e211
+         * otherwise invalidates the ct_label between the ingress and egress
61e211
+         * pipelines, then an alternative will need to be devised.
61e211
+         */
61e211
+        ds_clear(actions);
61e211
+        ds_put_cstr(actions, REGBIT_DST_NAT_IP_LOCAL" = 1; next;");
61e211
+        ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_CHECK_DNAT_LOCAL,
61e211
+                                50, ds_cstr(match), ds_cstr(actions),
61e211
+                                &od->nbr->header_);
61e211
+
61e211
+    }
61e211
+
61e211
     /* Handle force SNAT options set in the gateway router. */
61e211
     if (od->is_gw_router) {
61e211
         if (dnat_force_snat_ip) {
61e211
@@ -13925,7 +13959,8 @@ build_lswitch_and_lrouter_iterate_by_od(struct ovn_datapath *od,
61e211
     build_misc_local_traffic_drop_flows_for_lrouter(od, lsi->lflows);
61e211
     build_lrouter_arp_nd_for_datapath(od, lsi->lflows, lsi->meter_groups);
61e211
     build_lrouter_nat_defrag_and_lb(od, lsi->lflows, lsi->ports, &lsi->match,
61e211
-                                    &lsi->actions, lsi->meter_groups);
61e211
+                                    &lsi->actions, lsi->meter_groups,
61e211
+                                    lsi->features->ct_no_masked_label);
61e211
 }
61e211
 
61e211
 /* Helper function to combine all lflow generation which is iterated by port.
61e211
@@ -15148,6 +15183,11 @@ build_mcast_groups(struct lflow_input *input_data,
61e211
 
61e211
     hmap_init(mcast_groups);
61e211
     hmap_init(igmp_groups);
61e211
+    struct ovn_datapath *od;
61e211
+
61e211
+    HMAP_FOR_EACH (od, key_node, datapaths) {
61e211
+        init_mcast_flow_count(od);
61e211
+    }
61e211
 
61e211
     HMAP_FOR_EACH (op, key_node, ports) {
61e211
         if (op->nbrp && lrport_is_enabled(op->nbrp)) {
61e211
@@ -15205,8 +15245,7 @@ build_mcast_groups(struct lflow_input *input_data,
61e211
         }
61e211
 
61e211
         /* If the datapath value is stale, purge the group. */
61e211
-        struct ovn_datapath *od =
61e211
-            ovn_datapath_from_sbrec(datapaths, sb_igmp->datapath);
61e211
+        od = ovn_datapath_from_sbrec(datapaths, sb_igmp->datapath);
61e211
 
61e211
         if (!od || ovn_datapath_is_stale(od)) {
61e211
             sbrec_igmp_group_delete(sb_igmp);
61e211
@@ -15251,7 +15290,6 @@ build_mcast_groups(struct lflow_input *input_data,
61e211
      * IGMP groups are based on the groups learnt by their multicast enabled
61e211
      * peers.
61e211
      */
61e211
-    struct ovn_datapath *od;
61e211
     HMAP_FOR_EACH (od, key_node, datapaths) {
61e211
 
61e211
         if (ovs_list_is_empty(&od->mcast_info.groups)) {
61e211
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
61e211
index dae961c87..177b6341d 100644
61e211
--- a/northd/ovn-northd.8.xml
61e211
+++ b/northd/ovn-northd.8.xml
61e211
@@ -4392,6 +4392,22 @@ nd_ns {
61e211
       
61e211
     
61e211
 
61e211
+    

61e211
+      This table also installs a priority-50 logical flow for each logical
61e211
+      router that has NATs configured on it. The flow has match
61e211
+      ip && ct_label.natted == 1 and action
61e211
+      REGBIT_DST_NAT_IP_LOCAL = 1; next;. This is intended
61e211
+      to ensure that traffic that was DNATted locally will use a separate
61e211
+      conntrack zone for SNAT if SNAT is required later in the egress
61e211
+      pipeline. Note that this flow checks the value of
61e211
+      ct_label.natted, which is set in the ingress pipeline.
61e211
+      This means that ovn-northd assumes that this value is carried over
61e211
+      from the ingress pipeline to the egress pipeline and is not altered
61e211
+      or cleared. If conntrack label values are ever changed to be cleared
61e211
+      between the ingress and egress pipelines, then the match conditions
61e211
+      of this flow will be updated accordingly.
61e211
+    

61e211
+
61e211
     

Egress Table 1: UNDNAT

61e211
 
61e211
     

61e211
diff --git a/rhel/ovn-fedora.spec.in b/rhel/ovn-fedora.spec.in
61e211
index 821eb03cc..57dc977c1 100644
61e211
--- a/rhel/ovn-fedora.spec.in
61e211
+++ b/rhel/ovn-fedora.spec.in
61e211
@@ -65,6 +65,7 @@ BuildRequires: tcpdump
61e211
 BuildRequires: unbound unbound-devel
61e211
 
61e211
 Requires: openssl hostname iproute module-init-tools openvswitch
61e211
+Requires: python3-openvswitch
61e211
 
61e211
 Requires(post): systemd-units
61e211
 Requires(preun): systemd-units
61e211
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
61e211
index 7c3c84007..15588cc52 100644
61e211
--- a/tests/ovn-northd.at
61e211
+++ b/tests/ovn-northd.at
61e211
@@ -5019,6 +5019,7 @@ AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
61e211
 
61e211
 AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
61e211
   table=? (lr_out_chk_dnat_local), priority=0    , match=(1), action=(reg9[[4]] = 0; next;)
61e211
+  table=? (lr_out_chk_dnat_local), priority=50   , match=(ip && ct_mark.natted == 1), action=(reg9[[4]] = 1; next;)
61e211
   table=? (lr_out_chk_dnat_local), priority=50   , match=(ip && ip4.dst == 172.168.0.10 && is_chassis_resident("cr-lr0-public")), action=(reg9[[4]] = 1; next;)
61e211
   table=? (lr_out_chk_dnat_local), priority=50   , match=(ip && ip4.dst == 172.168.0.20 && is_chassis_resident("cr-lr0-public")), action=(reg9[[4]] = 1; next;)
61e211
   table=? (lr_out_chk_dnat_local), priority=50   , match=(ip && ip4.dst == 172.168.0.30 && is_chassis_resident("cr-lr0-public")), action=(reg9[[4]] = 1; next;)
61e211
@@ -5093,6 +5094,7 @@ AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
61e211
 
61e211
 AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
61e211
   table=? (lr_out_chk_dnat_local), priority=0    , match=(1), action=(reg9[[4]] = 0; next;)
61e211
+  table=? (lr_out_chk_dnat_local), priority=50   , match=(ip && ct_mark.natted == 1), action=(reg9[[4]] = 1; next;)
61e211
   table=? (lr_out_chk_dnat_local), priority=50   , match=(ip && ip4.dst == 172.168.0.10 && is_chassis_resident("cr-lr0-public")), action=(reg9[[4]] = 1; next;)
61e211
   table=? (lr_out_chk_dnat_local), priority=50   , match=(ip && ip4.dst == 172.168.0.20 && is_chassis_resident("cr-lr0-public")), action=(reg9[[4]] = 1; next;)
61e211
   table=? (lr_out_chk_dnat_local), priority=50   , match=(ip && ip4.dst == 172.168.0.30 && is_chassis_resident("cr-lr0-public")), action=(reg9[[4]] = 1; next;)
61e211
@@ -5161,6 +5163,7 @@ AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
61e211
 
61e211
 AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
61e211
   table=? (lr_out_chk_dnat_local), priority=0    , match=(1), action=(reg9[[4]] = 0; next;)
61e211
+  table=? (lr_out_chk_dnat_local), priority=50   , match=(ip && ct_mark.natted == 1), action=(reg9[[4]] = 1; next;)
61e211
 ])
61e211
 
61e211
 AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
61e211
@@ -5221,6 +5224,7 @@ AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
61e211
 
61e211
 AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
61e211
   table=? (lr_out_chk_dnat_local), priority=0    , match=(1), action=(reg9[[4]] = 0; next;)
61e211
+  table=? (lr_out_chk_dnat_local), priority=50   , match=(ip && ct_mark.natted == 1), action=(reg9[[4]] = 1; next;)
61e211
 ])
61e211
 
61e211
 AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
61e211
@@ -5286,6 +5290,7 @@ AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
61e211
 
61e211
 AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
61e211
   table=? (lr_out_chk_dnat_local), priority=0    , match=(1), action=(reg9[[4]] = 0; next;)
61e211
+  table=? (lr_out_chk_dnat_local), priority=50   , match=(ip && ct_mark.natted == 1), action=(reg9[[4]] = 1; next;)
61e211
 ])
61e211
 
61e211
 AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
61e211
@@ -5364,6 +5369,7 @@ AT_CHECK([grep "lr_in_dnat" lr0flows | sort], [0], [dnl
61e211
 
61e211
 AT_CHECK([grep "lr_out_chk_dnat_local" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
61e211
   table=? (lr_out_chk_dnat_local), priority=0    , match=(1), action=(reg9[[4]] = 0; next;)
61e211
+  table=? (lr_out_chk_dnat_local), priority=50   , match=(ip && ct_mark.natted == 1), action=(reg9[[4]] = 1; next;)
61e211
 ])
61e211
 
61e211
 AT_CHECK([grep "lr_out_undnat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl
61e211
@@ -6129,7 +6135,6 @@ AT_CHECK([grep -e "(lr_in_ip_routing   ).*outport" lr0flows | sed 's/table=../ta
61e211
 ])
61e211
 
61e211
 AT_CLEANUP
61e211
-])
61e211
 
61e211
 OVN_FOR_EACH_NORTHD([
61e211
 AT_SETUP([check exclude-lb-vips-from-garp option])
61e211
diff --git a/tests/ovn.at b/tests/ovn.at
61e211
index 80e9192ca..dd72996dd 100644
61e211
--- a/tests/ovn.at
61e211
+++ b/tests/ovn.at
61e211
@@ -32889,3 +32889,32 @@ check ovn-nbctl --wait=hv sync
61e211
 OVN_CLEANUP([hv1])
61e211
 AT_CLEANUP
61e211
 ])
61e211
+
61e211
+OVN_FOR_EACH_NORTHD([
61e211
+AT_SETUP([ovn-controller: batch add port and delete port in same IDL])
61e211
+ovn_start
61e211
+net_add n1
61e211
+
61e211
+sim_add hv1
61e211
+as hv1
61e211
+ovs-vsctl add-br br-phys
61e211
+ovn_attach n1 br-phys 192.168.0.1
61e211
+check ovs-vsctl add-port br-int p1
61e211
+
61e211
+check ovs-vsctl set interface p1 external-ids:iface-id=sw0-port1
61e211
+check ovn-nbctl --wait=hv sync
61e211
+ovn-appctl debug/pause
61e211
+OVS_WAIT_UNTIL([test x$(as hv1 ovn-appctl -t ovn-controller debug/status) = "xpaused"])
61e211
+
61e211
+check ovn-nbctl ls-add sw0 -- lsp-add sw0 sw0-port1
61e211
+check ovn-nbctl lsp-del sw0-port1
61e211
+check ovn-nbctl --wait=sb sync
61e211
+
61e211
+ovn-appctl debug/resume
61e211
+check ovn-nbctl --wait=hv sync
61e211
+
61e211
+check ovn-nbctl ls-del sw0
61e211
+check ovn-nbctl --wait=hv sync
61e211
+OVN_CLEANUP([hv1])
61e211
+AT_CLEANUP
61e211
+])
61e211
diff --git a/tests/system-common-macros.at b/tests/system-common-macros.at
61e211
index 616a87fcf..8e6cb415c 100644
61e211
--- a/tests/system-common-macros.at
61e211
+++ b/tests/system-common-macros.at
61e211
@@ -44,15 +44,38 @@ m4_define([NS_CHECK_EXEC],
61e211
 # appropriate type, and allows additional arguments to be passed.
61e211
 m4_define([ADD_BR], [ovs-vsctl _ADD_BR([$1]) -- $2])
61e211
 
61e211
-# ADD_INT([port], [namespace], [ovs-br], [ip_addr])
61e211
+# ADD_INT([port], [namespace], [ovs-br], [ip_addr] [ip6_addr])
61e211
 #
61e211
 # Add an internal port to 'ovs-br', then shift it into 'namespace' and
61e211
 # configure it with 'ip_addr' (specified in CIDR notation).
61e211
+# Optionally add an ipv6 address
61e211
 m4_define([ADD_INT],
61e211
     [ AT_CHECK([ovs-vsctl add-port $3 $1 -- set int $1 type=internal])
61e211
       AT_CHECK([ip link set $1 netns $2])
61e211
       NS_CHECK_EXEC([$2], [ip addr add $4 dev $1])
61e211
       NS_CHECK_EXEC([$2], [ip link set dev $1 up])
61e211
+      if test -n "$5"; then
61e211
+        NS_CHECK_EXEC([$2], [ip -6 addr add $5 dev $1])
61e211
+      fi
61e211
+    ]
61e211
+)
61e211
+
61e211
+# NS_ADD_INT([port], [namespace], [ovs-br], [ip_addr] [mac_addr] [ip6_addr] [default_gw] [default_ipv6_gw])
61e211
+# Create a namespace
61e211
+# Add an internal port to 'ovs-br', then shift it into 'namespace'.
61e211
+# Configure it with 'ip_addr' (specified in CIDR notation) and ip6_addr.
61e211
+# Set mac_addr
61e211
+# Add default gw for ipv4 and ipv6
61e211
+m4_define([NS_ADD_INT],
61e211
+    [ AT_CHECK([ovs-vsctl add-port $3 $1 -- set int $1 type=internal  external_ids:iface-id=$1])
61e211
+      ADD_NAMESPACES($2)
61e211
+      AT_CHECK([ip link set $1 netns $2])
61e211
+      NS_CHECK_EXEC([$2], [ip link set $1 address $5])
61e211
+      NS_CHECK_EXEC([$2], [ip link set dev $1 up])
61e211
+      NS_CHECK_EXEC([$2], [ip addr add $4 dev $1])
61e211
+      NS_CHECK_EXEC([$2], [ip addr add $6 dev $1])
61e211
+      NS_CHECK_EXEC([$2], [ip route add default via $7 dev $1])
61e211
+      NS_CHECK_EXEC([$2], [ip -6 route add default via $8 dev $1])
61e211
     ]
61e211
 )
61e211
 
61e211
@@ -333,4 +356,166 @@ m4_define([OVS_CHECK_CT_CLEAR],
61e211
 
61e211
 # OVS_CHECK_CT_ZERO_SNAT()
61e211
 m4_define([OVS_CHECK_CT_ZERO_SNAT],
61e211
-    [AT_SKIP_IF([! grep -q "Datapath supports ct_zero_snat" ovs-vswitchd.log])]))
61e211
+    [AT_SKIP_IF([! grep -q "Datapath supports ct_zero_snat" ovs-vswitchd.log])])
61e211
+
61e211
+# OVN_TEST_IPV6_PREFIX_DELEGATION()
61e211
+m4_define([OVN_TEST_IPV6_PREFIX_DELEGATION],
61e211
+[
61e211
+ovn_start
61e211
+OVS_TRAFFIC_VSWITCHD_START()
61e211
+
61e211
+ADD_BR([br-int])
61e211
+ADD_BR([br-ext])
61e211
+
61e211
+ovs-ofctl add-flow br-ext action=normal
61e211
+# Set external-ids in br-int needed for ovn-controller
61e211
+ovs-vsctl \
61e211
+        -- set Open_vSwitch . external-ids:system-id=hv1 \
61e211
+        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
61e211
+        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
61e211
+        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
61e211
+        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
61e211
+
61e211
+# Start ovn-controller
61e211
+start_daemon ovn-controller
61e211
+
61e211
+ADD_NAMESPACES(sw01)
61e211
+ADD_VETH(sw01, sw01, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \
61e211
+         "192.168.1.1")
61e211
+ADD_NAMESPACES(sw11)
61e211
+ADD_VETH(sw11, sw11, br-int, "192.168.2.2/24", "f0:00:00:02:02:03", \
61e211
+         "192.168.2.1")
61e211
+ADD_NAMESPACES(server)
61e211
+ADD_VETH(s1, server, br-ext, "2001:1db8:3333::2/64", "f0:00:00:01:02:05", \
61e211
+         "2001:1db8:3333::1")
61e211
+
61e211
+if test X"$1" = X"GR"; then
61e211
+   ovn-nbctl create Logical_Router name=R1 options:chassis=hv1
61e211
+else
61e211
+   ovn-nbctl lr-add R1
61e211
+fi
61e211
+
61e211
+ovn-nbctl ls-add sw0
61e211
+ovn-nbctl ls-add sw1
61e211
+ovn-nbctl ls-add public
61e211
+
61e211
+ovn-nbctl lrp-add R1 rp-sw0 00:00:01:01:02:03 192.168.1.1/24
61e211
+ovn-nbctl lrp-add R1 rp-sw1 00:00:03:01:02:03 192.168.2.1/24
61e211
+ovn-nbctl lrp-add R1 rp-public 00:00:02:01:02:03 172.16.1.1/24
61e211
+
61e211
+if test X"$1" != X"GR"; then
61e211
+    ovn-nbctl lrp-set-gateway-chassis rp-public hv1
61e211
+fi
61e211
+
61e211
+ovn-nbctl lsp-add sw0 sw0-rp -- set Logical_Switch_Port sw0-rp \
61e211
+    type=router options:router-port=rp-sw0 \
61e211
+    -- lsp-set-addresses sw0-rp router
61e211
+ovn-nbctl lsp-add sw1 sw1-rp -- set Logical_Switch_Port sw1-rp \
61e211
+    type=router options:router-port=rp-sw1 \
61e211
+    -- lsp-set-addresses sw1-rp router
61e211
+
61e211
+ovn-nbctl lsp-add public public-rp -- set Logical_Switch_Port public-rp \
61e211
+    type=router options:router-port=rp-public \
61e211
+    -- lsp-set-addresses public-rp router
61e211
+
61e211
+ovn-nbctl lsp-add sw0 sw01 \
61e211
+    -- lsp-set-addresses sw01 "f0:00:00:01:02:03 192.168.1.2"
61e211
+
61e211
+ovn-nbctl lsp-add sw1 sw11 \
61e211
+    -- lsp-set-addresses sw11 "f0:00:00:02:02:03 192.168.2.2"
61e211
+
61e211
+OVS_WAIT_UNTIL([test "$(ip netns exec server ip a | grep 2001:1db8:3333::2 | grep tentative)" = ""])
61e211
+OVS_WAIT_UNTIL([test "$(ip netns exec server ip a | grep fe80 | grep tentative)" = ""])
61e211
+
61e211
+AT_CHECK([ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext])
61e211
+ovn-nbctl lsp-add public public1 \
61e211
+        -- lsp-set-addresses public1 unknown \
61e211
+        -- lsp-set-type public1 localnet \
61e211
+        -- lsp-set-options public1 network_name=phynet
61e211
+
61e211
+ovn-nbctl set logical_router_port rp-public options:prefix_delegation=true
61e211
+ovn-nbctl set logical_router_port rp-public options:prefix=true
61e211
+ovn-nbctl set logical_router_port rp-sw0 options:prefix=true
61e211
+ovn-nbctl set logical_router_port rp-sw1 options:prefix=true
61e211
+
61e211
+OVN_POPULATE_ARP
61e211
+
61e211
+ovn-nbctl --wait=hv sync
61e211
+
61e211
+cat > /etc/dhcp/dhcpd.conf <
61e211
+option dhcp-rebinding-time 15;
61e211
+option dhcp-renewal-time 10;
61e211
+option dhcp6.unicast 2001:1db8:3333::1;
61e211
+subnet6 2001:1db8:3333::/64 {
61e211
+    prefix6 2001:1db8:3333:100:: 2001:1db8:3333:111:: /96;
61e211
+}
61e211
+EOF
61e211
+rm -f /var/lib/dhcp/dhcpd6.leases
61e211
+touch /var/lib/dhcp/dhcpd6.leases
61e211
+chown root:dhcpd /var/lib/dhcp /var/lib/dhcp/dhcpd6.leases
61e211
+chmod 775 /var/lib/dhcp
61e211
+chmod 664 /var/lib/dhcp/dhcpd6.leases
61e211
+
61e211
+NS_CHECK_EXEC([server], [tcpdump -nni s1 > pkt.pcap &])
61e211
+
61e211
+NETNS_DAEMONIZE([server], [dhcpd -6 -f s1 > dhcpd.log 2>&1], [dhcpd.pid])
61e211
+ovn-nbctl --wait=hv sync
61e211
+
61e211
+OVS_WAIT_WHILE([test "$(ovn-nbctl get logical_router_port rp-public ipv6_prefix | cut -c4-15)" = ""])
61e211
+OVS_WAIT_WHILE([test "$(ovn-nbctl get logical_router_port rp-sw0 ipv6_prefix | cut -c4-15)" = ""])
61e211
+OVS_WAIT_WHILE([test "$(ovn-nbctl get logical_router_port rp-sw1 ipv6_prefix | cut -c4-15)" = ""])
61e211
+
61e211
+AT_CHECK([ovn-nbctl get logical_router_port rp-public ipv6_prefix | cut -c3-16], [0], [dnl
61e211
+[2001:1db8:3333]
61e211
+])
61e211
+AT_CHECK([ovn-nbctl get logical_router_port rp-sw0 ipv6_prefix | cut -c3-16], [0], [dnl
61e211
+[2001:1db8:3333]
61e211
+])
61e211
+AT_CHECK([ovn-nbctl get logical_router_port rp-sw1 ipv6_prefix | cut -c3-16], [0], [dnl
61e211
+[2001:1db8:3333]
61e211
+])
61e211
+
61e211
+prefix=$(ovn-nbctl list logical_router_port rp-public | awk -F/ '/ipv6_prefix/{print substr($ 1,25,9)}' | sed 's/://g')
61e211
+ovn-nbctl list logical_router_port rp-public > /tmp/rp-public
61e211
+ovn-nbctl set logical_router_port rp-sw0 options:prefix=false
61e211
+ovn-nbctl set logical_router_port rp-sw1 options:prefix=false
61e211
+# Renew message
61e211
+NS_CHECK_EXEC([server], [tcpdump -c 1 -nni s1 ip6[[48:1]]=0x05 and ip6[[113:4]]=0x${prefix} > renew.pcap &])
61e211
+# Reply message with Status OK
61e211
+NS_CHECK_EXEC([server], [tcpdump -c 1 -nni s1 ip6[[48:1]]=0x07 and ip6[[81:4]]=0x${prefix} > reply.pcap &])
61e211
+
61e211
+OVS_WAIT_UNTIL([
61e211
+    total_pkts=$(cat renew.pcap | wc -l)
61e211
+    test "${total_pkts}" = "1"
61e211
+])
61e211
+
61e211
+OVS_WAIT_UNTIL([
61e211
+    total_pkts=$(cat reply.pcap | wc -l)
61e211
+    test "${total_pkts}" = "1"
61e211
+])
61e211
+
61e211
+kill $(pidof tcpdump)
61e211
+
61e211
+ovn-nbctl set logical_router_port rp-sw0 options:prefix=false
61e211
+ovn-nbctl clear logical_router_port rp-sw0 ipv6_prefix
61e211
+OVS_WAIT_WHILE([test "$(ovn-nbctl get logical_router_port rp-sw0 ipv6_prefix | cut -c3-16)" = "[2001:1db8:3333]"])
61e211
+AT_CHECK([ovn-nbctl get logical_router_port rp-sw0 ipv6_prefix | cut -c3-16], [0], [dnl
61e211
+[]
61e211
+])
61e211
+
61e211
+kill $(pidof ovn-controller)
61e211
+
61e211
+as ovn-sb
61e211
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
61e211
+
61e211
+as ovn-nb
61e211
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
61e211
+
61e211
+as northd
61e211
+OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE])
61e211
+
61e211
+as
61e211
+OVS_TRAFFIC_VSWITCHD_STOP(["/.*error receiving.*/d
61e211
+/failed to query port patch-.*/d
61e211
+/.*terminating with signal 15.*/d"])
61e211
+]))
61e211
diff --git a/tests/system-ovn.at b/tests/system-ovn.at
61e211
index 8acfb3e39..20c058415 100644
61e211
--- a/tests/system-ovn.at
61e211
+++ b/tests/system-ovn.at
61e211
@@ -5272,158 +5272,22 @@ AT_CLEANUP
61e211
 ])
61e211
 
61e211
 OVN_FOR_EACH_NORTHD([
61e211
-AT_SETUP([IPv6 prefix delegation])
61e211
+AT_SETUP([IPv6 prefix delegation - distributed router])
61e211
 AT_SKIP_IF([test $HAVE_DHCPD = no])
61e211
 AT_SKIP_IF([test $HAVE_TCPDUMP = no])
61e211
 AT_KEYWORDS([ovn-ipv6-prefix_d])
61e211
 
61e211
-ovn_start
61e211
-OVS_TRAFFIC_VSWITCHD_START()
61e211
-
61e211
-ADD_BR([br-int])
61e211
-ADD_BR([br-ext])
61e211
-
61e211
-ovs-ofctl add-flow br-ext action=normal
61e211
-# Set external-ids in br-int needed for ovn-controller
61e211
-ovs-vsctl \
61e211
-        -- set Open_vSwitch . external-ids:system-id=hv1 \
61e211
-        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
61e211
-        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
61e211
-        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
61e211
-        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
61e211
-
61e211
-# Start ovn-controller
61e211
-start_daemon ovn-controller
61e211
-
61e211
-ovn-nbctl lr-add R1
61e211
-
61e211
-ovn-nbctl ls-add sw0
61e211
-ovn-nbctl ls-add sw1
61e211
-ovn-nbctl ls-add public
61e211
-
61e211
-ovn-nbctl lrp-add R1 rp-sw0 00:00:01:01:02:03 192.168.1.1/24
61e211
-ovn-nbctl lrp-add R1 rp-sw1 00:00:03:01:02:03 192.168.2.1/24
61e211
-ovn-nbctl lrp-add R1 rp-public 00:00:02:01:02:03 172.16.1.1/24 \
61e211
-    -- lrp-set-gateway-chassis rp-public hv1
61e211
-
61e211
-ovn-nbctl lsp-add sw0 sw0-rp -- set Logical_Switch_Port sw0-rp \
61e211
-    type=router options:router-port=rp-sw0 \
61e211
-    -- lsp-set-addresses sw0-rp router
61e211
-ovn-nbctl lsp-add sw1 sw1-rp -- set Logical_Switch_Port sw1-rp \
61e211
-    type=router options:router-port=rp-sw1 \
61e211
-    -- lsp-set-addresses sw1-rp router
61e211
-
61e211
-ovn-nbctl lsp-add public public-rp -- set Logical_Switch_Port public-rp \
61e211
-    type=router options:router-port=rp-public \
61e211
-    -- lsp-set-addresses public-rp router
61e211
-
61e211
-ADD_NAMESPACES(sw01)
61e211
-ADD_VETH(sw01, sw01, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \
61e211
-         "192.168.1.1")
61e211
-ovn-nbctl lsp-add sw0 sw01 \
61e211
-    -- lsp-set-addresses sw01 "f0:00:00:01:02:03 192.168.1.2"
61e211
-
61e211
-ADD_NAMESPACES(sw11)
61e211
-ADD_VETH(sw11, sw11, br-int, "192.168.2.2/24", "f0:00:00:02:02:03", \
61e211
-         "192.168.2.1")
61e211
-ovn-nbctl lsp-add sw1 sw11 \
61e211
-    -- lsp-set-addresses sw11 "f0:00:00:02:02:03 192.168.2.2"
61e211
-
61e211
-ADD_NAMESPACES(server)
61e211
-ADD_VETH(s1, server, br-ext, "2001:1db8:3333::2/64", "f0:00:00:01:02:05", \
61e211
-         "2001:1db8:3333::1")
61e211
-
61e211
-OVS_WAIT_UNTIL([test "$(ip netns exec server ip a | grep 2001:1db8:3333::2 | grep tentative)" = ""])
61e211
-OVS_WAIT_UNTIL([test "$(ip netns exec server ip a | grep fe80 | grep tentative)" = ""])
61e211
-
61e211
-AT_CHECK([ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext])
61e211
-ovn-nbctl lsp-add public public1 \
61e211
-        -- lsp-set-addresses public1 unknown \
61e211
-        -- lsp-set-type public1 localnet \
61e211
-        -- lsp-set-options public1 network_name=phynet
61e211
-
61e211
-ovn-nbctl set logical_router_port rp-public options:prefix_delegation=true
61e211
-ovn-nbctl set logical_router_port rp-public options:prefix=true
61e211
-ovn-nbctl set logical_router_port rp-sw0 options:prefix=true
61e211
-ovn-nbctl set logical_router_port rp-sw1 options:prefix=true
61e211
-
61e211
-OVN_POPULATE_ARP
61e211
-
61e211
-ovn-nbctl --wait=hv sync
61e211
-
61e211
-cat > /etc/dhcp/dhcpd.conf <
61e211
-option dhcp-rebinding-time 15;
61e211
-option dhcp-renewal-time 10;
61e211
-option dhcp6.unicast 2001:1db8:3333::1;
61e211
-subnet6 2001:1db8:3333::/64 {
61e211
-    prefix6 2001:1db8:3333:100:: 2001:1db8:3333:111:: /96;
61e211
-}
61e211
-EOF
61e211
-rm -f /var/lib/dhcp/dhcpd6.leases
61e211
-touch /var/lib/dhcp/dhcpd6.leases
61e211
-chown root:dhcpd /var/lib/dhcp /var/lib/dhcp/dhcpd6.leases
61e211
-chmod 775 /var/lib/dhcp
61e211
-chmod 664 /var/lib/dhcp/dhcpd6.leases
61e211
-
61e211
-NETNS_DAEMONIZE([server], [dhcpd -6 -f s1 > dhcpd.log 2>&1], [dhcpd.pid])
61e211
-ovn-nbctl --wait=hv sync
61e211
-
61e211
-OVS_WAIT_WHILE([test "$(ovn-nbctl get logical_router_port rp-public ipv6_prefix | cut -c4-15)" = ""])
61e211
-OVS_WAIT_WHILE([test "$(ovn-nbctl get logical_router_port rp-sw0 ipv6_prefix | cut -c4-15)" = ""])
61e211
-OVS_WAIT_WHILE([test "$(ovn-nbctl get logical_router_port rp-sw1 ipv6_prefix | cut -c4-15)" = ""])
61e211
-
61e211
-AT_CHECK([ovn-nbctl get logical_router_port rp-public ipv6_prefix | cut -c3-16], [0], [dnl
61e211
-[2001:1db8:3333]
61e211
-])
61e211
-AT_CHECK([ovn-nbctl get logical_router_port rp-sw0 ipv6_prefix | cut -c3-16], [0], [dnl
61e211
-[2001:1db8:3333]
61e211
-])
61e211
-AT_CHECK([ovn-nbctl get logical_router_port rp-sw1 ipv6_prefix | cut -c3-16], [0], [dnl
61e211
-[2001:1db8:3333]
61e211
-])
61e211
-
61e211
-prefix=$(ovn-nbctl list logical_router_port rp-public | awk -F/ '/ipv6_prefix/{print substr($1,25,9)}' | sed 's/://g')
61e211
-ovn-nbctl set logical_router_port rp-sw0 options:prefix=false
61e211
-ovn-nbctl set logical_router_port rp-sw1 options:prefix=false
61e211
-
61e211
-# Renew message
61e211
-NS_CHECK_EXEC([server], [tcpdump -c 1 -nni s1 ip6[[48:1]]=0x05 and ip6[[113:4]]=0x${prefix} > renew.pcap &])
61e211
-# Reply message with Status OK
61e211
-NS_CHECK_EXEC([server], [tcpdump -c 1 -nni s1 ip6[[48:1]]=0x07 and ip6[[81:4]]=0x${prefix} > reply.pcap &])
61e211
-
61e211
-OVS_WAIT_UNTIL([
61e211
-    total_pkts=$(cat renew.pcap | wc -l)
61e211
-    test "${total_pkts}" = "1"
61e211
-])
61e211
-
61e211
-OVS_WAIT_UNTIL([
61e211
-    total_pkts=$(cat reply.pcap | wc -l)
61e211
-    test "${total_pkts}" = "1"
61e211
-])
61e211
-
61e211
-kill $(pidof tcpdump)
61e211
-
61e211
-ovn-nbctl set logical_router_port rp-sw0 options:prefix=false
61e211
-ovn-nbctl clear logical_router_port rp-sw0 ipv6_prefix
61e211
-OVS_WAIT_WHILE([test "$(ovn-nbctl get logical_router_port rp-sw0 ipv6_prefix | cut -c3-16)" = "[2001:1db8:3333]"])
61e211
-AT_CHECK([ovn-nbctl get logical_router_port rp-sw0 ipv6_prefix | cut -c3-16], [0], [dnl
61e211
-[]
61e211
+OVN_TEST_IPV6_PREFIX_DELEGATION(DGP)
61e211
+AT_CLEANUP
61e211
 ])
61e211
 
61e211
-kill $(pidof ovn-controller)
61e211
-
61e211
-as ovn-sb
61e211
-OVS_APP_EXIT_AND_WAIT([ovsdb-server])
61e211
-
61e211
-as ovn-nb
61e211
-OVS_APP_EXIT_AND_WAIT([ovsdb-server])
61e211
-
61e211
-as northd
61e211
-OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE])
61e211
+OVN_FOR_EACH_NORTHD([
61e211
+AT_SETUP([IPv6 prefix delegation - gw router])
61e211
+AT_SKIP_IF([test $HAVE_DHCPD = no])
61e211
+AT_SKIP_IF([test $HAVE_TCPDUMP = no])
61e211
+AT_KEYWORDS([ovn-ipv6-prefix_d])
61e211
 
61e211
-as
61e211
-OVS_TRAFFIC_VSWITCHD_STOP(["/.*error receiving.*/d
61e211
-/.*terminating with signal 15.*/d"])
61e211
+OVN_TEST_IPV6_PREFIX_DELEGATION(GR)
61e211
 AT_CLEANUP
61e211
 ])
61e211
 
61e211
@@ -8343,3 +8207,393 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
61e211
 
61e211
 AT_CLEANUP
61e211
 ])
61e211
+
61e211
+OVN_FOR_EACH_NORTHD([
61e211
+AT_SETUP([SNAT in gateway router mode])
61e211
+AT_KEYWORDS([ovnnat])
61e211
+
61e211
+CHECK_CONNTRACK()
61e211
+CHECK_CONNTRACK_NAT()
61e211
+ovn_start
61e211
+OVS_TRAFFIC_VSWITCHD_START()
61e211
+
61e211
+ADD_BR([br-int])
61e211
+check ovs-ofctl add-flow br0 action=normal
61e211
+# Set external-ids in br-int needed for ovn-controller
61e211
+ovs-vsctl \
61e211
+        -- set Open_vSwitch . external-ids:system-id=hv1 \
61e211
+        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
61e211
+        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
61e211
+        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
61e211
+        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
61e211
+
61e211
+# Start ovn-controller
61e211
+start_daemon ovn-controller
61e211
+
61e211
+check ip link set br0 up
61e211
+check ovs-vsctl set open . external-ids:ovn-bridge-mappings=provider:br0
61e211
+
61e211
+check ovn-nbctl ls-add ls1
61e211
+check ovn-nbctl lsp-add ls1 ls1p1
61e211
+check ovn-nbctl lsp-set-addresses ls1p1 "00:00:00:01:01:01 192.168.1.1 2001::1"
61e211
+check ovn-nbctl lsp-add ls1 ls1p2
61e211
+check ovn-nbctl lsp-set-addresses ls1p2 "00:00:00:01:01:02 192.168.1.2 2001::2"
61e211
+
61e211
+check ovn-nbctl lr-add lr1
61e211
+check ovn-nbctl lrp-add lr1 lr1-ls1 00:00:00:00:00:01 192.168.1.254/24 2001::a/64
61e211
+check ovn-nbctl lsp-add ls1 ls1-lr1
61e211
+check ovn-nbctl lsp-set-addresses ls1-lr1 "00:00:00:00:00:01 192.168.1.254 2001::a"
61e211
+check ovn-nbctl lsp-set-type ls1-lr1 router
61e211
+check ovn-nbctl lsp-set-options ls1-lr1 router-port=lr1-ls1
61e211
+
61e211
+check ovn-nbctl set logical_router lr1 options:chassis=hv1
61e211
+
61e211
+check ovn-nbctl lrp-add lr1 lr1-pub 00:00:00:00:0f:01 172.16.1.254/24 1711::a/64
61e211
+check ovn-nbctl ls-add pub
61e211
+check ovn-nbctl lsp-add pub pub-lr1
61e211
+check ovn-nbctl lsp-set-type pub-lr1 router
61e211
+check ovn-nbctl lsp-set-options pub-lr1 router-port=lr1-pub
61e211
+check ovn-nbctl lsp-set-addresses pub-lr1 router
61e211
+
61e211
+check ovn-nbctl lsp-add pub ln -- lsp-set-options ln network_name=provider
61e211
+check ovn-nbctl lsp-set-type ln localnet
61e211
+check ovn-nbctl lsp-set-addresses ln unknown
61e211
+
61e211
+check ovn-nbctl lr-nat-add lr1 snat 172.16.1.10 192.168.1.0/24
61e211
+check ovn-nbctl lr-nat-add lr1 snat 1711::10 2001::/64
61e211
+
61e211
+NS_ADD_INT(ls1p1, ls1p1, br-int, "192.168.1.1/24", "00:00:00:01:01:01", "2001::1/64", "192.168.1.254", "2001::a" )
61e211
+NS_ADD_INT(ls1p2, ls1p2, br-int, "192.168.1.2/24", "00:00:00:01:01:02", "2001::2/64", "192.168.1.254", "2001::a" )
61e211
+
61e211
+ADD_NAMESPACES(ext1)
61e211
+ADD_INT(ext1, ext1, br0, 172.16.1.1/24, 1711::1/64)
61e211
+check ovn-nbctl --wait=hv sync
61e211
+wait_for_ports_up
61e211
+OVS_WAIT_UNTIL([test "$(ip netns exec ls1p1 ip a | grep 2001::1 | grep tentative)" = ""])
61e211
+OVS_WAIT_UNTIL([test "$(ip netns exec ls1p2 ip a | grep 2002::1 | grep tentative)" = ""])
61e211
+
61e211
+NS_CHECK_EXEC([ls1p1], [ping -q -c 3 -i 0.3 -w 2  172.16.1.1 | FORMAT_PING], \
61e211
+[0], [dnl
61e211
+3 packets transmitted, 3 received, 0% packet loss, time 0ms
61e211
+])
61e211
+
61e211
+NS_CHECK_EXEC([ls1p1], [ping6 -v -q -c 3 -i 0.3 -w 2 1711::1  | FORMAT_PING], \
61e211
+[0], [dnl
61e211
+3 packets transmitted, 3 received, 0% packet loss, time 0ms
61e211
+])
61e211
+
61e211
+OVS_APP_EXIT_AND_WAIT([ovn-controller])
61e211
+as
61e211
+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
61e211
+/connection dropped.*/d
61e211
+/removing policing failed: No such device/d"])
61e211
+AT_CLEANUP
61e211
+])
61e211
+
61e211
+OVN_FOR_EACH_NORTHD([
61e211
+AT_SETUP([mcast flow count])
61e211
+AT_KEYWORDS([ovnigmp IP-multicast])
61e211
+AT_SKIP_IF([test $HAVE_TCPDUMP = no])
61e211
+ovn_start
61e211
+
61e211
+OVS_TRAFFIC_VSWITCHD_START()
61e211
+ADD_BR([br-int])
61e211
+
61e211
+# Set external-ids in br-int needed for ovn-controller
61e211
+ovs-vsctl \
61e211
+        -- set Open_vSwitch . external-ids:system-id=hv1 \
61e211
+        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
61e211
+        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
61e211
+        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
61e211
+        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
61e211
+
61e211
+# Start ovn-controller
61e211
+start_daemon ovn-controller
61e211
+
61e211
+check ovn-nbctl ls-add ls
61e211
+check ovn-nbctl lsp-add ls vm1
61e211
+check ovn-nbctl lsp-set-addresses vm1 00:00:00:00:00:01
61e211
+check ovn-nbctl lsp-add ls vm2
61e211
+check ovn-nbctl lsp-set-addresses vm2 00:00:00:00:00:02
61e211
+check ovn-nbctl lsp-add ls vm3
61e211
+check ovn-nbctl lsp-set-addresses vm3 00:00:00:00:00:03
61e211
+
61e211
+check ovn-nbctl set logical_switch ls other_config:mcast_querier=false other_config:mcast_snoop=true other_config:mcast_query_interval=30 other_config:mcast_eth_src=00:00:00:00:00:05 other_config:mcast_ip4_src=42.42.42.5 other_config:mcast_ip6_src=fe80::1 other_config:mcast_idle_timeout=3000
61e211
+ovn-sbctl list ip_multicast
61e211
+
61e211
+wait_igmp_flows_installed()
61e211
+{
61e211
+    OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int table=31 | \
61e211
+    grep 'priority=90' | grep "nw_dst=$1"])
61e211
+}
61e211
+
61e211
+ADD_NAMESPACES(vm1)
61e211
+ADD_INT([vm1], [vm1], [br-int], [42.42.42.1/24])
61e211
+NS_CHECK_EXEC([vm1], [ip link set vm1 address 00:00:00:00:00:01], [0])
61e211
+NS_CHECK_EXEC([vm1], [ip route add default via 42.42.42.5], [0])
61e211
+check ovs-vsctl set Interface vm1 external_ids:iface-id=vm1
61e211
+
61e211
+ADD_NAMESPACES(vm2)
61e211
+ADD_INT([vm2], [vm2], [br-int], [42.42.42.2/24])
61e211
+NS_CHECK_EXEC([vm2], [ip link set vm2 address 00:00:00:00:00:02], [0])
61e211
+NS_CHECK_EXEC([vm2], [ip link set lo up], [0])
61e211
+check ovs-vsctl set Interface vm2 external_ids:iface-id=vm2
61e211
+
61e211
+ADD_NAMESPACES(vm3)
61e211
+NETNS_DAEMONIZE([vm3], [tcpdump -n -i any -nnleX > vm3.pcap 2>/dev/null], [tcpdump3.pid])
61e211
+
61e211
+ADD_INT([vm3], [vm3], [br-int], [42.42.42.3/24])
61e211
+NS_CHECK_EXEC([vm3], [ip link set vm3 address 00:00:00:00:00:03], [0])
61e211
+NS_CHECK_EXEC([vm3], [ip link set lo up], [0])
61e211
+NS_CHECK_EXEC([vm3], [ip route add default via 42.42.42.5], [0])
61e211
+check ovs-vsctl set Interface vm3 external_ids:iface-id=vm3
61e211
+
61e211
+NS_CHECK_EXEC([vm2], [sysctl -w net.ipv4.igmp_max_memberships=100], [ignore], [ignore])
61e211
+NS_CHECK_EXEC([vm3], [sysctl -w net.ipv4.igmp_max_memberships=100], [ignore], [ignore])
61e211
+wait_for_ports_up
61e211
+
61e211
+NS_CHECK_EXEC([vm3], [ip addr add 228.0.0.1 dev vm3 autojoin], [0])
61e211
+wait_igmp_flows_installed 228.0.0.1
61e211
+
61e211
+NS_CHECK_EXEC([vm1], [ping -q -c 3 -i 0.3 -w 2 228.0.0.1], [ignore], [ignore])
61e211
+
61e211
+OVS_WAIT_UNTIL([
61e211
+    requests=`grep "ICMP echo request" -c vm3.pcap`
61e211
+    test "${requests}" -ge "3"
61e211
+])
61e211
+
61e211
+NETNS_DAEMONIZE([vm2], [tcpdump -n -i any -nnleX > vm2.pcap 2>/dev/null], [tcpdump2.pid])
61e211
+
61e211
+for i in `seq 1 40`;do
61e211
+    NS_CHECK_EXEC([vm2], [ip addr add 228.1.$i.1 dev vm2 autojoin &], [0])
61e211
+    NS_CHECK_EXEC([vm3], [ip addr add 229.1.$i.1 dev vm3 autojoin &], [0])
61e211
+    # Do not go too fast. If going fast, there is a higher chance of sb being busy, causing full recompute (engine has not run)
61e211
+    # In this test, we do not want too many recomputes as they might hide I+I related errors
61e211
+    sleep 0.2
61e211
+done
61e211
+
61e211
+for i in `seq 1 40`;do
61e211
+    wait_igmp_flows_installed 228.1.$i.1
61e211
+    wait_igmp_flows_installed 229.1.$i.1
61e211
+done
61e211
+ovn-sbctl list multicast_group
61e211
+
61e211
+NS_CHECK_EXEC([vm1], [ping -q -c 3 -i 0.3 -w 2 228.1.1.1], [ignore], [ignore])
61e211
+
61e211
+OVS_WAIT_UNTIL([
61e211
+    requests=`grep "ICMP echo request" -c vm2.pcap`
61e211
+    test "${requests}" -ge "3"
61e211
+])
61e211
+
61e211
+# The test could succeed thanks to a lucky northd recompute...after hitting too any flows
61e211
+# Double check we never hit error condition
61e211
+AT_CHECK([grep -qE 'Too many active mcast flows' northd/ovn-northd.log], [1])
61e211
+
61e211
+OVS_APP_EXIT_AND_WAIT([ovn-controller])
61e211
+
61e211
+as ovn-sb
61e211
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
61e211
+
61e211
+as ovn-nb
61e211
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
61e211
+
61e211
+as northd
61e211
+OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE])
61e211
+
61e211
+as
61e211
+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
61e211
+/connection dropped.*/d
61e211
+/removing policing failed: No such device/d"])
61e211
+AT_CLEANUP
61e211
+])
61e211
+
61e211
+OVN_FOR_EACH_NORTHD([
61e211
+AT_SETUP([DVR ping router port])
61e211
+AT_KEYWORDS([dvr])
61e211
+
61e211
+ovn_start
61e211
+
61e211
+OVS_TRAFFIC_VSWITCHD_START()
61e211
+ADD_BR([br-int])
61e211
+ADD_BR([br-ext])
61e211
+
61e211
+check ovs-ofctl add-flow br-ext action=normal
61e211
+# Set external-ids in br-int needed for ovn-controller
61e211
+ovs-vsctl \
61e211
+        -- set Open_vSwitch . external-ids:system-id=hv1 \
61e211
+        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
61e211
+        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
61e211
+        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
61e211
+        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
61e211
+
61e211
+# Start ovn-controller
61e211
+start_daemon ovn-controller
61e211
+
61e211
+check ovs-vsctl set open . external_ids:ovn-bridge-mappings=phys:br-ext
61e211
+check ovs-vsctl set open . external-ids:ovn-chassis-mac-mappings="phys:ee:00:00:00:00:10"
61e211
+
61e211
+
61e211
+check ovn-nbctl ls-add internal
61e211
+
61e211
+check ovn-nbctl lsp-add internal ln_internal "" 100
61e211
+check ovn-nbctl lsp-set-addresses ln_internal unknown
61e211
+check ovn-nbctl lsp-set-type ln_internal localnet
61e211
+check ovn-nbctl lsp-set-options ln_internal network_name=phys
61e211
+
61e211
+check ovn-nbctl lsp-add internal internal-gw
61e211
+check ovn-nbctl lsp-set-type internal-gw router
61e211
+check ovn-nbctl lsp-set-addresses internal-gw router
61e211
+check ovn-nbctl lsp-set-options internal-gw router-port=gw-internal
61e211
+
61e211
+check ovn-nbctl lsp-add internal vif0
61e211
+# Set address as unknown so that LRP has to generate ARP request
61e211
+check ovn-nbctl lsp-set-addresses vif0 unknown
61e211
+
61e211
+check ovn-nbctl lr-add gw
61e211
+check ovn-nbctl lrp-add gw gw-internal 00:00:00:00:20:00 192.168.20.1/24
61e211
+
61e211
+ADD_NAMESPACES(vif0)
61e211
+ADD_VETH(vif0, vif0, br-int, "192.168.20.10/24", "00:00:00:00:20:10", "192.168.20.1")
61e211
+
61e211
+check ovn-nbctl --wait=sb sync
61e211
+check ovn-nbctl --wait=hv sync
61e211
+
61e211
+NS_CHECK_EXEC([vif0], [ping -q -c 3 -i 0.3 -w 1 192.168.20.1 | FORMAT_PING], \
61e211
+[0], [dnl
61e211
+3 packets transmitted, 3 received, 0% packet loss, time 0ms
61e211
+])
61e211
+
61e211
+OVS_APP_EXIT_AND_WAIT([ovn-controller])
61e211
+
61e211
+as ovn-sb
61e211
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
61e211
+
61e211
+as ovn-nb
61e211
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
61e211
+
61e211
+as northd
61e211
+OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE])
61e211
+
61e211
+as
61e211
+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
61e211
+/connection dropped.*/d"])
61e211
+
61e211
+AT_CLEANUP
61e211
+])
61e211
+
61e211
+OVN_FOR_EACH_NORTHD([
61e211
+AT_SETUP([SNAT in separate zone from DNAT])
61e211
+
61e211
+CHECK_CONNTRACK()
61e211
+CHECK_CONNTRACK_NAT()
61e211
+ovn_start
61e211
+OVS_TRAFFIC_VSWITCHD_START()
61e211
+ADD_BR([br-int])
61e211
+
61e211
+# Set external-ids in br-int needed for ovn-controller
61e211
+ovs-vsctl \
61e211
+        -- set Open_vSwitch . external-ids:system-id=hv1 \
61e211
+        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
61e211
+        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
61e211
+        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
61e211
+        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
61e211
+
61e211
+# The goal of this test is to ensure that when traffic is first DNATted
61e211
+# (by way of a load balancer), and then SNATted, the SNAT happens in a
61e211
+# separate conntrack zone from the DNAT.
61e211
+
61e211
+start_daemon ovn-controller
61e211
+
61e211
+check ovn-nbctl ls-add public
61e211
+
61e211
+check ovn-nbctl lr-add r1
61e211
+check ovn-nbctl lrp-add r1 r1_public 00:de:ad:ff:00:01 172.16.0.1/16
61e211
+check ovn-nbctl lrp-add r1 r1_s1 00:de:ad:fe:00:01 173.0.1.1/24
61e211
+check ovn-nbctl lrp-set-gateway-chassis r1_public hv1
61e211
+
61e211
+check ovn-nbctl lb-add r1_lb 30.0.0.1 172.16.0.102
61e211
+check ovn-nbctl lr-lb-add r1 r1_lb
61e211
+
61e211
+check ovn-nbctl ls-add s1
61e211
+check ovn-nbctl lsp-add s1 s1_r1
61e211
+check ovn-nbctl lsp-set-type s1_r1 router
61e211
+check ovn-nbctl lsp-set-addresses s1_r1 router
61e211
+check ovn-nbctl lsp-set-options s1_r1 router-port=r1_s1
61e211
+
61e211
+check ovn-nbctl lsp-add s1 vm1
61e211
+check ovn-nbctl lsp-set-addresses vm1 "00:de:ad:01:00:01 173.0.1.2"
61e211
+
61e211
+check ovn-nbctl lsp-add public public_r1
61e211
+check ovn-nbctl lsp-set-type public_r1 router
61e211
+check ovn-nbctl lsp-set-addresses public_r1 router
61e211
+check ovn-nbctl lsp-set-options public_r1 router-port=r1_public nat-addresses=router
61e211
+
61e211
+check ovn-nbctl lr-add r2
61e211
+check ovn-nbctl lrp-add r2 r2_public 00:de:ad:ff:00:02 172.16.0.2/16
61e211
+check ovn-nbctl lrp-add r2 r2_s2 00:de:ad:fe:00:02 173.0.2.1/24
61e211
+check ovn-nbctl lr-nat-add r2 dnat_and_snat 172.16.0.102 173.0.2.2
61e211
+check ovn-nbctl lrp-set-gateway-chassis r2_public hv1
61e211
+
61e211
+check ovn-nbctl ls-add s2
61e211
+check ovn-nbctl lsp-add s2 s2_r2
61e211
+check ovn-nbctl lsp-set-type s2_r2 router
61e211
+check ovn-nbctl lsp-set-addresses s2_r2 router
61e211
+check ovn-nbctl lsp-set-options s2_r2 router-port=r2_s2
61e211
+
61e211
+check ovn-nbctl lsp-add s2 vm2
61e211
+check ovn-nbctl lsp-set-addresses vm2 "00:de:ad:01:00:02 173.0.2.2"
61e211
+
61e211
+check ovn-nbctl lsp-add public public_r2
61e211
+check ovn-nbctl lsp-set-type public_r2 router
61e211
+check ovn-nbctl lsp-set-addresses public_r2 router
61e211
+check ovn-nbctl lsp-set-options public_r2 router-port=r2_public nat-addresses=router
61e211
+
61e211
+ADD_NAMESPACES(vm1)
61e211
+ADD_VETH(vm1, vm1, br-int, "173.0.1.2/24", "00:de:ad:01:00:01", \
61e211
+         "173.0.1.1")
61e211
+ADD_NAMESPACES(vm2)
61e211
+ADD_VETH(vm2, vm2, br-int, "173.0.2.2/24", "00:de:ad:01:00:02", \
61e211
+         "173.0.2.1")
61e211
+
61e211
+check ovn-nbctl lr-nat-add r1 dnat_and_snat 172.16.0.101 173.0.1.2 vm1 00:00:00:01:02:03
61e211
+check ovn-nbctl --wait=hv sync
61e211
+
61e211
+# Next, make sure that a ping works as expected
61e211
+NS_CHECK_EXEC([vm1], [ping -q -c 3 -i 0.3 -w 2 30.0.0.1 | FORMAT_PING], \
61e211
+[0], [dnl
61e211
+3 packets transmitted, 3 received, 0% packet loss, time 0ms
61e211
+])
61e211
+
61e211
+# Finally, make sure that conntrack shows two separate zones being used for
61e211
+# DNAT and SNAT
61e211
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | \
61e211
+sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
61e211
+icmp,orig=(src=173.0.1.2,dst=30.0.0.1,id=<cleared>,type=8,code=0),reply=(src=172.16.0.102,dst=173.0.1.2,id=<cleared>,type=0,code=0),zone=<cleared>,mark=2
61e211
+])
61e211
+
61e211
+# The final two entries appear identical here. That is because FORMAT_CT
61e211
+# scrubs the zone numbers. In actuality, the zone numbers are different,
61e211
+# which is why there are two entries.
61e211
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.0.102) | \
61e211
+sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
61e211
+icmp,orig=(src=172.16.0.101,dst=172.16.0.102,id=<cleared>,type=8,code=0),reply=(src=173.0.2.2,dst=172.16.0.101,id=<cleared>,type=0,code=0),zone=<cleared>
61e211
+icmp,orig=(src=173.0.1.2,dst=172.16.0.102,id=<cleared>,type=8,code=0),reply=(src=172.16.0.102,dst=172.16.0.101,id=<cleared>,type=0,code=0),zone=<cleared>
61e211
+icmp,orig=(src=173.0.1.2,dst=172.16.0.102,id=<cleared>,type=8,code=0),reply=(src=172.16.0.102,dst=172.16.0.101,id=<cleared>,type=0,code=0),zone=<cleared>
61e211
+])
61e211
+
61e211
+OVS_APP_EXIT_AND_WAIT([ovn-controller])
61e211
+
61e211
+as ovn-sb
61e211
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
61e211
+
61e211
+as ovn-nb
61e211
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
61e211
+
61e211
+as northd
61e211
+OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE])
61e211
+
61e211
+as
61e211
+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
61e211
+/connection dropped.*/d"])
61e211
+AT_CLEANUP
61e211
+])