X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fclassifier.c;h=591322e7748fc5598c2ae82ab882b2b5fe0d3cba;hb=80642190644ae6fbcf485924b1c59e67d0be8a87;hp=6be47f8af110467e02aab44e1e455e102203080c;hpb=cd10ed7fb4fb5b1e3ed8e3fae1fd115c7ae96e77;p=openvswitch diff --git a/lib/classifier.c b/lib/classifier.c index 6be47f8a..591322e7 100644 --- a/lib/classifier.c +++ b/lib/classifier.c @@ -423,7 +423,7 @@ classifier_remove(struct classifier *cls, struct cls_rule *rule) hmap_replace(&table->rules, &rule->hmap_node, &next->hmap_node); } - if (--table->n_table_rules == 0 && !table->n_refs) { + if (--table->n_table_rules == 0) { destroy_table(cls, table); } @@ -507,10 +507,34 @@ classifier_rule_overlaps(const struct classifier *cls, return false; } + +/* Iteration. */ + +static bool +rule_matches(const struct cls_rule *rule, const struct cls_rule *target) +{ + return (!target + || flow_equal_except(&rule->flow, &target->flow, &target->wc)); +} + +static struct cls_rule * +search_table(const struct cls_table *table, const struct cls_rule *target) +{ + if (!target || !flow_wildcards_has_extra(&table->wc, &target->wc)) { + struct cls_rule *rule; + + HMAP_FOR_EACH (rule, hmap_node, &table->rules) { + if (rule_matches(rule, target)) { + return rule; + } + } + } + return NULL; +} -/* Searches 'cls' for rules that exactly match 'target' or are more specific - * than 'target'. That is, a given 'rule' matches 'target' if, for every - * field: +/* Initializes 'cursor' for iterating through 'cls' rules that exactly match + * 'target' or are more specific than 'target'. That is, a given 'rule' + * matches 'target' if, for every field: * * - 'target' and 'rule' specify the same (non-wildcarded) value for the * field, or @@ -541,72 +565,63 @@ classifier_rule_overlaps(const struct classifier *cls, * * Ignores target->priority. * - * '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 have the same - * wildcards as the argument rule. */ + * 'target' may be NULL to iterate over every rule in 'cls'. */ void -classifier_for_each_match(const struct classifier *cls_, - const struct cls_rule *target, - cls_cb_func *callback, void *aux) -{ - struct classifier *cls = (struct classifier *) cls_; - struct cls_table *table, *next_table; - - for (table = classifier_first_table(cls); table; table = next_table) { - if (!flow_wildcards_has_extra(&table->wc, &target->wc)) { - /* We have eliminated the "no" case in the truth table above. Two - * of the three remaining cases are trivial. We only need to check - * the fourth case, where both 'rule' and 'target' require an exact - * match. */ - struct cls_rule *head, *next_head; - - table->n_refs++; - HMAP_FOR_EACH_SAFE (head, next_head, hmap_node, &table->rules) { - if (flow_equal_except(&head->flow, &target->flow, - &target->wc)) { - struct cls_rule *rule, *next_rule; - - FOR_EACH_RULE_IN_LIST_SAFE (rule, next_rule, head) { - callback(rule, aux); - } - } - } - next_table = classifier_next_table(cls, table); - if (!--table->n_refs && !table->n_table_rules) { - destroy_table(cls, table); - } - } else { - next_table = classifier_next_table(cls, table); +cls_cursor_init(struct cls_cursor *cursor, const struct classifier *cls, + const struct cls_rule *target) +{ + cursor->cls = cls; + cursor->target = target; +} + +/* Returns the first matching cls_rule in 'cursor''s iteration, or a null + * pointer if there are no matches. */ +struct cls_rule * +cls_cursor_first(struct cls_cursor *cursor) +{ + struct cls_table *table; + + for (table = classifier_first_table(cursor->cls); table; + table = classifier_next_table(cursor->cls, table)) { + struct cls_rule *rule = search_table(table, cursor->target); + if (rule) { + cursor->table = table; + return rule; } } + + return NULL; } -/* '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 have the same - * wildcards as the argument rule. */ -void -classifier_for_each(const struct classifier *cls_, - cls_cb_func *callback, void *aux) +/* Returns the next matching cls_rule in 'cursor''s iteration, or a null + * pointer if there are no more matches. */ +struct cls_rule * +cls_cursor_next(struct cls_cursor *cursor, struct cls_rule *rule) { - struct classifier *cls = (struct classifier *) cls_; - struct cls_table *table, *next_table; - - for (table = classifier_first_table(cls); table; table = next_table) { - struct cls_rule *head, *next_head; + const struct cls_table *table; + struct cls_rule *next; - table->n_refs++; - HMAP_FOR_EACH_SAFE (head, next_head, hmap_node, &table->rules) { - struct cls_rule *rule, *next_rule; + next = next_rule_in_list(rule); + if (next) { + return next; + } - FOR_EACH_RULE_IN_LIST_SAFE (rule, next_rule, head) { - callback(rule, aux); - } + HMAP_FOR_EACH_CONTINUE (rule, hmap_node, &cursor->table->rules) { + if (rule_matches(rule, cursor->target)) { + return rule; } - next_table = classifier_next_table(cls, table); - if (!--table->n_refs && !table->n_table_rules) { - destroy_table(cls, table); + } + + for (table = classifier_next_table(cursor->cls, cursor->table); table; + table = classifier_next_table(cursor->cls, table)) { + rule = search_table(table, cursor->target); + if (rule) { + cursor->table = table; + return rule; } } + + return NULL; } static struct cls_table *