[ovs-dev] [PATCH v3 2/2 ovn] OVN: Use ip4.src and ip4.dst actions for NAT rules

Ankur Sharma ankur.sharma at nutanix.com
Tue Oct 29 21:59:05 UTC 2019


For dnat_and_snat rules which are meant to be stateless
instead of using ct_snat/dnat OVN actions, we will use
ip4.src/ip4.dst.

This actions will do 1:1 mapping to inner ip to external ip,
while recalculating the checksums.

Signed-off-by: Ankur Sharma <ankur.sharma at nutanix.com>
---
 northd/ovn-northd.8.xml |  34 ++++--
 northd/ovn-northd.c     |  86 +++++++++++--
 tests/ovn-northd.at     |  57 +++++++++
 tests/ovn.at            | 311 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 472 insertions(+), 16 deletions(-)

diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
index d3e0e5e..87a6909 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -1807,7 +1807,9 @@ icmp6 {
           to change the source IP address of a packet from <var>A</var> to
           <var>B</var>, a priority-90 flow matches <code>ip &amp;&amp;
           ip4.dst == <var>B</var></code> with an action
-          <code>ct_snat; </code>.
+          <code>ct_snat; </code>. If the NAT rule is of type dnat_and_snat
+          and has <code>stateless=true</code> in the options, then the action
+          would be <code>ip4.dst=(<var>B</var>)</code>.
         </p>
 
         <p>
@@ -1827,7 +1829,10 @@ icmp6 {
           <var>B</var>, a priority-100 flow matches <code>ip &amp;&amp;
           ip4.dst == <var>B</var> &amp;&amp; inport == <var>GW</var></code>,
           where <var>GW</var> is the logical router gateway port, with an
-          action <code>ct_snat;</code>.
+          action <code>ct_snat;</code>. If the NAT rule is of type
+          dnat_and_snat and has <code>stateless=true</code> in the
+          options, then the action would be <code>ip4.dst=
+          (<var>B</var>)</code>.
         </p>
 
         <p>
@@ -1947,7 +1952,10 @@ icmp6 {
         Gateway router is configured to force SNAT any DNATed packet,
         the above action will be replaced by
         <code>flags.force_snat_for_dnat = 1; flags.loopback = 1;
-        ct_dnat(<var>B</var>);</code>.
+        ct_dnat(<var>B</var>);</code>. If the NAT rule is of type
+        dnat_and_snat and has <code>stateless=true</code> in the
+        options, then the action would be <code>ip4.dst=
+        (<var>B</var>)</code>.
       </li>
 
       <li>
@@ -1979,7 +1987,10 @@ icmp6 {
           <var>B</var>, a priority-100 flow matches <code>ip &amp;&amp;
           ip4.dst == <var>B</var> &amp;&amp; inport == <var>GW</var></code>,
           where <var>GW</var> is the logical router gateway port, with an
-          action <code>ct_dnat(<var>B</var>);</code>.
+          action <code>ct_dnat(<var>B</var>);</code>. If the NAT rule is of
+          type dnat_and_snat and has <code>stateless=true</code> in the
+          options, then the action would be <code>ip4.dst=
+          (<var>B</var>)</code>.
         </p>
 
         <p>
@@ -2653,7 +2664,10 @@ nd_ns {
           matches <code>ip &amp;&amp; ip4.src == <var>B</var>
           &amp;&amp; outport == <var>GW</var></code>, where <var>GW</var>
           is the logical router gateway port, with an action
-          <code>ct_dnat;</code>.
+          <code>ct_dnat;</code>. If the NAT rule is of type
+          dnat_and_snat and has <code>stateless=true</code> in the
+          options, then the action would be <code>ip4.src=
+          (<var>B</var>)</code>.
         </p>
 
         <p>
@@ -2711,7 +2725,10 @@ nd_ns {
           <code>ip &amp;&amp; ip4.src == <var>A</var></code> with an action
           <code>ct_snat(<var>B</var>);</code>.  The priority of the flow
           is calculated based on the mask of <var>A</var>, with matches
-          having larger masks getting higher priorities.
+          having larger masks getting higher priorities. If the NAT rule is
+          of type dnat_and_snat and has <code>stateless=true</code> in the
+          options, then the action would be <code>ip4.src=
+          (<var>B</var>)</code>.
         </p>
         <p>
           A priority-0 logical flow with match <code>1</code> has actions
@@ -2734,7 +2751,10 @@ nd_ns {
           logical router gateway port, with an action
           <code>ct_snat(<var>B</var>);</code>.  The priority of the flow
           is calculated based on the mask of <var>A</var>, with matches
-          having larger masks getting higher priorities.
+          having larger masks getting higher priorities. If the NAT rule
+          is of type dnat_and_snat and has <code>stateless=true</code>
+          in the options, then the action would be <code>ip4.src=
+          (<var>B</var>)</code>.
         </p>
 
         <p>
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index 194e4bf..4431659 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -6500,6 +6500,18 @@ copy_ra_to_sb(struct ovn_port *op, const char *address_mode)
     smap_destroy(&options);
 }
 
+static inline bool
+lrouter_nat_is_stateless(const struct nbrec_nat *nat)
+{
+    const char *stateless = smap_get(&nat->options, "stateless");
+
+    if (stateless && !strcmp(stateless, "true")) {
+        return true;
+    }
+
+    return false;
+}
+
 static void
 build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
                     struct hmap *lflows, struct shash *meter_groups)
@@ -7261,6 +7273,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
             nat = od->nbr->nat[i];
 
             ovs_be32 ip, mask;
+            bool stateless = lrouter_nat_is_stateless(nat);
 
             char *error = ip_parse_masked(nat->external_ip, &ip, &mask);
             if (error || mask != OVS_BE32_MAX) {
@@ -7326,15 +7339,26 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
                 if (!od->l3dgw_port) {
                     /* Gateway router. */
                     ds_clear(&match);
+                    ds_clear(&actions);
                     ds_put_format(&match, "ip && ip4.dst == %s",
                                   nat->external_ip);
+
+                    if (!strcmp(nat->type, "dnat_and_snat") && stateless) {
+                        ds_put_format(&actions, "ip4.dst=%s; next;",
+                                      nat->logical_ip);
+                    } else {
+                        ds_put_cstr(&actions, "ct_snat;");
+                    }
+
                     ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 90,
-                                  ds_cstr(&match), "ct_snat;");
+                                  ds_cstr(&match), ds_cstr(&actions));
                 } else {
                     /* Distributed router. */
 
                     /* Traffic received on l3dgw_port is subject to NAT. */
                     ds_clear(&match);
+                    ds_clear(&actions);
+
                     ds_put_format(&match, "ip && ip4.dst == %s"
                                           " && inport == %s",
                                   nat->external_ip,
@@ -7345,8 +7369,16 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
                         ds_put_format(&match, " && is_chassis_resident(%s)",
                                       od->l3redirect_port->json_key);
                     }
+
+                    if (!strcmp(nat->type, "dnat_and_snat") && stateless) {
+                        ds_put_format(&actions, "ip4.dst=%s; next;",
+                                      nat->logical_ip);
+                    } else {
+                        ds_put_cstr(&actions, "ct_snat;");
+                    }
+
                     ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 100,
-                                  ds_cstr(&match), "ct_snat;");
+                                  ds_cstr(&match), ds_cstr(&actions));
 
                     /* Traffic received on other router ports must be
                      * redirected to the central instance of the l3dgw_port
@@ -7381,8 +7413,16 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
                         ds_put_format(&actions,
                                       "flags.force_snat_for_dnat = 1; ");
                     }
-                    ds_put_format(&actions, "flags.loopback = 1; ct_dnat(%s);",
-                                  nat->logical_ip);
+
+                    if (!strcmp(nat->type, "dnat_and_snat") && stateless) {
+                        ds_put_format(&actions, "flags.loopback = 1; "
+                                      "ip4.dst=%s; next;",
+                                      nat->logical_ip);
+                    } else {
+                        ds_put_format(&actions, "flags.loopback = 1; "
+                                      "ct_dnat(%s);", nat->logical_ip);
+                    }
+
                     ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 100,
                                   ds_cstr(&match), ds_cstr(&actions));
                 } else {
@@ -7401,8 +7441,15 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
                                       od->l3redirect_port->json_key);
                     }
                     ds_clear(&actions);
-                    ds_put_format(&actions, "ct_dnat(%s);",
-                                  nat->logical_ip);
+
+                    if (!strcmp(nat->type, "dnat_and_snat") && stateless) {
+                        ds_put_format(&actions, "ip4.dst=%s; next;",
+                                      nat->logical_ip);
+                    } else {
+                        ds_put_format(&actions, "ct_dnat(%s);",
+                                      nat->logical_ip);
+                    }
+
                     ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 100,
                                   ds_cstr(&match), ds_cstr(&actions));
 
@@ -7444,7 +7491,14 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
                     ds_put_format(&actions, "eth.src = "ETH_ADDR_FMT"; ",
                                   ETH_ADDR_ARGS(mac));
                 }
-                ds_put_format(&actions, "ct_dnat;");
+
+                if (!strcmp(nat->type, "dnat_and_snat") && stateless) {
+                    ds_put_format(&actions, "ip4.src=%s; next;",
+                                  nat->external_ip);
+                } else {
+                    ds_put_format(&actions, "ct_dnat;");
+                }
+
                 ovn_lflow_add(lflows, od, S_ROUTER_OUT_UNDNAT, 100,
                               ds_cstr(&match), ds_cstr(&actions));
             }
@@ -7460,7 +7514,14 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
                     ds_put_format(&match, "ip && ip4.src == %s",
                                   nat->logical_ip);
                     ds_clear(&actions);
-                    ds_put_format(&actions, "ct_snat(%s);", nat->external_ip);
+
+                    if (!strcmp(nat->type, "dnat_and_snat") && stateless) {
+                        ds_put_format(&actions, "ip4.src=%s; next;",
+                                      nat->external_ip);
+                    } else {
+                        ds_put_format(&actions, "ct_snat(%s);",
+                                      nat->external_ip);
+                    }
 
                     /* The priority here is calculated such that the
                      * nat->logical_ip with the longest mask gets a higher
@@ -7489,7 +7550,14 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
                         ds_put_format(&actions, "eth.src = "ETH_ADDR_FMT"; ",
                                       ETH_ADDR_ARGS(mac));
                     }
-                    ds_put_format(&actions, "ct_snat(%s);", nat->external_ip);
+
+                    if (!strcmp(nat->type, "dnat_and_snat") && stateless) {
+                        ds_put_format(&actions, "ip4.src=%s; next;",
+                                      nat->external_ip);
+                    } else {
+                        ds_put_format(&actions, "ct_snat(%s);",
+                                      nat->external_ip);
+                    }
 
                     /* The priority here is calculated such that the
                      * nat->logical_ip with the longest mask gets a higher
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index 42033d5..60b3d11 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -966,3 +966,60 @@ OVS_WAIT_UNTIL([ovn-sbctl get Port_Binding ${uuid} options:redirect-type], [0],
 ])
 
 AT_CLEANUP
+
+AT_SETUP([ovn -- check stateless dnat_and_snat rule])
+AT_SKIP_IF([test $HAVE_PYTHON = no])
+ovn_start
+
+ovn-sbctl chassis-add gw1 geneve 127.0.0.1
+
+ovn-nbctl lr-add R1
+ovn-nbctl lrp-add R1 R1-S1 02:ac:10:01:00:01 172.16.1.1/24
+
+ovn-nbctl ls-add S1
+ovn-nbctl lsp-add S1 S1-R1
+ovn-nbctl lsp-set-type S1-R1 router
+ovn-nbctl lsp-set-addresses S1-R1 router
+ovn-nbctl --wait=sb lsp-set-options S1-R1 router-port=R1-S1
+
+ovn-nbctl lrp-set-gateway-chassis R1-S1 gw1
+
+uuid=`ovn-sbctl --columns=_uuid --bare find Port_Binding logical_port=cr-R1-S1`
+echo "CR-LRP UUID is: " $uuid
+
+ovn-nbctl lr-nat-add R1 dnat_and_snat  172.16.1.1 50.0.0.11
+
+OVS_WAIT_UNTIL([test 3 = `ovn-sbctl dump-flows R1 | grep lr_in_unsnat | \
+wc -l`])
+
+AT_CHECK([ovn-sbctl dump-flows R1 | grep ct_snat | wc -l], [0], [2
+])
+
+AT_CHECK([ovn-sbctl dump-flows R1 | grep ct_dnat | wc -l], [0], [2
+])
+
+AT_CHECK([ovn-sbctl dump-flows R1 | grep ip4.dst=| wc -l], [0], [0
+])
+
+AT_CHECK([ovn-sbctl dump-flows R1 | grep ip4.src=| wc -l], [0], [0
+])
+
+ovn-nbctl lr-nat-del R1 dnat_and_snat  172.16.1.1
+
+ovn-nbctl --stateless lr-nat-add R1 dnat_and_snat  172.16.1.1 50.0.0.11
+OVS_WAIT_UNTIL([test 3 = `ovn-sbctl dump-flows R1 | grep lr_in_unsnat | \
+wc -l`])
+
+AT_CHECK([ovn-sbctl dump-flows R1 | grep ct_snat | wc -l], [0], [0
+])
+
+AT_CHECK([ovn-sbctl dump-flows R1 | grep ct_dnat | wc -l], [0], [0
+])
+
+AT_CHECK([ovn-sbctl dump-flows R1 | grep ip4.dst=| wc -l], [0], [2
+])
+
+AT_CHECK([ovn-sbctl dump-flows R1 | grep ip4.src=| wc -l], [0], [2
+])
+
+AT_CLEANUP
diff --git a/tests/ovn.at b/tests/ovn.at
index 9f06059..0922bf6 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -16359,3 +16359,314 @@ grep 101 | wc -l`])
 OVN_CLEANUP([hv1])
 
 AT_CLEANUP
+
+AT_SETUP([ovn -- Stateless Floating IP])
+ovn_start
+
+# In this test cases we create 3 switches, all connected to same
+# physical network (through br-phys on each HV). LS1 and LS2 have
+# 1 VIF each. Each HV has 1 VIF port. The first digit
+# of VIF port name indicates the hypervisor it is bound to, e.g.
+# lp23 means VIF 3 on hv2.
+#
+# All the switches are connected to a logical router "router".
+#
+# There is an external logical switch, ls-north.
+# This test validates the stateless floating ip implementation.
+#
+# Each switch's VLAN tag and their logical switch ports are:
+#   - ls1:
+#       - tagged with VLAN 101
+#       - ports: lp11
+#   - ls2:
+#       - tagged with VLAN 201
+#       - ports: lp22
+#   - ls-north:
+#       - tagged with VLAN 1000
+# Note: a localnet port is created for each switch to connect to
+# physical network.
+
+for i in 1 2; do
+    ls_name=ls$i
+    ovn-nbctl ls-add $ls_name
+    ln_port_name=ln$i
+    if test $i -eq 1; then
+        ovn-nbctl lsp-add $ls_name $ln_port_name "" 101
+    elif test $i -eq 2; then
+        ovn-nbctl lsp-add $ls_name $ln_port_name "" 201
+    fi
+    ovn-nbctl lsp-set-addresses $ln_port_name unknown
+    ovn-nbctl lsp-set-type $ln_port_name localnet
+    ovn-nbctl lsp-set-options $ln_port_name network_name=phys
+done
+
+# lsp_to_ls LSP
+#
+# Prints the name of the logical switch that contains LSP.
+lsp_to_ls () {
+    case $1 in dnl (
+        lp?[[11]]) echo ls1 ;; dnl (
+        lp?[[12]]) echo ls2 ;; dnl (
+        *) AT_FAIL_IF([:]) ;;
+    esac
+}
+
+vif_to_hv () {
+    case $1 in dnl (
+        vif[[1]]?) echo hv1 ;; dnl (
+        vif[[2]]?) echo hv2 ;; dnl (
+        vif?[[north]]?) echo hv4 ;; dnl (
+        *) AT_FAIL_IF([:]) ;;
+    esac
+}
+
+ip_to_hex() {
+       printf "%02x%02x%02x%02x" "$@"
+}
+
+net_add n1
+for i in 1 2; do
+    sim_add hv$i
+    as hv$i
+    ovs-vsctl add-br br-phys
+    ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
+    ovs-vsctl set open . external-ids:ovn-chassis-mac-mappings="phys:aa:bb:cc:dd:ee:$i$i"
+    ovn_attach n1 br-phys 192.168.0.$i
+
+    ovs-vsctl add-port br-int vif$i$i -- \
+        set Interface vif$i$i external-ids:iface-id=lp$i$i \
+                              options:tx_pcap=hv$i/vif$i$i-tx.pcap \
+                              options:rxq_pcap=hv$i/vif$i$i-rx.pcap \
+                              ofport-request=$i$i
+
+    lsp_name=lp$i$i
+    ls_name=$(lsp_to_ls $lsp_name)
+
+    ovn-nbctl lsp-add $ls_name $lsp_name
+    ovn-nbctl lsp-set-addresses $lsp_name "f0:00:00:00:00:$i$i 192.168.$i.$i"
+    ovn-nbctl lsp-set-port-security $lsp_name f0:00:00:00:00:$i$i
+
+    OVS_WAIT_UNTIL([test x`ovn-nbctl lsp-get-up $lsp_name` = xup])
+
+done
+
+ovn-nbctl ls-add ls-underlay
+ovn-nbctl lsp-add ls-underlay ln3 "" 1000
+ovn-nbctl lsp-set-addresses ln3 unknown
+ovn-nbctl lsp-set-type ln3 localnet
+ovn-nbctl lsp-set-options ln3 network_name=phys
+
+ovn-nbctl ls-add ls-north
+ovn-nbctl lsp-add ls-north ln4 "" 1000
+ovn-nbctl lsp-set-addresses ln4 unknown
+ovn-nbctl lsp-set-type ln4 localnet
+ovn-nbctl lsp-set-options ln4 network_name=phys
+
+# Add a VM on ls-north
+ovn-nbctl lsp-add ls-north lp-north
+ovn-nbctl lsp-set-addresses lp-north "f0:f0:00:00:00:11 172.31.0.10"
+ovn-nbctl lsp-set-port-security lp-north f0:f0:00:00:00:11
+
+# Add 3rd hypervisor
+sim_add hv3
+as hv3 ovs-vsctl add-br br-phys
+as hv3 ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
+as hv3 ovs-vsctl set open . external-ids:ovn-chassis-mac-mappings="phys:aa:bb:cc:dd:ee:33"
+as hv3 ovn_attach n1 br-phys 192.168.0.3
+
+# Add 4th hypervisor
+sim_add hv4
+as hv4 ovs-vsctl add-br br-phys
+as hv4 ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
+as hv4 ovs-vsctl set open . external-ids:ovn-chassis-mac-mappings="phys:aa:bb:cc:dd:ee:44"
+as hv4 ovn_attach n1 br-phys 192.168.0.4
+
+as hv4 ovs-vsctl add-port br-int vif-north -- \
+        set Interface vif-north external-ids:iface-id=lp-north \
+                              options:tx_pcap=hv4/vif-north-tx.pcap \
+                              options:rxq_pcap=hv4/vif-north-rx.pcap \
+                              ofport-request=44
+
+ovn-nbctl lr-add router
+ovn-nbctl lrp-add router router-to-ls1 00:00:01:01:02:03 192.168.1.3/24
+ovn-nbctl lrp-add router router-to-ls2 00:00:01:01:02:05 192.168.2.3/24
+ovn-nbctl lrp-add router router-to-underlay 00:00:01:01:02:07 172.31.0.1/24
+
+ovn-nbctl lsp-add ls1 ls1-to-router -- set Logical_Switch_Port ls1-to-router type=router \
+          options:router-port=router-to-ls1 -- lsp-set-addresses ls1-to-router router
+ovn-nbctl lsp-add ls2 ls2-to-router -- set Logical_Switch_Port ls2-to-router type=router \
+          options:router-port=router-to-ls2 -- lsp-set-addresses ls2-to-router router
+ovn-nbctl lsp-add ls-underlay underlay-to-router -- set Logical_Switch_Port \
+                              underlay-to-router type=router \
+                              options:router-port=router-to-underlay \
+                              -- lsp-set-addresses underlay-to-router router
+
+ovn-nbctl lrp-set-gateway-chassis router-to-underlay hv3
+ovn-nbctl --stateless lr-nat-add router dnat_and_snat 172.31.0.100 192.168.1.1
+ovn-nbctl lrp-set-redirect-type router-to-underlay bridged
+
+ovn-nbctl --wait=sb sync
+
+
+OVN_POPULATE_ARP
+
+# lsp_to_ls LSP
+#
+# Prints the name of the logical switch that contains LSP.
+lsp_to_ls () {
+    case $1 in dnl (
+        lp?[[11]]) echo ls1 ;; dnl (
+        lp?[[12]]) echo ls2 ;; dnl (
+        *) AT_FAIL_IF([:]) ;;
+    esac
+}
+
+vif_to_ls () {
+    case $1 in dnl (
+        vif?[[11]]) echo ls1 ;; dnl (
+        vif?[[12]]) echo ls2 ;; dnl (
+        vif-north) echo ls-north ;; dnl (
+        *) AT_FAIL_IF([:]) ;;
+    esac
+}
+
+hv_to_num () {
+    case $1 in dnl (
+        hv1) echo 1 ;; dnl (
+        hv2) echo 2 ;; dnl (
+        hv3) echo 3 ;; dnl (
+        hv4) echo 4 ;; dnl (
+        *) AT_FAIL_IF([:]) ;;
+    esac
+}
+
+vif_to_num () {
+    case $1 in dnl (
+        vif22) echo 22 ;; dnl (
+        vif21) echo 21 ;; dnl (
+        vif11) echo 11 ;; dnl (
+        *) AT_FAIL_IF([:]) ;;
+    esac
+}
+
+vif_to_hv () {
+    case $1 in dnl (
+        vif[[1]]?) echo hv1 ;; dnl (
+        vif[[2]]?) echo hv2 ;; dnl (
+        vif-north) echo hv4 ;; dnl (
+        *) AT_FAIL_IF([:]) ;;
+    esac
+}
+
+vif_to_lrp () {
+    echo router-to-`vif_to_ls $1`
+}
+
+ip_to_hex() {
+       printf "%02x%02x%02x%02x" "$@"
+}
+
+
+test_ip() {
+        # This packet has bad checksums but logical L3 routing doesn't check.
+        local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5 outport=$6
+        local packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000
+        shift; shift; shift; shift; shift
+        hv=`vif_to_hv $inport`
+        as $hv ovs-appctl netdev-dummy/receive $inport $packet
+        in_ls=`vif_to_ls $inport`
+        for outport; do
+            out_ls=`vif_to_ls $outport`
+            if test $in_ls = $out_ls; then
+                # Ports on the same logical switch receive exactly the same packet.
+                echo $packet
+            else
+                # Routing decrements TTL and updates source and dest MAC
+                # (and checksum).
+                out_lrp=`vif_to_lrp $outport`
+                # For North-South, packet will come via gateway chassis, i.e hv3
+                if test $inport = vif-north; then
+                    echo f0000000001100000101020308004500001c000000003f110100${src_ip}${dst_ip}0035111100080000 >> $outport.expected
+                fi
+                if test $outport = vif-north; then
+                    echo f0f00000001100000101020708004500001c000000003e111726ac1f0064${dst_ip}0035111100080000 >> $outport.expected
+                fi
+            fi >> $outport.expected
+        done
+}
+
+# Dump a bunch of info helpful for debugging if there's a failure.
+
+echo "------ OVN dump ------"
+ovn-nbctl show
+ovn-nbctl lr-nat-list router
+ovn-sbctl show
+ovn-sbctl list port_binding
+ovn-sbctl list mac_binding
+ovn-sbctl dump-flows
+
+echo "------ hv1 dump ------"
+as hv1 ovs-vsctl show
+as hv1 ovs-vsctl list Open_Vswitch
+
+echo "------ hv2 dump ------"
+as hv2 ovs-vsctl show
+as hv2 ovs-vsctl list Open_Vswitch
+
+echo "------ hv3 dump ------"
+as hv3 ovs-vsctl show
+as hv3 ovs-vsctl list Open_Vswitch
+
+echo "------ hv4 dump ------"
+as hv4 ovs-vsctl show
+as hv4 ovs-vsctl list Open_Vswitch
+
+echo "Send traffic South to Nouth"
+sip=`ip_to_hex 192 168 1 1`
+dip=`ip_to_hex 172 31 0 10`
+test_ip vif11 f00000000011 000001010203 $sip $dip vif-north
+
+# Confirm that South to North traffic works fine.
+OVN_CHECK_PACKETS_REMOVE_BROADCAST([hv4/vif-north-tx.pcap], [vif-north.expected])
+
+# Confirm that NATing happened without connection tracker
+
+AT_CHECK([ovn-sbctl dump-flows router | grep ct_snat | wc -l], [0], [0
+])
+
+AT_CHECK([ovn-sbctl dump-flows router | grep ct_dnat | wc -l], [0], [0
+])
+
+AT_CHECK([ovn-sbctl dump-flows router | grep ip4.dst=| wc -l], [0], [2
+])
+
+AT_CHECK([ovn-sbctl dump-flows router | grep ip4.src=| wc -l], [0], [2
+])
+
+echo "----------- Post Traffic hv1 dump -----------"
+as hv1 ovs-ofctl dump-flows br-int
+as hv1 ovs-ofctl show br-phys
+as hv1 ovs-appctl fdb/show br-phys
+as hv1 ovs-dpctl dump-flows
+
+echo "----------- Post Traffic hv2 dump -----------"
+as hv2 ovs-ofctl dump-flows br-int
+as hv2 ovs-ofctl show br-phys
+as hv2 ovs-appctl fdb/show br-phys
+
+echo "----------- Post Traffic hv3 dump -----------"
+as hv3 ovs-ofctl dump-flows br-int
+as hv3 ovs-ofctl show br-phys
+as hv3 ovs-appctl dpctl/dump-conntrack
+as hv3 ovs-appctl fdb/show br-phys
+as hv3 ovs-dpctl dump-flows
+as hv3 ovs-ofctl dump-flows br-int
+
+echo "----------- Post Traffic hv4 dump -----------"
+as hv4 ovs-ofctl dump-flows br-int
+as hv4 ovs-ofctl show br-phys
+as hv4 ovs-appctl fdb/show br-phys
+
+OVN_CLEANUP([hv1],[hv2],[hv3],[hv4])
+
+AT_CLEANUP
-- 
1.8.3.1



More information about the dev mailing list