- * 'callback' is allowed to delete the rule that is passed as its argument, but
- * it must not delete (or move) any other rules in 'cls' that are in the same
- * table as the argument rule. Two rules are in the same table if their
- * cls_rule structs have the same table_idx; as a special case, a rule with
- * wildcards and an exact-match rule will never be in the same table. */
-void
-classifier_for_each_match(const struct classifier *cls,
- const struct cls_rule *target,
- int include, cls_cb_func *callback, void *aux)
-{
- if (include & CLS_INC_WILD) {
- const struct hmap *table;
-
- for (table = &cls->tables[0]; table < &cls->tables[CLS_N_FIELDS];
- table++) {
- struct cls_bucket *bucket, *next_bucket;
-
- HMAP_FOR_EACH_SAFE (bucket, next_bucket, hmap_node, table) {
- /* XXX there is a bit of room for optimization here based on
- * rejecting entire buckets on their fixed fields, but it will
- * only be worthwhile for big buckets (which we hope we won't
- * get anyway, but...) */
- struct cls_rule *prev_rule, *rule;
-
- /* We can't just use LIST_FOR_EACH_SAFE here because, if the
- * callback deletes the last rule in the bucket, then the
- * bucket itself will be destroyed. The bucket contains the
- * list head so that's a use-after-free error. */
- prev_rule = NULL;
- LIST_FOR_EACH (rule, node.list, &bucket->rules) {
- if (rules_match_1wild(rule, target, 0)) {
- if (prev_rule) {
- callback(prev_rule, aux);
- }
- prev_rule = rule;
- }
- }
- if (prev_rule) {
- callback(prev_rule, aux);
- }
- }
- }
- }
-
- if (include & CLS_INC_EXACT) {
- if (target->wc.wildcards) {
- struct cls_rule *rule, *next_rule;
-
- HMAP_FOR_EACH_SAFE (rule, next_rule, node.hmap,
- &cls->exact_table) {
- if (rules_match_1wild(rule, target, 0)) {
- callback(rule, aux);
- }
- }
- } else {
- /* Optimization: there can be at most one match in the exact
- * table. */
- size_t hash = flow_hash(&target->flow, 0);
- struct cls_rule *rule = search_exact_table(cls, hash,
- &target->flow);
- if (rule) {
- callback(rule, aux);
- }
- }
- }
-}
-
-/* 'callback' is allowed to delete the rule that is passed as its argument, but
- * it must not delete (or move) any other rules in 'cls' that are in the same
- * table as the argument rule. Two rules are in the same table if their
- * cls_rule structs have the same table_idx; as a special case, a rule with
- * wildcards and an exact-match rule will never be in the same table. */
-void
-classifier_for_each(const struct classifier *cls, int include,
- void (*callback)(struct cls_rule *, void *aux),
- void *aux)
-{
- if (include & CLS_INC_WILD) {
- const struct hmap *tbl;
-
- for (tbl = &cls->tables[0]; tbl < &cls->tables[CLS_N_FIELDS]; tbl++) {
- struct cls_bucket *bucket, *next_bucket;
-
- HMAP_FOR_EACH_SAFE (bucket, next_bucket, hmap_node, tbl) {
- struct cls_rule *prev_rule, *rule;
-
- /* We can't just use LIST_FOR_EACH_SAFE here because, if the
- * callback deletes the last rule in the bucket, then the
- * bucket itself will be destroyed. The bucket contains the
- * list head so that's a use-after-free error. */
- prev_rule = NULL;
- LIST_FOR_EACH (rule, node.list, &bucket->rules) {
- if (prev_rule) {
- callback(prev_rule, aux);
- }
- prev_rule = rule;
- }
- if (prev_rule) {
- callback(prev_rule, aux);
- }
- }
- }
- }
-
- if (include & CLS_INC_EXACT) {
- struct cls_rule *rule, *next_rule;
-
- HMAP_FOR_EACH_SAFE (rule, next_rule, node.hmap, &cls->exact_table) {
- callback(rule, aux);
- }
- }
+ * - 'criteria' and 'rule' specify the same (non-wildcarded) value for the
+ * field, or
+ *
+ * - 'criteria' wildcards the field,
+ *
+ * Conversely, 'rule' does not match 'criteria' and this function returns false
+ * if, for at least one field:
+ *
+ * - 'criteria' and 'rule' specify different values for the field, or
+ *
+ * - 'criteria' specifies a value for the field but 'rule' wildcards it.
+ *
+ * Equivalently, the truth table for whether a field matches is:
+ *
+ * rule
+ *
+ * c wildcard exact
+ * r +---------+---------+
+ * i wild | yes | yes |
+ * t card | | |
+ * e +---------+---------+
+ * r exact | no |if values|
+ * i | |are equal|
+ * a +---------+---------+
+ *
+ * This is the matching rule used by OpenFlow 1.0 non-strict OFPT_FLOW_MOD
+ * commands and by OpenFlow 1.0 aggregate and flow stats.
+ *
+ * Ignores rule->priority. */
+bool
+cls_rule_is_loose_match(const struct cls_rule *rule,
+ const struct minimatch *criteria)
+{
+ return (!minimask_has_extra(&rule->match.mask, &criteria->mask)
+ && miniflow_equal_in_minimask(&rule->match.flow, &criteria->flow,
+ &criteria->mask));