+ struct flow flow;
+ unsigned int idx;
+
+ random_set_seed(0xb3faca38);
+ for (idx = 0; next_random_flow(&flow, idx); idx++) {
+ const uint32_t *flow_u32 = (const uint32_t *) &flow;
+ struct miniflow miniflow, miniflow2, miniflow3;
+ struct flow flow2, flow3;
+ struct flow_wildcards mask;
+ struct minimask minimask;
+ int i;
+
+ /* Convert flow to miniflow. */
+ miniflow_init(&miniflow, &flow);
+
+ /* Check that the flow equals its miniflow. */
+ assert(miniflow_get_vid(&miniflow) == vlan_tci_to_vid(flow.vlan_tci));
+ for (i = 0; i < FLOW_U32S; i++) {
+ assert(miniflow_get_u32(&miniflow, i * 4) == flow_u32[i]);
+ }
+
+ /* Check that the miniflow equals itself. */
+ assert(miniflow_equal(&miniflow, &miniflow));
+
+ /* Convert miniflow back to flow and verify that it's the same. */
+ miniflow_expand(&miniflow, &flow2);
+ assert(flow_equal(&flow, &flow2));
+
+ /* Check that copying a miniflow works properly. */
+ miniflow_clone(&miniflow2, &miniflow);
+ assert(miniflow_equal(&miniflow, &miniflow2));
+ assert(miniflow_hash(&miniflow, 0) == miniflow_hash(&miniflow2, 0));
+ miniflow_expand(&miniflow2, &flow3);
+ assert(flow_equal(&flow, &flow3));
+
+ /* Check that masked matches work as expected for identical flows and
+ * miniflows. */
+ do {
+ next_random_flow(&mask.masks, 1);
+ } while (flow_wildcards_is_catchall(&mask));
+ minimask_init(&minimask, &mask);
+ assert(minimask_is_catchall(&minimask)
+ == flow_wildcards_is_catchall(&mask));
+ assert(miniflow_equal_in_minimask(&miniflow, &miniflow2, &minimask));
+ assert(miniflow_equal_flow_in_minimask(&miniflow, &flow2, &minimask));
+ assert(miniflow_hash_in_minimask(&miniflow, &minimask, 0x12345678) ==
+ flow_hash_in_minimask(&flow, &minimask, 0x12345678));
+
+ /* Check that masked matches work as expected for differing flows and
+ * miniflows. */
+ toggle_masked_flow_bits(&flow2, &mask);
+ assert(!miniflow_equal_flow_in_minimask(&miniflow, &flow2, &minimask));
+ miniflow_init(&miniflow3, &flow2);
+ assert(!miniflow_equal_in_minimask(&miniflow, &miniflow3, &minimask));
+
+ /* Clean up. */
+ miniflow_destroy(&miniflow);
+ miniflow_destroy(&miniflow2);
+ miniflow_destroy(&miniflow3);
+ minimask_destroy(&minimask);
+ }
+}
+
+static void
+test_minimask_has_extra(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+{
+ struct flow_wildcards catchall;
+ struct minimask minicatchall;
+ struct flow flow;
+ unsigned int idx;
+
+ flow_wildcards_init_catchall(&catchall);
+ minimask_init(&minicatchall, &catchall);
+ assert(minimask_is_catchall(&minicatchall));
+
+ random_set_seed(0x2ec7905b);
+ for (idx = 0; next_random_flow(&flow, idx); idx++) {
+ struct flow_wildcards mask;
+ struct minimask minimask;
+
+ mask.masks = flow;
+ minimask_init(&minimask, &mask);
+ assert(!minimask_has_extra(&minimask, &minimask));
+ assert(minimask_has_extra(&minicatchall, &minimask)
+ == !minimask_is_catchall(&minimask));
+ if (!minimask_is_catchall(&minimask)) {
+ struct minimask minimask2;
+
+ wildcard_extra_bits(&mask);
+ minimask_init(&minimask2, &mask);
+ assert(minimask_has_extra(&minimask2, &minimask));
+ assert(!minimask_has_extra(&minimask, &minimask2));
+ minimask_destroy(&minimask2);
+ }
+
+ minimask_destroy(&minimask);
+ }
+
+ minimask_destroy(&minicatchall);
+}
+
+static void
+test_minimask_combine(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+{
+ struct flow_wildcards catchall;
+ struct minimask minicatchall;
+ struct flow flow;
+ unsigned int idx;
+
+ flow_wildcards_init_catchall(&catchall);
+ minimask_init(&minicatchall, &catchall);
+ assert(minimask_is_catchall(&minicatchall));
+
+ random_set_seed(0x181bf0cd);
+ for (idx = 0; next_random_flow(&flow, idx); idx++) {
+ struct minimask minimask, minimask2, minicombined;
+ struct flow_wildcards mask, mask2, combined, combined2;
+ uint32_t storage[FLOW_U32S];
+ struct flow flow2;
+
+ mask.masks = flow;
+ minimask_init(&minimask, &mask);
+
+ minimask_combine(&minicombined, &minimask, &minicatchall, storage);
+ assert(minimask_is_catchall(&minicombined));
+
+ any_random_flow(&flow2);
+ mask2.masks = flow2;
+ minimask_init(&minimask2, &mask2);
+
+ minimask_combine(&minicombined, &minimask, &minimask2, storage);
+ flow_wildcards_and(&combined, &mask, &mask2);
+ minimask_expand(&minicombined, &combined2);
+ assert(flow_wildcards_equal(&combined, &combined2));
+
+ minimask_destroy(&minimask);
+ minimask_destroy(&minimask2);
+ }
+
+ minimask_destroy(&minicatchall);
+}
+\f
+static const struct command commands[] = {
+ /* Classifier tests. */
+ {"empty", 0, 0, test_empty},
+ {"destroy-null", 0, 0, test_destroy_null},
+ {"single-rule", 0, 0, test_single_rule},
+ {"rule-replacement", 0, 0, test_rule_replacement},
+ {"many-rules-in-one-list", 0, 0, test_many_rules_in_one_list},
+ {"many-rules-in-one-table", 0, 0, test_many_rules_in_one_table},
+ {"many-rules-in-two-tables", 0, 0, test_many_rules_in_two_tables},
+ {"many-rules-in-five-tables", 0, 0, test_many_rules_in_five_tables},
+
+ /* Miniflow and minimask tests. */
+ {"miniflow", 0, 0, test_miniflow},
+ {"minimask_has_extra", 0, 0, test_minimask_has_extra},
+ {"minimask_combine", 0, 0, test_minimask_combine},
+
+ {NULL, 0, 0, NULL},
+};
+
+static void
+test_classifier_main(int argc, char *argv[])
+{
+ set_program_name(argv[0]);