+ HMAP_FOR_EACH_SAFE (subtable, next_subtable, hmap_node,
+ &cls->subtables) {
+ destroy_subtable(cls, subtable);
+ }
+ hmap_destroy(&cls->subtables);
+
+ HMAP_FOR_EACH_SAFE (partition, next_partition, hmap_node,
+ &cls->partitions) {
+ hmap_remove(&cls->partitions, &partition->hmap_node);
+ free(partition);
+ }
+ hmap_destroy(&cls->partitions);
+
+ cls_subtable_cache_destroy(&cls->subtables_priority);
+ free(cls);
+ }
+}
+
+/* We use uint64_t as a set for the fields below. */
+BUILD_ASSERT_DECL(MFF_N_IDS <= 64);
+
+/* Set the fields for which prefix lookup should be performed. */
+void
+classifier_set_prefix_fields(struct classifier *cls_,
+ const enum mf_field_id *trie_fields,
+ unsigned int n_fields)
+{
+ struct cls_classifier *cls = cls_->cls;
+ uint64_t fields = 0;
+ int i, trie;
+
+ for (i = 0, trie = 0; i < n_fields && trie < CLS_MAX_TRIES; i++) {
+ const struct mf_field *field = mf_from_id(trie_fields[i]);
+ if (field->flow_be32ofs < 0 || field->n_bits % 32) {
+ /* Incompatible field. This is the only place where we
+ * enforce these requirements, but the rest of the trie code
+ * depends on the flow_be32ofs to be non-negative and the
+ * field length to be a multiple of 32 bits. */
+ continue;
+ }
+
+ if (fields & (UINT64_C(1) << trie_fields[i])) {
+ /* Duplicate field, there is no need to build more than
+ * one index for any one field. */
+ continue;
+ }
+ fields |= UINT64_C(1) << trie_fields[i];
+
+ if (trie >= cls->n_tries || field != cls->tries[trie].field) {
+ trie_init(cls, trie, field);
+ }
+ trie++;
+ }
+
+ /* Destroy the rest. */
+ for (i = trie; i < cls->n_tries; i++) {
+ trie_init(cls, i, NULL);
+ }
+ cls->n_tries = trie;
+}
+
+static void
+trie_init(struct cls_classifier *cls, int trie_idx,
+ const struct mf_field *field)
+{
+ struct cls_trie *trie = &cls->tries[trie_idx];
+ struct cls_subtable *subtable;
+ struct cls_subtable_entry *iter;
+
+ if (trie_idx < cls->n_tries) {
+ trie_destroy(trie->root);
+ }
+ trie->root = NULL;
+ trie->field = field;
+
+ /* Add existing rules to the trie. */
+ CLS_SUBTABLE_CACHE_FOR_EACH (subtable, iter, &cls->subtables_priority) {
+ unsigned int plen;
+
+ plen = field ? minimask_get_prefix_len(&subtable->mask, field) : 0;
+ /* Initialize subtable's prefix length on this field. */
+ subtable->trie_plen[trie_idx] = plen;
+
+ if (plen) {
+ struct cls_match *head;
+
+ HMAP_FOR_EACH (head, hmap_node, &subtable->rules) {
+ struct cls_match *match;
+
+ FOR_EACH_RULE_IN_LIST (match, head) {
+ trie_insert(trie, match->cls_rule, plen);
+ }
+ }