On Wed, Mar 27, 2024 at 12:46 AM Ales Musil <[email protected]> wrote:
>
> On Wed, Mar 27, 2024 at 7:14 AM Han Zhou <[email protected]> wrote:
>
> >
> >
> > On Tue, Mar 19, 2024 at 9:45 AM Ales Musil <[email protected]> wrote:
> > >
> > >
> > >
> > > On Tue, Mar 19, 2024 at 5:43 PM Ales Musil <[email protected]> wrote:
> > >>
> > >> Instead of tracking address set per struct expr_constant_set track it
> > >> per individual struct expr_constant. This allows more fine grained
> > >> control for I-P processing of address sets in controller. It helps
with
> > >> scenarios like matching on two address sets in one expression e.g.
> > >> "ip4.src == {$as1, $as2}". This allows any addition or removal of
> > >> individual adress from the set to be incrementally processed instead
> > >> of reprocessing all the flows.
> > >>
> > >> This unfortunately doesn't help with the following flows:
> > >> "ip4.src == $as1 && ip4.dst == $as2"
> > >> "ip4.src == $as1 || ip4.dst == $as2"
> > >>
> > >> The memory impact should be minimal as there is only increase of 8
bytes
> > >> per the struct expr_constant.
> > >>
> > >> Signed-off-by: Ales Musil <[email protected]>
> >
> > Thanks Ales for the improvement! The approach looks good to me. Please
see
> > some comments below:
> >
> >
> >
> Hi Han,
>
> thank you for the review.
>
>
> >
> > >> ---
> > >> controller/lflow.c | 4 +-
> > >> include/ovn/actions.h | 2 +-
> > >> include/ovn/expr.h | 46 ++++++++++----------
> > >> lib/actions.c | 20 ++++-----
> > >> lib/expr.c | 95
+++++++++++++++++------------------------
> > >> tests/ovn-controller.at | 14 +++---
> > >> 6 files changed, 83 insertions(+), 98 deletions(-)
> > >>
> > >> diff --git a/controller/lflow.c b/controller/lflow.c
> > >> index 895d17d19..730dc879d 100644
> > >> --- a/controller/lflow.c
> > >> +++ b/controller/lflow.c
> > >> @@ -278,7 +278,7 @@ lflow_handle_changed_flows(struct lflow_ctx_in
> > *l_ctx_in,
> > >> }
> > >>
> > >> static bool
> > >> -as_info_from_expr_const(const char *as_name, const union
expr_constant
> > *c,
> > >> +as_info_from_expr_const(const char *as_name, const struct
> > expr_constant *c,
> > >> struct addrset_info *as_info)
> > >> {
> > >> as_info->name = as_name;
> > >> @@ -714,7 +714,7 @@ lflow_handle_addr_set_update(const char *as_name,
> > >> if (as_diff->deleted) {
> > >> struct addrset_info as_info;
> > >> for (size_t i = 0; i < as_diff->deleted->n_values; i++)
{
> > >> - union expr_constant *c =
&as_diff->deleted->values[i];
> > >> + struct expr_constant *c =
&as_diff->deleted->values[i];
> > >> if (!as_info_from_expr_const(as_name, c, &as_info))
{
> > >> continue;
> > >> }
> > >> diff --git a/include/ovn/actions.h b/include/ovn/actions.h
> > >> index dcacbb1ff..1e20f9b81 100644
> > >> --- a/include/ovn/actions.h
> > >> +++ b/include/ovn/actions.h
> > >> @@ -238,7 +238,7 @@ struct ovnact_next {
> > >> struct ovnact_load {
> > >> struct ovnact ovnact;
> > >> struct expr_field dst;
> > >> - union expr_constant imm;
> > >> + struct expr_constant imm;
> > >> };
> > >>
> > >> /* OVNACT_MOVE, OVNACT_EXCHANGE. */
> > >> diff --git a/include/ovn/expr.h b/include/ovn/expr.h
> > >> index c48f82398..e54edb5bf 100644
> > >> --- a/include/ovn/expr.h
> > >> +++ b/include/ovn/expr.h
> > >> @@ -368,7 +368,7 @@ bool expr_relop_from_token(enum lex_type type,
enum
> > expr_relop *relop);
> > >> struct expr {
> > >> struct ovs_list node; /* In parent EXPR_T_AND or EXPR_T_OR
> > if any. */
> > >> enum expr_type type; /* Expression type. */
> > >> - char *as_name; /* Address set name. Null if it is
not
> > an
> > >> + const char *as_name; /* Address set name. Null if it is
not
> > an
> > >> address set. */
> > >>
> > >> union {
> > >> @@ -505,40 +505,42 @@ enum expr_constant_type {
> > >> };
> > >>
> > >> /* A string or integer constant (one must know which from context).
*/
> > >> -union expr_constant {
> > >> - /* Integer constant.
> > >> - *
> > >> - * The width of a constant isn't always clear, e.g. if you write
> > "1",
> > >> - * there's no way to tell whether you mean for that to be a
1-bit
> > constant
> > >> - * or a 128-bit constant or somewhere in between. */
> > >> - struct {
> > >> - union mf_subvalue value;
> > >> - union mf_subvalue mask; /* Only initialized if 'masked'. */
> > >> - bool masked;
> > >> -
> > >> - enum lex_format format; /* From the constant's lex_token. */
> > >> - };
> > >> +struct expr_constant {
> > >> + const char *as_name;
> > >>
> > >> - /* Null-terminated string constant. */
> > >> - char *string;
> > >> + union {
> > >> + /* Integer constant.
> > >> + *
> > >> + * The width of a constant isn't always clear, e.g. if you
> > write "1",
> > >> + * there's no way to tell whether you mean for that to be a
> > 1-bit
> > >> + * constant or a 128-bit constant or somewhere in between.
*/
> > >> + struct {
> > >> + union mf_subvalue value;
> > >> + union mf_subvalue mask; /* Only initialized if
'masked'. */
> > >> + bool masked;
> > >> +
> > >> + enum lex_format format; /* From the constant's
lex_token.
> > */
> > >> + };
> > >> +
> > >> + /* Null-terminated string constant. */
> > >> + char *string;
> > >> + };
> > >> };
> > >>
> > >> bool expr_constant_parse(struct lexer *,
> > >> const struct expr_field *,
> > >> - union expr_constant *);
> > >> -void expr_constant_format(const union expr_constant *,
> > >> + struct expr_constant *);
> > >> +void expr_constant_format(const struct expr_constant *,
> > >> enum expr_constant_type, struct ds *);
> > >> -void expr_constant_destroy(const union expr_constant *,
> > >> +void expr_constant_destroy(const struct expr_constant *,
> > >> enum expr_constant_type);
> > >>
> > >> /* A collection of "union expr_constant"s of the same type. */
> > >> struct expr_constant_set {
> > >> - union expr_constant *values; /* Constants. */
> > >> + struct expr_constant *values; /* Constants. */
> > >> size_t n_values; /* Number of constants. */
> > >> enum expr_constant_type type; /* Type of the constants. */
> > >> bool in_curlies; /* Whether the constants were in
{}.
> > */
> > >> - char *as_name; /* Name of an address set. It is
> > NULL if not
> > >> - an address set. */
> > >> };
> > >>
> > >> bool expr_constant_set_parse(struct lexer *, struct
expr_constant_set
> > *);
> > >> diff --git a/lib/actions.c b/lib/actions.c
> > >> index 71615fc53..6574c4df4 100644
> > >> --- a/lib/actions.c
> > >> +++ b/lib/actions.c
> > >> @@ -450,7 +450,7 @@ encode_LOAD(const struct ovnact_load *load,
> > >> const struct ovnact_encode_params *ep,
> > >> struct ofpbuf *ofpacts)
> > >> {
> > >> - const union expr_constant *c = &load->imm;
> > >> + const struct expr_constant *c = &load->imm;
> > >> struct mf_subfield dst = expr_resolve_field(&load->dst);
> > >> struct ofpact_set_field *sf = ofpact_put_set_field(ofpacts,
> > dst.field,
> > >> NULL, NULL);
> > >> @@ -2122,7 +2122,7 @@ encode_event_empty_lb_backends_opts(struct
ofpbuf
> > *ofpacts,
> > >> /* All empty_lb_backends fields are of type 'str' */
> > >> ovs_assert(!strcmp(o->option->type, "str"));
> > >>
> > >> - const union expr_constant *c = o->value.values;
> > >> + const struct expr_constant *c = o->value.values;
> > >> size_t size = strlen(c->string);
> > >> struct controller_event_opt_header hdr =
> > >> (struct controller_event_opt_header) {
> > >> @@ -2598,7 +2598,7 @@ validate_empty_lb_backends(struct
action_context
> > *ctx,
> > >> {
> > >> for (size_t i = 0; i < n_options; i++) {
> > >> const struct ovnact_gen_option *o = &options[i];
> > >> - const union expr_constant *c = o->value.values;
> > >> + const struct expr_constant *c = o->value.values;
> > >> struct sockaddr_storage ss;
> > >> struct uuid uuid;
> > >>
> > >> @@ -2801,7 +2801,7 @@ encode_put_dhcpv4_option(const struct
> > ovnact_gen_option *o,
> > >> uint8_t *opt_header = ofpbuf_put_zeros(ofpacts, 2);
> > >> opt_header[0] = o->option->code;
> > >>
> > >> - const union expr_constant *c = o->value.values;
> > >> + const struct expr_constant *c = o->value.values;
> > >> size_t n_values = o->value.n_values;
> > >> if (!strcmp(o->option->type, "bool") ||
> > >> !strcmp(o->option->type, "uint8")) {
> > >> @@ -2967,7 +2967,7 @@ encode_put_dhcpv6_option(const struct
> > ovnact_gen_option *o,
> > >> struct ofpbuf *ofpacts)
> > >> {
> > >> struct dhcpv6_opt_header *opt = ofpbuf_put_uninit(ofpacts,
sizeof
> > *opt);
> > >> - const union expr_constant *c = o->value.values;
> > >> + const struct expr_constant *c = o->value.values;
> > >> size_t n_values = o->value.n_values;
> > >> size_t size;
> > >>
> > >> @@ -3023,7 +3023,7 @@ encode_PUT_DHCPV4_OPTS(const struct
> > ovnact_put_opts *pdo,
> > >> find_opt(pdo->options, pdo->n_options,
DHCP_OPT_BOOTFILE_CODE);
> > >> if (boot_opt) {
> > >> uint8_t *opt_header = ofpbuf_put_zeros(ofpacts, 2);
> > >> - const union expr_constant *c = boot_opt->value.values;
> > >> + const struct expr_constant *c = boot_opt->value.values;
> > >> opt_header[0] = boot_opt->option->code;
> > >> opt_header[1] = strlen(c->string);
> > >> ofpbuf_put(ofpacts, c->string, opt_header[1]);
> > >> @@ -3033,7 +3033,7 @@ encode_PUT_DHCPV4_OPTS(const struct
> > ovnact_put_opts *pdo,
> > >> find_opt(pdo->options, pdo->n_options,
> > DHCP_OPT_BOOTFILE_ALT_CODE);
> > >> if (boot_alt_opt) {
> > >> uint8_t *opt_header = ofpbuf_put_zeros(ofpacts, 2);
> > >> - const union expr_constant *c = boot_alt_opt->value.values;
> > >> + const struct expr_constant *c = boot_alt_opt->value.values;
> > >> opt_header[0] = boot_alt_opt->option->code;
> > >> opt_header[1] = strlen(c->string);
> > >> ofpbuf_put(ofpacts, c->string, opt_header[1]);
> > >> @@ -3043,7 +3043,7 @@ encode_PUT_DHCPV4_OPTS(const struct
> > ovnact_put_opts *pdo,
> > >> pdo->options, pdo->n_options, DHCP_OPT_NEXT_SERVER_CODE);
> > >> if (next_server_opt) {
> > >> uint8_t *opt_header = ofpbuf_put_zeros(ofpacts, 2);
> > >> - const union expr_constant *c =
next_server_opt->value.values;
> > >> + const struct expr_constant *c =
next_server_opt->value.values;
> > >> opt_header[0] = next_server_opt->option->code;
> > >> opt_header[1] = sizeof(ovs_be32);
> > >> ofpbuf_put(ofpacts, &c->value.ipv4, sizeof(ovs_be32));
> > >> @@ -3247,7 +3247,7 @@ parse_put_nd_ra_opts(struct action_context
*ctx,
> > const struct expr_field *dst,
> > >> /* Let's validate the options. */
> > >> for (size_t i = 0; i < po->n_options; i++) {
> > >> const struct ovnact_gen_option *o = &po->options[i];
> > >> - const union expr_constant *c = o->value.values;
> > >> + const struct expr_constant *c = o->value.values;
> > >> if (o->value.n_values > 1) {
> > >> lexer_error(ctx->lexer, "Invalid value for \"%s\"
option",
> > >> o->option->name);
> > >> @@ -3430,7 +3430,7 @@ static void
> > >> encode_put_nd_ra_option(const struct ovnact_gen_option *o,
> > >> struct ofpbuf *ofpacts, ptrdiff_t ra_offset)
> > >> {
> > >> - const union expr_constant *c = o->value.values;
> > >> + const struct expr_constant *c = o->value.values;
> > >>
> > >> switch (o->option->code) {
> > >> case ND_RA_FLAG_ADDR_MODE:
> > >> diff --git a/lib/expr.c b/lib/expr.c
> > >> index 0cb44e1b6..286782025 100644
> > >> --- a/lib/expr.c
> > >> +++ b/lib/expr.c
> > >> @@ -179,12 +179,10 @@ expr_combine(enum expr_type type, struct expr
*a,
> > struct expr *b)
> > >> } else {
> > >> ovs_list_push_back(&a->andor, &b->node);
> > >> }
> > >> - free(a->as_name);
> > >> a->as_name = NULL;
> > >> return a;
> > >> } else if (b->type == type) {
> > >> ovs_list_push_front(&b->andor, &a->node);
> > >> - free(b->as_name);
> > >> b->as_name = NULL;
> > >> return b;
> > >> } else {
> > >> @@ -521,12 +519,13 @@ static bool parse_field(struct expr_context *,
> > struct expr_field *);
> > >>
> > >> static struct expr *
> > >> make_cmp__(const struct expr_field *f, enum expr_relop r,
> > >> - const union expr_constant *c)
> > >> + const struct expr_constant *c)
> > >> {
> > >> struct expr *e = xzalloc(sizeof *e);
> > >> e->type = EXPR_T_CMP;
> > >> e->cmp.symbol = f->symbol;
> > >> e->cmp.relop = r;
> > >> + e->as_name = c->as_name;
> > >> if (f->symbol->width) {
> > >> bitwise_copy(&c->value, sizeof c->value, 0,
> > >> &e->cmp.value, sizeof e->cmp.value, f->ofs,
> > >> @@ -547,7 +546,7 @@ make_cmp__(const struct expr_field *f, enum
> > expr_relop r,
> > >>
> > >> /* Returns the minimum reasonable width for integer constant 'c'. */
> > >> static int
> > >> -expr_constant_width(const union expr_constant *c)
> > >> +expr_constant_width(const struct expr_constant *c)
> > >> {
> > >> if (c->masked) {
> > >> return mf_subvalue_width(&c->mask);
> > >> @@ -674,10 +673,7 @@ make_cmp(struct expr_context *ctx,
> > >> e = expr_combine(r == EXPR_R_EQ ? EXPR_T_OR : EXPR_T_AND,
> > >> e, make_cmp__(f, r, &cs->values[i]));
> > >> }
> > >> - /* Track address set */
> > >> - if (r == EXPR_R_EQ && e->type == EXPR_T_OR && cs->as_name) {
> > >> - e->as_name = xstrdup(cs->as_name);
> > >> - }
> > >> +
> > >> exit:
> > >> expr_constant_set_destroy(cs);
> > >> return e;
> > >> @@ -797,11 +793,10 @@ parse_addr_sets(struct expr_context *ctx,
struct
> > expr_constant_set *cs,
> > >> }
> > >> }
> > >>
> > >> - struct expr_constant_set *addr_sets
> > >> - = (ctx->addr_sets
> > >> - ? shash_find_data(ctx->addr_sets, ctx->lexer->token.s)
> > >> - : NULL);
> > >> - if (!addr_sets) {
> > >> + struct shash_node *node = ctx->addr_sets
> > >> + ? shash_find(ctx->addr_sets,
> > ctx->lexer->token.s)
> > >> + : NULL;
> > >> + if (!node) {
> > >> lexer_syntax_error(ctx->lexer, "expecting address set
name");
> > >> return false;
> > >> }
> > >> @@ -810,17 +805,16 @@ parse_addr_sets(struct expr_context *ctx,
struct
> > expr_constant_set *cs,
> > >> return false;
> > >> }
> > >>
> > >> - if (!cs->n_values) {
> > >> - cs->as_name = xstrdup(ctx->lexer->token.s);
> > >> - }
> > >> -
> > >> + struct expr_constant_set *addr_sets = node->data;
> > >> size_t n_values = cs->n_values + addr_sets->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_sets->n_values; i++) {
> > >> - cs->values[cs->n_values++] = addr_sets->values[i];
> > >> + struct expr_constant *c = &cs->values[cs->n_values++];
> > >> + *c = addr_sets->values[i];
> > >> + c->as_name = node->name;
> >
> > I am not sure if it is safe enough to just store the reference. We need
to
> > check carefully if there is any chance the pointer becomes dangling when
> > the corresponding address set is destroyed or in any other
circumstances.
> >
>
> Currently it is safe to store as it is only for the duration of the whole
> expression, in the current code base the set outlives the expression.
> However it might be a problem later on, I don't know how viable it would
be
> in terms of memory to store clone.
>
>
> >
> > >> }
> > >>
> > >> return true;
> > >> @@ -859,8 +853,9 @@ parse_port_group(struct expr_context *ctx, struct
> > expr_constant_set *cs,
> > >> *allocated_values = n_values;
> > >> }
> > >> for (size_t i = 0; i < port_group->n_values; i++) {
> > >> - cs->values[cs->n_values++].string =
> > >> - xstrdup(port_group->values[i].string);
> > >> + struct expr_constant *c = &cs->values[cs->n_values++];
> > >> + c->string = xstrdup(port_group->values[i].string);
> > >> + c->as_name = NULL;
> > >> }
> > >>
> > >> return true;
> > >> @@ -875,11 +870,6 @@ parse_constant(struct expr_context *ctx, struct
> > expr_constant_set *cs,
> > >> sizeof *cs->values);
> > >> }
> > >>
> > >> - /* Combining other values to the constant set that is tracking
an
> > >> - * address set, so untrack it. */
> > >> - free(cs->as_name);
> > >> - cs->as_name = NULL;
> > >> -
> > >> if (ctx->lexer->token.type == LEX_T_TEMPLATE) {
> > >> lexer_error(ctx->lexer, "Unexpanded template.");
> > >> return false;
> > >> @@ -887,7 +877,9 @@ parse_constant(struct expr_context *ctx, struct
> > expr_constant_set *cs,
> > >> if (!assign_constant_set_type(ctx, cs, EXPR_C_STRING)) {
> > >> return false;
> > >> }
> > >> - cs->values[cs->n_values++].string =
> > xstrdup(ctx->lexer->token.s);
> > >> + struct expr_constant *c = &cs->values[cs->n_values++];
> > >> + c->string = xstrdup(ctx->lexer->token.s);
> > >> + c->as_name = NULL;
> > >> lexer_get(ctx->lexer);
> > >> return true;
> > >> } else if (ctx->lexer->token.type == LEX_T_INTEGER ||
> > >> @@ -896,13 +888,14 @@ parse_constant(struct expr_context *ctx, struct
> > expr_constant_set *cs,
> > >> return false;
> > >> }
> > >>
> > >> - union expr_constant *c = &cs->values[cs->n_values++];
> > >> + struct expr_constant *c = &cs->values[cs->n_values++];
> > >> c->value = ctx->lexer->token.value;
> > >> c->format = ctx->lexer->token.format;
> > >> c->masked = ctx->lexer->token.type == LEX_T_MASKED_INTEGER;
> > >> if (c->masked) {
> > >> c->mask = ctx->lexer->token.mask;
> > >> }
> > >> + c->as_name = NULL;
> > >> lexer_get(ctx->lexer);
> > >> return true;
> > >> } else if (ctx->lexer->token.type == LEX_T_MACRO) {
> > >> @@ -961,7 +954,7 @@ parse_constant_set(struct expr_context *ctx,
struct
> > expr_constant_set *cs)
> > >> * indeterminate. */
> > >> bool
> > >> expr_constant_parse(struct lexer *lexer, const struct expr_field *f,
> > >> - union expr_constant *c)
> > >> + struct expr_constant *c)
> > >> {
> > >> if (lexer->error) {
> > >> return false;
> > >> @@ -987,7 +980,7 @@ expr_constant_parse(struct lexer *lexer, const
> > struct expr_field *f,
> > >> /* Appends to 's' a re-parseable representation of constant 'c' with
> > the given
> > >> * 'type'. */
> > >> void
> > >> -expr_constant_format(const union expr_constant *c,
> > >> +expr_constant_format(const struct expr_constant *c,
> > >> enum expr_constant_type type, struct ds *s)
> > >> {
> > >> if (type == EXPR_C_STRING) {
> > >> @@ -1010,7 +1003,7 @@ expr_constant_format(const union expr_constant
*c,
> > >> *
> > >> * Does not free(c). */
> > >> void
> > >> -expr_constant_destroy(const union expr_constant *c,
> > >> +expr_constant_destroy(const struct expr_constant *c,
> > >> enum expr_constant_type type)
> > >> {
> > >> if (c && type == EXPR_C_STRING) {
> > >> @@ -1043,7 +1036,7 @@ expr_constant_set_format(const struct
> > expr_constant_set *cs, struct ds *s)
> > >> ds_put_char(s, '{');
> > >> }
> > >>
> > >> - for (const union expr_constant *c = cs->values;
> > >> + for (const struct expr_constant *c = cs->values;
> > >> c < &cs->values[cs->n_values]; c++) {
> > >> if (c != cs->values) {
> > >> ds_put_cstr(s, ", ");
> > >> @@ -1067,15 +1060,14 @@ expr_constant_set_destroy(struct
> > expr_constant_set *cs)
> > >> }
> > >> }
> > >> free(cs->values);
> > >> - free(cs->as_name);
> > >> }
> > >> }
> > >>
> > >> static int
> > >> compare_expr_constant_integer_cb(const void *a_, const void *b_)
> > >> {
> > >> - const union expr_constant *a = a_;
> > >> - const union expr_constant *b = b_;
> > >> + const struct expr_constant *a = a_;
> > >> + const struct expr_constant *b = b_;
> > >>
> > >> int d = memcmp(&a->value, &b->value, sizeof a->value);
> > >> if (d) {
> > >> @@ -1114,7 +1106,7 @@ expr_constant_set_create_integers(const char
> > *const *values, size_t n_values)
> > >> VLOG_WARN("Invalid constant set entry: '%s', token type:
> > %d",
> > >> values[i], lex.token.type);
> > >> } else {
> > >> - union expr_constant *c = &cs->values[cs->n_values++];
> > >> + struct 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;
> > >> @@ -1135,7 +1127,7 @@ expr_constant_set_create_integers(const char
> > *const *values, size_t n_values)
> > >>
> > >> static void
> > >> expr_constant_set_add_value(struct expr_constant_set **p_cs,
> > >> - union expr_constant *c, size_t
*allocated)
> > >> + struct expr_constant *c, size_t
*allocated)
> > >> {
> > >> struct expr_constant_set *cs = *p_cs;
> > >> if (!cs) {
> > >> @@ -1246,7 +1238,7 @@ expr_const_sets_add_strings(struct shash
> > *const_sets, const char *name,
> > >> values[i], name);
> > >> continue;
> > >> }
> > >> - union expr_constant *c = &cs->values[cs->n_values++];
> > >> + struct expr_constant *c = &cs->values[cs->n_values++];
> > >> c->string = xstrdup(values[i]);
> > >> }
> > >>
> > >> @@ -1359,7 +1351,7 @@ expr_parse_primary(struct expr_context *ctx,
bool
> > *atomic)
> > >>
> > >> *atomic = true;
> > >>
> > >> - union expr_constant *cst = xzalloc(sizeof *cst);
> > >> + struct expr_constant *cst = xzalloc(sizeof *cst);
> > >> cst->format = LEX_F_HEXADECIMAL;
> > >> cst->masked = false;
> > >>
> > >> @@ -1367,7 +1359,6 @@ expr_parse_primary(struct expr_context *ctx,
bool
> > *atomic)
> > >> c.values = cst;
> > >> c.n_values = 1;
> > >> c.in_curlies = false;
> > >> - c.as_name = NULL;
> > >> return make_cmp(ctx, &f, EXPR_R_NE, &c);
> > >> } else if (parse_relop(ctx, &r) && parse_constant_set(ctx,
> > &c)) {
> > >> return make_cmp(ctx, &f, r, &c);
> > >> @@ -1834,7 +1825,6 @@ expr_symtab_destroy(struct shash *symtab)
> > >> static struct expr *
> > >> expr_clone_cmp(struct expr *expr)
> > >> {
> > >> - ovs_assert(!expr->as_name);
> > >> struct expr *new = xmemdup(expr, sizeof *expr);
> > >> if (!new->cmp.symbol->width) {
> > >> new->cmp.string = xstrdup(new->cmp.string);
> > >> @@ -1858,7 +1848,6 @@ expr_clone_andor(struct expr *expr)
> > >> static struct expr *
> > >> expr_clone_condition(struct expr *expr)
> > >> {
> > >> - ovs_assert(!expr->as_name);
> > >> struct expr *new = xmemdup(expr, sizeof *expr);
> > >> new->cond.string = xstrdup(new->cond.string);
> > >> return new;
> > >> @@ -1894,8 +1883,6 @@ expr_destroy(struct expr *expr)
> > >> return;
> > >> }
> > >>
> > >> - free(expr->as_name);
> > >> -
> > >> struct expr *sub;
> > >>
> > >> switch (expr->type) {
> > >> @@ -2567,7 +2554,6 @@ crush_or_supersets(struct expr *expr, const
> > struct expr_symbol *symbol)
> > >> * mask sizes. */
> > >> size_t n = ovs_list_size(&expr->andor);
> > >> struct expr **subs = xmalloc(n * sizeof *subs);
> > >> - bool modified = false;
> > >> /* Linked list over the 'subs' array to quickly skip deleted
> > elements,
> > >> * i.e. the index of the next potentially non-NULL element. */
> > >> size_t *next = xmalloc(n * sizeof *next);
> > >> @@ -2596,14 +2582,14 @@ crush_or_supersets(struct expr *expr, const
> > struct expr_symbol *symbol)
> > >> next[last] = i;
> > >> last = i;
> > >> } else {
> > >> + /* Remove address set reference from the duplicate. */
> > >> + subs[last]->as_name = NULL;
> > >> expr_destroy(subs[i]);
> > >> subs[i] = NULL;
> > >> - modified = true;
> > >> }
> > >> }
> > >>
> > >> - if (!symbol->width || symbol->level != EXPR_L_ORDINAL
> > >> - || (!modified && expr->as_name)) {
> > >> + if (!symbol->width || symbol->level != EXPR_L_ORDINAL) {
> > >> /* Not a fully maskable field or this expression is
tracking an
> > >> * address set. Don't try to optimize to preserve address
set
> > I-P. */
> >
> > The above comment needs to be updated since it obviously doesn't
preserve
> > address set I-P any more. What's the reason it is not considered any
more?
> >
>
> Because of the AS reference per sub expression we can actually allow this
> optimization to happen. In the case of the smaller mask we will lose track
> of only that address instead of the whole set. I'll update the comment.
>
The question is, is it worth losing track of those addresses for the
optimization? I think in most cases address sets shouldn't contain too many
overlapping entries. So the optimization may not make a big difference
anyway, but handling removal of such addresses that are not tracked will
cost much more. I don't have a strong opinion on this though, if
overlapping is rare.
>
> >
> > >> goto done;
> > >> @@ -2658,10 +2644,11 @@ crush_or_supersets(struct expr *expr, const
> > struct expr_symbol *symbol)
> > >> if (expr_bitmap_intersect_check(a_value, a_mask,
b_value,
> > b_mask,
> > >> bit_width)
> > >> && bitmap_is_superset(b_mask, a_mask, bit_width)) {
> > >> - /* 'a' is the same expression with a smaller mask.
*/
> > >> + /* 'a' is the same expression with a smaller mask.
> > >> + * Remove address set reference from the duplicate.
*/
> > >> + a->as_name = NULL;
> > >> expr_destroy(subs[j]);
> > >> subs[j] = NULL;
> > >> - modified = true;
> > >>
> > >> /* Shorten the path for the next round. */
> > >> if (last) {
> > >> @@ -2685,12 +2672,6 @@ done:
> > >> }
> > >> }
> > >>
> > >> - if (modified) {
> > >> - /* Members modified, so untrack address set. */
> > >> - free(expr->as_name);
> > >> - expr->as_name = NULL;
> > >> - }
> > >> -
> > >> free(next);
> > >> free(subs);
> > >> return expr;
> > >> @@ -3271,10 +3252,10 @@ add_disjunction(const struct expr *or,
> > >> LIST_FOR_EACH (sub, node, &or->andor) {
> > >> struct expr_match *match = expr_match_new(m, clause,
n_clauses,
> > >> conj_id);
> > >> - if (or->as_name) {
> > >> + if (sub->as_name) {
> > >> ovs_assert(sub->type == EXPR_T_CMP);
> > >> ovs_assert(sub->cmp.symbol->width);
> > >> - match->as_name = xstrdup(or->as_name);
> > >> + match->as_name = xstrdup(sub->as_name);
> > >> match->as_ip = sub->cmp.value.ipv6;
> > >> match->as_mask = sub->cmp.mask.ipv6;
> > >> }
> > >> diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at
> > >> index fdcc5aab2..626dd34f6 100644
> > >> --- a/tests/ovn-controller.at
> > >> +++ b/tests/ovn-controller.at
> > >> @@ -1630,7 +1630,9 @@
> > priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.8
> > actions=lo
> > >> done
> > >>
> > >> reprocess_count_new=$(read_counter consider_logical_flow)
> > >> -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))],
[0],
> > [10
> > >> +# First 2 reprocess are due to change from 1 IP in AS to 2.
> > >> +# Last 5 is due to overlap in IP addresses between as1 and as2.
> > >> +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))],
[0],
> > [7
> > >> ])
> > >>
> > >> # Remove the IPs from as1 and as2, 1 IP each time.
> > >> @@ -1653,9 +1655,9 @@ for i in $(seq 10); do
> > >> done
> > >>
> > >> reprocess_count_new=$(read_counter consider_logical_flow)
> > >> -# In this case the as1 and as2 are merged to a single OR expr, so we
> > lose track of
> > >> -# address set information - can't handle deletion incrementally.
> > >> -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))],
[0],
> > [10
> > >> +# First 5 are due to overlap in IP addresses between as1 and as2.
> > >> +# Last 2 are due to change from 2 IP in AS to 1.
> > >> +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))],
[0],
> > [7
> > >> ])
> > >>
> > >> OVN_CLEANUP([hv1])
> > >> @@ -1822,7 +1824,7 @@
> > priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.5
> > actions=co
> > >>
> >
priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.10.10.10
> > actions=conjunction,2/2)
> > >> ])
> > >> reprocess_count_new=$(read_counter consider_logical_flow)
> > >> -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))],
[0],
> > [1
> > >> +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))],
[0],
> > [0
> > >> ])
> > >>
> > >> # Delete 2 IPs
> > >> @@ -1842,7 +1844,7 @@
> > priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.0.0.3
> > actions=co
> > >>
> >
priority=1100,ip,reg15=0x$port_key,metadata=0x$dp_key,nw_src=10.10.10.10
> > actions=conjunction,2/2)
> > >> ])
> > >> reprocess_count_new=$(read_counter consider_logical_flow)
> > >> -AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))],
[0],
> > [1
> > >> +AT_CHECK([echo $(($reprocess_count_new - $reprocess_count_old))],
[0],
> > [0
> > >> ])
> > >>
> > >> OVN_CLEANUP([hv1])
> > >> --
> > >> 2.44.0
> > >>
> > >
> > > Please consider it as RFC, I forgot to add the tag into subject.
> >
> > Is there a reason why this is RFC? Do you have any TODOs in mind?
> >
>
> Mainly to be sure if this approach is heading the right direction, which
it
> seems it does. There shouldn't be any additional TODO right now.
>
I see. I will take a closer look at this patch and see if I have any more
findings before you send v2.
Thanks,
Han
>
> > I am just not 100% confident about corner cases. The existing test cases
> > seem to be handled correctly. We might need to think about if there are
any
> > other potentially risky scenarios that need to be tested, although I
don't
> > see any obvious problem for now.
> >
>
>
> So things that came to my mind are covered by the tests, let's see if
> others will think about potentially dangerous scenarios.
>
>
> > Thanks,
> > Han
> >
> > > --
> > >
> > > Ales Musil
> > >
> > > Senior Software Engineer - OVN Core
> > >
> > > Red Hat EMEA
> > >
> > > [email protected]
> >
>
>
> I'll wait a bit for feedback from others before posting v2.
>
>
> Thanks,
> Ales
> --
>
> Ales Musil
>
> Senior Software Engineer - OVN Core
>
> Red Hat EMEA <https://www.redhat.com>
>
> [email protected]
> <https://red.ht/sig>
> _______________________________________________
> dev mailing list
> [email protected]
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev