27fe97e19d3a4d947594db4c65af62b9c00dcf8f
[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 void
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 }
415
416 static void
417 destroy_classifier(struct classifier *cls)
418 {
419     classifier_for_each(cls, CLS_INC_ALL, free_rule, cls);
420     classifier_destroy(cls);
421 }
422
423 static void
424 check_tables(const struct classifier *cls,
425              int n_tables, int n_buckets, int n_rules)
426 {
427     int found_tables = 0;
428     int found_buckets = 0;
429     int found_rules = 0;
430     int i;
431
432     BUILD_ASSERT(CLS_N_FIELDS == ARRAY_SIZE(cls->tables));
433     for (i = 0; i < CLS_N_FIELDS; i++) {
434         const struct cls_bucket *bucket;
435         if (!hmap_is_empty(&cls->tables[i])) {
436             found_tables++;
437         }
438         HMAP_FOR_EACH (bucket, struct cls_bucket, hmap_node, &cls->tables[i]) {
439             found_buckets++;
440             assert(!list_is_empty(&bucket->rules));
441             found_rules += list_size(&bucket->rules);
442         }
443     }
444
445     if (!hmap_is_empty(&cls->exact_table)) {
446         found_tables++;
447         found_buckets++;
448         found_rules += hmap_count(&cls->exact_table);
449     }
450
451     assert(n_tables == -1 || found_tables == n_tables);
452     assert(n_rules == -1 || found_rules == n_rules);
453     assert(n_buckets == -1 || found_buckets == n_buckets);
454 }
455
456 static struct test_rule *
457 make_rule(int wc_fields, unsigned int priority, int value_pat)
458 {
459     const struct cls_field *f;
460     struct test_rule *rule;
461     flow_t flow;
462
463     memset(&flow, 0, sizeof flow);
464     flow.priority = priority;
465     for (f = &cls_fields[0]; f < &cls_fields[CLS_N_FIELDS]; f++) {
466         int f_idx = f - cls_fields;
467         if (wc_fields & (1u << f_idx)) {
468             flow.wildcards |= f->wildcards;
469         } else {
470             int value_idx = (value_pat & (1u << f_idx)) != 0;
471             memcpy((char *) &flow + f->ofs, values[f_idx][value_idx], f->len);
472         }
473     }
474
475     rule = xzalloc(sizeof *rule);
476     cls_rule_from_flow(&flow, &rule->cls_rule);
477     return rule;
478 }
479
480 static void
481 shuffle(unsigned int *p, size_t n)
482 {
483     for (; n > 1; n--, p++) {
484         unsigned int *q = &p[rand() % n];
485         unsigned int tmp = *p;
486         *p = *q;
487         *q = tmp;
488     }
489 }
490 \f
491 /* Tests an empty classifier. */
492 static void
493 test_empty(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
494 {
495     struct classifier cls;
496     struct tcls tcls;
497
498     classifier_init(&cls);
499     tcls_init(&tcls);
500     assert(classifier_is_empty(&cls));
501     assert(tcls_is_empty(&tcls));
502     compare_classifiers(&cls, &tcls);
503     classifier_destroy(&cls);
504     tcls_destroy(&tcls);
505 }
506
507 /* Destroys a null classifier. */
508 static void
509 test_destroy_null(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
510 {
511     classifier_destroy(NULL);
512 }
513
514 /* Tests classification with one rule at a time. */
515 static void
516 test_single_rule(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
517 {
518     unsigned int wc_fields;     /* Hilarious. */
519
520     for (wc_fields = 0; wc_fields < (1u << CLS_N_FIELDS); wc_fields++) {
521         struct classifier cls;
522         struct test_rule *rule, *tcls_rule;
523         struct tcls tcls;
524
525         rule = make_rule(wc_fields,
526                          hash_bytes(&wc_fields, sizeof wc_fields, 0), 0);
527
528         classifier_init(&cls);
529         tcls_init(&tcls);
530
531         tcls_rule = tcls_insert(&tcls, rule);
532         if (wc_fields) {
533             assert(!classifier_insert(&cls, &rule->cls_rule));
534         } else {
535             classifier_insert_exact(&cls, &rule->cls_rule);
536         }
537         check_tables(&cls, 1, 1, 1);
538         compare_classifiers(&cls, &tcls);
539
540         classifier_remove(&cls, &rule->cls_rule);
541         tcls_remove(&tcls, tcls_rule);
542         assert(classifier_is_empty(&cls));
543         assert(tcls_is_empty(&tcls));
544         compare_classifiers(&cls, &tcls);
545
546         free(rule);
547         classifier_destroy(&cls);
548         tcls_destroy(&tcls);
549     }
550 }
551
552 /* Tests replacing one rule by another. */
553 static void
554 test_rule_replacement(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
555 {
556     unsigned int wc_fields;
557
558     for (wc_fields = 0; wc_fields < (1u << CLS_N_FIELDS); wc_fields++) {
559         struct classifier cls;
560         struct test_rule *rule1;
561         struct test_rule *rule2;
562         struct tcls tcls;
563
564         rule1 = make_rule(wc_fields, OFP_DEFAULT_PRIORITY, UINT_MAX);
565         rule2 = make_rule(wc_fields, OFP_DEFAULT_PRIORITY, UINT_MAX);
566         rule2->aux += 5;
567         rule2->aux += 5;
568
569         classifier_init(&cls);
570         tcls_init(&tcls);
571         tcls_insert(&tcls, rule1);
572         assert(!classifier_insert(&cls, &rule1->cls_rule));
573         check_tables(&cls, 1, 1, 1);
574         compare_classifiers(&cls, &tcls);
575         tcls_destroy(&tcls);
576
577         tcls_init(&tcls);
578         tcls_insert(&tcls, rule2);
579         assert(test_rule_from_cls_rule(
580                    classifier_insert(&cls, &rule2->cls_rule)) == rule1);
581         free(rule1);
582         check_tables(&cls, 1, 1, 1);
583         compare_classifiers(&cls, &tcls);
584         tcls_destroy(&tcls);
585         destroy_classifier(&cls);
586     }
587 }
588
589 static int
590 table_mask(int table)
591 {
592     return ((1u << CLS_N_FIELDS) - 1) & ~((1u << table) - 1);
593 }
594
595 static int
596 random_wcf_in_table(int table, int seed)
597 {
598     int wc_fields = (1u << table) | hash_int(seed, 0);
599     return wc_fields & table_mask(table);
600 }
601
602 /* Tests classification with two rules at a time that fall into the same
603  * bucket. */
604 static void
605 test_two_rules_in_one_bucket(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
606 {
607     int table, rel_pri, wcf_pat, value_pat;
608
609     for (table = 0; table <= CLS_N_FIELDS; table++) {
610         for (rel_pri = -1; rel_pri <= +1; rel_pri++) {
611             for (wcf_pat = 0; wcf_pat < 4; wcf_pat++) {
612                 int n_value_pats = table == CLS_N_FIELDS - 1 ? 1 : 2;
613                 for (value_pat = 0; value_pat < n_value_pats; value_pat++) {
614                     struct test_rule *rule1, *tcls_rule1;
615                     struct test_rule *rule2, *tcls_rule2;
616                     struct test_rule *displaced_rule;
617                     struct classifier cls;
618                     struct tcls tcls;
619                     unsigned int pri1, pri2;
620                     int wcf1, wcf2;
621
622                     if (table != CLS_F_IDX_EXACT) {
623                         /* We can use identical priorities in this test because
624                          * the classifier always chooses the rule added later
625                          * for equal-priority rules that fall into the same
626                          * bucket.  */
627                         pri1 = table * 257 + 50;
628                         pri2 = pri1 + rel_pri;
629
630                         wcf1 = (wcf_pat & 1
631                                 ? random_wcf_in_table(table, pri1)
632                                 : 1u << table);
633                         wcf2 = (wcf_pat & 2
634                                 ? random_wcf_in_table(table, pri2)
635                                 : 1u << table);
636                         if (value_pat) {
637                             wcf1 &= ~(1u << (CLS_N_FIELDS - 1));
638                             wcf2 &= ~(1u << (CLS_N_FIELDS - 1));
639                         }
640                     } else {
641                         /* This classifier always puts exact-match rules at
642                          * maximum priority.  */
643                         pri1 = pri2 = UINT_MAX;
644
645                         /* No wildcard fields. */
646                         wcf1 = wcf2 = 0;
647                     }
648
649                     rule1 = make_rule(wcf1, pri1, 0);
650                     rule2 = make_rule(wcf2, pri2,
651                                       value_pat << (CLS_N_FIELDS - 1));
652
653                     classifier_init(&cls);
654                     tcls_init(&tcls);
655
656                     tcls_rule1 = tcls_insert(&tcls, rule1);
657                     tcls_rule2 = tcls_insert(&tcls, rule2);
658                     assert(!classifier_insert(&cls, &rule1->cls_rule));
659                     displaced_rule = test_rule_from_cls_rule(
660                         classifier_insert(&cls, &rule2->cls_rule));
661                     if (wcf1 != wcf2 || pri1 != pri2 || value_pat) {
662                         assert(!displaced_rule);
663
664                         check_tables(&cls, 1, 1, 2);
665                         compare_classifiers(&cls, &tcls);
666
667                         classifier_remove(&cls, &rule1->cls_rule);
668                         tcls_remove(&tcls, tcls_rule1);
669                         check_tables(&cls, 1, 1, 1);
670                         compare_classifiers(&cls, &tcls);
671                     } else {
672                         assert(displaced_rule == rule1);
673                         check_tables(&cls, 1, 1, 1);
674                         compare_classifiers(&cls, &tcls);
675                     }
676                     free(rule1);
677
678                     classifier_remove(&cls, &rule2->cls_rule);
679                     tcls_remove(&tcls, tcls_rule2);
680                     compare_classifiers(&cls, &tcls);
681                     free(rule2);
682
683                     destroy_classifier(&cls);
684                     tcls_destroy(&tcls);
685                 }
686             }
687         }
688     }
689 }
690
691 /* Tests classification with two rules at a time that fall into the same
692  * table but different buckets. */
693 static void
694 test_two_rules_in_one_table(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
695 {
696     int table, rel_pri, wcf_pat;
697
698     /* Skip tables 0 and CLS_F_IDX_EXACT because they have one bucket. */
699     for (table = 1; table < CLS_N_FIELDS; table++) {
700         for (rel_pri = -1; rel_pri <= +1; rel_pri++) {
701             for (wcf_pat = 0; wcf_pat < 5; wcf_pat++) {
702                 struct test_rule *rule1, *tcls_rule1;
703                 struct test_rule *rule2, *tcls_rule2;
704                 struct classifier cls;
705                 struct tcls tcls;
706                 unsigned int pri1, pri2;
707                 int wcf1, wcf2;
708                 int value_mask, value_pat1, value_pat2;
709                 int i;
710
711                 /* We can use identical priorities in this test because the
712                  * classifier always chooses the rule added later for
713                  * equal-priority rules that fall into the same table.  */
714                 pri1 = table * 257 + 50;
715                 pri2 = pri1 + rel_pri;
716
717                 if (wcf_pat & 4) {
718                     wcf1 = wcf2 = random_wcf_in_table(table, pri1);
719                 } else {
720                     wcf1 = (wcf_pat & 1
721                             ? random_wcf_in_table(table, pri1)
722                             : 1u << table);
723                     wcf2 = (wcf_pat & 2
724                             ? random_wcf_in_table(table, pri2)
725                             : 1u << table);
726                 }
727
728                 /* Generate value patterns that will put the two rules into
729                  * different buckets. */
730                 value_mask = ((1u << table) - 1);
731                 value_pat1 = hash_int(pri1, 1) & value_mask;
732                 i = 0;
733                 do {
734                     value_pat2 = (hash_int(pri2, i++) & value_mask);
735                 } while (value_pat1 == value_pat2);
736                 rule1 = make_rule(wcf1, pri1, value_pat1);
737                 rule2 = make_rule(wcf2, pri2, value_pat2);
738
739                 classifier_init(&cls);
740                 tcls_init(&tcls);
741
742                 tcls_rule1 = tcls_insert(&tcls, rule1);
743                 tcls_rule2 = tcls_insert(&tcls, rule2);
744                 assert(!classifier_insert(&cls, &rule1->cls_rule));
745                 assert(!classifier_insert(&cls, &rule2->cls_rule));
746                 check_tables(&cls, 1, 2, 2);
747                 compare_classifiers(&cls, &tcls);
748
749                 classifier_remove(&cls, &rule1->cls_rule);
750                 tcls_remove(&tcls, tcls_rule1);
751                 check_tables(&cls, 1, 1, 1);
752                 compare_classifiers(&cls, &tcls);
753                 free(rule1);
754
755                 classifier_remove(&cls, &rule2->cls_rule);
756                 tcls_remove(&tcls, tcls_rule2);
757                 compare_classifiers(&cls, &tcls);
758                 free(rule2);
759
760                 classifier_destroy(&cls);
761                 tcls_destroy(&tcls);
762             }
763         }
764     }
765 }
766
767 /* Tests classification with two rules at a time that fall into different
768  * tables. */
769 static void
770 test_two_rules_in_different_tables(int argc OVS_UNUSED,
771                                    char *argv[] OVS_UNUSED)
772 {
773     int table1, table2, rel_pri, wcf_pat;
774
775     for (table1 = 0; table1 < CLS_N_FIELDS; table1++) {
776         for (table2 = table1 + 1; table2 <= CLS_N_FIELDS; table2++) {
777             for (rel_pri = 0; rel_pri < 2; rel_pri++) {
778                 for (wcf_pat = 0; wcf_pat < 4; wcf_pat++) {
779                     struct test_rule *rule1, *tcls_rule1;
780                     struct test_rule *rule2, *tcls_rule2;
781                     struct classifier cls;
782                     struct tcls tcls;
783                     unsigned int pri1, pri2;
784                     int wcf1, wcf2;
785
786                     /* We must use unique priorities in this test because the
787                      * classifier makes the rule choice undefined for rules of
788                      * equal priority that fall into different tables.  (In
789                      * practice, lower-numbered tables win.)  */
790                     pri1 = table1 * 257 + 50;
791                     pri2 = rel_pri ? pri1 - 1 : pri1 + 1;
792
793                     wcf1 = (wcf_pat & 1
794                             ? random_wcf_in_table(table1, pri1)
795                             : 1u << table1);
796                     wcf2 = (wcf_pat & 2
797                             ? random_wcf_in_table(table2, pri2)
798                             : 1u << table2);
799
800                     if (table2 == CLS_F_IDX_EXACT) {
801                         pri2 = UINT16_MAX;
802                         wcf2 = 0;
803                     }
804
805                     rule1 = make_rule(wcf1, pri1, 0);
806                     rule2 = make_rule(wcf2, pri2, 0);
807
808                     classifier_init(&cls);
809                     tcls_init(&tcls);
810
811                     tcls_rule1 = tcls_insert(&tcls, rule1);
812                     tcls_rule2 = tcls_insert(&tcls, rule2);
813                     assert(!classifier_insert(&cls, &rule1->cls_rule));
814                     assert(!classifier_insert(&cls, &rule2->cls_rule));
815                     check_tables(&cls, 2, 2, 2);
816                     compare_classifiers(&cls, &tcls);
817
818                     classifier_remove(&cls, &rule1->cls_rule);
819                     tcls_remove(&tcls, tcls_rule1);
820                     check_tables(&cls, 1, 1, 1);
821                     compare_classifiers(&cls, &tcls);
822                     free(rule1);
823
824                     classifier_remove(&cls, &rule2->cls_rule);
825                     tcls_remove(&tcls, tcls_rule2);
826                     compare_classifiers(&cls, &tcls);
827                     free(rule2);
828
829                     classifier_destroy(&cls);
830                     tcls_destroy(&tcls);
831                 }
832             }
833         }
834     }
835 }
836
837 /* Tests classification with many rules at a time that fall into the same
838  * bucket but have unique priorities (and various wildcards). */
839 static void
840 test_many_rules_in_one_bucket(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
841 {
842     enum { MAX_RULES = 50 };
843     int iteration, table;
844
845     for (iteration = 0; iteration < 3; iteration++) {
846         for (table = 0; table <= CLS_N_FIELDS; table++) {
847             unsigned int priorities[MAX_RULES];
848             struct classifier cls;
849             struct tcls tcls;
850             int i;
851
852             srand(hash_int(table, iteration));
853             for (i = 0; i < MAX_RULES; i++) {
854                 priorities[i] = i * 129;
855             }
856             shuffle(priorities, ARRAY_SIZE(priorities));
857
858             classifier_init(&cls);
859             tcls_init(&tcls);
860
861             for (i = 0; i < MAX_RULES; i++) {
862                 struct test_rule *rule;
863                 unsigned int priority = priorities[i];
864                 int wcf;
865
866                 wcf = random_wcf_in_table(table, priority);
867                 rule = make_rule(wcf, priority,
868                                  table == CLS_F_IDX_EXACT ? i : 1234);
869                 tcls_insert(&tcls, rule);
870                 assert(!classifier_insert(&cls, &rule->cls_rule));
871                 check_tables(&cls, 1, 1, i + 1);
872                 compare_classifiers(&cls, &tcls);
873             }
874
875             destroy_classifier(&cls);
876             tcls_destroy(&tcls);
877         }
878     }
879 }
880
881 /* Tests classification with many rules at a time that fall into the same
882  * table but random buckets. */
883 static void
884 test_many_rules_in_one_table(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
885 {
886     enum { MAX_RULES = 50 };
887     int iteration, table;
888
889     for (iteration = 0; iteration < 3; iteration++) {
890         for (table = 0; table < CLS_N_FIELDS; table++) {
891             unsigned int priorities[MAX_RULES];
892             struct classifier cls;
893             struct tcls tcls;
894             int i;
895
896             srand(hash_int(table, iteration));
897             for (i = 0; i < MAX_RULES; i++) {
898                 priorities[i] = i * 129;
899             }
900             shuffle(priorities, ARRAY_SIZE(priorities));
901
902             classifier_init(&cls);
903             tcls_init(&tcls);
904
905             for (i = 0; i < MAX_RULES; i++) {
906                 struct test_rule *rule;
907                 unsigned int priority = priorities[i];
908                 int wcf;
909
910                 wcf = random_wcf_in_table(table, priority);
911                 rule = make_rule(wcf, priority, hash_int(priority, 1));
912                 tcls_insert(&tcls, rule);
913                 assert(!classifier_insert(&cls, &rule->cls_rule));
914                 check_tables(&cls, 1, -1, i + 1);
915                 compare_classifiers(&cls, &tcls);
916             }
917
918             destroy_classifier(&cls);
919             tcls_destroy(&tcls);
920         }
921     }
922 }
923
924 /* Tests classification with many rules at a time that fall into random buckets
925  * in random tables. */
926 static void
927 test_many_rules_in_different_tables(int argc OVS_UNUSED,
928                                     char *argv[] OVS_UNUSED)
929 {
930     enum { MAX_RULES = 50 };
931     int iteration;
932
933     for (iteration = 0; iteration < 30; iteration++) {
934         unsigned int priorities[MAX_RULES];
935         struct classifier cls;
936         struct tcls tcls;
937         int i;
938
939         srand(iteration);
940         for (i = 0; i < MAX_RULES; i++) {
941             priorities[i] = i * 129;
942         }
943         shuffle(priorities, ARRAY_SIZE(priorities));
944
945         classifier_init(&cls);
946         tcls_init(&tcls);
947
948         for (i = 0; i < MAX_RULES; i++) {
949             struct test_rule *rule;
950             unsigned int priority = priorities[i];
951             int table = rand() % (CLS_N_FIELDS + 1);
952             int wcf = random_wcf_in_table(table, rand());
953             int value_pat = rand() & ((1u << CLS_N_FIELDS) - 1);
954             rule = make_rule(wcf, priority, value_pat);
955             tcls_insert(&tcls, rule);
956             assert(!classifier_insert(&cls, &rule->cls_rule));
957             check_tables(&cls, -1, -1, i + 1);
958             compare_classifiers(&cls, &tcls);
959         }
960
961         while (!classifier_is_empty(&cls)) {
962             struct test_rule *rule = xmemdup(tcls.rules[rand() % tcls.n_rules],
963                                              sizeof(struct test_rule));
964             int include = rand() % 2 ? CLS_INC_WILD : CLS_INC_EXACT;
965             include |= (rule->cls_rule.flow.wildcards
966                         ? CLS_INC_WILD : CLS_INC_EXACT);
967             classifier_for_each_match(&cls, &rule->cls_rule.flow, include,
968                                       free_rule, &cls);
969             tcls_delete_matches(&tcls, &rule->cls_rule, include);
970             compare_classifiers(&cls, &tcls);
971             free(rule);
972         }
973
974         destroy_classifier(&cls);
975         tcls_destroy(&tcls);
976     }
977 }
978 \f
979 int
980 main(int argc, char *argv[])
981 {
982     static const struct command all_commands[] = {
983         { "empty", 0, 0, test_empty },
984         { "destroy-null", 0, 0, test_destroy_null },
985         { "single-rule", 0, 0, test_single_rule },
986         { "rule-replacement", 0, 0, test_rule_replacement },
987         { "two-rules-in-one-bucket", 0, 0, test_two_rules_in_one_bucket },
988         { "two-rules-in-one-table", 0, 0, test_two_rules_in_one_table },
989         { "two-rules-in-different-tables", 0, 0,
990           test_two_rules_in_different_tables },
991         { "many-rules-in-one-bucket", 0, 0,
992           test_many_rules_in_one_bucket },
993         { "many-rules-in-one-table", 0, 0, test_many_rules_in_one_table },
994         { "many-rules-in-different-tables", 0, 0,
995           test_many_rules_in_different_tables },
996         { NULL, 0, 0, NULL },
997     };
998
999     set_program_name(argv[0]);
1000     init_values();
1001     parse_test_options(argc, argv, all_commands);
1002     run_command(argc - 1, argv + 1, all_commands);
1003     return 0;
1004 }