Learn actions cache struct ofproto_flow_mod instances, but
ofproto_flow_mod_start() used to destroy their rule_criteria,
leaving later replays with dangling minimask pointers that
crashed in classifier_find_rule_exactly().
This change adds a keep_flow_mod flag, clones the criteria
before the initial start, restores it afterward via new
clone/replace helpers, and lets normal ofproto_flow_mod_uninit()
free the clone. As a result, cached learn xcache
entries can safely replay without touching freed memory.
The call trace:
*0 minimask_hash (basis=0, mask=0x7f05d7fd3f38) at lib/classifier-private.h:325
*1 find_subtable (cls=cls@entry=0x5598cf591588, mask=0x7f05d7fd3f38) at
lib/classifier.c:1431
*2 0x00007f0770ab207d in classifier_find_rule_exactly
(cls=cls@entry=0x5598cf591588,
target=target@entry=0x7f064c696e30, version=18446744073709551615) at
lib/classifier.c:1184
*3 0x00007f077110edb8 in collect_rules_strict
(ofproto=ofproto@entry=0x5598cf4f45c0,
criteria=criteria@entry=0x7f064c696e28, rules=rules@entry=0x7f064c696ec0)
at ofproto/ofproto.c:4524
*4 0x00007f0771112c17 in modify_flow_start_strict (ofm=0x7f064c696e20,
ofproto=0x5598cf4f45c0) at ofproto/ofproto.c:5789
*5 ofproto_flow_mod_start (ofproto=0x5598cf4f45c0,
ofm=ofm@entry=0x7f064c696e20) at ofproto/ofproto.c:7943
*6 0x00007f0771112fd0 in ofproto_flow_mod_learn_start (
ofm=ofm@entry=0x7f064c696e20) at ofproto/ofproto.c:5331
*7 0x00007f0771114cad in ofproto_flow_mod_learn (ofm=0x7f064c696e20,
keep_ref=<optimized out>, limit=<optimized out>, below_limitp=0x0) at
ofproto/ofproto.c:5416
*8 0x00007f0771141f73 in xlate_push_stats_entry (entry=0x7f0651563d10,
stats=0x0) at ofproto/ofproto-dpif-xlate-cache.c:127
*9 0x00007f077114206d in ofpbuf_try_pull (size=40,
b=<synthetic pointer>) at include/openvswitch/ofpbuf.h:262
*10 xlate_push_stats (xcache=<optimized out>,
stats=0x0) at ofproto/ofproto-dpif-xlate-cache.c:180
*11 0x00007f077112e080 in push_dp_ops (udpif=0x5598cf4caf90,
ops=<optimized out>, n_ops=<optimized out>) at
ofproto/ofproto-dpif-upcall.c:2409
*12 0x00007f077112e195 in push_ukey_ops (udpif=0x5598cf591588, umap=0x0,
ops=0x7f0669b1ffd0, n_ops=860610658) at ofproto/ofproto-dpif-upcall.c:2439
*13 0x00005598cf4cb9a8 in ?? ()
*14 0x00007f077112ef7d in revalidator_sweep__ (revalidator=<optimized out>,
purge=false) at ofproto/ofproto-dpif-upcall.c:2799
*15 0x00007f07711323c5 in udpif_revalidator (arg=0x5598cf4dcf80) at
ofproto/ofproto-dpif-upcall.c:945
*16 0x00007f0770b6715f in ovsthread_wrapper (aux_=<optimized out>) at
lib/ovs-thread.c:383
*17 0x00007f076f922e65 in start_thread (arg=0x0) at pthread_create.c:282
*18 0x00007f076ee4088d in __libc_ifunc_impl_list (name=<optimized out>,
array=0x7f0669b22700, max=<optimized out>) at
../sysdeps/x86_64/multiarch/ifunc-impl-list.c:329
Signed-off-by: LIU Yulong <[email protected]>
---
ofproto/ofproto-provider.h | 1 +
ofproto/ofproto.c | 45 ++++++++++++++++++++++++++++++++++++++
2 files changed, 46 insertions(+)
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index 7df3f5246..be58dbed8 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -2007,6 +2007,7 @@ struct ofproto_flow_mod {
bool modify_keep_counts;
enum nx_flow_update_event event;
uint8_t table_id;
+ bool keep_flow_mod; /* Preserve criteria beyond start. */
/* These are only used during commit execution.
* ofproto_flow_mod_uninit() does NOT clean these up. */
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index ec6d60a44..ae63b86ba 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -143,6 +143,10 @@ static void rule_criteria_init(struct rule_criteria *,
uint8_t table_id,
static void rule_criteria_require_rw(struct rule_criteria *,
bool can_write_readonly);
static void rule_criteria_destroy(struct rule_criteria *);
+static void rule_criteria_clone(struct rule_criteria *,
+ const struct rule_criteria *);
+static void rule_criteria_replace(struct rule_criteria *,
+ const struct rule_criteria *);
static enum ofperr collect_rules_loose(struct ofproto *,
const struct rule_criteria *,
@@ -4600,6 +4604,31 @@ rules_mark_for_removal(struct ofproto *ofproto, struct
rule_collection *rules)
rule_collection_destroy(rules);
}
+static void
+rule_criteria_clone(struct rule_criteria *dst,
+ const struct rule_criteria *src)
+{
+ cls_rule_clone(&dst->cr, &src->cr);
+ dst->table_id = src->table_id;
+ dst->version = src->version;
+ dst->cookie = src->cookie;
+ dst->cookie_mask = src->cookie_mask;
+ dst->out_port = src->out_port;
+ dst->out_group = src->out_group;
+ dst->include_hidden = src->include_hidden;
+ dst->include_readonly = src->include_readonly;
+}
+
+static void
+rule_criteria_replace(struct rule_criteria *dst,
+ const struct rule_criteria *src)
+{
+ if (dst->version != OVS_VERSION_NOT_REMOVED) {
+ rule_criteria_destroy(dst);
+ }
+ rule_criteria_clone(dst, src);
+}
+
/* Schedules postponed removal of rules, destroys 'rules'. */
static void
remove_rules_postponed(struct rule_collection *rules)
@@ -5605,6 +5634,14 @@ ofproto_flow_mod_learn_start(struct ofproto_flow_mod
*ofm)
OVS_REQUIRES(ofproto_mutex)
{
struct rule *rule = ofm->temp_rule;
+ struct rule_criteria saved_criteria;
+ bool saved = false;
+
+ if (ofm->keep_flow_mod
+ && ofm->criteria.version != OVS_VERSION_NOT_REMOVED) {
+ rule_criteria_clone(&saved_criteria, &ofm->criteria);
+ saved = true;
+ }
/* ofproto_flow_mod_start() consumes the reference, so we
* take a new one. */
@@ -5612,6 +5649,11 @@ ofproto_flow_mod_learn_start(struct ofproto_flow_mod
*ofm)
enum ofperr error = ofproto_flow_mod_start(rule->ofproto, ofm);
ofm->temp_rule = rule;
+ if (saved) {
+ rule_criteria_replace(&ofm->criteria, &saved_criteria);
+ rule_criteria_destroy(&saved_criteria);
+ }
+
return error;
}
@@ -5674,6 +5716,8 @@ ofproto_flow_mod_learn(struct ofproto_flow_mod *ofm, bool
keep_ref,
struct rule *rule = ofm->temp_rule;
bool below_limit = true;
+ ofm->keep_flow_mod = keep_ref;
+
/* Do we need to insert the rule? */
if (!error && rule->state == RULE_INITIALIZED) {
ovs_mutex_lock(&ofproto_mutex);
@@ -8232,6 +8276,7 @@ ofproto_flow_mod_init(struct ofproto *ofproto, struct
ofproto_flow_mod *ofm,
ofm->conjs = NULL;
ofm->n_conjs = 0;
ofm->table_id = fm->table_id;
+ ofm->keep_flow_mod = false;
/* Initialize flag used by ofproto_dpif_xcache_execute(). */
ofm->learn_adds_rule = false;
--
2.50.1 (Apple Git-155)
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev