diff mbox series

[ovs-dev,v2,2/4] ovn: Allow ct_lb actions to take IPv6 address arguments.

Message ID 20171031142704.13870-3-mmichels@redhat.com
State Superseded
Headers show
Series Add support for IPv6 load balancers | expand

Commit Message

Mark Michelson Oct. 31, 2017, 2:27 p.m. UTC
The ct_lb action previously assumed that any address arguments were
IPv4. This patch expands the parsing, formatting, and encoding of ct_lb
to be amenable to IPv6 addresses as well.

Signed-off-by: Mark Michelson <mmichels@redhat.com>
---
 include/ovn/actions.h |  6 +++-
 ovn/lib/actions.c     | 99 ++++++++++++++++++++++++++++++++++++++++-----------
 tests/ovn.at          |  8 ++++-
 3 files changed, 91 insertions(+), 22 deletions(-)

Comments

Ben Pfaff Nov. 1, 2017, 9:53 p.m. UTC | #1
On Tue, Oct 31, 2017 at 09:27:02AM -0500, Mark Michelson wrote:
> The ct_lb action previously assumed that any address arguments were
> IPv4. This patch expands the parsing, formatting, and encoding of ct_lb
> to be amenable to IPv6 addresses as well.
> 
> Signed-off-by: Mark Michelson <mmichels@redhat.com>

Thanks for working on this.

With this change, I get the following warning from Clang 3.8:

    ../ovn/lib/actions.c:939:32: error: variable 'dst' is used uninitialized whenever 'if' condition is false [-Werror,-Wsometimes-uninitialized]
    ../ovn/lib/actions.c:953:30: note: uninitialized use occurs here
    ../ovn/lib/actions.c:939:28: note: remove the 'if' if its condition is always true
    ../ovn/lib/actions.c:932:21: error: variable 'dst' is used uninitialized whenever 'if' condition is false [-Werror,-Wsometimes-uninitialized]
    ../ovn/lib/actions.c:953:30: note: uninitialized use occurs here
    ../ovn/lib/actions.c:932:17: note: remove the 'if' if its condition is always true
    ../ovn/lib/actions.c:886:13: note: variable 'dst' is declared here

I can't figure out what it's talking about, and I can't figure out a
simple way to suppress it.  Do you have any idea?
Mark Michelson Nov. 2, 2017, 2:57 p.m. UTC | #2
On Wed, Nov 1, 2017 at 4:53 PM Ben Pfaff <blp@ovn.org> wrote:

> On Tue, Oct 31, 2017 at 09:27:02AM -0500, Mark Michelson wrote:
> > The ct_lb action previously assumed that any address arguments were
> > IPv4. This patch expands the parsing, formatting, and encoding of ct_lb
> > to be amenable to IPv6 addresses as well.
> >
> > Signed-off-by: Mark Michelson <mmichels@redhat.com>
>
> Thanks for working on this.
>
> With this change, I get the following warning from Clang 3.8:
>
>     ../ovn/lib/actions.c:939:32: error: variable 'dst' is used
> uninitialized whenever 'if' condition is false
> [-Werror,-Wsometimes-uninitialized]
>     ../ovn/lib/actions.c:953:30: note: uninitialized use occurs here
>     ../ovn/lib/actions.c:939:28: note: remove the 'if' if its condition is
> always true
>     ../ovn/lib/actions.c:932:21: error: variable 'dst' is used
> uninitialized whenever 'if' condition is false
> [-Werror,-Wsometimes-uninitialized]
>     ../ovn/lib/actions.c:953:30: note: uninitialized use occurs here
>     ../ovn/lib/actions.c:932:17: note: remove the 'if' if its condition is
> always true
>     ../ovn/lib/actions.c:886:13: note: variable 'dst' is declared here
>
> I can't figure out what it's talking about, and I can't figure out a
> simple way to suppress it.  Do you have any idea?
>

I see what's wrong. There is a declaration of a "dst" variable in an inner
scope that shadows the declaration of a "dst" variable in an outer scope.
In the case where the if statement is false, the inner scope "dst" gets
declared and its parameters set. What we want is for the outer scope "dst"
to have its parameters set in that case. The easy solution is just to
remove the inner scope declaration of dst. I'll do that and repost the
patch.
Ben Pfaff Nov. 2, 2017, 6:11 p.m. UTC | #3
On Thu, Nov 02, 2017 at 02:57:00PM +0000, Mark Michelson wrote:
> On Wed, Nov 1, 2017 at 4:53 PM Ben Pfaff <blp@ovn.org> wrote:
> 
> > On Tue, Oct 31, 2017 at 09:27:02AM -0500, Mark Michelson wrote:
> > > The ct_lb action previously assumed that any address arguments were
> > > IPv4. This patch expands the parsing, formatting, and encoding of ct_lb
> > > to be amenable to IPv6 addresses as well.
> > >
> > > Signed-off-by: Mark Michelson <mmichels@redhat.com>
> >
> > Thanks for working on this.
> >
> > With this change, I get the following warning from Clang 3.8:
> >
> >     ../ovn/lib/actions.c:939:32: error: variable 'dst' is used
> > uninitialized whenever 'if' condition is false
> > [-Werror,-Wsometimes-uninitialized]
> >     ../ovn/lib/actions.c:953:30: note: uninitialized use occurs here
> >     ../ovn/lib/actions.c:939:28: note: remove the 'if' if its condition is
> > always true
> >     ../ovn/lib/actions.c:932:21: error: variable 'dst' is used
> > uninitialized whenever 'if' condition is false
> > [-Werror,-Wsometimes-uninitialized]
> >     ../ovn/lib/actions.c:953:30: note: uninitialized use occurs here
> >     ../ovn/lib/actions.c:932:17: note: remove the 'if' if its condition is
> > always true
> >     ../ovn/lib/actions.c:886:13: note: variable 'dst' is declared here
> >
> > I can't figure out what it's talking about, and I can't figure out a
> > simple way to suppress it.  Do you have any idea?
> >
> 
> I see what's wrong. There is a declaration of a "dst" variable in an inner
> scope that shadows the declaration of a "dst" variable in an outer scope.
> In the case where the if statement is false, the inner scope "dst" gets
> declared and its parameters set. What we want is for the outer scope "dst"
> to have its parameters set in that case. The easy solution is just to
> remove the inner scope declaration of dst. I'll do that and repost the
> patch.

Thanks!
diff mbox series

Patch

diff --git a/include/ovn/actions.h b/include/ovn/actions.h
index 0a04af7aa..63885da3c 100644
--- a/include/ovn/actions.h
+++ b/include/ovn/actions.h
@@ -200,7 +200,11 @@  struct ovnact_ct_nat {
 };
 
 struct ovnact_ct_lb_dst {
-    ovs_be32 ip;
+    int family;
+    union {
+        struct in6_addr ipv6;
+        ovs_be32 ipv4;
+    };
     uint16_t port;
 };
 
diff --git a/ovn/lib/actions.c b/ovn/lib/actions.c
index c9876436d..3c21eb382 100644
--- a/ovn/lib/actions.c
+++ b/ovn/lib/actions.c
@@ -883,23 +883,63 @@  parse_ct_lb_action(struct action_context *ctx)
 
     if (lexer_match(ctx->lexer, LEX_T_LPAREN)) {
         while (!lexer_match(ctx->lexer, LEX_T_RPAREN)) {
-            if (ctx->lexer->token.type != LEX_T_INTEGER
-                || mf_subvalue_width(&ctx->lexer->token.value) > 32) {
-                free(dsts);
-                lexer_syntax_error(ctx->lexer, "expecting IPv4 address");
-                return;
-            }
+            struct ovnact_ct_lb_dst dst;
+            if (lexer_match(ctx->lexer, LEX_T_LSQUARE)) {
+                /* IPv6 address and port */
+                if (ctx->lexer->token.type != LEX_T_INTEGER
+                    || ctx->lexer->token.format != LEX_F_IPV6) {
+                    free(dsts);
+                    lexer_syntax_error(ctx->lexer, "expecting IPv6 address");
+                    return;
+                }
+                dst.family = AF_INET6;
+                dst.ipv6 = ctx->lexer->token.value.ipv6;
 
-            /* Parse IP. */
-            ovs_be32 ip = ctx->lexer->token.value.ipv4;
-            lexer_get(ctx->lexer);
+                lexer_get(ctx->lexer);
+                if (!lexer_match(ctx->lexer, LEX_T_RSQUARE)) {
+                    free(dsts);
+                    lexer_syntax_error(ctx->lexer, "no closing square "
+                                                   "bracket");
+                    return;
+                }
+                dst.port = 0;
+                if (lexer_match(ctx->lexer, LEX_T_COLON)
+                    && !action_parse_port(ctx, &dst.port)) {
+                    free(dsts);
+                    return;
+                }
+            } else {
+                if (ctx->lexer->token.type != LEX_T_INTEGER
+                    || (ctx->lexer->token.format != LEX_F_IPV4
+                    && ctx->lexer->token.format != LEX_F_IPV6)) {
+                    free(dsts);
+                    lexer_syntax_error(ctx->lexer, "expecting IP address");
+                    return;
+                }
 
-            /* Parse optional port. */
-            uint16_t port = 0;
-            if (lexer_match(ctx->lexer, LEX_T_COLON)
-                && !action_parse_port(ctx, &port)) {
-                free(dsts);
-                return;
+                /* Parse IP. */
+                struct ovnact_ct_lb_dst dst;
+                if (ctx->lexer->token.format == LEX_F_IPV4) {
+                    dst.family = AF_INET;
+                    dst.ipv4 = ctx->lexer->token.value.ipv4;
+                } else {
+                    dst.family = AF_INET6;
+                    dst.ipv6 = ctx->lexer->token.value.ipv6;
+                }
+
+                lexer_get(ctx->lexer);
+                dst.port = 0;
+                if (lexer_match(ctx->lexer, LEX_T_COLON)) {
+                    if (dst.family == AF_INET6) {
+                        free(dsts);
+                        lexer_syntax_error(ctx->lexer, "IPv6 address needs "
+                                "square brackets if port is included");
+                        return;
+                    } else if (!action_parse_port(ctx, &dst.port)) {
+                        free(dsts);
+                        return;
+                    }
+                }
             }
             lexer_match(ctx->lexer, LEX_T_COMMA);
 
@@ -907,7 +947,7 @@  parse_ct_lb_action(struct action_context *ctx)
             if (n_dsts >= allocated_dsts) {
                 dsts = x2nrealloc(dsts, &allocated_dsts, sizeof *dsts);
             }
-            dsts[n_dsts++] = (struct ovnact_ct_lb_dst) { ip, port };
+            dsts[n_dsts++] = dst;
         }
     }
 
@@ -929,9 +969,19 @@  format_CT_LB(const struct ovnact_ct_lb *cl, struct ds *s)
             }
 
             const struct ovnact_ct_lb_dst *dst = &cl->dsts[i];
-            ds_put_format(s, IP_FMT, IP_ARGS(dst->ip));
-            if (dst->port) {
-                ds_put_format(s, ":%"PRIu16, dst->port);
+            if (dst->family == AF_INET) {
+                ds_put_format(s, IP_FMT, IP_ARGS(dst->ipv4));
+                if (dst->port) {
+                    ds_put_format(s, ":%"PRIu16, dst->port);
+                }
+            } else {
+                if (dst->port) {
+                    ds_put_char(s, '[');
+                }
+                ipv6_format_addr(&dst->ipv6, s);
+                if (dst->port) {
+                    ds_put_format(s, "]:%"PRIu16, dst->port);
+                }
             }
         }
         ds_put_char(s, ')');
@@ -991,8 +1041,17 @@  encode_CT_LB(const struct ovnact_ct_lb *cl,
     BUILD_ASSERT(MFF_LOG_DNAT_ZONE < MFF_REG0 + FLOW_N_REGS);
     for (size_t bucket_id = 0; bucket_id < cl->n_dsts; bucket_id++) {
         const struct ovnact_ct_lb_dst *dst = &cl->dsts[bucket_id];
+        char ip_addr[INET6_ADDRSTRLEN];
+        if (dst->family == AF_INET) {
+            inet_ntop(AF_INET, &dst->ipv4, ip_addr, sizeof ip_addr);
+        } else {
+            inet_ntop(AF_INET6, &dst->ipv6, ip_addr, sizeof ip_addr);
+        }
         ds_put_format(&ds, ",bucket=bucket_id=%"PRIuSIZE",weight:100,actions="
-                      "ct(nat(dst="IP_FMT, bucket_id, IP_ARGS(dst->ip));
+                      "ct(nat(dst=%s%s%s", bucket_id,
+                      dst->family == AF_INET6 && dst->port ? "[" : "",
+                      ip_addr,
+                      dst->family == AF_INET6 && dst->port ? "]" : "");
         if (dst->port) {
             ds_put_format(&ds, ":%"PRIu16, dst->port);
         }
diff --git a/tests/ovn.at b/tests/ovn.at
index 490841c63..67709b55b 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -825,13 +825,19 @@  ct_lb(192.168.1.2, 192.168.1.3, );
     formats as ct_lb(192.168.1.2, 192.168.1.3);
     encodes as group:2
     has prereqs ip
+ct_lb(fd0f::2, fd0f::3, );
+    formats as ct_lb(fd0f::2, fd0f::3);
+    encodes as group:3
+    has prereqs ip
 
 ct_lb(192.168.1.2:);
     Syntax error at `)' expecting port number.
 ct_lb(192.168.1.2:123456);
     Syntax error at `123456' expecting port number.
 ct_lb(foo);
-    Syntax error at `foo' expecting IPv4 address.
+    Syntax error at `foo' expecting IP address.
+ct_lb([192.168.1.2]);
+    Syntax error at `192.168.1.2' expecting IPv6 address.
 
 # ct_next
 ct_next;