34
34
static void destroy_table(struct classifier *, struct cls_table *);
36
static void update_tables_after_insertion(struct classifier *,
38
unsigned int new_priority);
39
static void update_tables_after_removal(struct classifier *,
41
unsigned int del_priority);
36
43
static struct cls_rule *find_match(const struct cls_table *,
37
44
const struct flow *);
38
45
static struct cls_rule *find_equal(struct cls_table *,
39
46
const struct miniflow *, uint32_t hash);
40
static struct cls_rule *insert_rule(struct cls_table *, struct cls_rule *);
47
static struct cls_rule *insert_rule(struct classifier *,
48
struct cls_table *, struct cls_rule *);
42
50
/* Iterates RULE over HEAD and all of the cls_rules on HEAD->list. */
43
51
#define FOR_EACH_RULE_IN_LIST(RULE, HEAD) \
236
245
if (--table->n_table_rules == 0) {
237
246
destroy_table(cls, table);
248
update_tables_after_removal(cls, table, rule->priority);
243
253
/* Finds and returns the highest-priority rule in 'cls' that matches 'flow'.
244
254
* Returns a null pointer if no rules in 'cls' match 'flow'. If multiple rules
245
* of equal priority match 'flow', returns one arbitrarily. */
255
* of equal priority match 'flow', returns one arbitrarily.
257
* If a rule is found and 'wc' is non-null, bitwise-OR's 'wc' with the
258
* set of bits that were significant in the lookup. At some point
259
* earlier, 'wc' should have been initialized (e.g., by
260
* flow_wildcards_init_catchall()). */
246
261
struct cls_rule *
247
classifier_lookup(const struct classifier *cls, const struct flow *flow)
262
classifier_lookup(const struct classifier *cls, const struct flow *flow,
263
struct flow_wildcards *wc)
249
265
struct cls_table *table;
250
266
struct cls_rule *best;
253
HMAP_FOR_EACH (table, hmap_node, &cls->tables) {
269
LIST_FOR_EACH (table, list_node, &cls->tables_priority) {
254
270
struct cls_rule *rule = find_match(table, flow);
255
if (rule && (!best || rule->priority > best->priority)) {
273
flow_wildcards_fold_minimask(wc, &table->mask);
277
LIST_FOR_EACH_CONTINUE (table, list_node, &cls->tables_priority) {
278
if (table->max_priority <= best->priority) {
279
/* Tables in descending priority order,
280
* can not find anything better. */
283
rule = find_match(table, flow);
285
flow_wildcards_fold_minimask(wc, &table->mask);
287
if (rule && rule->priority > best->priority) {
313
353
struct cls_table *table;
315
HMAP_FOR_EACH (table, hmap_node, &cls->tables) {
355
/* Iterate tables in the descending max priority order. */
356
LIST_FOR_EACH (table, list_node, &cls->tables_priority) {
316
357
uint32_t storage[FLOW_U32S];
317
358
struct minimask mask;
318
359
struct cls_rule *head;
361
if (target->priority > table->max_priority) {
362
break; /* Can skip this and the rest of the tables. */
320
365
minimask_combine(&mask, &target->match.mask, &table->mask, storage);
321
366
HMAP_FOR_EACH (head, hmap_node, &table->rules) {
322
367
struct cls_rule *rule;
324
369
FOR_EACH_RULE_IN_LIST (rule, head) {
370
if (rule->priority < target->priority) {
371
break; /* Rules in descending priority order. */
325
373
if (rule->priority == target->priority
326
374
&& miniflow_equal_in_minimask(&target->match.flow,
327
375
&rule->match.flow, &mask)) {
504
553
minimask_destroy(&table->mask);
505
554
hmap_remove(&cls->tables, &table->hmap_node);
506
555
hmap_destroy(&table->rules);
556
list_remove(&table->list_node);
560
/* This function performs the following updates for 'table' in 'cls' following
561
* the addition of a new rule with priority 'new_priority' to 'table':
563
* - Update 'table->max_priority' and 'table->max_count' if necessary.
565
* - Update 'table''s position in 'cls->tables_priority' if necessary.
567
* This function should only be called after adding a new rule, not after
568
* replacing a rule by an identical one or modifying a rule in-place. */
570
update_tables_after_insertion(struct classifier *cls, struct cls_table *table,
571
unsigned int new_priority)
573
if (new_priority == table->max_priority) {
575
} else if (new_priority > table->max_priority) {
576
struct cls_table *iter;
578
table->max_priority = new_priority;
579
table->max_count = 1;
581
/* Possibly move 'table' earlier in the priority list. If we break out
582
* of the loop, then 'table' should be moved just after that 'iter'.
583
* If the loop terminates normally, then 'iter' will be the list head
584
* and we'll move table just after that (e.g. to the front of the
587
LIST_FOR_EACH_REVERSE_CONTINUE (iter, list_node,
588
&cls->tables_priority) {
589
if (iter->max_priority >= table->max_priority) {
594
/* Move 'table' just after 'iter' (unless it's already there). */
595
if (iter->list_node.next != &table->list_node) {
596
list_splice(iter->list_node.next,
597
&table->list_node, table->list_node.next);
602
/* This function performs the following updates for 'table' in 'cls' following
603
* the deletion of a rule with priority 'del_priority' from 'table':
605
* - Update 'table->max_priority' and 'table->max_count' if necessary.
607
* - Update 'table''s position in 'cls->tables_priority' if necessary.
609
* This function should only be called after removing a rule, not after
610
* replacing a rule by an identical one or modifying a rule in-place. */
612
update_tables_after_removal(struct classifier *cls, struct cls_table *table,
613
unsigned int del_priority)
615
struct cls_table *iter;
617
if (del_priority == table->max_priority && --table->max_count == 0) {
618
struct cls_rule *head;
620
table->max_priority = 0;
621
HMAP_FOR_EACH (head, hmap_node, &table->rules) {
622
if (head->priority > table->max_priority) {
623
table->max_priority = head->priority;
624
table->max_count = 1;
625
} else if (head->priority == table->max_priority) {
630
/* Possibly move 'table' later in the priority list. If we break out
631
* of the loop, then 'table' should be moved just before that 'iter'.
632
* If the loop terminates normally, then 'iter' will be the list head
633
* and we'll move table just before that (e.g. to the back of the
636
LIST_FOR_EACH_CONTINUE (iter, list_node, &cls->tables_priority) {
637
if (iter->max_priority <= table->max_priority) {
642
/* Move 'table' just before 'iter' (unless it's already there). */
643
if (iter->list_node.prev != &table->list_node) {
644
list_splice(&iter->list_node,
645
&table->list_node, table->list_node.next);
510
650
static struct cls_rule *
511
651
find_match(const struct cls_table *table, const struct flow *flow)