* rule, even rules that cannot have any effect because the new rule matches a
* superset of their flows and has higher priority. */
struct cls_rule *
-classifier_insert(struct classifier *cls, struct cls_rule *rule)
+classifier_replace(struct classifier *cls, struct cls_rule *rule)
{
struct cls_rule *old_rule;
struct cls_table *table;
return old_rule;
}
+/* Inserts 'rule' into 'cls'. Until 'rule' is removed from 'cls', the caller
+ * must not modify or free it.
+ *
+ * 'cls' must not contain an identical rule (including wildcards, values of
+ * fixed fields, and priority). Use classifier_find_rule_exactly() to find
+ * such a rule. */
+void
+classifier_insert(struct classifier *cls, struct cls_rule *rule)
+{
+ struct cls_rule *displaced_rule = classifier_replace(cls, rule);
+ assert(!displaced_rule);
+}
+
/* Removes 'rule' from 'cls'. It is the caller's responsibility to free
* 'rule', if this is desirable. */
void
void classifier_destroy(struct classifier *);
bool classifier_is_empty(const struct classifier *);
int classifier_count(const struct classifier *);
-struct cls_rule *classifier_insert(struct classifier *, struct cls_rule *);
+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 *,
const struct flow *);
{
struct rule_dpif *rule = rule_dpif_cast(rule_);
struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
- struct cls_rule *displaced_rule;
+ struct rule_dpif *old_rule;
int error;
error = validate_actions(rule->up.actions, rule->up.n_actions,
return error;
}
+ old_rule = rule_dpif_cast(rule_from_cls_rule(classifier_find_rule_exactly(
+ &ofproto->up.cls,
+ &rule->up.cr)));
+ if (old_rule) {
+ ofproto_rule_destroy(&old_rule->up);
+ }
+
rule->used = rule->up.created;
rule->packet_count = 0;
rule->byte_count = 0;
list_init(&rule->facets);
+ classifier_insert(&ofproto->up.cls, &rule->up.cr);
- displaced_rule = classifier_insert(&ofproto->up.cls, &rule->up.cr);
- if (displaced_rule) {
- ofproto_rule_destroy(rule_from_cls_rule(displaced_rule));
- }
ofproto->need_revalidate = true;
return 0;
struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
struct facet *facet, *next_facet;
- ofproto->need_revalidate = true;
+ classifier_remove(&ofproto->up.cls, &rule->up.cr);
LIST_FOR_EACH_SAFE (facet, next_facet, list_node, &rule->facets) {
facet_revalidate(ofproto, facet);
}
-}
-
-static void
-rule_remove(struct rule *rule_)
-{
- struct rule_dpif *rule = rule_dpif_cast(rule_);
- struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
-
ofproto->need_revalidate = true;
- classifier_remove(&ofproto->up.cls, &rule->up.cr);
}
static void
rule_construct,
rule_destruct,
rule_dealloc,
- rule_remove,
rule_get_stats,
rule_execute,
rule_modify_actions,
static void ofproto_rule_destroy__(struct rule *);
static void ofproto_rule_send_removed(struct rule *, uint8_t reason);
-static void ofproto_rule_remove(struct rule *);
static void handle_openflow(struct ofconn *, struct ofpbuf *);
rule = rule_from_cls_rule(classifier_find_rule_exactly(&ofproto->cls,
target));
- if (rule) {
- ofproto_rule_remove(rule);
- }
+ ofproto_rule_destroy(rule);
}
static void
cls_cursor_init(&cursor, &ofproto->cls, NULL);
CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, cr, &cursor) {
- ofproto_rule_remove(rule);
+ ofproto_rule_destroy(rule);
}
}
rule->ofproto->ofproto_class->rule_dealloc(rule);
}
-/* Destroys 'rule' and removes it from the datapath.
- *
- * The caller must have already removed 'rule' from the classifier. */
+/* Destroys 'rule' and removes it from the flow table and the datapath. */
void
ofproto_rule_destroy(struct rule *rule)
{
- rule->ofproto->ofproto_class->rule_destruct(rule);
- ofproto_rule_destroy__(rule);
+ if (rule) {
+ rule->ofproto->ofproto_class->rule_destruct(rule);
+ ofproto_rule_destroy__(rule);
+ }
}
/* Returns true if 'rule' has an OpenFlow OFPAT_OUTPUT or OFPAT_ENQUEUE action
return rule->ofproto->ofproto_class->rule_execute(rule, &flow, packet);
}
-/* Removes 'rule' from 'ofproto' and frees up the associated memory. Removes
- * 'rule' from the classifier. */
-void
-ofproto_rule_remove(struct rule *rule)
-{
- rule->ofproto->ofproto_class->rule_remove(rule);
- ofproto_rule_destroy(rule);
-}
-
/* Returns true if 'rule' should be hidden from the controller.
*
* Rules with priority higher than UINT16_MAX are set up by ofproto itself
}
ofproto_rule_send_removed(rule, OFPRR_DELETE);
- ofproto_rule_remove(rule);
+ ofproto_rule_destroy(rule);
}
static void
{
assert(reason == OFPRR_HARD_TIMEOUT || reason == OFPRR_IDLE_TIMEOUT);
ofproto_rule_send_removed(rule, reason);
- ofproto_rule_remove(rule);
+ ofproto_rule_destroy(rule);
}
\f
static int
* flow table:
*
* - If there was already a rule with exactly the same matching criteria
- * and priority in the classifier, then it should remove that rule from
- * the classifier and destroy it (with ofproto_rule_destroy()).
+ * and priority in the classifier, then it should destroy it (with
+ * ofproto_rule_destroy()).
+ *
+ * To the greatest extent possible, the old rule should be destroyed
+ * only if inserting the new rule succeeds; that is, ->rule_construct()
+ * should be transactional.
+ *
+ * The function classifier_find_rule_exactly() can locate such a rule.
*
* - Insert the new rule into the ofproto's 'cls' classifier, and into
* the datapath flow table.
*
- * (The function classifier_insert() both inserts a rule into the
- * classifier and removes any rule with identical matching criteria, so
- * this single call implements parts of both steps above.)
+ * The function classifier_insert() inserts a rule into the classifier.
*
* Other than inserting 'rule->cr' into the classifier, ->rule_construct()
* should not modify any base members of struct rule.
*
- * When ->rule_destruct() is called, 'rule' has already been removed from
- * the classifier and the datapath flow table (by calling ->rule_remove()),
- * so ->rule_destruct() should not duplicate that behavior. */
+ * ->rule_destruct() should remove 'rule' from the ofproto's 'cls'
+ * classifier (e.g. with classifier_remove()) and from the datapath flow
+ * table. */
struct rule *(*rule_alloc)(void);
int (*rule_construct)(struct rule *rule);
void (*rule_destruct)(struct rule *rule);
void (*rule_dealloc)(struct rule *rule);
- /* Removes 'rule' from 'rule->ofproto->cls' and from the datapath.
- *
- * 'rule' will be destructed, with ->rule_destruct(), soon after. */
- void (*rule_remove)(struct rule *rule);
-
/* Obtains statistics for 'rule', storing the number of packets that have
* matched it in '*packet_count' and the number of bytes in those packets
* in '*byte_count'. */
tcls_init(&tcls);
tcls_rule = tcls_insert(&tcls, rule);
- assert(!classifier_insert(&cls, &rule->cls_rule));
+ classifier_insert(&cls, &rule->cls_rule);
check_tables(&cls, 1, 1, 0);
compare_classifiers(&cls, &tcls);
classifier_init(&cls);
tcls_init(&tcls);
tcls_insert(&tcls, rule1);
- assert(!classifier_insert(&cls, &rule1->cls_rule));
+ classifier_insert(&cls, &rule1->cls_rule);
check_tables(&cls, 1, 1, 0);
compare_classifiers(&cls, &tcls);
tcls_destroy(&tcls);
tcls_init(&tcls);
tcls_insert(&tcls, rule2);
assert(test_rule_from_cls_rule(
- classifier_insert(&cls, &rule2->cls_rule)) == rule1);
+ classifier_replace(&cls, &rule2->cls_rule)) == rule1);
free(rule1);
check_tables(&cls, 1, 1, 0);
compare_classifiers(&cls, &tcls);
tcls_rules[j] = tcls_insert(&tcls, rules[j]);
displaced_rule = test_rule_from_cls_rule(
- classifier_insert(&cls, &rules[j]->cls_rule));
+ classifier_replace(&cls, &rules[j]->cls_rule));
if (pri_rules[pris[j]] >= 0) {
int k = pri_rules[pris[j]];
assert(displaced_rule != NULL);
rules[i] = make_rule(wcf, priority, value_pats[i]);
tcls_rules[i] = tcls_insert(&tcls, rules[i]);
- assert(!classifier_insert(&cls, &rules[i]->cls_rule));
+ classifier_insert(&cls, &rules[i]->cls_rule);
check_tables(&cls, 1, i + 1, 0);
compare_classifiers(&cls, &tcls);
int value_pat = rand() & ((1u << CLS_N_FIELDS) - 1);
rule = make_rule(wcf, priority, value_pat);
tcls_insert(&tcls, rule);
- assert(!classifier_insert(&cls, &rule->cls_rule));
+ classifier_insert(&cls, &rule->cls_rule);
check_tables(&cls, -1, i + 1, -1);
compare_classifiers(&cls, &tcls);
}
fte->rule = *rule;
fte->versions[index] = version;
- old = fte_from_cls_rule(classifier_insert(cls, &fte->rule));
+ old = fte_from_cls_rule(classifier_replace(cls, &fte->rule));
if (old) {
fte_version_free(old->versions[index]);
fte->versions[!index] = old->versions[!index];