We currently have the ability to add a large network to
match on the source IP address of a packet and then SNAT
it to a external_ip.  For e.g. one could add a SNAT rule
that SNATs all packets with source IP address of
"0.0.0.0/0" to 10.1.1.10.

It is useful to make a small subnet to pass-through without
any SNAT done on it. For e.g a subnet that is routable in
the external network. This commit adds a "nosnat" option
to the NAT table.

Signed-off-by: Gurucharan Shetty <g...@ovn.org>
---
 ovn/northd/ovn-northd.8.xml |  8 ++++++++
 ovn/northd/ovn-northd.c     | 38 ++++++++++++++++++++++++++++----------
 ovn/ovn-nb.ovsschema        |  5 +++--
 ovn/ovn-nb.xml              |  7 +++++++
 tests/system-ovn.at         | 17 +++++++++++++++++
 5 files changed, 63 insertions(+), 12 deletions(-)

diff --git a/ovn/northd/ovn-northd.8.xml b/ovn/northd/ovn-northd.8.xml
index df53d4c..b406db6 100644
--- a/ovn/northd/ovn-northd.8.xml
+++ b/ovn/northd/ovn-northd.8.xml
@@ -1434,6 +1434,14 @@ arp {
       <li>
         <p>
           For each configuration in the OVN Northbound database, that asks
+          NOT to change the source IP address of a packet with address
+          <var>A</var> or NOT to change the source IP address of a packet that
+          belongs to network <var>A</var>, a priority-100 flow with a match of
+          <code>ip &amp;&amp; ip4.src == <var>A</var></code> and an action of
+          <code>next;</code>.
+        </p>
+        <p>
+          For each configuration in the OVN Northbound database, that asks
           to change the source IP address of a packet from an IP address of
           <var>A</var> or to change the source IP address of a packet that
           belongs to network <var>A</var> to <var>B</var>, a flow matches
diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index 07c7b2d..86504aa 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -3680,6 +3680,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap 
*ports,
 
             nat = op->od->nbr->nat[i];
 
+            if (!strcmp(nat->type, "nosnat")) {
+                continue;
+            }
+
             ovs_be32 ip;
             if (!ip_parse(nat->external_ip, &ip) || !ip) {
                 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
@@ -3920,19 +3924,24 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap 
*ports,
 
             ovs_be32 ip, mask;
 
-            char *error = ip_parse_masked(nat->external_ip, &ip, &mask);
-            if (error || mask != OVS_BE32_MAX) {
-                static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
-                VLOG_WARN_RL(&rl, "bad external ip %s for nat",
-                             nat->external_ip);
-                free(error);
-                continue;
+            if (strcmp(nat->type, "nosnat")) {
+                /* "nosnat" cases do not have a 'external_ip'.  Every other
+                 * case should have a valid 'external_ip'. */
+                char *error = ip_parse_masked(nat->external_ip, &ip, &mask);
+                if (error || mask != OVS_BE32_MAX) {
+                    static struct vlog_rate_limit rl
+                            = VLOG_RATE_LIMIT_INIT(5, 1);
+                    VLOG_WARN_RL(&rl, "bad external ip %s for nat",
+                                 nat->external_ip);
+                    free(error);
+                    continue;
+                }
             }
 
             /* Check the validity of nat->logical_ip. 'logical_ip' can
-             * be a subnet when the type is "snat". */
-            error = ip_parse_masked(nat->logical_ip, &ip, &mask);
-            if (!strcmp(nat->type, "snat")) {
+             * be a subnet when the type is "snat" or "nosnat". */
+            char *error = ip_parse_masked(nat->logical_ip, &ip, &mask);
+            if (!strcmp(nat->type, "snat") || !strcmp(nat->type, "nosnat")) {
                 if (error) {
                     static struct vlog_rate_limit rl =
                         VLOG_RATE_LIMIT_INIT(5, 1);
@@ -3987,6 +3996,15 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap 
*ports,
                               ds_cstr(&match), ds_cstr(&actions));
             }
 
+            /* Egress SNAT table: Skip packets that have a specific 'nosnat'
+             * rule. */
+            if (!strcmp(nat->type, "nosnat")) {
+                ds_clear(&match);
+                ds_put_format(&match, "ip && ip4.src == %s", nat->logical_ip);
+                ovn_lflow_add(lflows, od, S_ROUTER_OUT_SNAT, 100,
+                              ds_cstr(&match), "next;");
+            }
+
             /* Egress SNAT table: Packets enter the egress pipeline with
              * source ip address that needs to be SNATted to a external ip
              * address. */
diff --git a/ovn/ovn-nb.ovsschema b/ovn/ovn-nb.ovsschema
index 65f2d7c..8cfc8a6 100644
--- a/ovn/ovn-nb.ovsschema
+++ b/ovn/ovn-nb.ovsschema
@@ -1,7 +1,7 @@
 {
     "name": "OVN_Northbound",
-    "version": "5.4.1",
-    "cksum": "3773248894 11490",
+    "version": "5.4.2",
+    "cksum": "3390487716 11561",
     "tables": {
         "NB_Global": {
             "columns": {
@@ -210,6 +210,7 @@
                 "type": {"type": {"key": {"type": "string",
                                            "enum": ["set", ["dnat",
                                                              "snat",
+                                                             "nosnat",
                                                              "dnat_and_snat"
                                                                ]]}}}},
             "isRoot": false},
diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml
index 7626551..e16e1c2 100644
--- a/ovn/ovn-nb.xml
+++ b/ovn/ovn-nb.xml
@@ -1155,6 +1155,13 @@
           <ref column="external_ip"/>.
         </li>
         <li>
+          When <ref column="type"/> is <code>nosnat</code>, IP packets
+          with their source IP address that either matches the IP address
+          in <ref column="logical_ip"/> or is in the network provided by
+          <ref column="logical_ip"/> is not SNATed and is allowed to
+          pass-through.
+        </li>
+        <li>
           When <ref column="type"/> is <code>dnat_and_snat</code>, the
           externally visible IP address <ref column="external_ip"/> is
           DNATted to the IP address <ref column="logical_ip"/> in the
diff --git a/tests/system-ovn.at b/tests/system-ovn.at
index 21226d9..d627f76 100644
--- a/tests/system-ovn.at
+++ b/tests/system-ovn.at
@@ -263,6 +263,23 @@ sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
 
icmp,orig=(src=192.168.1.2,dst=172.16.1.2,id=<cleared>,type=8,code=0),reply=(src=172.16.1.2,dst=172.16.1.1,id=<cleared>,type=0,code=0),zone=<cleared>
 ])
 
+ovs-appctl dpctl/flush-conntrack
+
+# Add a "nosnat" rule.
+ovn-nbctl -- --id=@nat create nat type="nosnat" logical_ip=192.168.1.0/24 \
+     -- add logical_router R2 nat @nat
+
+# South-North NOSNAT: 'foo1' pings 'alice1'. 'alice1' receives traffic
+# from 192.168.1.2 (i.e without NAT)
+NS_CHECK_EXEC([foo1], [ping -q -c 3 -i 0.3 -w 2 172.16.1.2 | FORMAT_PING], \
+[0], [dnl
+3 packets transmitted, 3 received, 0% packet loss, time 0ms
+])
+
+# We verify that SNAT did not happen via 'dump-conntrack' command.
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.1.1)], [0], [dnl
+])
+
 OVS_APP_EXIT_AND_WAIT([ovn-controller])
 
 as ovn-sb
-- 
1.9.1

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to