wdp-xflow: Remove wx structure from global list when closing.
[sliver-openvswitch.git] / tests / test-classifier.c
1 /*
2  * Copyright (c) 2009, 2010 Nicira Networks.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /* "White box" tests for classifier.
18  *
19  * With very few exceptions, these tests obtain complete coverage of every
20  * basic block and every branch in the classifier implementation, e.g. a clean
21  * report from "gcov -b".  (Covering the exceptions would require finding
22  * collisions in the hash function used for flow data, etc.)
23  *
24  * This test should receive a clean report from "valgrind --leak-check=full":
25  * it frees every heap block that it allocates.
26  */
27
28 #include <config.h>
29 #include "classifier.h"
30 #include <errno.h>
31 #include <limits.h>
32 #include "command-line.h"
33 #include "flow.h"
34 #include "packets.h"
35 #include "test-command-line.h"
36
37 #undef NDEBUG
38 #include <assert.h>
39
40 struct test_rule {
41     int aux;                    /* Auxiliary data. */
42     struct cls_rule cls_rule;   /* Classifier rule data. */
43 };
44
45 static struct test_rule *
46 test_rule_from_cls_rule(const struct cls_rule *rule)
47 {
48     return rule ? CONTAINER_OF(rule, struct test_rule, cls_rule) : NULL;
49 }
50
51 /* Trivial (linear) classifier. */
52 struct tcls {
53     size_t n_rules;
54     size_t allocated_rules;
55     struct test_rule **rules;
56 };
57
58 static void
59 tcls_init(struct tcls *tcls)
60 {
61     tcls->n_rules = 0;
62     tcls->allocated_rules = 0;
63     tcls->rules = NULL;
64 }
65
66 static void
67 tcls_destroy(struct tcls *tcls)
68 {
69     if (tcls) {
70         size_t i;
71
72         for (i = 0; i < tcls->n_rules; i++) {
73             free(tcls->rules[i]);
74         }
75         free(tcls->rules);
76     }
77 }
78
79 static int
80 tcls_count_exact(const struct tcls *tcls)
81 {
82     int n_exact;
83     size_t i;
84
85     n_exact = 0;
86     for (i = 0; i < tcls->n_rules; i++) {
87         n_exact += tcls->rules[i]->cls_rule.flow.wildcards == 0;
88     }
89     return n_exact;
90 }
91
92 static bool
93 tcls_is_empty(const struct tcls *tcls)
94 {
95     return tcls->n_rules == 0;
96 }
97
98 static unsigned int
99 effective_priority(const flow_t *flow)
100 {
101     return flow->wildcards ? flow->priority : MAX(flow->priority, UINT16_MAX);
102 }
103
104 static struct test_rule *
105 tcls_insert(struct tcls *tcls, const struct test_rule *rule)
106 {
107     unsigned int priority = effective_priority(&rule->cls_rule.flow);
108     size_t i;
109
110     for (i = 0; i < tcls->n_rules; i++) {
111         const struct cls_rule *pos = &tcls->rules[i]->cls_rule;
112         if (pos->flow.priority == priority
113             && pos->flow.wildcards == rule->cls_rule.flow.wildcards
114             && flow_equal_headers(&pos->flow, &rule->cls_rule.flow)) {
115             /* Exact match. */
116             free(tcls->rules[i]);
117             tcls->rules[i] = xmemdup(rule, sizeof *rule);
118             return tcls->rules[i];
119         } else if (pos->flow.priority < priority) {
120             break;
121         }
122     }
123
124     if (tcls->n_rules >= tcls->allocated_rules) {
125         tcls->rules = x2nrealloc(tcls->rules, &tcls->allocated_rules,
126                                  sizeof *tcls->rules);
127     }
128     if (i != tcls->n_rules) {
129         memmove(&tcls->rules[i + 1], &tcls->rules[i],
130                 sizeof *tcls->rules * (tcls->n_rules - i));
131     }
132     tcls->rules[i] = xmemdup(rule, sizeof *rule);
133     tcls->n_rules++;
134     return tcls->rules[i];
135 }
136
137 static void
138 tcls_remove(struct tcls *cls, const struct test_rule *rule)
139 {
140     size_t i;
141
142     for (i = 0; i < cls->n_rules; i++) {
143         struct test_rule *pos = cls->rules[i];
144         if (pos == rule) {
145             free(pos);
146             memmove(&cls->rules[i], &cls->rules[i + 1],
147                     sizeof *cls->rules * (cls->n_rules - i - 1));
148             cls->n_rules--;
149             return;
150         }
151     }
152     NOT_REACHED();
153 }
154
155 static uint32_t
156 read_uint32(const void *p)
157 {
158     uint32_t x;
159     memcpy(&x, p, sizeof x);
160     return x;
161 }
162
163 static bool
164 match(const struct cls_rule *wild, const flow_t *fixed)
165 {
166     int f_idx;
167
168     for (f_idx = 0; f_idx < CLS_N_FIELDS; f_idx++) {
169         const struct cls_field *f = &cls_fields[f_idx];
170         void *wild_field = (char *) &wild->flow + f->ofs;
171         void *fixed_field = (char *) fixed + f->ofs;
172
173         if ((wild->flow.wildcards & f->wildcards) == f->wildcards ||
174             !memcmp(wild_field, fixed_field, f->len)) {
175             /* Definite match. */
176             continue;
177         }
178
179         if (wild->flow.wildcards & f->wildcards) {
180             uint32_t test = read_uint32(wild_field);
181             uint32_t ip = read_uint32(fixed_field);
182             int shift = (f_idx == CLS_F_IDX_NW_SRC
183                          ? OFPFW_NW_SRC_SHIFT : OFPFW_NW_DST_SHIFT);
184             uint32_t mask = flow_nw_bits_to_mask(wild->flow.wildcards, shift);
185             if (!((test ^ ip) & mask)) {
186                 continue;
187             }
188         }
189
190         return false;
191     }
192     return true;
193 }
194
195 static struct cls_rule *
196 tcls_lookup(const struct tcls *cls, const flow_t *flow, int include)
197 {
198     size_t i;
199
200     for (i = 0; i < cls->n_rules; i++) {
201         struct test_rule *pos = cls->rules[i];
202         uint32_t wildcards = pos->cls_rule.flow.wildcards;
203         if (include & (wildcards ? CLS_INC_WILD : CLS_INC_EXACT)
204             && match(&pos->cls_rule, flow)) {
205             return &pos->cls_rule;
206         }
207     }
208     return NULL;
209 }
210
211 static void
212 tcls_delete_matches(struct tcls *cls,
213                     const struct cls_rule *target,
214                     int include)
215 {
216     size_t i;
217
218     for (i = 0; i < cls->n_rules; ) {
219         struct test_rule *pos = cls->rules[i];
220         uint32_t wildcards = pos->cls_rule.flow.wildcards;
221         if (include & (wildcards ? CLS_INC_WILD : CLS_INC_EXACT)
222             && match(target, &pos->cls_rule.flow)) {
223             tcls_remove(cls, pos);
224         } else {
225             i++;
226         }
227     }
228 }
229 \f
230 #ifdef WORDS_BIGENDIAN
231 #define T_HTONL(VALUE) ((uint32_t) (VALUE))
232 #define T_HTONS(VALUE) ((uint32_t) (VALUE))
233 #else
234 #define T_HTONL(VALUE) (((((uint32_t) (VALUE)) & 0x000000ff) << 24) | \
235                       ((((uint32_t) (VALUE)) & 0x0000ff00) <<  8) | \
236                       ((((uint32_t) (VALUE)) & 0x00ff0000) >>  8) | \
237                       ((((uint32_t) (VALUE)) & 0xff000000) >> 24))
238 #define T_HTONS(VALUE) (((((uint16_t) (VALUE)) & 0xff00) >> 8) |  \
239                       ((((uint16_t) (VALUE)) & 0x00ff) << 8))
240 #endif
241
242 static uint32_t nw_src_values[] = { T_HTONL(0xc0a80001),
243                                     T_HTONL(0xc0a04455) };
244 static uint32_t nw_dst_values[] = { T_HTONL(0xc0a80002),
245                                     T_HTONL(0xc0a04455) };
246 static uint32_t tun_id_values[] = { 0, 0xffff0000 };
247 static uint16_t in_port_values[] = { T_HTONS(1), T_HTONS(OFPP_LOCAL) };
248 static uint16_t dl_vlan_values[] = { T_HTONS(101), T_HTONS(0) };
249 static uint8_t dl_vlan_pcp_values[] = { 7, 0 };
250 static uint16_t dl_type_values[]
251             = { T_HTONS(ETH_TYPE_IP), T_HTONS(ETH_TYPE_ARP) };
252 static uint16_t tp_src_values[] = { T_HTONS(49362), T_HTONS(80) };
253 static uint16_t tp_dst_values[] = { T_HTONS(6667), T_HTONS(22) };
254 static uint8_t dl_src_values[][6] = { { 0x00, 0x02, 0xe3, 0x0f, 0x80, 0xa4 },
255                                       { 0x5e, 0x33, 0x7f, 0x5f, 0x1e, 0x99 } };
256 static uint8_t dl_dst_values[][6] = { { 0x4a, 0x27, 0x71, 0xae, 0x64, 0xc1 },
257                                       { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
258 static uint8_t nw_proto_values[] = { IP_TYPE_TCP, IP_TYPE_ICMP };
259 static uint8_t nw_tos_values[] = { 49, 0 };
260
261 static void *values[CLS_N_FIELDS][2];
262
263 static void
264 init_values(void)
265 {
266     values[CLS_F_IDX_TUN_ID][0] = &tun_id_values[0];
267     values[CLS_F_IDX_TUN_ID][1] = &tun_id_values[1];
268
269     values[CLS_F_IDX_IN_PORT][0] = &in_port_values[0];
270     values[CLS_F_IDX_IN_PORT][1] = &in_port_values[1];
271
272     values[CLS_F_IDX_DL_VLAN][0] = &dl_vlan_values[0];
273     values[CLS_F_IDX_DL_VLAN][1] = &dl_vlan_values[1];
274
275     values[CLS_F_IDX_DL_VLAN_PCP][0] = &dl_vlan_pcp_values[0];
276     values[CLS_F_IDX_DL_VLAN_PCP][1] = &dl_vlan_pcp_values[1];
277
278     values[CLS_F_IDX_DL_SRC][0] = dl_src_values[0];
279     values[CLS_F_IDX_DL_SRC][1] = dl_src_values[1];
280
281     values[CLS_F_IDX_DL_DST][0] = dl_dst_values[0];
282     values[CLS_F_IDX_DL_DST][1] = dl_dst_values[1];
283
284     values[CLS_F_IDX_DL_TYPE][0] = &dl_type_values[0];
285     values[CLS_F_IDX_DL_TYPE][1] = &dl_type_values[1];
286
287     values[CLS_F_IDX_NW_SRC][0] = &nw_src_values[0];
288     values[CLS_F_IDX_NW_SRC][1] = &nw_src_values[1];
289
290     values[CLS_F_IDX_NW_DST][0] = &nw_dst_values[0];
291     values[CLS_F_IDX_NW_DST][1] = &nw_dst_values[1];
292
293     values[CLS_F_IDX_NW_PROTO][0] = &nw_proto_values[0];
294     values[CLS_F_IDX_NW_PROTO][1] = &nw_proto_values[1];
295
296     values[CLS_F_IDX_NW_TOS][0] = &nw_tos_values[0];
297     values[CLS_F_IDX_NW_TOS][1] = &nw_tos_values[1];
298
299     values[CLS_F_IDX_TP_SRC][0] = &tp_src_values[0];
300     values[CLS_F_IDX_TP_SRC][1] = &tp_src_values[1];
301
302     values[CLS_F_IDX_TP_DST][0] = &tp_dst_values[0];
303     values[CLS_F_IDX_TP_DST][1] = &tp_dst_values[1];
304 }
305
306 #define N_NW_SRC_VALUES ARRAY_SIZE(nw_src_values)
307 #define N_NW_DST_VALUES ARRAY_SIZE(nw_dst_values)
308 #define N_TUN_ID_VALUES ARRAY_SIZE(tun_id_values)
309 #define N_IN_PORT_VALUES ARRAY_SIZE(in_port_values)
310 #define N_DL_VLAN_VALUES ARRAY_SIZE(dl_vlan_values)
311 #define N_DL_VLAN_PCP_VALUES ARRAY_SIZE(dl_vlan_pcp_values)
312 #define N_DL_TYPE_VALUES ARRAY_SIZE(dl_type_values)
313 #define N_TP_SRC_VALUES ARRAY_SIZE(tp_src_values)
314 #define N_TP_DST_VALUES ARRAY_SIZE(tp_dst_values)
315 #define N_DL_SRC_VALUES ARRAY_SIZE(dl_src_values)
316 #define N_DL_DST_VALUES ARRAY_SIZE(dl_dst_values)
317 #define N_NW_PROTO_VALUES ARRAY_SIZE(nw_proto_values)
318 #define N_NW_TOS_VALUES ARRAY_SIZE(nw_tos_values)
319
320 #define N_FLOW_VALUES (N_NW_SRC_VALUES *        \
321                        N_NW_DST_VALUES *        \
322                        N_TUN_ID_VALUES *        \
323                        N_IN_PORT_VALUES *       \
324                        N_DL_VLAN_VALUES *       \
325                        N_DL_VLAN_PCP_VALUES *   \
326                        N_DL_TYPE_VALUES *       \
327                        N_TP_SRC_VALUES *        \
328                        N_TP_DST_VALUES *        \
329                        N_DL_SRC_VALUES *        \
330                        N_DL_DST_VALUES *        \
331                        N_NW_PROTO_VALUES *      \
332                        N_NW_TOS_VALUES)
333
334 static unsigned int
335 get_value(unsigned int *x, unsigned n_values)
336 {
337     unsigned int rem = *x % n_values;
338     *x /= n_values;
339     return rem;
340 }
341
342 static struct cls_rule *
343 lookup_with_include_bits(const struct classifier *cls,
344                          const flow_t *flow, int include)
345 {
346     switch (include) {
347     case CLS_INC_WILD:
348         return classifier_lookup_wild(cls, flow);
349     case CLS_INC_EXACT:
350         return classifier_lookup_exact(cls, flow);
351     case CLS_INC_WILD | CLS_INC_EXACT:
352         return classifier_lookup(cls, flow);
353     default:
354         abort();
355     }
356 }
357
358 static void
359 compare_classifiers(struct classifier *cls, struct tcls *tcls)
360 {
361     static const int confidence = 500;
362     unsigned int i;
363
364     assert(classifier_count(cls) == tcls->n_rules);
365     assert(classifier_count_exact(cls) == tcls_count_exact(tcls));
366     for (i = 0; i < confidence; i++) {
367         struct cls_rule *cr0, *cr1;
368         flow_t flow;
369         unsigned int x;
370         int include;
371
372         x = rand () % N_FLOW_VALUES;
373         flow.nw_src = nw_src_values[get_value(&x, N_NW_SRC_VALUES)];
374         flow.nw_dst = nw_dst_values[get_value(&x, N_NW_DST_VALUES)];
375         flow.tun_id = tun_id_values[get_value(&x, N_TUN_ID_VALUES)];
376         flow.in_port = in_port_values[get_value(&x, N_IN_PORT_VALUES)];
377         flow.dl_vlan = dl_vlan_values[get_value(&x, N_DL_VLAN_VALUES)];
378         flow.dl_vlan_pcp = dl_vlan_pcp_values[get_value(&x,
379                 N_DL_VLAN_PCP_VALUES)];
380         flow.dl_type = dl_type_values[get_value(&x, N_DL_TYPE_VALUES)];
381         flow.tp_src = tp_src_values[get_value(&x, N_TP_SRC_VALUES)];
382         flow.tp_dst = tp_dst_values[get_value(&x, N_TP_DST_VALUES)];
383         memcpy(flow.dl_src, dl_src_values[get_value(&x, N_DL_SRC_VALUES)],
384                ETH_ADDR_LEN);
385         memcpy(flow.dl_dst, dl_dst_values[get_value(&x, N_DL_DST_VALUES)],
386                ETH_ADDR_LEN);
387         flow.nw_proto = nw_proto_values[get_value(&x, N_NW_PROTO_VALUES)];
388         flow.nw_tos = nw_tos_values[get_value(&x, N_NW_TOS_VALUES)];
389
390         for (include = 1; include <= 3; include++) {
391             cr0 = lookup_with_include_bits(cls, &flow, include);
392             cr1 = tcls_lookup(tcls, &flow, include);
393             assert((cr0 == NULL) == (cr1 == NULL));
394             if (cr0 != NULL) {
395                 const struct test_rule *tr0 = test_rule_from_cls_rule(cr0);
396                 const struct test_rule *tr1 = test_rule_from_cls_rule(cr1);
397
398                 assert(flow_equal_headers(&cr0->flow, &cr1->flow));
399                 assert(cr0->flow.wildcards == cr1->flow.wildcards);
400                 assert(cr0->flow.priority == cr1->flow.priority);
401                 /* Skip nw_src_mask, nw_dst_mask, and dl_tci_mask, because they
402                  * are derived members used only for optimization. */
403                 assert(tr0->aux == tr1->aux);
404             }
405         }
406     }
407 }
408
409 static int
410 free_rule(struct cls_rule *cls_rule, void *cls)
411 {
412     classifier_remove(cls, cls_rule);
413     free(test_rule_from_cls_rule(cls_rule));
414     return 0;
415 }
416
417 static void
418 destroy_classifier(struct classifier *cls)
419 {
420     classifier_for_each(cls, CLS_INC_ALL, free_rule, cls);
421     classifier_destroy(cls);
422 }
423
424 static void
425 check_tables(const struct classifier *cls,
426              int n_tables, int n_buckets, int n_rules)
427 {
428     int found_tables = 0;
429     int found_buckets = 0;
430     int found_rules = 0;
431     int i;
432
433     BUILD_ASSERT(CLS_N_FIELDS == ARRAY_SIZE(cls->tables));
434     for (i = 0; i < CLS_N_FIELDS; i++) {
435         const struct cls_bucket *bucket;
436         if (!hmap_is_empty(&cls->tables[i])) {
437             found_tables++;
438         }
439         HMAP_FOR_EACH (bucket, hmap_node, &cls->tables[i]) {
440             found_buckets++;
441             assert(!list_is_empty(&bucket->rules));
442             found_rules += list_size(&bucket->rules);
443         }
444     }
445
446     if (!hmap_is_empty(&cls->exact_table)) {
447         found_tables++;
448         found_buckets++;
449         found_rules += hmap_count(&cls->exact_table);
450     }
451
452     assert(n_tables == -1 || found_tables == n_tables);
453     assert(n_rules == -1 || found_rules == n_rules);
454     assert(n_buckets == -1 || found_buckets == n_buckets);
455 }
456
457 static struct test_rule *
458 make_rule(int wc_fields, unsigned int priority, int value_pat)
459 {
460     const struct cls_field *f;
461     struct test_rule *rule;
462     flow_t flow;
463
464     memset(&flow, 0, sizeof flow);
465     flow.priority = priority;
466     for (f = &cls_fields[0]; f < &cls_fields[CLS_N_FIELDS]; f++) {
467         int f_idx = f - cls_fields;
468         if (wc_fields & (1u << f_idx)) {
469             flow.wildcards |= f->wildcards;
470         } else {
471             int value_idx = (value_pat & (1u << f_idx)) != 0;
472             memcpy((char *) &flow + f->ofs, values[f_idx][value_idx], f->len);
473         }
474     }
475
476     rule = xzalloc(sizeof *rule);
477     cls_rule_from_flow(&flow, &rule->cls_rule);
478     return rule;
479 }
480
481 static void
482 shuffle(unsigned int *p, size_t n)
483 {
484     for (; n > 1; n--, p++) {
485         unsigned int *q = &p[rand() % n];
486         unsigned int tmp = *p;
487         *p = *q;
488         *q = tmp;
489     }
490 }
491 \f
492 /* Tests an empty classifier. */
493 static void
494 test_empty(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
495 {
496     struct classifier cls;
497     struct tcls tcls;
498
499     classifier_init(&cls);
500     tcls_init(&tcls);
501     assert(classifier_is_empty(&cls));
502     assert(tcls_is_empty(&tcls));
503     compare_classifiers(&cls, &tcls);
504     classifier_destroy(&cls);
505     tcls_destroy(&tcls);
506 }
507
508 /* Destroys a null classifier. */
509 static void
510 test_destroy_null(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
511 {
512     classifier_destroy(NULL);
513 }
514
515 /* Tests classification with one rule at a time. */
516 static void
517 test_single_rule(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
518 {
519     unsigned int wc_fields;     /* Hilarious. */
520
521     for (wc_fields = 0; wc_fields < (1u << CLS_N_FIELDS); wc_fields++) {
522         struct classifier cls;
523         struct test_rule *rule, *tcls_rule;
524         struct tcls tcls;
525
526         rule = make_rule(wc_fields,
527                          hash_bytes(&wc_fields, sizeof wc_fields, 0), 0);
528
529         classifier_init(&cls);
530         tcls_init(&tcls);
531
532         tcls_rule = tcls_insert(&tcls, rule);
533         if (wc_fields) {
534             assert(!classifier_insert(&cls, &rule->cls_rule));
535         } else {
536             classifier_insert_exact(&cls, &rule->cls_rule);
537         }
538         check_tables(&cls, 1, 1, 1);
539         compare_classifiers(&cls, &tcls);
540
541         classifier_remove(&cls, &rule->cls_rule);
542         tcls_remove(&tcls, tcls_rule);
543         assert(classifier_is_empty(&cls));
544         assert(tcls_is_empty(&tcls));
545         compare_classifiers(&cls, &tcls);
546
547         free(rule);
548         classifier_destroy(&cls);
549         tcls_destroy(&tcls);
550     }
551 }
552
553 /* Tests replacing one rule by another. */
554 static void
555 test_rule_replacement(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
556 {
557     unsigned int wc_fields;
558
559     for (wc_fields = 0; wc_fields < (1u << CLS_N_FIELDS); wc_fields++) {
560         struct classifier cls;
561         struct test_rule *rule1;
562         struct test_rule *rule2;
563         struct tcls tcls;
564
565         rule1 = make_rule(wc_fields, OFP_DEFAULT_PRIORITY, UINT_MAX);
566         rule2 = make_rule(wc_fields, OFP_DEFAULT_PRIORITY, UINT_MAX);
567         rule2->aux += 5;
568         rule2->aux += 5;
569
570         classifier_init(&cls);
571         tcls_init(&tcls);
572         tcls_insert(&tcls, rule1);
573         assert(!classifier_insert(&cls, &rule1->cls_rule));
574         check_tables(&cls, 1, 1, 1);
575         compare_classifiers(&cls, &tcls);
576         tcls_destroy(&tcls);
577
578         tcls_init(&tcls);
579         tcls_insert(&tcls, rule2);
580         assert(test_rule_from_cls_rule(
581                    classifier_insert(&cls, &rule2->cls_rule)) == rule1);
582         free(rule1);
583         check_tables(&cls, 1, 1, 1);
584         compare_classifiers(&cls, &tcls);
585         tcls_destroy(&tcls);
586         destroy_classifier(&cls);
587     }
588 }
589
590 static int
591 table_mask(int table)
592 {
593     return ((1u << CLS_N_FIELDS) - 1) & ~((1u << table) - 1);
594 }
595
596 static int
597 random_wcf_in_table(int table, int seed)
598 {
599     int wc_fields = (1u << table) | hash_int(seed, 0);
600     return wc_fields & table_mask(table);
601 }
602
603 /* Tests classification with two rules at a time that fall into the same
604  * bucket. */
605 static void
606 test_two_rules_in_one_bucket(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
607 {
608     int table, rel_pri, wcf_pat, value_pat;
609
610     for (table = 0; table <= CLS_N_FIELDS; table++) {
611         for (rel_pri = -1; rel_pri <= +1; rel_pri++) {
612             for (wcf_pat = 0; wcf_pat < 4; wcf_pat++) {
613                 int n_value_pats = table == CLS_N_FIELDS - 1 ? 1 : 2;
614                 for (value_pat = 0; value_pat < n_value_pats; value_pat++) {
615                     struct test_rule *rule1, *tcls_rule1;
616                     struct test_rule *rule2, *tcls_rule2;
617                     struct test_rule *displaced_rule;
618                     struct classifier cls;
619                     struct tcls tcls;
620                     unsigned int pri1, pri2;
621                     int wcf1, wcf2;
622
623                     if (table != CLS_F_IDX_EXACT) {
624                         /* We can use identical priorities in this test because
625                          * the classifier always chooses the rule added later
626                          * for equal-priority rules that fall into the same
627                          * bucket.  */
628                         pri1 = table * 257 + 50;
629                         pri2 = pri1 + rel_pri;
630
631                         wcf1 = (wcf_pat & 1
632                                 ? random_wcf_in_table(table, pri1)
633                                 : 1u << table);
634                         wcf2 = (wcf_pat & 2
635                                 ? random_wcf_in_table(table, pri2)
636                                 : 1u << table);
637                         if (value_pat) {
638                             wcf1 &= ~(1u << (CLS_N_FIELDS - 1));
639                             wcf2 &= ~(1u << (CLS_N_FIELDS - 1));
640                         }
641                     } else {
642                         /* This classifier always puts exact-match rules at
643                          * maximum priority.  */
644                         pri1 = pri2 = UINT_MAX;
645
646                         /* No wildcard fields. */
647                         wcf1 = wcf2 = 0;
648                     }
649
650                     rule1 = make_rule(wcf1, pri1, 0);
651                     rule2 = make_rule(wcf2, pri2,
652                                       value_pat << (CLS_N_FIELDS - 1));
653
654                     classifier_init(&cls);
655                     tcls_init(&tcls);
656
657                     tcls_rule1 = tcls_insert(&tcls, rule1);
658                     tcls_rule2 = tcls_insert(&tcls, rule2);
659                     assert(!classifier_insert(&cls, &rule1->cls_rule));
660                     displaced_rule = test_rule_from_cls_rule(
661                         classifier_insert(&cls, &rule2->cls_rule));
662                     if (wcf1 != wcf2 || pri1 != pri2 || value_pat) {
663                         assert(!displaced_rule);
664
665                         check_tables(&cls, 1, 1, 2);
666                         compare_classifiers(&cls, &tcls);
667
668                         classifier_remove(&cls, &rule1->cls_rule);
669                         tcls_remove(&tcls, tcls_rule1);
670                         check_tables(&cls, 1, 1, 1);
671                         compare_classifiers(&cls, &tcls);
672                     } else {
673                         assert(displaced_rule == rule1);
674                         check_tables(&cls, 1, 1, 1);
675                         compare_classifiers(&cls, &tcls);
676                     }
677                     free(rule1);
678
679                     classifier_remove(&cls, &rule2->cls_rule);
680                     tcls_remove(&tcls, tcls_rule2);
681                     compare_classifiers(&cls, &tcls);
682                     free(rule2);
683
684                     destroy_classifier(&cls);
685                     tcls_destroy(&tcls);
686                 }
687             }
688         }
689     }
690 }
691
692 /* Tests classification with two rules at a time that fall into the same
693  * table but different buckets. */
694 static void
695 test_two_rules_in_one_table(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
696 {
697     int table, rel_pri, wcf_pat;
698
699     /* Skip tables 0 and CLS_F_IDX_EXACT because they have one bucket. */
700     for (table = 1; table < CLS_N_FIELDS; table++) {
701         for (rel_pri = -1; rel_pri <= +1; rel_pri++) {
702             for (wcf_pat = 0; wcf_pat < 5; wcf_pat++) {
703                 struct test_rule *rule1, *tcls_rule1;
704                 struct test_rule *rule2, *tcls_rule2;
705                 struct classifier cls;
706                 struct tcls tcls;
707                 unsigned int pri1, pri2;
708                 int wcf1, wcf2;
709                 int value_mask, value_pat1, value_pat2;
710                 int i;
711
712                 /* We can use identical priorities in this test because the
713                  * classifier always chooses the rule added later for
714                  * equal-priority rules that fall into the same table.  */
715                 pri1 = table * 257 + 50;
716                 pri2 = pri1 + rel_pri;
717
718                 if (wcf_pat & 4) {
719                     wcf1 = wcf2 = random_wcf_in_table(table, pri1);
720                 } else {
721                     wcf1 = (wcf_pat & 1
722                             ? random_wcf_in_table(table, pri1)
723                             : 1u << table);
724                     wcf2 = (wcf_pat & 2
725                             ? random_wcf_in_table(table, pri2)
726                             : 1u << table);
727                 }
728
729                 /* Generate value patterns that will put the two rules into
730                  * different buckets. */
731                 value_mask = ((1u << table) - 1);
732                 value_pat1 = hash_int(pri1, 1) & value_mask;
733                 i = 0;
734                 do {
735                     value_pat2 = (hash_int(pri2, i++) & value_mask);
736                 } while (value_pat1 == value_pat2);
737                 rule1 = make_rule(wcf1, pri1, value_pat1);
738                 rule2 = make_rule(wcf2, pri2, value_pat2);
739
740                 classifier_init(&cls);
741                 tcls_init(&tcls);
742
743                 tcls_rule1 = tcls_insert(&tcls, rule1);
744                 tcls_rule2 = tcls_insert(&tcls, rule2);
745                 assert(!classifier_insert(&cls, &rule1->cls_rule));
746                 assert(!classifier_insert(&cls, &rule2->cls_rule));
747                 check_tables(&cls, 1, 2, 2);
748                 compare_classifiers(&cls, &tcls);
749
750                 classifier_remove(&cls, &rule1->cls_rule);
751                 tcls_remove(&tcls, tcls_rule1);
752                 check_tables(&cls, 1, 1, 1);
753                 compare_classifiers(&cls, &tcls);
754                 free(rule1);
755
756                 classifier_remove(&cls, &rule2->cls_rule);
757                 tcls_remove(&tcls, tcls_rule2);
758                 compare_classifiers(&cls, &tcls);
759                 free(rule2);
760
761                 classifier_destroy(&cls);
762                 tcls_destroy(&tcls);
763             }
764         }
765     }
766 }
767
768 /* Tests classification with two rules at a time that fall into different
769  * tables. */
770 static void
771 test_two_rules_in_different_tables(int argc OVS_UNUSED,
772                                    char *argv[] OVS_UNUSED)
773 {
774     int table1, table2, rel_pri, wcf_pat;
775
776     for (table1 = 0; table1 < CLS_N_FIELDS; table1++) {
777         for (table2 = table1 + 1; table2 <= CLS_N_FIELDS; table2++) {
778             for (rel_pri = 0; rel_pri < 2; rel_pri++) {
779                 for (wcf_pat = 0; wcf_pat < 4; wcf_pat++) {
780                     struct test_rule *rule1, *tcls_rule1;
781                     struct test_rule *rule2, *tcls_rule2;
782                     struct classifier cls;
783                     struct tcls tcls;
784                     unsigned int pri1, pri2;
785                     int wcf1, wcf2;
786
787                     /* We must use unique priorities in this test because the
788                      * classifier makes the rule choice undefined for rules of
789                      * equal priority that fall into different tables.  (In
790                      * practice, lower-numbered tables win.)  */
791                     pri1 = table1 * 257 + 50;
792                     pri2 = rel_pri ? pri1 - 1 : pri1 + 1;
793
794                     wcf1 = (wcf_pat & 1
795                             ? random_wcf_in_table(table1, pri1)
796                             : 1u << table1);
797                     wcf2 = (wcf_pat & 2
798                             ? random_wcf_in_table(table2, pri2)
799                             : 1u << table2);
800
801                     if (table2 == CLS_F_IDX_EXACT) {
802                         pri2 = UINT16_MAX;
803                         wcf2 = 0;
804                     }
805
806                     rule1 = make_rule(wcf1, pri1, 0);
807                     rule2 = make_rule(wcf2, pri2, 0);
808
809                     classifier_init(&cls);
810                     tcls_init(&tcls);
811
812                     tcls_rule1 = tcls_insert(&tcls, rule1);
813                     tcls_rule2 = tcls_insert(&tcls, rule2);
814                     assert(!classifier_insert(&cls, &rule1->cls_rule));
815                     assert(!classifier_insert(&cls, &rule2->cls_rule));
816                     check_tables(&cls, 2, 2, 2);
817                     compare_classifiers(&cls, &tcls);
818
819                     classifier_remove(&cls, &rule1->cls_rule);
820                     tcls_remove(&tcls, tcls_rule1);
821                     check_tables(&cls, 1, 1, 1);
822                     compare_classifiers(&cls, &tcls);
823                     free(rule1);
824
825                     classifier_remove(&cls, &rule2->cls_rule);
826                     tcls_remove(&tcls, tcls_rule2);
827                     compare_classifiers(&cls, &tcls);
828                     free(rule2);
829
830                     classifier_destroy(&cls);
831                     tcls_destroy(&tcls);
832                 }
833             }
834         }
835     }
836 }
837
838 /* Tests classification with many rules at a time that fall into the same
839  * bucket but have unique priorities (and various wildcards). */
840 static void
841 test_many_rules_in_one_bucket(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
842 {
843     enum { MAX_RULES = 50 };
844     int iteration, table;
845
846     for (iteration = 0; iteration < 3; iteration++) {
847         for (table = 0; table <= CLS_N_FIELDS; table++) {
848             unsigned int priorities[MAX_RULES];
849             struct classifier cls;
850             struct tcls tcls;
851             int i;
852
853             srand(hash_int(table, iteration));
854             for (i = 0; i < MAX_RULES; i++) {
855                 priorities[i] = i * 129;
856             }
857             shuffle(priorities, ARRAY_SIZE(priorities));
858
859             classifier_init(&cls);
860             tcls_init(&tcls);
861
862             for (i = 0; i < MAX_RULES; i++) {
863                 struct test_rule *rule;
864                 unsigned int priority = priorities[i];
865                 int wcf;
866
867                 wcf = random_wcf_in_table(table, priority);
868                 rule = make_rule(wcf, priority,
869                                  table == CLS_F_IDX_EXACT ? i : 1234);
870                 tcls_insert(&tcls, rule);
871                 assert(!classifier_insert(&cls, &rule->cls_rule));
872                 check_tables(&cls, 1, 1, i + 1);
873                 compare_classifiers(&cls, &tcls);
874             }
875
876             destroy_classifier(&cls);
877             tcls_destroy(&tcls);
878         }
879     }
880 }
881
882 /* Tests classification with many rules at a time that fall into the same
883  * table but random buckets. */
884 static void
885 test_many_rules_in_one_table(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
886 {
887     enum { MAX_RULES = 50 };
888     int iteration, table;
889
890     for (iteration = 0; iteration < 3; iteration++) {
891         for (table = 0; table < CLS_N_FIELDS; table++) {
892             unsigned int priorities[MAX_RULES];
893             struct classifier cls;
894             struct tcls tcls;
895             int i;
896
897             srand(hash_int(table, iteration));
898             for (i = 0; i < MAX_RULES; i++) {
899                 priorities[i] = i * 129;
900             }
901             shuffle(priorities, ARRAY_SIZE(priorities));
902
903             classifier_init(&cls);
904             tcls_init(&tcls);
905
906             for (i = 0; i < MAX_RULES; i++) {
907                 struct test_rule *rule;
908                 unsigned int priority = priorities[i];
909                 int wcf;
910
911                 wcf = random_wcf_in_table(table, priority);
912                 rule = make_rule(wcf, priority, hash_int(priority, 1));
913                 tcls_insert(&tcls, rule);
914                 assert(!classifier_insert(&cls, &rule->cls_rule));
915                 check_tables(&cls, 1, -1, i + 1);
916                 compare_classifiers(&cls, &tcls);
917             }
918
919             destroy_classifier(&cls);
920             tcls_destroy(&tcls);
921         }
922     }
923 }
924
925 /* Tests classification with many rules at a time that fall into random buckets
926  * in random tables. */
927 static void
928 test_many_rules_in_different_tables(int argc OVS_UNUSED,
929                                     char *argv[] OVS_UNUSED)
930 {
931     enum { MAX_RULES = 50 };
932     int iteration;
933
934     for (iteration = 0; iteration < 30; iteration++) {
935         unsigned int priorities[MAX_RULES];
936         struct classifier cls;
937         struct tcls tcls;
938         int i;
939
940         srand(iteration);
941         for (i = 0; i < MAX_RULES; i++) {
942             priorities[i] = i * 129;
943         }
944         shuffle(priorities, ARRAY_SIZE(priorities));
945
946         classifier_init(&cls);
947         tcls_init(&tcls);
948
949         for (i = 0; i < MAX_RULES; i++) {
950             struct test_rule *rule;
951             unsigned int priority = priorities[i];
952             int table = rand() % (CLS_N_FIELDS + 1);
953             int wcf = random_wcf_in_table(table, rand());
954             int value_pat = rand() & ((1u << CLS_N_FIELDS) - 1);
955             rule = make_rule(wcf, priority, value_pat);
956             tcls_insert(&tcls, rule);
957             assert(!classifier_insert(&cls, &rule->cls_rule));
958             check_tables(&cls, -1, -1, i + 1);
959             compare_classifiers(&cls, &tcls);
960         }
961
962         while (!classifier_is_empty(&cls)) {
963             struct test_rule *rule = xmemdup(tcls.rules[rand() % tcls.n_rules],
964                                              sizeof(struct test_rule));
965             int include = rand() % 2 ? CLS_INC_WILD : CLS_INC_EXACT;
966             include |= (rule->cls_rule.flow.wildcards
967                         ? CLS_INC_WILD : CLS_INC_EXACT);
968             classifier_for_each_match(&cls, &rule->cls_rule.flow, include,
969                                       free_rule, &cls);
970             tcls_delete_matches(&tcls, &rule->cls_rule, include);
971             compare_classifiers(&cls, &tcls);
972             free(rule);
973         }
974
975         destroy_classifier(&cls);
976         tcls_destroy(&tcls);
977     }
978 }
979 \f
980 int
981 main(int argc, char *argv[])
982 {
983     static const struct command all_commands[] = {
984         { "empty", 0, 0, test_empty },
985         { "destroy-null", 0, 0, test_destroy_null },
986         { "single-rule", 0, 0, test_single_rule },
987         { "rule-replacement", 0, 0, test_rule_replacement },
988         { "two-rules-in-one-bucket", 0, 0, test_two_rules_in_one_bucket },
989         { "two-rules-in-one-table", 0, 0, test_two_rules_in_one_table },
990         { "two-rules-in-different-tables", 0, 0,
991           test_two_rules_in_different_tables },
992         { "many-rules-in-one-bucket", 0, 0,
993           test_many_rules_in_one_bucket },
994         { "many-rules-in-one-table", 0, 0, test_many_rules_in_one_table },
995         { "many-rules-in-different-tables", 0, 0,
996           test_many_rules_in_different_tables },
997         { NULL, 0, 0, NULL },
998     };
999
1000     set_program_name(argv[0]);
1001     init_values();
1002     parse_test_options(argc, argv, all_commands);
1003     run_command(argc - 1, argv + 1, all_commands);
1004     return 0;
1005 }