[ovs-dev] [PATCH v4 2/2 ovn] NAT: Northd and parser changes to support port range

Ankur Sharma svc.mail.git at nutanix.com
Thu Apr 2 19:08:58 UTC 2020


From: Ankur Sharma <ankur.sharma at nutanix.com>

This patch has northd changes to put
port range in the logical flow based on configuration.

Port range is NOT applicable for stateless dnat_and_snat
rules.

Changes to parse the logical flow, which specifies port_range
for ct_nat action.

Example logical flow:
ct_snat(10.15.24.135,1-30000)

Signed-off-by: Ankur Sharma <ankur.sharma at nutanix.com>
Acked-by: Mark Michelson <mmichels at redhat.com>
---
 include/ovn/actions.h |  7 ++++++
 include/ovn/lex.h     |  1 +
 lib/actions.c         | 48 ++++++++++++++++++++++++++++++++++++++
 lib/lex.c             |  5 +++-
 northd/ovn-northd.c   | 31 +++++++++++++++++++++----
 tests/ovn-northd.at   | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++
 tests/ovn.at          | 34 +++++++++++++++++++++++----
 7 files changed, 180 insertions(+), 10 deletions(-)

diff --git a/include/ovn/actions.h b/include/ovn/actions.h
index 9b01492..2cec369 100644
--- a/include/ovn/actions.h
+++ b/include/ovn/actions.h
@@ -233,6 +233,13 @@ struct ovnact_ct_nat {
         struct in6_addr ipv6;
         ovs_be32 ipv4;
     };
+
+    struct {
+       bool exists;
+       uint16_t port_lo;
+       uint16_t port_hi;
+    } port_range;
+
     uint8_t ltable;             /* Logical table ID of next table. */
 };
 
diff --git a/include/ovn/lex.h b/include/ovn/lex.h
index 8d55857..1da6ccc 100644
--- a/include/ovn/lex.h
+++ b/include/ovn/lex.h
@@ -63,6 +63,7 @@ enum lex_type {
     LEX_T_EXCHANGE,             /* <-> */
     LEX_T_DECREMENT,            /* -- */
     LEX_T_COLON,                /* : */
+    LEX_T_HYPHEN,               /* - */
 };
 
 /* Subtype for LEX_T_INTEGER and LEX_T_MASKED_INTEGER tokens.
diff --git a/lib/actions.c b/lib/actions.c
index 6351db7..5d9d93b 100644
--- a/lib/actions.c
+++ b/lib/actions.c
@@ -770,6 +770,38 @@ parse_ct_nat(struct action_context *ctx, const char *name,
         }
         lexer_get(ctx->lexer);
 
+        if (lexer_match(ctx->lexer, LEX_T_COMMA)) {
+
+           if (ctx->lexer->token.type != LEX_T_INTEGER ||
+               ctx->lexer->token.format != LEX_F_DECIMAL) {
+              lexer_syntax_error(ctx->lexer, "expecting Integer for port "
+                                 "range");
+           }
+
+           cn->port_range.port_lo = ntohll(ctx->lexer->token.value.integer);
+           lexer_get(ctx->lexer);
+
+           if (lexer_match(ctx->lexer, LEX_T_HYPHEN)) {
+
+               if (ctx->lexer->token.type != LEX_T_INTEGER) {
+                   lexer_syntax_error(ctx->lexer, "expecting Integer for port "
+                                      "range");
+               }
+               cn->port_range.port_hi = ntohll(
+                                        ctx->lexer->token.value.integer);
+
+               if (cn->port_range.port_hi <= cn->port_range.port_lo) {
+                   lexer_syntax_error(ctx->lexer, "range high should be "
+                                      "greater than range lo");
+               }
+               lexer_get(ctx->lexer);
+           } else {
+               cn->port_range.port_hi = 0;
+           }
+
+           cn->port_range.exists = true;
+        }
+
         if (!lexer_force_match(ctx->lexer, LEX_T_RPAREN)) {
             return;
         }
@@ -799,6 +831,17 @@ format_ct_nat(const struct ovnact_ct_nat *cn, const char *name, struct ds *s)
         ipv6_format_addr(&cn->ipv6, s);
         ds_put_char(s, ')');
     }
+
+    if (cn->port_range.exists) {
+        ds_chomp(s, ')');
+        ds_put_format(s, ",%d", cn->port_range.port_lo);
+
+        if (cn->port_range.port_hi) {
+            ds_put_format(s, "-%d", cn->port_range.port_hi);
+        }
+        ds_put_char(s, ')');
+    }
+
     ds_put_char(s, ';');
 }
 
@@ -861,6 +904,11 @@ encode_ct_nat(const struct ovnact_ct_nat *cn,
         }
     }
 
+    if (cn->port_range.exists) {
+       nat->range.proto.min = cn->port_range.port_lo;
+       nat->range.proto.max = cn->port_range.port_hi;
+    }
+
     ofpacts->header = ofpbuf_push_uninit(ofpacts, nat_offset);
     ct = ofpacts->header;
     if (cn->family == AF_INET || cn->family == AF_INET6) {
diff --git a/lib/lex.c b/lib/lex.c
index 7a2ab41..94f6c77 100644
--- a/lib/lex.c
+++ b/lib/lex.c
@@ -301,6 +301,9 @@ lex_token_format(const struct lex_token *token, struct ds *s)
     case LEX_T_COLON:
         ds_put_char(s, ':');
         break;
+    case LEX_T_HYPHEN:
+        ds_put_char(s, '-');
+        break;
     default:
         OVS_NOT_REACHED();
     }
@@ -757,7 +760,7 @@ next:
             token->type = LEX_T_DECREMENT;
             p++;
         } else {
-            lex_error(token, "`-' is only valid as part of `--'.");
+           token->type = LEX_T_HYPHEN;
         }
         break;
 
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index 0762781..71d420d 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -8849,7 +8849,13 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
                                       is_v6 ? "6" : "4", nat->logical_ip);
                     } else {
                         ds_put_format(&actions, "flags.loopback = 1; "
-                                      "ct_dnat(%s);", nat->logical_ip);
+                                      "ct_dnat(%s", nat->logical_ip);
+
+                        if (strlen(nat->external_port_range)) {
+                            ds_put_format(&actions, ",%s",
+                                          nat->external_port_range);
+                        }
+                        ds_put_format(&actions, ");");
                     }
 
                     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, 100,
@@ -8877,8 +8883,12 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
                         ds_put_format(&actions, "ip%s.dst=%s; next;",
                                       is_v6 ? "6" : "4", nat->logical_ip);
                     } else {
-                        ds_put_format(&actions, "ct_dnat(%s);",
-                                      nat->logical_ip);
+                        ds_put_format(&actions, "ct_dnat(%s", nat->logical_ip);
+                        if (strlen(nat->external_port_range)) {
+                            ds_put_format(&actions, ",%s",
+                                          nat->external_port_range);
+                        }
+                        ds_put_format(&actions, ");");
                     }
 
                     ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, 100,
@@ -8982,8 +8992,14 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
                         ds_put_format(&actions, "ip%s.src=%s; next;",
                                       is_v6 ? "6" : "4", nat->external_ip);
                     } else {
-                        ds_put_format(&actions, "ct_snat(%s);",
+                        ds_put_format(&actions, "ct_snat(%s",
                                       nat->external_ip);
+
+                        if (strlen(nat->external_port_range)) {
+                            ds_put_format(&actions, ",%s",
+                                          nat->external_port_range);
+                        }
+                        ds_put_format(&actions, ");");
                     }
 
                     /* The priority here is calculated such that the
@@ -9020,8 +9036,13 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
                         ds_put_format(&actions, "ip%s.src=%s; next;",
                                       is_v6 ? "6" : "4", nat->external_ip);
                     } else {
-                        ds_put_format(&actions, "ct_snat(%s);",
+                        ds_put_format(&actions, "ct_snat(%s",
                                       nat->external_ip);
+                        if (strlen(nat->external_port_range)) {
+                            ds_put_format(&actions, ",%s",
+                                          nat->external_port_range);
+                        }
+                        ds_put_format(&actions, ");");
                     }
 
                     /* The priority here is calculated such that the
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index d127152..8cc3f70 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -1074,6 +1074,70 @@ AT_CHECK([ovn-sbctl dump-flows R1 | grep ip6.src=| wc -l], [0], [2
 
 AT_CLEANUP
 
+AT_SETUP([ovn -- check portrange dnat, snat and dnat_and_snat rules])
+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
+
+# IPV4
+ovn-nbctl --portrange lr-nat-add R1 dnat_and_snat  172.16.1.1 50.0.0.11 1-3000
+
+OVS_WAIT_UNTIL([test 2 = `ovn-sbctl dump-flows R1 | grep lr_in_unsnat | \
+wc -l`])
+
+AT_CHECK([ovn-sbctl dump-flows R1 | grep ct_snat | grep 3000 | wc -l], [0], [1
+])
+
+AT_CHECK([ovn-sbctl dump-flows R1 | grep ct_dnat | grep 3000 | wc -l], [0], [1
+])
+
+
+ovn-nbctl lr-nat-del R1 dnat_and_snat  172.16.1.1
+
+ovn-nbctl --portrange lr-nat-add R1 snat  172.16.1.1 50.0.0.11 1-3000
+
+OVS_WAIT_UNTIL([test 2 = `ovn-sbctl dump-flows R1 | grep lr_in_unsnat | \
+wc -l`])
+
+AT_CHECK([ovn-sbctl dump-flows R1 | grep ct_snat | grep 3000 | wc -l], [0], [1
+])
+
+AT_CHECK([ovn-sbctl dump-flows R1 | grep ct_dnat | grep 3000 | wc -l], [0], [0
+])
+
+ovn-nbctl lr-nat-del R1 snat  172.16.1.1
+
+ovn-nbctl --portrange --stateless lr-nat-add R1 dnat_and_snat  172.16.1.2 50.0.0.12 1-3000
+ovn-sbctl dump-flows R1
+
+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 | grep 3000 | grep 172.16.1.2 | wc -l], [0], [0
+])
+
+AT_CHECK([ovn-sbctl dump-flows R1 | grep ct_dnat | grep 3000 | grep 172.16.1.2 | wc -l], [0], [0
+])
+
+
+ovn-nbctl lr-nat-del R1 dnat_and_snat  172.16.1.1
+
+AT_CLEANUP
+
 AT_SETUP([ovn -- check Load balancer health check and Service Monitor sync])
 AT_SKIP_IF([test $HAVE_PYTHON = no])
 ovn_start
diff --git a/tests/ovn.at b/tests/ovn.at
index 0135838..314be47 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -136,7 +136,6 @@ fe:x => error("Invalid numeric constant.")
 (){}[[]]==!=<<=>>=!&&||..,;=<->--: => ( ) { } [[ ]] == != < <= > >= ! && || .. , ; = <-> -- :
 & => error("`&' is only valid as part of `&&'.")
 | => error("`|' is only valid as part of `||'.")
-- => error("`-' is only valid as part of `--'.")
 
 ^ => error("Invalid character `^' in input.")
 ])
@@ -1049,15 +1048,29 @@ ct_dnat(192.168.1.2);
 ct_dnat(fd11::2);
     encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(dst=fd11::2))
     has prereqs ip
+ct_dnat(192.168.1.2, 1-3000);
+    formats as ct_dnat(192.168.1.2,1-3000);
+    encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(dst=192.168.1.2:1-3000))
+    has prereqs ip
 
 ct_dnat(192.168.1.2, 192.168.1.3);
-    Syntax error at `,' expecting `)'.
+    Syntax error at `192.168.1.3' expecting Integer for port range.
 ct_dnat(foo);
     Syntax error at `foo' expecting IPv4 or IPv6 address.
 ct_dnat(foo, bar);
     Syntax error at `foo' expecting IPv4 or IPv6 address.
 ct_dnat();
     Syntax error at `)' expecting IPv4 or IPv6 address.
+ct_dnat(192.168.1.2, foo);
+    Syntax error at `foo' expecting Integer for port range.
+ct_dnat(192.168.1.2, 1000-foo);
+    Syntax error at `foo' expecting Integer for port range.
+ct_dnat(192.168.1.2, 1000);
+    formats as ct_dnat(192.168.1.2,1000);
+    encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(dst=192.168.1.2:1000))
+    has prereqs ip
+ct_dnat(192.168.1.2, 1000-100);
+    Syntax error at `100' range high should be greater than range lo.
 
 # ct_snat
 ct_snat;
@@ -1069,16 +1082,29 @@ ct_snat(192.168.1.2);
 ct_snat(fd11::2);
     encodes as ct(commit,table=19,zone=NXM_NX_REG12[0..15],nat(src=fd11::2))
     has prereqs ip
+ct_snat(192.168.1.2, 1-3000);
+    formats as ct_snat(192.168.1.2,1-3000);
+    encodes as ct(commit,table=19,zone=NXM_NX_REG12[0..15],nat(src=192.168.1.2:1-3000))
+    has prereqs ip
 
 ct_snat(192.168.1.2, 192.168.1.3);
-    Syntax error at `,' expecting `)'.
+    Syntax error at `192.168.1.3' expecting Integer for port range.
 ct_snat(foo);
     Syntax error at `foo' expecting IPv4 or IPv6 address.
 ct_snat(foo, bar);
     Syntax error at `foo' expecting IPv4 or IPv6 address.
 ct_snat();
     Syntax error at `)' expecting IPv4 or IPv6 address.
-
+ct_snat(192.168.1.2, foo);
+    Syntax error at `foo' expecting Integer for port range.
+ct_snat(192.168.1.2, 1000-foo);
+    Syntax error at `foo' expecting Integer for port range.
+ct_snat(192.168.1.2, 1000);
+    formats as ct_snat(192.168.1.2,1000);
+    encodes as ct(commit,table=19,zone=NXM_NX_REG12[0..15],nat(src=192.168.1.2:1000))
+    has prereqs ip
+ct_snat(192.168.1.2, 1000-100);
+    Syntax error at `100' range high should be greater than range lo.
 # ct_clear
 ct_clear;
     encodes as ct_clear
-- 
1.8.3.1



More information about the dev mailing list