[ovs-dev] [thread 11/15] classifier: Make use of the classifier thread safe.
Ethan Jackson
ethan at nicira.com
Fri Aug 9 00:33:51 UTC 2013
Here's a new version. The most interesting thing is what I've done around
oftable_remove_rule(). It wasn't strictly necessary, but it made clang thread
safety a lot happier.
---
lib/classifier.c | 3 ++
lib/classifier.h | 57 ++++++++++++++++++++-----------
ofproto/ofproto-dpif.c | 36 ++++++++++++++++++--
ofproto/ofproto-provider.h | 3 +-
ofproto/ofproto.c | 81 +++++++++++++++++++++++++++++++++++++-------
tests/test-classifier.c | 19 +++++++++--
utilities/ovs-ofctl.c | 8 +++++
7 files changed, 170 insertions(+), 37 deletions(-)
diff --git a/lib/classifier.c b/lib/classifier.c
index a717bd3..556278f 100644
--- a/lib/classifier.c
+++ b/lib/classifier.c
@@ -25,6 +25,7 @@
#include "odp-util.h"
#include "ofp-util.h"
#include "packets.h"
+#include "ovs-thread.h"
static struct cls_table *find_table(const struct classifier *,
const struct minimask *);
@@ -143,6 +144,7 @@ classifier_init(struct classifier *cls)
cls->n_rules = 0;
hmap_init(&cls->tables);
list_init(&cls->tables_priority);
+ ovs_rwlock_init(&cls->rwlock);
}
/* Destroys 'cls'. Rules within 'cls', if any, are not freed; this is the
@@ -157,6 +159,7 @@ classifier_destroy(struct classifier *cls)
destroy_table(cls, table);
}
hmap_destroy(&cls->tables);
+ ovs_rwlock_destroy(&cls->rwlock);
}
}
diff --git a/lib/classifier.h b/lib/classifier.h
index a14a24d..3f89196 100644
--- a/lib/classifier.h
+++ b/lib/classifier.h
@@ -24,7 +24,14 @@
* a hash map from fixed field values to "struct cls_rule",
* which can contain a list of otherwise identical rules
* with lower priorities.
- */
+ *
+ * Thread-safety
+ * =============
+ *
+ * When locked properly, the classifier is thread safe as long as the following
+ * conditions are satisfied.
+ * - Only the main thread calls functions requiring a write lock.
+ * - Only the main thread is allowed to iterate over rules. */
#include "flow.h"
#include "hmap.h"
@@ -32,6 +39,8 @@
#include "match.h"
#include "openflow/nicira-ext.h"
#include "openflow/openflow.h"
+#include "ovs-thread.h"
+#include "util.h"
#ifdef __cplusplus
extern "C" {
@@ -42,6 +51,7 @@ struct classifier {
int n_rules; /* Total number of rules. */
struct hmap tables; /* Contains "struct cls_table"s. */
struct list tables_priority; /* Tables in descending priority order */
+ struct ovs_rwlock rwlock;
};
/* A set of rules that all have the same fields wildcarded. */
@@ -88,26 +98,35 @@ bool cls_rule_is_catchall(const struct cls_rule *);
bool cls_rule_is_loose_match(const struct cls_rule *rule,
const struct minimatch *criteria);
-void classifier_init(struct classifier *);
+void classifier_init(struct classifier *cls);
void classifier_destroy(struct classifier *);
-bool classifier_is_empty(const struct classifier *);
-int classifier_count(const struct classifier *);
-void classifier_insert(struct classifier *, struct cls_rule *);
-struct cls_rule *classifier_replace(struct classifier *, struct cls_rule *);
-void classifier_remove(struct classifier *, struct cls_rule *);
-struct cls_rule *classifier_lookup(const struct classifier *,
+bool classifier_is_empty(const struct classifier *cls)
+ OVS_REQ_RDLOCK(cls->rwlock);
+int classifier_count(const struct classifier *cls)
+ OVS_REQ_RDLOCK(cls->rwlock);
+void classifier_insert(struct classifier *cls, struct cls_rule *)
+ OVS_REQ_WRLOCK(cls->rwlock);
+struct cls_rule *classifier_replace(struct classifier *cls, struct cls_rule *)
+ OVS_REQ_WRLOCK(cls->rwlock);
+void classifier_remove(struct classifier *cls, struct cls_rule *)
+ OVS_REQ_WRLOCK(cls->rwlock);
+struct cls_rule *classifier_lookup(const struct classifier *cls,
const struct flow *,
- struct flow_wildcards *);
-bool classifier_rule_overlaps(const struct classifier *,
- const struct cls_rule *);
+ struct flow_wildcards *)
+ OVS_REQ_RDLOCK(cls->rwlock);
+bool classifier_rule_overlaps(const struct classifier *cls,
+ const struct cls_rule *)
+ OVS_REQ_RDLOCK(cls->rwlock);
typedef void cls_cb_func(struct cls_rule *, void *aux);
-struct cls_rule *classifier_find_rule_exactly(const struct classifier *,
- const struct cls_rule *);
-struct cls_rule *classifier_find_match_exactly(const struct classifier *,
+struct cls_rule *classifier_find_rule_exactly(const struct classifier *cls,
+ const struct cls_rule *)
+ OVS_REQ_RDLOCK(cls->rwlock);
+struct cls_rule *classifier_find_match_exactly(const struct classifier *cls,
const struct match *,
- unsigned int priority);
+ unsigned int priority)
+ OVS_REQ_RDLOCK(cls->rwlock);
/* Iteration. */
@@ -117,10 +136,10 @@ struct cls_cursor {
const struct cls_rule *target;
};
-void cls_cursor_init(struct cls_cursor *, const struct classifier *,
- const struct cls_rule *match);
-struct cls_rule *cls_cursor_first(struct cls_cursor *);
-struct cls_rule *cls_cursor_next(struct cls_cursor *, struct cls_rule *);
+void cls_cursor_init(struct cls_cursor *cursor, const struct classifier *cls,
+ const struct cls_rule *match) OVS_REQ_RDLOCK(cls->rwlock);
+struct cls_rule *cls_cursor_first(struct cls_cursor *cursor);
+struct cls_rule *cls_cursor_next(struct cls_cursor *cursor, struct cls_rule *);
#define CLS_CURSOR_FOR_EACH(RULE, MEMBER, CURSOR) \
for (ASSIGN_CONTAINER(RULE, cls_cursor_first(CURSOR), MEMBER); \
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 6ef2eb8..68042ef 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -829,7 +829,11 @@ type_run(const char *type)
ofport->may_enable);
}
+ /* Only ofproto-dpif cares about the facet classifier so we just
+ * lock cls_cursor_init() to appease the thread safety analysis. */
+ ovs_rwlock_rdlock(&ofproto->facets.rwlock);
cls_cursor_init(&cursor, &ofproto->facets, NULL);
+ ovs_rwlock_unlock(&ofproto->facets.rwlock);
CLS_CURSOR_FOR_EACH_SAFE (facet, next, cr, &cursor) {
facet_revalidate(facet);
run_fast_rl();
@@ -1453,10 +1457,12 @@ destruct(struct ofproto *ofproto_)
OFPROTO_FOR_EACH_TABLE (table, &ofproto->up) {
struct cls_cursor cursor;
+ ovs_rwlock_wrlock(&table->cls.rwlock);
cls_cursor_init(&cursor, &table->cls, NULL);
CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, up.cr, &cursor) {
- ofproto_rule_destroy(&rule->up);
+ ofproto_rule_destroy(&ofproto->up, &table->cls, &rule->up);
}
+ ovs_rwlock_unlock(&table->cls.rwlock);
}
ovs_mutex_lock(&ofproto->flow_mod_mutex);
@@ -1617,6 +1623,7 @@ run(struct ofproto *ofproto_)
ovs_rwlock_unlock(&ofproto->ml->rwlock);
/* Check the consistency of a random facet, to aid debugging. */
+ ovs_rwlock_rdlock(&ofproto->facets.rwlock);
if (time_msec() >= ofproto->consistency_rl
&& !classifier_is_empty(&ofproto->facets)
&& !ofproto->backer->need_revalidate) {
@@ -1636,6 +1643,7 @@ run(struct ofproto *ofproto_)
ofproto->backer->need_revalidate = REV_INCONSISTENCY;
}
}
+ ovs_rwlock_unlock(&ofproto->facets.rwlock);
return 0;
}
@@ -1688,12 +1696,16 @@ get_memory_usage(const struct ofproto *ofproto_, struct simap *usage)
size_t n_subfacets = 0;
struct facet *facet;
+ ovs_rwlock_rdlock(&ofproto->facets.rwlock);
simap_increase(usage, "facets", classifier_count(&ofproto->facets));
+ ovs_rwlock_unlock(&ofproto->facets.rwlock);
+ ovs_rwlock_rdlock(&ofproto->facets.rwlock);
cls_cursor_init(&cursor, &ofproto->facets, NULL);
CLS_CURSOR_FOR_EACH (facet, cr, &cursor) {
n_subfacets += list_size(&facet->subfacets);
}
+ ovs_rwlock_unlock(&ofproto->facets.rwlock);
simap_increase(usage, "subfacets", n_subfacets);
}
@@ -4364,7 +4376,9 @@ facet_create(const struct flow_miss *miss, struct rule_dpif *rule,
match_init(&match, &facet->flow, &facet->xout.wc);
cls_rule_init(&facet->cr, &match, OFP_DEFAULT_PRIORITY);
+ ovs_rwlock_wrlock(&ofproto->facets.rwlock);
classifier_insert(&ofproto->facets, &facet->cr);
+ ovs_rwlock_unlock(&ofproto->facets.rwlock);
facet->nf_flow.output_iface = facet->xout.nf_output_iface;
facet->fail_open = rule->up.cr.priority == FAIL_OPEN_PRIORITY;
@@ -4432,7 +4446,9 @@ facet_remove(struct facet *facet)
&facet->subfacets) {
subfacet_destroy__(subfacet);
}
+ ovs_rwlock_wrlock(&facet->ofproto->facets.rwlock);
classifier_remove(&facet->ofproto->facets, &facet->cr);
+ ovs_rwlock_unlock(&facet->ofproto->facets.rwlock);
cls_rule_destroy(&facet->cr);
facet_free(facet);
}
@@ -4576,7 +4592,11 @@ facet_flush_stats(struct facet *facet)
static struct facet *
facet_find(struct ofproto_dpif *ofproto, const struct flow *flow)
{
- struct cls_rule *cr = classifier_lookup(&ofproto->facets, flow, NULL);
+ struct cls_rule *cr;
+
+ ovs_rwlock_rdlock(&ofproto->facets.rwlock);
+ cr = classifier_lookup(&ofproto->facets, flow, NULL);
+ ovs_rwlock_unlock(&ofproto->facets.rwlock);
return cr ? CONTAINER_OF(cr, struct facet, cr) : NULL;
}
@@ -4821,6 +4841,7 @@ push_all_stats__(bool run_fast)
struct cls_cursor cursor;
struct facet *facet;
+ ovs_rwlock_rdlock(&ofproto->facets.rwlock);
cls_cursor_init(&cursor, &ofproto->facets, NULL);
CLS_CURSOR_FOR_EACH (facet, cr, &cursor) {
facet_push_stats(facet, false);
@@ -4828,6 +4849,7 @@ push_all_stats__(bool run_fast)
run_fast_rl();
}
}
+ ovs_rwlock_unlock(&ofproto->facets.rwlock);
}
rl = time_msec() + 100;
@@ -5148,14 +5170,18 @@ rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto,
struct flow ofpc_normal_flow = *flow;
ofpc_normal_flow.tp_src = htons(0);
ofpc_normal_flow.tp_dst = htons(0);
+ ovs_rwlock_rdlock(&cls->rwlock);
cls_rule = classifier_lookup(cls, &ofpc_normal_flow, wc);
+ ovs_rwlock_unlock(&cls->rwlock);
} else if (frag && ofproto->up.frag_handling == OFPC_FRAG_DROP) {
cls_rule = &ofproto->drop_frags_rule->up.cr;
if (wc) {
flow_wildcards_init_exact(wc);
}
} else {
+ ovs_rwlock_rdlock(&cls->rwlock);
cls_rule = classifier_lookup(cls, flow, wc);
+ ovs_rwlock_unlock(&cls->rwlock);
}
return rule_dpif_cast(rule_from_cls_rule(cls_rule));
}
@@ -5483,10 +5509,12 @@ send_netflow_active_timeouts(struct ofproto_dpif *ofproto)
struct cls_cursor cursor;
struct facet *facet;
+ ovs_rwlock_rdlock(&ofproto->facets.rwlock);
cls_cursor_init(&cursor, &ofproto->facets, NULL);
CLS_CURSOR_FOR_EACH (facet, cr, &cursor) {
send_active_timeout(ofproto, facet);
}
+ ovs_rwlock_unlock(&ofproto->facets.rwlock);
}
static struct ofproto_dpif *
@@ -5885,12 +5913,14 @@ ofproto_dpif_self_check__(struct ofproto_dpif *ofproto, struct ds *reply)
int errors;
errors = 0;
+ ovs_rwlock_rdlock(&ofproto->facets.rwlock);
cls_cursor_init(&cursor, &ofproto->facets, NULL);
CLS_CURSOR_FOR_EACH (facet, cr, &cursor) {
if (!facet_check_consistency(facet)) {
errors++;
}
}
+ ovs_rwlock_unlock(&ofproto->facets.rwlock);
if (errors) {
ofproto->backer->need_revalidate = REV_INCONSISTENCY;
}
@@ -6111,6 +6141,7 @@ ofproto_unixctl_dpif_dump_megaflows(struct unixctl_conn *conn,
return;
}
+ ovs_rwlock_rdlock(&ofproto->facets.rwlock);
cls_cursor_init(&cursor, &ofproto->facets, NULL);
CLS_CURSOR_FOR_EACH (facet, cr, &cursor) {
cls_rule_format(&facet->cr, &ds);
@@ -6133,6 +6164,7 @@ ofproto_unixctl_dpif_dump_megaflows(struct unixctl_conn *conn,
}
ds_put_cstr(&ds, "\n");
}
+ ovs_rwlock_unlock(&ofproto->facets.rwlock);
ds_chomp(&ds, '\n');
unixctl_command_reply(conn, ds_cstr(&ds));
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index 68f4a80..f081482 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -266,7 +266,8 @@ rule_from_cls_rule(const struct cls_rule *cls_rule)
void ofproto_rule_update_used(struct rule *, long long int used);
void ofproto_rule_expire(struct rule *, uint8_t reason);
-void ofproto_rule_destroy(struct rule *);
+void ofproto_rule_destroy(struct ofproto *, struct classifier *cls,
+ struct rule *) OVS_REQ_WRLOCK(cls->rwlock);
bool ofproto_rule_has_out_port(const struct rule *, ofp_port_t out_port);
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index fad8746..3cdc72c 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -153,6 +153,9 @@ static void oftable_enable_eviction(struct oftable *,
size_t n_fields);
static void oftable_remove_rule(struct rule *);
+static void oftable_remove_rule__(struct ofproto *ofproto,
+ struct classifier *cls, struct rule *rule)
+ OVS_REQ_WRLOCK(cls->rwlock);
static struct rule *oftable_replace_rule(struct rule *);
static void oftable_substitute_rule(struct rule *old, struct rule *new);
@@ -1018,6 +1021,7 @@ ofproto_configure_table(struct ofproto *ofproto, int table_id,
}
table->max_flows = s->max_flows;
+ ovs_rwlock_rdlock(&table->cls.rwlock);
if (classifier_count(&table->cls) > table->max_flows
&& table->eviction_fields) {
/* 'table' contains more flows than allowed. We might not be able to
@@ -1033,6 +1037,7 @@ ofproto_configure_table(struct ofproto *ofproto, int table_id,
break;
}
}
+ ovs_rwlock_unlock(&table->cls.rwlock);
}
bool
@@ -1066,15 +1071,17 @@ ofproto_flush__(struct ofproto *ofproto)
continue;
}
+ ovs_rwlock_wrlock(&table->cls.rwlock);
cls_cursor_init(&cursor, &table->cls, NULL);
CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, cr, &cursor) {
if (!rule->pending) {
ofoperation_create(group, rule, OFOPERATION_DELETE,
OFPRR_DELETE);
- oftable_remove_rule(rule);
+ oftable_remove_rule__(ofproto, &table->cls, rule);
ofproto->ofproto_class->rule_destruct(rule);
}
}
+ ovs_rwlock_unlock(&table->cls.rwlock);
}
ofopgroup_submit(group);
}
@@ -1387,7 +1394,9 @@ ofproto_get_memory_usage(const struct ofproto *ofproto, struct simap *usage)
n_rules = 0;
OFPROTO_FOR_EACH_TABLE (table, ofproto) {
+ ovs_rwlock_rdlock(&table->cls.rwlock);
n_rules += classifier_count(&table->cls);
+ ovs_rwlock_unlock(&table->cls.rwlock);
}
simap_increase(usage, "rules", n_rules);
@@ -1614,8 +1623,10 @@ ofproto_add_flow(struct ofproto *ofproto, const struct match *match,
{
const struct rule *rule;
+ ovs_rwlock_rdlock(&ofproto->tables[0].cls.rwlock);
rule = rule_from_cls_rule(classifier_find_match_exactly(
&ofproto->tables[0].cls, match, priority));
+ ovs_rwlock_unlock(&ofproto->tables[0].cls.rwlock);
if (!rule || !ofpacts_equal(rule->ofpacts, rule->ofpacts_len,
ofpacts, ofpacts_len)) {
struct ofputil_flow_mod fm;
@@ -1652,8 +1663,10 @@ ofproto_delete_flow(struct ofproto *ofproto,
{
struct rule *rule;
+ ovs_rwlock_rdlock(&ofproto->tables[0].cls.rwlock);
rule = rule_from_cls_rule(classifier_find_match_exactly(
&ofproto->tables[0].cls, target, priority));
+ ovs_rwlock_unlock(&ofproto->tables[0].cls.rwlock);
if (!rule) {
/* No such rule -> success. */
return true;
@@ -2181,10 +2194,11 @@ ofproto_rule_destroy__(struct rule *rule)
* This function should only be called from an ofproto implementation's
* ->destruct() function. It is not suitable elsewhere. */
void
-ofproto_rule_destroy(struct rule *rule)
+ofproto_rule_destroy(struct ofproto *ofproto, struct classifier *cls,
+ struct rule *rule) OVS_REQ_WRLOCK(cls->rwlock)
{
ovs_assert(!rule->pending);
- oftable_remove_rule(rule);
+ oftable_remove_rule__(ofproto, cls, rule);
ofproto_rule_destroy__(rule);
}
@@ -2616,7 +2630,9 @@ handle_table_stats_request(struct ofconn *ofconn,
ots[i].instructions = htonl(OFPIT11_ALL);
ots[i].config = htonl(OFPTC11_TABLE_MISS_MASK);
ots[i].max_entries = htonl(1000000); /* An arbitrary big number. */
+ ovs_rwlock_rdlock(&p->tables[i].cls.rwlock);
ots[i].active_count = htonl(classifier_count(&p->tables[i].cls));
+ ovs_rwlock_unlock(&p->tables[i].cls.rwlock);
}
p->ofproto_class->get_tables(p, ots);
@@ -2883,9 +2899,11 @@ collect_rules_loose(struct ofproto *ofproto, uint8_t table_id,
struct cls_cursor cursor;
struct rule *rule;
+ ovs_rwlock_rdlock(&table->cls.rwlock);
cls_cursor_init(&cursor, &table->cls, &cr);
CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
if (rule->pending) {
+ ovs_rwlock_unlock(&table->cls.rwlock);
error = OFPROTO_POSTPONE;
goto exit;
}
@@ -2895,6 +2913,7 @@ collect_rules_loose(struct ofproto *ofproto, uint8_t table_id,
list_push_back(rules, &rule->ofproto_node);
}
}
+ ovs_rwlock_unlock(&table->cls.rwlock);
}
exit:
@@ -2959,8 +2978,10 @@ collect_rules_strict(struct ofproto *ofproto, uint8_t table_id,
FOR_EACH_MATCHING_TABLE (table, table_id, ofproto) {
struct rule *rule;
+ ovs_rwlock_rdlock(&table->cls.rwlock);
rule = rule_from_cls_rule(classifier_find_rule_exactly(&table->cls,
&cr));
+ ovs_rwlock_unlock(&table->cls.rwlock);
if (rule) {
if (rule->pending) {
error = OFPROTO_POSTPONE;
@@ -3080,10 +3101,12 @@ ofproto_get_all_flows(struct ofproto *p, struct ds *results)
struct cls_cursor cursor;
struct rule *rule;
+ ovs_rwlock_rdlock(&table->cls.rwlock);
cls_cursor_init(&cursor, &table->cls, NULL);
CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
flow_stats_ds(rule, results);
}
+ ovs_rwlock_unlock(&table->cls.rwlock);
}
}
@@ -3313,6 +3336,7 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
struct rule *victim;
struct rule *rule;
uint8_t table_id;
+ bool overlaps;
int error;
error = check_table_id(ofproto, fm->table_id);
@@ -3369,8 +3393,10 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
}
/* Check for overlap, if requested. */
- if (fm->flags & OFPFF_CHECK_OVERLAP
- && classifier_rule_overlaps(&table->cls, &rule->cr)) {
+ ovs_rwlock_rdlock(&table->cls.rwlock);
+ overlaps = classifier_rule_overlaps(&table->cls, &rule->cr);
+ ovs_rwlock_unlock(&table->cls.rwlock);
+ if (fm->flags & OFPFF_CHECK_OVERLAP && overlaps) {
cls_rule_destroy(&rule->cr);
ofproto->ofproto_class->rule_dealloc(rule);
return OFPERR_OFPFMFC_OVERLAP;
@@ -3413,8 +3439,12 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
} else {
struct ofoperation *op;
struct rule *evict;
+ size_t n_rules;
- if (classifier_count(&table->cls) > table->max_flows) {
+ ovs_rwlock_rdlock(&table->cls.rwlock);
+ n_rules = classifier_count(&table->cls);
+ ovs_rwlock_unlock(&table->cls.rwlock);
+ if (n_rules > table->max_flows) {
bool was_evictable;
was_evictable = rule->evictable;
@@ -4099,11 +4129,13 @@ ofproto_collect_ofmonitor_refresh_rules(const struct ofmonitor *m,
struct cls_cursor cursor;
struct rule *rule;
+ ovs_rwlock_rdlock(&table->cls.rwlock);
cls_cursor_init(&cursor, &table->cls, &target);
CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
ovs_assert(!rule->pending); /* XXX */
ofproto_collect_ofmonitor_refresh_rule(m, rule, seqno, rules);
}
+ ovs_rwlock_unlock(&table->cls.rwlock);
}
HMAP_FOR_EACH (op, hmap_node, &ofproto->deletions) {
@@ -5085,9 +5117,17 @@ ofproto_evict(struct ofproto *ofproto)
group = ofopgroup_create_unattached(ofproto);
OFPROTO_FOR_EACH_TABLE (table, ofproto) {
- while (classifier_count(&table->cls) > table->max_flows
- && table->eviction_fields) {
+ while (table->eviction_fields) {
struct rule *rule;
+ size_t n_rules;
+
+ ovs_rwlock_rdlock(&table->cls.rwlock);
+ n_rules = classifier_count(&table->cls);
+ ovs_rwlock_unlock(&table->cls.rwlock);
+
+ if (n_rules <= table->max_flows) {
+ break;
+ }
rule = choose_rule_to_evict(table);
if (!rule || rule->pending) {
@@ -5304,7 +5344,9 @@ oftable_init(struct oftable *table)
static void
oftable_destroy(struct oftable *table)
{
+ ovs_rwlock_rdlock(&table->cls.rwlock);
ovs_assert(classifier_is_empty(&table->cls));
+ ovs_rwlock_unlock(&table->cls.rwlock);
oftable_disable_eviction(table);
classifier_destroy(&table->cls);
free(table->name);
@@ -5384,20 +5426,20 @@ oftable_enable_eviction(struct oftable *table,
hmap_init(&table->eviction_groups_by_id);
heap_init(&table->eviction_groups_by_size);
+ ovs_rwlock_rdlock(&table->cls.rwlock);
cls_cursor_init(&cursor, &table->cls, NULL);
CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
eviction_group_add_rule(rule);
}
+ ovs_rwlock_unlock(&table->cls.rwlock);
}
/* Removes 'rule' from the oftable that contains it. */
static void
-oftable_remove_rule(struct rule *rule)
+oftable_remove_rule__(struct ofproto *ofproto, struct classifier *cls,
+ struct rule *rule) OVS_REQ_WRLOCK(cls->rwlock)
{
- struct ofproto *ofproto = rule->ofproto;
- struct oftable *table = &ofproto->tables[rule->table_id];
-
- classifier_remove(&table->cls, &rule->cr);
+ classifier_remove(cls, &rule->cr);
if (rule->meter_id) {
list_remove(&rule->meter_list_node);
}
@@ -5413,6 +5455,17 @@ oftable_remove_rule(struct rule *rule)
}
}
+static void
+oftable_remove_rule(struct rule *rule)
+{
+ struct ofproto *ofproto = rule->ofproto;
+ struct oftable *table = &ofproto->tables[rule->table_id];
+
+ ovs_rwlock_wrlock(&table->cls.rwlock);
+ oftable_remove_rule__(ofproto, &table->cls, rule);
+ ovs_rwlock_unlock(&table->cls.rwlock);
+}
+
/* Inserts 'rule' into its oftable. Removes any existing rule from 'rule''s
* oftable that has an identical cls_rule. Returns the rule that was removed,
* if any, and otherwise NULL. */
@@ -5438,7 +5491,9 @@ oftable_replace_rule(struct rule *rule)
struct meter *meter = ofproto->meters[rule->meter_id];
list_insert(&meter->rules, &rule->meter_list_node);
}
+ ovs_rwlock_wrlock(&table->cls.rwlock);
victim = rule_from_cls_rule(classifier_replace(&table->cls, &rule->cr));
+ ovs_rwlock_unlock(&table->cls.rwlock);
if (victim) {
if (victim->meter_id) {
list_remove(&victim->meter_list_node);
diff --git a/tests/test-classifier.c b/tests/test-classifier.c
index 7fb1447..1d3d2d4 100644
--- a/tests/test-classifier.c
+++ b/tests/test-classifier.c
@@ -396,6 +396,7 @@ get_value(unsigned int *x, unsigned n_values)
static void
compare_classifiers(struct classifier *cls, struct tcls *tcls)
+ OVS_REQ_RDLOCK(cls->rwlock)
{
static const int confidence = 500;
unsigned int i;
@@ -444,17 +445,19 @@ destroy_classifier(struct classifier *cls)
struct test_rule *rule, *next_rule;
struct cls_cursor cursor;
+ ovs_rwlock_wrlock(&cls->rwlock);
cls_cursor_init(&cursor, cls, NULL);
CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, cls_rule, &cursor) {
classifier_remove(cls, &rule->cls_rule);
free_rule(rule);
}
+ ovs_rwlock_unlock(&cls->rwlock);
classifier_destroy(cls);
}
static void
-check_tables(const struct classifier *cls,
- int n_tables, int n_rules, int n_dups)
+check_tables(const struct classifier *cls, int n_tables, int n_rules,
+ int n_dups) OVS_REQ_RDLOCK(cls->rwlock)
{
const struct cls_table *table;
struct test_rule *test_rule;
@@ -610,10 +613,12 @@ test_empty(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
struct tcls tcls;
classifier_init(&cls);
+ ovs_rwlock_rdlock(&cls.rwlock);
tcls_init(&tcls);
assert(classifier_is_empty(&cls));
assert(tcls_is_empty(&tcls));
compare_classifiers(&cls, &tcls);
+ ovs_rwlock_unlock(&cls.rwlock);
classifier_destroy(&cls);
tcls_destroy(&tcls);
}
@@ -640,6 +645,7 @@ test_single_rule(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
hash_bytes(&wc_fields, sizeof wc_fields, 0), 0);
classifier_init(&cls);
+ ovs_rwlock_wrlock(&cls.rwlock);
tcls_init(&tcls);
tcls_rule = tcls_insert(&tcls, rule);
@@ -654,6 +660,7 @@ test_single_rule(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
compare_classifiers(&cls, &tcls);
free_rule(rule);
+ ovs_rwlock_unlock(&cls.rwlock);
classifier_destroy(&cls);
tcls_destroy(&tcls);
}
@@ -677,6 +684,7 @@ test_rule_replacement(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
rule2->aux += 5;
classifier_init(&cls);
+ ovs_rwlock_wrlock(&cls.rwlock);
tcls_init(&tcls);
tcls_insert(&tcls, rule1);
classifier_insert(&cls, &rule1->cls_rule);
@@ -692,6 +700,7 @@ test_rule_replacement(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
check_tables(&cls, 1, 1, 0);
compare_classifiers(&cls, &tcls);
tcls_destroy(&tcls);
+ ovs_rwlock_unlock(&cls.rwlock);
destroy_classifier(&cls);
}
}
@@ -787,6 +796,7 @@ test_many_rules_in_one_list (int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
}
classifier_init(&cls);
+ ovs_rwlock_wrlock(&cls.rwlock);
tcls_init(&tcls);
for (i = 0; i < ARRAY_SIZE(ops); i++) {
@@ -825,6 +835,7 @@ test_many_rules_in_one_list (int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
compare_classifiers(&cls, &tcls);
}
+ ovs_rwlock_unlock(&cls.rwlock);
classifier_destroy(&cls);
tcls_destroy(&tcls);
@@ -887,6 +898,7 @@ test_many_rules_in_one_table(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
} while ((1 << count_ones(value_mask)) < N_RULES);
classifier_init(&cls);
+ ovs_rwlock_wrlock(&cls.rwlock);
tcls_init(&tcls);
for (i = 0; i < N_RULES; i++) {
@@ -913,6 +925,7 @@ test_many_rules_in_one_table(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
compare_classifiers(&cls, &tcls);
}
+ ovs_rwlock_unlock(&cls.rwlock);
classifier_destroy(&cls);
tcls_destroy(&tcls);
}
@@ -947,6 +960,7 @@ test_many_rules_in_n_tables(int n_tables)
shuffle(priorities, ARRAY_SIZE(priorities));
classifier_init(&cls);
+ ovs_rwlock_wrlock(&cls.rwlock);
tcls_init(&tcls);
for (i = 0; i < MAX_RULES; i++) {
@@ -979,6 +993,7 @@ test_many_rules_in_n_tables(int n_tables)
free_rule(target);
}
+ ovs_rwlock_unlock(&cls.rwlock);
destroy_classifier(&cls);
tcls_destroy(&tcls);
}
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index 35a2ca7..899ce4e 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -1941,11 +1941,13 @@ fte_free_all(struct classifier *cls)
struct cls_cursor cursor;
struct fte *fte, *next;
+ ovs_rwlock_wrlock(&cls->rwlock);
cls_cursor_init(&cursor, cls, NULL);
CLS_CURSOR_FOR_EACH_SAFE (fte, next, rule, &cursor) {
classifier_remove(cls, &fte->rule);
fte_free(fte);
}
+ ovs_rwlock_unlock(&cls->rwlock);
classifier_destroy(cls);
}
@@ -1964,7 +1966,9 @@ fte_insert(struct classifier *cls, const struct match *match,
cls_rule_init(&fte->rule, match, priority);
fte->versions[index] = version;
+ ovs_rwlock_wrlock(&cls->rwlock);
old = fte_from_cls_rule(classifier_replace(cls, &fte->rule));
+ ovs_rwlock_unlock(&cls->rwlock);
if (old) {
fte_version_free(old->versions[index]);
fte->versions[!index] = old->versions[!index];
@@ -2174,6 +2178,7 @@ ofctl_replace_flows(int argc OVS_UNUSED, char *argv[])
list_init(&requests);
/* Delete flows that exist on the switch but not in the file. */
+ ovs_rwlock_rdlock(&cls.rwlock);
cls_cursor_init(&cursor, &cls, NULL);
CLS_CURSOR_FOR_EACH (fte, rule, &cursor) {
struct fte_version *file_ver = fte->versions[FILE_IDX];
@@ -2197,6 +2202,7 @@ ofctl_replace_flows(int argc OVS_UNUSED, char *argv[])
fte_make_flow_mod(fte, FILE_IDX, OFPFC_ADD, protocol, &requests);
}
}
+ ovs_rwlock_unlock(&cls.rwlock);
transact_multiple_noreply(vconn, &requests);
vconn_close(vconn);
@@ -2238,6 +2244,7 @@ ofctl_diff_flows(int argc OVS_UNUSED, char *argv[])
ds_init(&a_s);
ds_init(&b_s);
+ ovs_rwlock_rdlock(&cls.rwlock);
cls_cursor_init(&cursor, &cls, NULL);
CLS_CURSOR_FOR_EACH (fte, rule, &cursor) {
struct fte_version *a = fte->versions[0];
@@ -2257,6 +2264,7 @@ ofctl_diff_flows(int argc OVS_UNUSED, char *argv[])
}
}
}
+ ovs_rwlock_unlock(&cls.rwlock);
ds_destroy(&a_s);
ds_destroy(&b_s);
--
1.7.9.5
More information about the dev
mailing list