Skip to content

Commit

Permalink
ovn: Add address set support.
Browse files Browse the repository at this point in the history
Update the OVN expression parser to support address sets.  Previously,
you could have a set of IP or MAC addresses in this form:

    {addr1, addr2, ..., addrN}

This patch adds support for a bit of indirection where we can define a
set of addresses and refer to them by name.

    $name

This '$name' can be used in the expresssions like

    {addr1, addr2, $name, ... }
    {$name}
    $name

A future patch will expose the ability to define address sets for use.

Signed-off-by: Russell Bryant <[email protected]>
Co-authored-by: Babu Shanmugam <[email protected]>
Signed-off-by: Babu Shanmugam <[email protected]>
[[email protected] made numerous small changes]
Signed-off-by: Ben Pfaff <[email protected]>
  • Loading branch information
2 people authored and blp committed Jul 3, 2016
1 parent eff49a5 commit 2c5cbb1
Show file tree
Hide file tree
Showing 8 changed files with 255 additions and 24 deletions.
2 changes: 1 addition & 1 deletion ovn/controller/lflow.c
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ add_logical_flows(struct controller_ctx *ctx, const struct lport_index *lports,
struct hmap matches;
struct expr *expr;

expr = expr_parse_string(lflow->match, &symtab, &error);
expr = expr_parse_string(lflow->match, &symtab, NULL, &error);
if (!error) {
if (prereqs) {
expr = expr_combine(EXPR_T_AND, expr, prereqs);
Expand Down
2 changes: 1 addition & 1 deletion ovn/lib/actions.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ add_prerequisite(struct action_context *ctx, const char *prerequisite)
struct expr *expr;
char *error;

expr = expr_parse_string(prerequisite, ctx->ap->symtab, &error);
expr = expr_parse_string(prerequisite, ctx->ap->symtab, NULL, &error);
ovs_assert(!error);
ctx->prereqs = expr_combine(EXPR_T_AND, ctx->prereqs, expr);
}
Expand Down
113 changes: 107 additions & 6 deletions ovn/lib/expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ expr_print(const struct expr *e)
struct expr_context {
struct lexer *lexer; /* Lexer for pulling more tokens. */
const struct shash *symtab; /* Symbol table. */
const struct shash *macros; /* Table of macros. */
char *error; /* Error, if any, otherwise NULL. */
bool not; /* True inside odd number of NOT operators. */
};
Expand Down Expand Up @@ -728,6 +729,33 @@ assign_constant_set_type(struct expr_context *ctx,
}
}

static bool
parse_macros(struct expr_context *ctx, struct expr_constant_set *cs,
size_t *allocated_values)
{
struct expr_constant_set *addr_set
= shash_find_data(ctx->macros, ctx->lexer->token.s);
if (!addr_set) {
expr_syntax_error(ctx, "expecting address set name.");
return false;
}

if (!assign_constant_set_type(ctx, cs, EXPR_C_INTEGER)) {
return false;
}

size_t n_values = cs->n_values + addr_set->n_values;
if (n_values >= *allocated_values) {
cs->values = xrealloc(cs->values, n_values * sizeof *cs->values);
*allocated_values = n_values;
}
for (size_t i = 0; i < addr_set->n_values; i++) {
cs->values[cs->n_values++] = addr_set->values[i];
}

return true;
}

static bool
parse_constant(struct expr_context *ctx, struct expr_constant_set *cs,
size_t *allocated_values)
Expand Down Expand Up @@ -759,6 +787,12 @@ parse_constant(struct expr_context *ctx, struct expr_constant_set *cs,
}
lexer_get(ctx->lexer);
return true;
} else if (ctx->lexer->token.type == LEX_T_MACRO) {
if (!parse_macros(ctx, cs, allocated_values)) {
return false;
}
lexer_get(ctx->lexer);
return true;
} else {
expr_syntax_error(ctx, "expecting constant.");
return false;
Expand Down Expand Up @@ -808,6 +842,69 @@ expr_constant_set_destroy(struct expr_constant_set *cs)
}
}

/* Adds a macro named 'name' to 'macros', replacing any existing macro with the
* given name. */
void
expr_macros_add(struct shash *macros, const char *name,
const char *const *values, size_t n_values)
{
/* Replace any existing entry for this name. */
expr_macros_remove(macros, name);

struct expr_constant_set *cs = xzalloc(sizeof *cs);
cs->type = EXPR_C_INTEGER;
cs->in_curlies = true;
cs->n_values = 0;
cs->values = xmalloc(n_values * sizeof *cs->values);
for (size_t i = 0; i < n_values; i++) {
/* Use the lexer to convert each macro into the proper
* integer format. */
struct lexer lex;
lexer_init(&lex, values[i]);
lexer_get(&lex);
if (lex.token.type != LEX_T_INTEGER
&& lex.token.type != LEX_T_MASKED_INTEGER) {
VLOG_WARN("Invalid address set entry: '%s', token type: %d",
values[i], lex.token.type);
} else {
union expr_constant *c = &cs->values[cs->n_values++];
c->value = lex.token.value;
c->format = lex.token.format;
c->masked = lex.token.type == LEX_T_MASKED_INTEGER;
if (c->masked) {
c->mask = lex.token.mask;
}
}
lexer_destroy(&lex);
}

shash_add(macros, name, cs);
}

void
expr_macros_remove(struct shash *macros, const char *name)
{
struct expr_constant_set *cs = shash_find_and_delete(macros, name);
if (cs) {
expr_constant_set_destroy(cs);
free(cs);
}
}

/* Destroy all contents of 'macros'. */
void
expr_macros_destroy(struct shash *macros)
{
struct shash_node *node, *next;

SHASH_FOR_EACH_SAFE (node, next, macros) {
struct expr_constant_set *cs = node->data;

shash_delete(macros, node);
expr_constant_set_destroy(cs);
}
}

static struct expr *
expr_parse_primary(struct expr_context *ctx, bool *atomic)
{
Expand Down Expand Up @@ -980,9 +1077,12 @@ expr_parse__(struct expr_context *ctx)
* The caller must eventually free the returned expression (with
* expr_destroy()) or error (with free()). */
struct expr *
expr_parse(struct lexer *lexer, const struct shash *symtab, char **errorp)
expr_parse(struct lexer *lexer, const struct shash *symtab,
const struct shash *macros, char **errorp)
{
struct expr_context ctx = { .lexer = lexer, .symtab = symtab };
struct expr_context ctx = { .lexer = lexer,
.symtab = symtab,
.macros = macros };
struct expr *e = expr_parse__(&ctx);
*errorp = ctx.error;
ovs_assert((ctx.error != NULL) != (e != NULL));
Expand All @@ -991,14 +1091,15 @@ expr_parse(struct lexer *lexer, const struct shash *symtab, char **errorp)

/* Like expr_parse(), but the expression is taken from 's'. */
struct expr *
expr_parse_string(const char *s, const struct shash *symtab, char **errorp)
expr_parse_string(const char *s, const struct shash *symtab,
const struct shash *macros, char **errorp)
{
struct lexer lexer;
struct expr *expr;

lexer_init(&lexer, s);
lexer_get(&lexer);
expr = expr_parse(&lexer, symtab, errorp);
expr = expr_parse(&lexer, symtab, macros, errorp);
if (!*errorp && lexer.token.type != LEX_T_END) {
*errorp = xstrdup("Extra tokens at end of input.");
expr_destroy(expr);
Expand Down Expand Up @@ -1149,7 +1250,7 @@ expr_get_level(const struct expr *expr)
static enum expr_level
expr_parse_level(const char *s, const struct shash *symtab, char **errorp)
{
struct expr *expr = expr_parse_string(s, symtab, errorp);
struct expr *expr = expr_parse_string(s, symtab, NULL, errorp);
enum expr_level level = expr ? expr_get_level(expr) : EXPR_L_NOMINAL;
expr_destroy(expr);
return level;
Expand Down Expand Up @@ -1292,7 +1393,7 @@ parse_and_annotate(const char *s, const struct shash *symtab,
char *error;
struct expr *expr;

expr = expr_parse_string(s, symtab, &error);
expr = expr_parse_string(s, symtab, NULL, &error);
if (expr) {
expr = expr_annotate__(expr, symtab, nesting, &error);
}
Expand Down
18 changes: 18 additions & 0 deletions ovn/lib/expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -352,8 +352,10 @@ expr_from_node(const struct ovs_list *node)
void expr_format(const struct expr *, struct ds *);
void expr_print(const struct expr *);
struct expr *expr_parse(struct lexer *, const struct shash *symtab,
const struct shash *macros,
char **errorp);
struct expr *expr_parse_string(const char *, const struct shash *symtab,
const struct shash *macros,
char **errorp);

struct expr *expr_clone(struct expr *);
Expand Down Expand Up @@ -453,4 +455,20 @@ char *expr_parse_constant_set(struct lexer *, const struct shash *symtab,
OVS_WARN_UNUSED_RESULT;
void expr_constant_set_destroy(struct expr_constant_set *cs);


/* Address sets, aka "macros".
*
* Instead of referring to a set of value as:
* {addr1, addr2, ..., addrN}
* You can register a set of values and refer to them as:
* $name
* The macros should all have integer/masked-integer values.
* The values that don't qualify are ignored.
*/

void expr_macros_add(struct shash *macros, const char *name,
const char * const *values, size_t n_values);
void expr_macros_remove(struct shash *macros, const char *name);
void expr_macros_destroy(struct shash *macros);

#endif /* ovn/expr.h */
30 changes: 25 additions & 5 deletions ovn/lib/lex.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015 Nicira, Inc.
* Copyright (c) 2015, 2016 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -227,6 +227,10 @@ lex_token_format(const struct lex_token *token, struct ds *s)
lex_token_format_masked_integer(token, s);
break;

case LEX_T_MACRO:
ds_put_format(s, "$%s", token->s);
break;

case LEX_T_LPAREN:
ds_put_cstr(s, "(");
break;
Expand Down Expand Up @@ -514,19 +518,31 @@ lex_is_idn(unsigned char c)
}

static const char *
lex_parse_id(const char *p, struct lex_token *token)
lex_parse_id(const char *p, enum lex_type type, struct lex_token *token)
{
const char *start = p;

do {
p++;
} while (lex_is_idn(*p));

token->type = LEX_T_ID;
token->type = type;
lex_token_strcpy(token, start, p - start);
return p;
}

static const char *
lex_parse_macro(const char *p, struct lex_token *token)
{
p++;
if (!lex_is_id1(*p)) {
lex_error(token, "`$' must be followed by a valid identifier.");
return p;
}

return lex_parse_id(p, LEX_T_MACRO, token);
}

/* Initializes 'token' and parses the first token from the beginning of
* null-terminated string 'p' into 'token'. Stores a pointer to the start of
* the token (after skipping white space and comments, if any) into '*startp'.
Expand Down Expand Up @@ -697,6 +713,10 @@ lex_token_parse(struct lex_token *token, const char *p, const char **startp)
}
break;

case '$':
p = lex_parse_macro(p, token);
break;

case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case ':':
Expand All @@ -715,12 +735,12 @@ lex_token_parse(struct lex_token *token, const char *p, const char **startp)
* digits followed by a colon, but identifiers never do. */
p = (p[strspn(p, "0123456789abcdefABCDEF")] == ':'
? lex_parse_integer(p, token)
: lex_parse_id(p, token));
: lex_parse_id(p, LEX_T_ID, token));
break;

default:
if (lex_is_id1(*p)) {
p = lex_parse_id(p, token);
p = lex_parse_id(p, LEX_T_ID, token);
} else {
if (isprint((unsigned char) *p)) {
lex_error(token, "Invalid character `%c' in input.", *p);
Expand Down
29 changes: 21 additions & 8 deletions ovn/lib/lex.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ enum lex_type {
LEX_T_STRING, /* "foo" */
LEX_T_INTEGER, /* 12345 or 1.2.3.4 or ::1 or 01:02:03:04:05 */
LEX_T_MASKED_INTEGER, /* 12345/10 or 1.2.0.0/16 or ::2/127 or... */
LEX_T_MACRO, /* $NAME */
LEX_T_ERROR, /* invalid input */

/* Bare tokens. */
Expand Down Expand Up @@ -77,20 +78,32 @@ enum lex_format {
};
const char *lex_format_to_string(enum lex_format);

/* A token.
*
* 's' may point to 'buffer'; otherwise, it points to malloc()ed memory owned
* by the token. */
/* A token. */
struct lex_token {
enum lex_type type; /* One of LEX_*. */
char *s; /* LEX_T_ID, LEX_T_STRING, LEX_T_ERROR only. */
enum lex_format format; /* LEX_T_INTEGER, LEX_T_MASKED_INTEGER only. */
/* One of LEX_*. */
enum lex_type type;

/* Meaningful for LEX_T_ID, LEX_T_STRING, LEX_T_ERROR, LEX_T_MACRO only.
* For these token types, 's' may point to 'buffer'; otherwise, it points
* to malloc()ed memory owned by the token.
*
* Must be NULL for other token types.
*
* For LEX_T_MACRO, 's' does not include the leading $. */
char *s;

/* LEX_T_INTEGER, LEX_T_MASKED_INTEGER only. */
enum lex_format format;

union {
/* LEX_T_INTEGER, LEX_T_MASKED_INTEGER only. */
struct {
union mf_subvalue value; /* LEX_T_INTEGER, LEX_T_MASKED_INTEGER. */
union mf_subvalue mask; /* LEX_T_MASKED_INTEGER only. */
};
char buffer[256]; /* Buffer for LEX_T_ID/LEX_T_STRING. */

/* LEX_T_ID, LEX_T_STRING, LEX_T_ERROR, LEX_T_MACRO only. */
char buffer[256];
};
};

Expand Down
Loading

0 comments on commit 2c5cbb1

Please sign in to comment.