[ovs-dev] [PATCH] learn: Fix iteration over learning specs.
Ben Pfaff
blp at ovn.org
Fri Sep 2 20:26:50 UTC 2016
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 <blp at 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
More information about the dev
mailing list