Skip to content

Commit

Permalink
ovn: Allow ct_lb actions to take IPv6 address arguments.
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Ben Pfaff <[email protected]>
  • Loading branch information
putnopvut authored and blp committed Nov 2, 2017
1 parent e463f31 commit 9d236af
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 22 deletions.
6 changes: 5 additions & 1 deletion include/ovn/actions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down
98 changes: 78 additions & 20 deletions ovn/lib/actions.c
Original file line number Diff line number Diff line change
Expand Up @@ -883,31 +883,70 @@ 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);

/* Append to dsts. */
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;
}
}

Expand All @@ -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, ')');
Expand Down Expand Up @@ -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);
}
Expand Down
8 changes: 7 additions & 1 deletion tests/ovn.at
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 9d236af

Please sign in to comment.