Good catch (== thanks for finding an embarrassing bug to mine :-) Acked-by: Jarno Rajahalme <ja...@ovn.org>
> On Sep 2, 2016, at 1:26 PM, Ben Pfaff <b...@ovn.org> wrote: > > struct ofpact_learn_spec is variable-length. The 'n_specs' member of > struct ofpact_learn counted the number of specs, but the iteration loops > over struct ofpact_learn_spec only iterated as far as the *minimum* length > of 'n_specs' specs. > > This fixes the problem, which exhibited as consistent failures for test 431 > (learning action - TCPv6 port learning), seemingly only on i386 since it > shows up for my personal development machine but appears to not happen for > anyone else. > > Fixes: dfe191d5faa6 ("ofp-actions: Waste less memory in learn actions.") > Signed-off-by: Ben Pfaff <b...@ovn.org> > --- > include/openvswitch/ofp-actions.h | 33 +++++++++++++++++++++++---------- > lib/learn.c | 13 ++++--------- > lib/ofp-actions.c | 4 +--- > 3 files changed, 28 insertions(+), 22 deletions(-) > > diff --git a/include/openvswitch/ofp-actions.h > b/include/openvswitch/ofp-actions.h > index bf7d62f..6759201 100644 > --- a/include/openvswitch/ofp-actions.h > +++ b/include/openvswitch/ofp-actions.h > @@ -744,21 +744,34 @@ ofpact_learn_spec_next(const struct ofpact_learn_spec > *spec) > * > * Used for NXAST_LEARN. */ > struct ofpact_learn { > - struct ofpact ofpact; > + OFPACT_PADDED_MEMBERS( > + struct ofpact ofpact; > > - uint16_t idle_timeout; /* Idle time before discarding (seconds). */ > - uint16_t hard_timeout; /* Max time before discarding (seconds). */ > - uint16_t priority; /* Priority level of flow entry. */ > - uint8_t table_id; /* Table to insert flow entry. */ > - enum nx_learn_flags flags; /* NX_LEARN_F_*. */ > - ovs_be64 cookie; /* Cookie for new flow. */ > - uint16_t fin_idle_timeout; /* Idle timeout after FIN, if nonzero. */ > - uint16_t fin_hard_timeout; /* Hard timeout after FIN, if nonzero. */ > + uint16_t idle_timeout; /* Idle time before discarding (seconds). > */ > + uint16_t hard_timeout; /* Max time before discarding (seconds). > */ > + uint16_t priority; /* Priority level of flow entry. */ > + uint8_t table_id; /* Table to insert flow entry. */ > + enum nx_learn_flags flags; /* NX_LEARN_F_*. */ > + ovs_be64 cookie; /* Cookie for new flow. */ > + uint16_t fin_idle_timeout; /* Idle timeout after FIN, if nonzero. */ > + uint16_t fin_hard_timeout; /* Hard timeout after FIN, if nonzero. */ > + ); > > - unsigned int n_specs; > struct ofpact_learn_spec specs[]; > }; > > +static inline const struct ofpact_learn_spec * > +ofpact_learn_spec_end(const struct ofpact_learn *learn) > +{ > + return ALIGNED_CAST(const struct ofpact_learn_spec *, > + ofpact_next(&learn->ofpact)); > +} > + > +#define OFPACT_LEARN_SPEC_FOR_EACH(SPEC, LEARN) \ > + for ((SPEC) = (LEARN)->specs; \ > + (SPEC) < ofpact_learn_spec_end(LEARN); \ > + (SPEC) = ofpact_learn_spec_next(SPEC)) > + > /* Multipath link choice algorithm to apply. > * > * In the descriptions below, 'n_links' is max_link + 1. */ > diff --git a/lib/learn.c b/lib/learn.c > index bb57f7d..9cab759 100644 > --- a/lib/learn.c > +++ b/lib/learn.c > @@ -41,8 +41,7 @@ learn_check(const struct ofpact_learn *learn, const struct > flow *flow) > struct match match; > > match_init_catchall(&match); > - for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; > - spec = ofpact_learn_spec_next(spec)) { > + OFPACT_LEARN_SPEC_FOR_EACH (spec, learn) { > enum ofperr error; > > /* Check the source. */ > @@ -123,8 +122,7 @@ learn_execute(const struct ofpact_learn *learn, const > struct flow *flow, > oft->fin_hard_timeout = learn->fin_hard_timeout; > } > > - for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; > - spec = ofpact_learn_spec_next(spec)) { > + OFPACT_LEARN_SPEC_FOR_EACH (spec, learn) { > struct ofpact_set_field *sf; > union mf_subvalue value; > > @@ -179,8 +177,7 @@ learn_mask(const struct ofpact_learn *learn, struct > flow_wildcards *wc) > union mf_subvalue value; > > memset(&value, 0xff, sizeof value); > - for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; > - spec = ofpact_learn_spec_next(spec)) { > + OFPACT_LEARN_SPEC_FOR_EACH (spec, learn) { > if (spec->src_type == NX_LEARN_SRC_FIELD) { > mf_write_subfield_flow(&spec->src, &value, &wc->masks); > } > @@ -386,7 +383,6 @@ learn_parse__(char *orig, char *arg, struct ofpbuf > *ofpacts) > return error; > } > learn = ofpacts->header; > - learn->n_specs++; > } > } > ofpact_finish_LEARN(ofpacts, &learn); > @@ -459,8 +455,7 @@ learn_format(const struct ofpact_learn *learn, struct ds > *s) > colors.param, colors.end, ntohll(learn->cookie)); > } > > - for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; > - spec = ofpact_learn_spec_next(spec)) { > + OFPACT_LEARN_SPEC_FOR_EACH (spec, learn) { > unsigned int n_bytes = DIV_ROUND_UP(spec->n_bits, 8); > ds_put_char(s, ','); > > diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c > index f27ff21..22c7b16 100644 > --- a/lib/ofp-actions.c > +++ b/lib/ofp-actions.c > @@ -4321,7 +4321,6 @@ decode_NXAST_RAW_LEARN(const struct nx_action_learn > *nal, > > spec = ofpbuf_put_zeros(ofpacts, sizeof *spec); > learn = ofpacts->header; > - learn->n_specs++; > > spec->src_type = header & NX_LEARN_SRC_MASK; > spec->dst_type = header & NX_LEARN_DST_MASK; > @@ -4421,8 +4420,7 @@ encode_LEARN(const struct ofpact_learn *learn, > nal->flags = htons(learn->flags); > nal->table_id = learn->table_id; > > - for (spec = learn->specs; spec < &learn->specs[learn->n_specs]; > - spec = ofpact_learn_spec_next(spec)) { > + OFPACT_LEARN_SPEC_FOR_EACH (spec, learn) { > put_u16(out, spec->n_bits | spec->dst_type | spec->src_type); > > if (spec->src_type == NX_LEARN_SRC_FIELD) { > -- > 2.1.3 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev