summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Michelson <mmichels@redhat.com>2017-11-02 11:13:57 -0500
committerBen Pfaff <blp@ovn.org>2017-11-02 10:49:54 -0700
commit9d236afafb7817df8a4e9fe6a46f00109e3b86d9 (patch)
tree752cbabe9d9d3a58dbc014849c870b0ef2795ee8
parente463f310b17d7dda864c33c8c3e6f19bd8f66c67 (diff)
downloadopenvswitch-9d236afafb7817df8a4e9fe6a46f00109e3b86d9.tar.gz
ovn: Allow ct_lb actions to take IPv6 address arguments.
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> Signed-off-by: Ben Pfaff <blp@ovn.org>
-rw-r--r--include/ovn/actions.h6
-rw-r--r--ovn/lib/actions.c98
-rw-r--r--tests/ovn.at8
3 files changed, 90 insertions, 22 deletions
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..2aace1487 100644
--- a/ovn/lib/actions.c
+++ b/ovn/lib/actions.c
@@ -883,23 +883,62 @@ 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. */
+ 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 +946,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 +968,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 +1040,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;