[ovs-dev] [PATCH 11/12] lib/classifier: RCUify prefix trie code.

Jarno Rajahalme jrajahalme at nicira.com
Mon Jun 30 15:17:27 UTC 2014


cls_set_prefix_fields() now synchronizes explicitly with the readers,
waiting them to finish using the old configuration before changing to
the new configuration.

Signed-off-by: Jarno Rajahalme <jrajahalme at nicira.com>
---
 lib/classifier.c        |  214 +++++++++++++++++++++++++++++++++--------------
 lib/classifier.h        |    2 +-
 ofproto/ofproto.c       |    6 +-
 tests/test-classifier.c |   65 +++++++++++---
 4 files changed, 208 insertions(+), 79 deletions(-)

diff --git a/lib/classifier.c b/lib/classifier.c
index 8698561..65beaf6 100644
--- a/lib/classifier.c
+++ b/lib/classifier.c
@@ -42,10 +42,12 @@ struct trie_ctx;
 #define TP_PORTS_OFS32 (offsetof(struct flow, tp_src) / 4)
 BUILD_ASSERT_DECL(TP_PORTS_OFS32 == offsetof(struct flow, tp_dst) / 4);
 
+typedef OVSRCU_TYPE(struct trie_node *) rcu_trie_ptr;
+
 /* Prefix trie for a 'field' */
 struct cls_trie {
     const struct mf_field *field; /* Trie field, or NULL. */
-    struct trie_node *root;       /* NULL if none. */
+    rcu_trie_ptr root;            /* NULL if none. */
 };
 
 enum {
@@ -86,7 +88,7 @@ struct cls_subtable {
                                              * (runtime configurable). */
     int ports_mask_len;                     /* (const) */
     struct cmap indices[CLS_MAX_INDICES];   /* Staged lookup indices. */
-    struct trie_node *ports_trie;           /* NULL if none. */
+    rcu_trie_ptr ports_trie;                /* NULL if none. */
 
     /* These fields are accessed by all readers. */
     struct cmap rules;                      /* Contains "struct cls_rule"s. */
@@ -180,16 +182,16 @@ static void trie_init(struct cls_classifier *cls, int trie_idx,
     OVS_REQUIRES(cls->mutex);
 static unsigned int trie_lookup(const struct cls_trie *, const struct flow *,
                                 unsigned int *checkbits);
-static unsigned int trie_lookup_value(const struct trie_node *,
+static unsigned int trie_lookup_value(const rcu_trie_ptr *,
                                       const ovs_be32 value[],
                                       unsigned int value_bits,
                                       unsigned int *checkbits);
-static void trie_destroy(struct trie_node *);
+static void trie_destroy(rcu_trie_ptr *);
 static void trie_insert(struct cls_trie *, const struct cls_rule *, int mlen);
-static void trie_insert_prefix(struct trie_node **, const ovs_be32 *prefix,
+static void trie_insert_prefix(rcu_trie_ptr *, const ovs_be32 *prefix,
                                int mlen);
 static void trie_remove(struct cls_trie *, const struct cls_rule *, int mlen);
-static void trie_remove_prefix(struct trie_node **, const ovs_be32 *prefix,
+static void trie_remove_prefix(rcu_trie_ptr *, const ovs_be32 *prefix,
                                int mlen);
 static void mask_set_prefix_bits(struct flow_wildcards *, uint8_t be32ofs,
                                  unsigned int n_bits);
@@ -522,7 +524,7 @@ classifier_destroy(struct classifier *cls_)
 
         ovs_mutex_lock(&cls->mutex);
         for (i = 0; i < cls->n_tries; i++) {
-            trie_destroy(cls->tries[i].root);
+            trie_destroy(&cls->tries[i].root);
         }
 
         CMAP_FOR_EACH_SAFE (subtable, next_subtable, cmap_node,
@@ -548,7 +550,7 @@ classifier_destroy(struct classifier *cls_)
 BUILD_ASSERT_DECL(MFF_N_IDS <= 64);
 
 /* Set the fields for which prefix lookup should be performed. */
-void
+bool
 classifier_set_prefix_fields(struct classifier *cls_,
                              const enum mf_field_id *trie_fields,
                              unsigned int n_fields)
@@ -556,10 +558,12 @@ classifier_set_prefix_fields(struct classifier *cls_,
 {
     struct cls_classifier *cls = cls_->cls;
     uint64_t fields = 0;
-    int i, trie;
+    const struct mf_field * new_fields[CLS_MAX_TRIES];
+    int i, n_tries = 0;
+    bool changed = false;
 
     ovs_mutex_lock(&cls->mutex);
-    for (i = 0, trie = 0; i < n_fields && trie < CLS_MAX_TRIES; i++) {
+    for (i = 0; i < n_fields && n_tries < 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
@@ -576,18 +580,57 @@ classifier_set_prefix_fields(struct classifier *cls_,
         }
         fields |= UINT64_C(1) << trie_fields[i];
 
-        if (trie >= cls->n_tries || field != cls->tries[trie].field) {
-            trie_init(cls, trie, field);
+        new_fields[n_tries] = NULL;
+        if (n_tries >= cls->n_tries || field != cls->tries[n_tries].field) {
+            new_fields[n_tries] = field;
+            changed = true;
+        }
+        n_tries++;
+    }
+
+    if (changed || n_tries < cls->n_tries) {
+        struct cls_subtable *subtable;
+
+        /* Trie configuration needs to change.  Disable trie lookups
+         * for the tries that are changing and wait all the current readers
+         * with the old configuration to be done. */
+        changed = false;
+        CMAP_FOR_EACH (subtable, cmap_node, &cls->subtables_map) {
+            for (i = 0; i < cls->n_tries; i++) {
+                if ((i < n_tries && new_fields[i]) || i >= n_tries) {
+                    if (subtable->trie_plen[i]) {
+                        subtable->trie_plen[i] = 0;
+                        changed = true;
+                    }
+                }
+            }
+        }
+        /* Synchronize if any readers were using tries.  The readers may
+         * temporarily function without the trie lookup based optimizations. */
+        if (changed) {
+            /* ovsrcu_synchronize() functions as a memory barrier, so it does
+             * not matter that subtable->trie_plen is not atomic. */
+            ovsrcu_synchronize();
         }
-        trie++;
-    }
 
-    /* Destroy the rest. */
-    for (i = trie; i < cls->n_tries; i++) {
-        trie_init(cls, i, NULL);
+        /* Now set up the tries. */
+        for (i = 0; i < n_tries; i++) {
+            if (new_fields[i]) {
+                trie_init(cls, i, new_fields[i]);
+            }
+        }
+        /* Destroy the rest, if any. */
+        for (; i < cls->n_tries; i++) {
+            trie_init(cls, i, NULL);
+        }
+
+        cls->n_tries = n_tries;
+        ovs_mutex_unlock(&cls->mutex);
+        return true;
     }
-    cls->n_tries = trie;
+
     ovs_mutex_unlock(&cls->mutex);
+    return false; /* No change. */
 }
 
 static void
@@ -599,19 +642,17 @@ trie_init(struct cls_classifier *cls, int trie_idx,
     struct cls_subtable *subtable;
 
     if (trie_idx < cls->n_tries) {
-        trie_destroy(trie->root);
+        trie_destroy(&trie->root);
+    } else {
+        ovsrcu_set_hidden(&trie->root, NULL);
     }
-    trie->root = NULL;
     trie->field = field;
 
-    /* Add existing rules to the trie. */
+    /* Add existing rules to the new trie. */
     CMAP_FOR_EACH (subtable, cmap_node, &cls->subtables_map) {
         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;
 
@@ -623,6 +664,10 @@ trie_init(struct cls_classifier *cls, int trie_idx,
                 }
             }
         }
+        /* Initialize subtable's prefix length on this field.  This will
+         * allow readers to use the trie. */
+        atomic_thread_fence(memory_order_release);
+        subtable->trie_plen[trie_idx] = plen;
     }
 }
 
@@ -908,6 +953,11 @@ classifier_lookup(const struct classifier *cls_, const struct flow *flow,
     struct trie_ctx trie_ctx[CLS_MAX_TRIES];
     struct cls_subtable *subtable;
 
+    /* Synchronize for cls->n_tries and subtable->trie_plen.  They can change
+     * when table configuration changes, which happens typically only on
+     * startup. */
+    atomic_thread_fence(memory_order_acquire);
+
     /* Determine 'tags' such that, if 'subtable->tag' doesn't intersect them,
      * then 'flow' cannot possibly match in 'subtable':
      *
@@ -1360,7 +1410,7 @@ insert_subtable(struct cls_classifier *cls, const struct minimask *mask)
     }
 
     /* Ports trie. */
-    subtable->ports_trie = NULL;
+    ovsrcu_set_hidden(&subtable->ports_trie, NULL);
     subtable->ports_mask_len
         = 32 - ctz32(ntohl(MINIFLOW_GET_BE32(&mask->masks, tp_src)));
 
@@ -1376,7 +1426,7 @@ destroy_subtable(struct cls_classifier *cls, struct cls_subtable *subtable)
     int i;
 
     pvector_remove(&cls->subtables, subtable);
-    trie_destroy(subtable->ports_trie);
+    trie_destroy(&subtable->ports_trie);
 
     for (i = 0; i < subtable->n_indices; i++) {
         cmap_destroy(&subtable->indices[i]);
@@ -1616,7 +1666,7 @@ find_match_wc(const struct cls_subtable *subtable, const struct flow *flow,
 
         mask = MINIFLOW_GET_BE32(&subtable->mask.masks, tp_src);
         value = ((OVS_FORCE ovs_be32 *)flow)[TP_PORTS_OFS32] & mask;
-        trie_lookup_value(subtable->ports_trie, &value, 32, &mbits);
+        trie_lookup_value(&subtable->ports_trie, &value, 32, &mbits);
 
         ((OVS_FORCE ovs_be32 *)&wc->masks)[TP_PORTS_OFS32] |=
             mask & htonl(~0 << (32 - mbits));
@@ -1745,7 +1795,7 @@ struct trie_node {
     uint32_t prefix;           /* Prefix bits for this node, MSB first. */
     uint8_t  n_bits;           /* Never zero, except for the root node. */
     unsigned int n_rules;      /* Number of rules that have this prefix. */
-    struct trie_node *edges[2]; /* Both NULL if leaf. */
+    rcu_trie_ptr edges[2];     /* Both NULL if leaf. */
 };
 
 /* Max bits per node.  Must fit in struct trie_node's 'prefix'.
@@ -1838,8 +1888,8 @@ trie_branch_create(const ovs_be32 *prefix, unsigned int ofs, unsigned int plen,
 
     if (plen <= TRIE_PREFIX_BITS) {
         node->n_bits = plen;
-        node->edges[0] = NULL;
-        node->edges[1] = NULL;
+        ovsrcu_set_hidden(&node->edges[0], NULL);
+        ovsrcu_set_hidden(&node->edges[1], NULL);
         node->n_rules = n_rules;
     } else { /* Need intermediate nodes. */
         struct trie_node *subnode = trie_branch_create(prefix,
@@ -1848,33 +1898,51 @@ trie_branch_create(const ovs_be32 *prefix, unsigned int ofs, unsigned int plen,
                                                        n_rules);
         int bit = get_bit_at(subnode->prefix, 0);
         node->n_bits = TRIE_PREFIX_BITS;
-        node->edges[bit] = subnode;
-        node->edges[!bit] = NULL;
+        ovsrcu_set_hidden(&node->edges[bit], subnode);
+        ovsrcu_set_hidden(&node->edges[!bit], NULL);
         node->n_rules = 0;
     }
     return node;
 }
 
 static void
-trie_node_destroy(struct trie_node *node)
+trie_node_destroy(const struct trie_node *node)
 {
-    free(node);
+    ovsrcu_postpone(free, CONST_CAST(struct trie_node *, node));
+}
+
+/* Copy a trie node for modification and postpone delete the old one. */
+static struct trie_node *
+trie_node_rcu_realloc(const struct trie_node *node)
+{
+    struct trie_node *new_node = xmalloc(sizeof *node);
+
+    *new_node = *node;
+    trie_node_destroy(node);
+
+    return new_node;
 }
 
+/* May only be called while holding the cls_classifier mutex. */
 static void
-trie_destroy(struct trie_node *node)
+trie_destroy(rcu_trie_ptr *trie)
 {
+    struct trie_node *node = ovsrcu_get_protected(struct trie_node *, trie);
+
     if (node) {
-        trie_destroy(node->edges[0]);
-        trie_destroy(node->edges[1]);
-        free(node);
+        ovsrcu_set_hidden(trie, NULL);
+        trie_destroy(&node->edges[0]);
+        trie_destroy(&node->edges[1]);
+        trie_node_destroy(node);
     }
 }
 
 static bool
 trie_is_leaf(const struct trie_node *trie)
 {
-    return !trie->edges[0] && !trie->edges[1]; /* No children. */
+    /* No children? */
+    return !ovsrcu_get(struct trie_node *, &trie->edges[0])
+        && !ovsrcu_get(struct trie_node *, &trie->edges[1]);
 }
 
 static void
@@ -1910,7 +1978,7 @@ mask_prefix_bits_set(const struct flow_wildcards *wc, uint8_t be32ofs,
     return !zeroes; /* All 'n_bits' bits set. */
 }
 
-static struct trie_node **
+static rcu_trie_ptr *
 trie_next_edge(struct trie_node *node, const ovs_be32 value[],
                unsigned int ofs)
 {
@@ -1921,7 +1989,8 @@ static const struct trie_node *
 trie_next_node(const struct trie_node *node, const ovs_be32 value[],
                unsigned int ofs)
 {
-    return node->edges[be_get_bit_at(value, ofs)];
+    return ovsrcu_get(struct trie_node *,
+                      &node->edges[be_get_bit_at(value, ofs)]);
 }
 
 /* Return the prefix mask length necessary to find the longest-prefix match for
@@ -1931,9 +2000,10 @@ trie_next_node(const struct trie_node *node, const ovs_be32 value[],
  * the one that matched.
  */
 static unsigned int
-trie_lookup_value(const struct trie_node *node, const ovs_be32 value[],
+trie_lookup_value(const rcu_trie_ptr *trie, const ovs_be32 value[],
                   unsigned int n_bits, unsigned int *checkbits)
 {
+    const struct trie_node *node = ovsrcu_get(struct trie_node *, trie);
     unsigned int ofs = 0, match_len = 0;
     const struct trie_node *prev = NULL;
 
@@ -1972,7 +2042,7 @@ trie_lookup(const struct cls_trie *trie, const struct flow *flow,
      * field.  Some match fields are used for multiple purposes, so we
      * must check that the trie is relevant for this flow. */
     if (mf_are_prereqs_ok(mf, flow)) {
-        return trie_lookup_value(trie->root,
+        return trie_lookup_value(&trie->root,
                                  &((ovs_be32 *)flow)[mf->flow_be32ofs],
                                  mf->n_bits, checkbits);
     }
@@ -2036,34 +2106,37 @@ trie_insert(struct cls_trie *trie, const struct cls_rule *rule, int mlen)
 }
 
 static void
-trie_insert_prefix(struct trie_node **edge, const ovs_be32 *prefix, int mlen)
+trie_insert_prefix(rcu_trie_ptr *edge, const ovs_be32 *prefix, int mlen)
 {
     struct trie_node *node;
     int ofs = 0;
 
     /* Walk the tree. */
-    for (; (node = *edge) != NULL;
+    for (; (node = ovsrcu_get_protected(struct trie_node *, edge));
          edge = trie_next_edge(node, prefix, ofs)) {
         unsigned int eqbits = trie_prefix_equal_bits(node, prefix, ofs, mlen);
         ofs += eqbits;
         if (eqbits < node->n_bits) {
             /* Mismatch, new node needs to be inserted above. */
             int old_branch = get_bit_at(node->prefix, eqbits);
+            struct trie_node *new_parent;
 
-            /* New parent node. */
-            *edge = trie_branch_create(prefix, ofs - eqbits, eqbits,
-                                       ofs == mlen ? 1 : 0);
-
-            /* Adjust old node for its new position in the tree. */
+            new_parent = trie_branch_create(prefix, ofs - eqbits, eqbits,
+                                            ofs == mlen ? 1 : 0);
+            /* Copy the node to modify it. */
+            node = trie_node_rcu_realloc(node);
+            /* Adjust the new node for its new position in the tree. */
             node->prefix <<= eqbits;
             node->n_bits -= eqbits;
-            (*edge)->edges[old_branch] = node;
+            ovsrcu_set_hidden(&new_parent->edges[old_branch], node);
 
             /* Check if need a new branch for the new rule. */
             if (ofs < mlen) {
-                (*edge)->edges[!old_branch]
-                    = trie_branch_create(prefix, ofs, mlen - ofs, 1);
+                ovsrcu_set_hidden(&new_parent->edges[!old_branch],
+                                  trie_branch_create(prefix, ofs, mlen - ofs,
+                                                     1));
             }
+            ovsrcu_set(edge, new_parent); /* Publish changes. */
             return;
         }
         /* Full match so far. */
@@ -2075,7 +2148,7 @@ trie_insert_prefix(struct trie_node **edge, const ovs_be32 *prefix, int mlen)
         }
     }
     /* Must insert a new tree branch for the new rule. */
-    *edge = trie_branch_create(prefix, ofs, mlen - ofs, 1);
+    ovsrcu_set(edge, trie_branch_create(prefix, ofs, mlen - ofs, 1));
 }
 
 /* 'mlen' must be the (non-zero) CIDR prefix length of the 'trie->field' mask
@@ -2090,15 +2163,15 @@ trie_remove(struct cls_trie *trie, const struct cls_rule *rule, int mlen)
 /* 'mlen' must be the (non-zero) CIDR prefix length of the 'trie->field' mask
  * in 'rule'. */
 static void
-trie_remove_prefix(struct trie_node **root, const ovs_be32 *prefix, int mlen)
+trie_remove_prefix(rcu_trie_ptr *root, const ovs_be32 *prefix, int mlen)
 {
     struct trie_node *node;
-    struct trie_node **edges[sizeof(union mf_value) * 8];
+    rcu_trie_ptr *edges[sizeof(union mf_value) * 8];
     int depth = 0, ofs = 0;
 
     /* Walk the tree. */
     for (edges[0] = root;
-         (node = *edges[depth]) != NULL;
+         (node = ovsrcu_get_protected(struct trie_node *, edges[depth]));
          edges[++depth] = trie_next_edge(node, prefix, ofs)) {
         unsigned int eqbits = trie_prefix_equal_bits(node, prefix, ofs, mlen);
 
@@ -2118,27 +2191,40 @@ trie_remove_prefix(struct trie_node **root, const ovs_be32 *prefix, int mlen)
             node->n_rules--;
 
             /* Check if can prune the tree. */
-            while (!node->n_rules && !(node->edges[0] && node->edges[1])) {
-                /* No rules and at most one child node, remove this node. */
-                struct trie_node *next;
-                next = node->edges[0] ? node->edges[0] : node->edges[1];
+            while (!node->n_rules) {
+                struct trie_node *next,
+                    *edge0 = ovsrcu_get_protected(struct trie_node *,
+                                                  &node->edges[0]),
+                    *edge1 = ovsrcu_get_protected(struct trie_node *,
+                                                  &node->edges[1]);
+
+                if (edge0 && edge1) {
+                    break; /* A branching point, cannot prune. */
+                }
+
+                /* Else have at most one child node, remove this node. */
+                next = edge0 ? edge0 : edge1;
 
                 if (next) {
                     if (node->n_bits + next->n_bits > TRIE_PREFIX_BITS) {
                         break;   /* Cannot combine. */
                     }
+                    next = trie_node_rcu_realloc(next); /* Modify. */
+
                     /* Combine node with next. */
                     next->prefix = node->prefix | next->prefix >> node->n_bits;
                     next->n_bits += node->n_bits;
                 }
-                trie_node_destroy(node);
                 /* Update the parent's edge. */
-                *edges[depth] = next;
+                ovsrcu_set(edges[depth], next); /* Publish changes. */
+                trie_node_destroy(node);
+
                 if (next || !depth) {
                     /* Branch not pruned or at root, nothing more to do. */
                     break;
                 }
-                node = *edges[--depth];
+                node = ovsrcu_get_protected(struct trie_node *,
+                                            edges[--depth]);
             }
             return;
         }
diff --git a/lib/classifier.h b/lib/classifier.h
index 3f7fb3d..9f61ad5 100644
--- a/lib/classifier.h
+++ b/lib/classifier.h
@@ -268,7 +268,7 @@ bool cls_rule_is_loose_match(const struct cls_rule *rule,
 
 void classifier_init(struct classifier *cls, const uint8_t *flow_segments);
 void classifier_destroy(struct classifier *);
-void classifier_set_prefix_fields(struct classifier *cls,
+bool classifier_set_prefix_fields(struct classifier *cls,
                                   const enum mf_field_id *trie_fields,
                                   unsigned int n_trie_fields)
     OVS_REQ_WRLOCK(cls->rwlock);
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 6bc5614..b020379 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -1215,8 +1215,10 @@ ofproto_configure_table(struct ofproto *ofproto, int table_id,
 
     table->max_flows = s->max_flows;
     fat_rwlock_wrlock(&table->cls.rwlock);
-    classifier_set_prefix_fields(&table->cls,
-                                 s->prefix_fields, s->n_prefix_fields);
+    if (classifier_set_prefix_fields(&table->cls,
+                                     s->prefix_fields, s->n_prefix_fields)) {
+        /* XXX: Trigger revalidation. */
+    }
     fat_rwlock_unlock(&table->cls.rwlock);
 
     ovs_mutex_lock(&ofproto_mutex);
diff --git a/tests/test-classifier.c b/tests/test-classifier.c
index 130f867..c63b7dc 100644
--- a/tests/test-classifier.c
+++ b/tests/test-classifier.c
@@ -480,6 +480,39 @@ pvector_verify(struct pvector *pvec)
     }
 }
 
+static unsigned int
+trie_verify(const rcu_trie_ptr *trie, unsigned int ofs, unsigned int n_bits)
+{
+    const struct trie_node *node = ovsrcu_get(struct trie_node *, trie);
+
+    if (node) {
+        assert(node->n_rules == 0 || node->n_bits > 0);
+        ofs += node->n_bits;
+        assert((ofs > 0 || (ofs == 0 && node->n_bits == 0)) && ofs <= n_bits);
+
+        return node->n_rules
+            + trie_verify(&node->edges[0], ofs, n_bits)
+            + trie_verify(&node->edges[1], ofs, n_bits);
+    }
+    return 0;
+}
+
+static void
+verify_tries(struct classifier *cls_)
+{
+    struct cls_classifier *cls = cls_->cls;
+    unsigned int n_rules = 0;
+    int i;
+
+    for (i = 0; i < cls->n_tries; i++) {
+        n_rules += trie_verify(&cls->tries[i].root, 0,
+                               cls->tries[i].field->n_bits);
+    }
+    ovs_mutex_lock(&cls->mutex);
+    assert(n_rules <= cls->n_rules);
+    ovs_mutex_unlock(&cls->mutex);
+}
+
 static void
 check_tables(const struct classifier *cls, int n_tables, int n_rules,
              int n_dups) OVS_EXCLUDED(cls->rwlock)
@@ -492,7 +525,6 @@ check_tables(const struct classifier *cls, int n_tables, int n_rules,
     int found_rules2 = 0;
 
     pvector_verify(&cls->cls->subtables);
-
     CMAP_FOR_EACH (table, cmap_node, &cls->cls->subtables_map) {
         const struct cls_match *head;
         unsigned int max_priority = 0;
@@ -516,6 +548,11 @@ check_tables(const struct classifier *cls, int n_tables, int n_rules,
 
         assert(!cmap_is_empty(&table->rules));
 
+        ovs_mutex_lock(&cls->cls->mutex);
+        assert(trie_verify(&table->ports_trie, 0, table->ports_mask_len)
+               == (table->ports_mask_len ? table->n_rules : 0));
+        ovs_mutex_unlock(&cls->cls->mutex);
+
         found_tables++;
         CMAP_FOR_EACH (head, cmap_node, &table->rules) {
             unsigned int prev_priority = UINT_MAX;
@@ -658,6 +695,15 @@ static enum mf_field_id trie_fields[2] = {
     MFF_IPV4_DST, MFF_IPV4_SRC
 };
 
+static void
+set_prefix_fields(struct classifier *cls)
+    OVS_REQ_WRLOCK(cls->rwlock)
+{
+    verify_tries(cls);
+    classifier_set_prefix_fields(cls, trie_fields, ARRAY_SIZE(trie_fields));
+    verify_tries(cls);
+}
+
 /* Tests an empty classifier. */
 static void
 test_empty(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
@@ -667,7 +713,7 @@ test_empty(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 
     classifier_init(&cls, flow_segment_u32s);
     fat_rwlock_wrlock(&cls.rwlock);
-    classifier_set_prefix_fields(&cls, trie_fields, ARRAY_SIZE(trie_fields));
+    set_prefix_fields(&cls);
     tcls_init(&tcls);
     assert(classifier_is_empty(&cls));
     assert(tcls_is_empty(&tcls));
@@ -700,8 +746,7 @@ test_single_rule(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 
         classifier_init(&cls, flow_segment_u32s);
         fat_rwlock_wrlock(&cls.rwlock);
-        classifier_set_prefix_fields(&cls, trie_fields,
-                                     ARRAY_SIZE(trie_fields));
+        set_prefix_fields(&cls);
         tcls_init(&tcls);
 
         tcls_rule = tcls_insert(&tcls, rule);
@@ -743,8 +788,7 @@ test_rule_replacement(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 
         classifier_init(&cls, flow_segment_u32s);
         fat_rwlock_wrlock(&cls.rwlock);
-        classifier_set_prefix_fields(&cls, trie_fields,
-                                     ARRAY_SIZE(trie_fields));
+        set_prefix_fields(&cls);
         tcls_init(&tcls);
         tcls_insert(&tcls, rule1);
         classifier_insert(&cls, &rule1->cls_rule);
@@ -861,8 +905,7 @@ test_many_rules_in_one_list (int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 
             classifier_init(&cls, flow_segment_u32s);
             fat_rwlock_wrlock(&cls.rwlock);
-            classifier_set_prefix_fields(&cls, trie_fields,
-                                         ARRAY_SIZE(trie_fields));
+            set_prefix_fields(&cls);
             fat_rwlock_unlock(&cls.rwlock);
             tcls_init(&tcls);
 
@@ -970,8 +1013,7 @@ test_many_rules_in_one_table(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 
         classifier_init(&cls, flow_segment_u32s);
         fat_rwlock_wrlock(&cls.rwlock);
-        classifier_set_prefix_fields(&cls, trie_fields,
-                                     ARRAY_SIZE(trie_fields));
+        set_prefix_fields(&cls);
         fat_rwlock_unlock(&cls.rwlock);
         tcls_init(&tcls);
 
@@ -1039,8 +1081,7 @@ test_many_rules_in_n_tables(int n_tables)
 
         classifier_init(&cls, flow_segment_u32s);
         fat_rwlock_wrlock(&cls.rwlock);
-        classifier_set_prefix_fields(&cls, trie_fields,
-                                     ARRAY_SIZE(trie_fields));
+        set_prefix_fields(&cls);
         fat_rwlock_unlock(&cls.rwlock);
         tcls_init(&tcls);
 
-- 
1.7.10.4




More information about the dev mailing list