[ovs-dev,2/3] ovn: Ability to skip some IP addresses for SNAT.
diff mbox

Message ID 1478170006-15289-2-git-send-email-guru@ovn.org
State Superseded
Headers show

Commit Message

Gurucharan Shetty Nov. 3, 2016, 10:46 a.m. UTC
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 <guru@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(-)

Comments

Manoj Sharma June 19, 2017, 7:16 p.m. UTC | #1
Hi Guru,

It looked very useful patch. Do you plan to commit it into main?
Was there any reason to not merge it so far?


Regards
- Manoj


On 11/3/16, 3:46 AM, "dev on behalf of Gurucharan Shetty" <dev-bounces@openvswitch.org on behalf of guru@ovn.org> wrote:

>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 <guru@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
Gurucharan Shetty June 19, 2017, 8:04 p.m. UTC | #2
On 19 June 2017 at 12:16, Manoj Sharma <manoj.sharma@nutanix.com> wrote:

> Hi Guru,
>
> It looked very useful patch. Do you plan to commit it into main?
> Was there any reason to not merge it so far?
>

Is there a use case for which you want to use it? What is the use case?
This is an old patch and if you think it is useful, please consider
spending some time rebasing it to the current master and running all the
system tests to make sure that it does not introduce any regression.


>
>
> Regards
> - Manoj
>
>
> On 11/3/16, 3:46 AM, "dev on behalf of Gurucharan Shetty" <
> dev-bounces@openvswitch.org on behalf of guru@ovn.org> wrote:
>
> >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 <guru@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
>
Manoj Sharma June 20, 2017, 6:17 a.m. UTC | #3
The use case is if someone wants to access a VM from on-prem then it is an l3vpn and we should not do SNAT for it. Both sides should be using their logical IPs.
However the match for “nosnat” should be on destination IP.

I will rebase it to current master and run the tests.

Regards
- Manoj

From: Guru Shetty <guru@ovn.org<mailto:guru@ovn.org>>

Date: Monday, June 19, 2017 at 1:04 PM
To: Manoj Sharma <manoj.sharma@nutanix.com<mailto:manoj.sharma@nutanix.com>>
Cc: "dev@openvswitch.org<mailto:dev@openvswitch.org>" <dev@openvswitch.org<mailto:dev@openvswitch.org>>
Subject: Re: [ovs-dev] [PATCH 2/3] ovn: Ability to skip some IP addresses for SNAT.



On 19 June 2017 at 12:16, Manoj Sharma <manoj.sharma@nutanix.com<mailto:manoj.sharma@nutanix.com>> wrote:
Hi Guru,

It looked very useful patch. Do you plan to commit it into main?
Was there any reason to not merge it so far?

Is there a use case for which you want to use it? What is the use case? This is an old patch and if you think it is useful, please consider spending some time rebasing it to the current master and running all the system tests to make sure that it does not introduce any regression.



Regards
- Manoj


On 11/3/16, 3:46 AM, "dev on behalf of Gurucharan Shetty" <dev-bounces@openvswitch.org<mailto:dev-bounces@openvswitch.org> on behalf of guru@ovn.org<mailto:guru@ovn.org>> wrote:

>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<http://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 <guru@ovn.org<mailto:guru@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<http://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 && 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<http://system-ovn.at> b/tests/system-ovn.at<http://system-ovn.at>

>index 21226d9..d627f76 100644

>--- a/tests/system-ovn.at<http://system-ovn.at>

>+++ b/tests/system-ovn.at<http://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<http://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<mailto:dev@openvswitch.org>

>http://openvswitch.org/mailman/listinfo/dev<http://openvswitch.org/mailman/listinfo/dev>
Gurucharan Shetty June 20, 2017, 2:04 p.m. UTC | #4
On 19 June 2017 at 23:17, Manoj Sharma <manoj.sharma@nutanix.com> wrote:

> The use case is if someone wants to access a VM from on-prem then it is an
> l3vpn and we should not do SNAT for it.
>

Please expand on the above. What does "on-prem" mean in the context of OVN?
And is the VM a OVN logical port?



> Both sides should be using their logical IPs.
>
This confuses me. If both sides use logical IP, it reads to me that both
sides are OVN logical ports. In that case, why do we even needs SNATs? Why
is the packet even going to a gateway?


> However the match for “nosnat” should be on destination IP.
>
> I will rebase it to current master and run the tests.
>
> Regards
> - Manoj
>
> From: Guru Shetty <guru@ovn.org>
> Date: Monday, June 19, 2017 at 1:04 PM
> To: Manoj Sharma <manoj.sharma@nutanix.com>
> Cc: "dev@openvswitch.org" <dev@openvswitch.org>
> Subject: Re: [ovs-dev] [PATCH 2/3] ovn: Ability to skip some IP addresses
> for SNAT.
>
>
>
> On 19 June 2017 at 12:16, Manoj Sharma <manoj.sharma@nutanix.com> wrote:
>
>> Hi Guru,
>>
>> It looked very useful patch. Do you plan to commit it into main?
>> Was there any reason to not merge it so far?
>>
>
> Is there a use case for which you want to use it? What is the use case?
> This is an old patch and if you think it is useful, please consider
> spending some time rebasing it to the current master and running all the
> system tests to make sure that it does not introduce any regression.
>
>
>>
>>
>> Regards
>> - Manoj
>>
>>
>> On 11/3/16, 3:46 AM, "dev on behalf of Gurucharan Shetty" <
>> dev-bounces@openvswitch.org on behalf of guru@ovn.org> wrote:
>>
>> >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 <guru@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 && 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
>>
>
>
Manoj Sharma June 20, 2017, 9:52 p.m. UTC | #5
Hi Guru,

Please see my answer below:

On 19 June 2017 at 23:17, Manoj Sharma <manoj.sharma@nutanix.com<mailto:manoj.sharma@nutanix.com>> wrote:
The use case is if someone wants to access a VM from on-prem then it is an l3vpn and we should not do SNAT for it.

> Please expand on the above. What does "on-prem" mean in the context of OVN? And is the VM a OVN logical port?


I have two OVN networks at two different locations and they are connected through a gateway. I want the SNAT to happen for internet traffic but not for the inter-office traffic because it is a single private network stretched across two locations.


Both sides should be using their logical IPs.
> This confuses me. If both sides use logical IP, it reads to me that both sides are OVN logical ports. In that case, why do we even needs SNATs? Why is the packet even >going to a gateway?


Its a single layer 3 private network spanning across two OVN domains. They should use their logical IP while talking to each other.


However the match for “nosnat” should be on destination IP.

I will rebase it to current master and run the tests.

Regards
- Manoj

From: Guru Shetty <guru@ovn.org<mailto:guru@ovn.org>>

Date: Monday, June 19, 2017 at 1:04 PM
To: Manoj Sharma <manoj.sharma@nutanix.com<mailto:manoj.sharma@nutanix.com>>
Cc: "dev@openvswitch.org<mailto:dev@openvswitch.org>" <dev@openvswitch.org<mailto:dev@openvswitch.org>>
Subject: Re: [ovs-dev] [PATCH 2/3] ovn: Ability to skip some IP addresses for SNAT.



On 19 June 2017 at 12:16, Manoj Sharma <manoj.sharma@nutanix.com<mailto:manoj.sharma@nutanix.com>> wrote:
Hi Guru,

It looked very useful patch. Do you plan to commit it into main?
Was there any reason to not merge it so far?

Is there a use case for which you want to use it? What is the use case? This is an old patch and if you think it is useful, please consider spending some time rebasing it to the current master and running all the system tests to make sure that it does not introduce any regression.



Regards
- Manoj


On 11/3/16, 3:46 AM, "dev on behalf of Gurucharan Shetty" <dev-bounces@openvswitch.org<mailto:dev-bounces@openvswitch.org> on behalf of guru@ovn.org<mailto:guru@ovn.org>> wrote:

>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<http://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 <guru@ovn.org<mailto:guru@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<http://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 && 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<http://system-ovn.at> b/tests/system-ovn.at<http://system-ovn.at>

>index 21226d9..d627f76 100644

>--- a/tests/system-ovn.at<http://system-ovn.at>

>+++ b/tests/system-ovn.at<http://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<http://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<mailto:dev@openvswitch.org>

>http://openvswitch.org/mailman/listinfo/dev<http://openvswitch.org/mailman/listinfo/dev>
Gurucharan Shetty June 21, 2017, 3:09 p.m. UTC | #6
On 20 June 2017 at 14:52, Manoj Sharma <manoj.sharma@nutanix.com> wrote:

> Hi Guru,
>
> Please see my answer below:
>
> On 19 June 2017 at 23:17, Manoj Sharma <manoj.sharma@nutanix.com> wrote:
>
>> The use case is if someone wants to access a VM from on-prem then it is
>> an l3vpn and we should not do SNAT for it.
>>
>
> > Please expand on the above. What does "on-prem" mean in the context of
> OVN? And is the VM a OVN logical port?
>
> I have two OVN networks at two different locations and they are connected
> through a gateway. I want the SNAT to happen for internet traffic but not
> for the inter-office traffic because it is a single private network
> stretched across two locations.
>

Okay. Your physical infrastructure knows how to route OVN's logical IP
addresses?

Does this use gateway routers or does it use distributed router ports?


>
>
>
>> Both sides should be using their logical IPs.
>>
> > This confuses me. If both sides use logical IP, it reads to me that both
> sides are OVN logical ports. In that case, why do we even needs SNATs? Why
> is the packet even >going to a gateway?
>
> Its a single layer 3 private network spanning across two OVN domains. They
> should use their logical IP while talking to each other.
>
>
> However the match for “nosnat” should be on destination IP.
>>
>> I will rebase it to current master and run the tests.
>>
>> Regards
>> - Manoj
>>
>> From: Guru Shetty <guru@ovn.org>
>> Date: Monday, June 19, 2017 at 1:04 PM
>> To: Manoj Sharma <manoj.sharma@nutanix.com>
>> Cc: "dev@openvswitch.org" <dev@openvswitch.org>
>> Subject: Re: [ovs-dev] [PATCH 2/3] ovn: Ability to skip some IP
>> addresses for SNAT.
>>
>>
>>
>> On 19 June 2017 at 12:16, Manoj Sharma <manoj.sharma@nutanix.com> wrote:
>>
>>> Hi Guru,
>>>
>>> It looked very useful patch. Do you plan to commit it into main?
>>> Was there any reason to not merge it so far?
>>>
>>
>> Is there a use case for which you want to use it? What is the use case?
>> This is an old patch and if you think it is useful, please consider
>> spending some time rebasing it to the current master and running all the
>> system tests to make sure that it does not introduce any regression.
>>
>>
>>>
>>>
>>> Regards
>>> - Manoj
>>>
>>>
>>> On 11/3/16, 3:46 AM, "dev on behalf of Gurucharan Shetty" <
>>> dev-bounces@openvswitch.org on behalf of guru@ovn.org> wrote:
>>>
>>> >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 <guru@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 && 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
>>>
>>
>>
>
Manoj Sharma June 21, 2017, 9:19 p.m. UTC | #7
On 20 June 2017 at 14:52, Manoj Sharma <manoj.sharma@nutanix.com<mailto:manoj.sharma@nutanix.com>> wrote:
Hi Guru,

Please see my answer below:

On 19 June 2017 at 23:17, Manoj Sharma <manoj.sharma@nutanix.com<mailto:manoj.sharma@nutanix.com>> wrote:
The use case is if someone wants to access a VM from on-prem then it is an l3vpn and we should not do SNAT for it.

> Please expand on the above. What does "on-prem" mean in the context of OVN? And is the VM a OVN logical port?


I have two OVN networks at two different locations and they are connected through a gateway. I want the SNAT to happen for internet traffic but not for the inter-office traffic because it is a single private network stretched across two locations.

> Okay. Your physical infrastructure knows how to route OVN's logical IP addresses?


Yes, the physical infrastructure can route the logical IP addresses.

> Does this use gateway routers or does it use distributed router ports?


The gateway router port is after distributed router port for south->north traffic. The snat/nosnat will happen as part of the distributed router port and then it will be sent out using the gateway router port.





Both sides should be using their logical IPs.
> This confuses me. If both sides use logical IP, it reads to me that both sides are OVN logical ports. In that case, why do we even needs SNATs? Why is the packet even >going to a gateway?


Its a single layer 3 private network spanning across two OVN domains. They should use their logical IP while talking to each other.


However the match for “nosnat” should be on destination IP.

I will rebase it to current master and run the tests.

Regards
- Manoj

From: Guru Shetty <guru@ovn.org<mailto:guru@ovn.org>>

Date: Monday, June 19, 2017 at 1:04 PM
To: Manoj Sharma <manoj.sharma@nutanix.com<mailto:manoj.sharma@nutanix.com>>
Cc: "dev@openvswitch.org<mailto:dev@openvswitch.org>" <dev@openvswitch.org<mailto:dev@openvswitch.org>>
Subject: Re: [ovs-dev] [PATCH 2/3] ovn: Ability to skip some IP addresses for SNAT.



On 19 June 2017 at 12:16, Manoj Sharma <manoj.sharma@nutanix.com<mailto:manoj.sharma@nutanix.com>> wrote:
Hi Guru,

It looked very useful patch. Do you plan to commit it into main?
Was there any reason to not merge it so far?

Is there a use case for which you want to use it? What is the use case? This is an old patch and if you think it is useful, please consider spending some time rebasing it to the current master and running all the system tests to make sure that it does not introduce any regression.



Regards
- Manoj


On 11/3/16, 3:46 AM, "dev on behalf of Gurucharan Shetty" <dev-bounces@openvswitch.org<mailto:dev-bounces@openvswitch.org> on behalf of guru@ovn.org<mailto:guru@ovn.org>> wrote:

>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<http://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 <guru@ovn.org<mailto:guru@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<http://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 && 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<http://system-ovn.at> b/tests/system-ovn.at<http://system-ovn.at>

>index 21226d9..d627f76 100644

>--- a/tests/system-ovn.at<http://system-ovn.at>

>+++ b/tests/system-ovn.at<http://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<http://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<mailto:dev@openvswitch.org>

>http://openvswitch.org/mailman/listinfo/dev<http://openvswitch.org/mailman/listinfo/dev>

Patch
diff mbox

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