}
}
+/* '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 will be visited
+ * by this call to classifier_for_each(). (It must not even delete rules that
+ * would fall into other tables, e.g. exact-match rules if the argument rule
+ * has wildcards.) */
void
-classifier_for_each(const struct classifier *cls,
+classifier_for_each(const struct classifier *cls, int include,
void (*callback)(struct cls_rule *, void *aux),
void *aux)
{
- struct cls_bucket *bucket, *next_bucket;
struct cls_rule *prev_rule, *rule, *next_rule;
const struct hmap *tbl;
prev_rule = NULL;
- for (tbl = &cls->tables[0]; tbl < &cls->tables[CLS_N_FIELDS]; tbl++) {
- HMAP_FOR_EACH_SAFE (bucket, next_bucket,
- struct cls_bucket, hmap_node, tbl) {
- LIST_FOR_EACH (rule, struct cls_rule, node.list, &bucket->rules) {
- if (prev_rule) {
- callback(prev_rule, aux);
+ if (include & CLS_INC_WILD) {
+ struct cls_bucket *bucket, *next_bucket;
+ for (tbl = &cls->tables[0]; tbl < &cls->tables[CLS_N_FIELDS]; tbl++) {
+ HMAP_FOR_EACH_SAFE (bucket, next_bucket,
+ struct cls_bucket, hmap_node, tbl) {
+ LIST_FOR_EACH (rule, struct cls_rule, node.list,
+ &bucket->rules) {
+ if (prev_rule) {
+ callback(prev_rule, aux);
+ }
+ prev_rule = rule;
}
- prev_rule = rule;
}
}
}
- HMAP_FOR_EACH_SAFE (rule, next_rule,
- struct cls_rule, node.hmap, &cls->exact_table) {
- if (prev_rule) {
- callback(prev_rule, aux);
+ if (include & CLS_INC_EXACT) {
+ HMAP_FOR_EACH_SAFE (rule, next_rule,
+ struct cls_rule, node.hmap, &cls->exact_table) {
+ if (prev_rule) {
+ callback(prev_rule, aux);
+ }
+ prev_rule = rule;
}
- prev_rule = rule;
}
if (prev_rule) {
callback(prev_rule, aux);
const flow_t *);
typedef void cls_cb_func(struct cls_rule *, void *aux);
-void classifier_for_each(const struct classifier *, cls_cb_func *, void *aux);
-void classifier_for_each_with_wildcards(const struct classifier *,
- uint32_t wildcards,
- cls_cb_func *, void *aux);
enum {
CLS_INC_EXACT = 1 << 0, /* Include exact-match flows? */
CLS_INC_WILD = 1 << 1 /* Include flows with wildcards? */
};
+void classifier_for_each(const struct classifier *, int include,
+ cls_cb_func *, void *aux);
+void classifier_for_each_with_wildcards(const struct classifier *,
+ uint32_t wildcards,
+ cls_cb_func *, void *aux);
+
void classifier_for_each_match(const struct classifier *,
const struct cls_rule *,
int include, cls_cb_func *, void *aux);
if (time_msec() >= p->next_expiration) {
p->next_expiration = time_msec() + 1000;
update_used(p);
- classifier_for_each(&p->cls, expire_rule, p);
+
+ /* This is broken into two calls to classifier_for_each() due to that
+ * function's requirement that the callback not delete any rules that
+ * will be visited, other than the callback's argument. In particular,
+ * calling expire_rule() on a rule with wildcards can delete an
+ * arbitrary number of exact-match rules. */
+ classifier_for_each(&p->cls, CLS_INC_WILD, expire_rule, p);
+ classifier_for_each(&p->cls, CLS_INC_EXACT, expire_rule, p);
}
if (p->need_revalidate) {
- classifier_for_each_with_wildcards(&p->cls, 0, revalidate_subrule_cb,
- p);
+ classifier_for_each(&p->cls, CLS_INC_EXACT, revalidate_subrule_cb, p);
p->need_revalidate = false;
}
}