struct field_array is included in each ofgroup, but the current
implementation is very sparse, using more than 20kb of data.

Also loop over 1-bits instead of each and every MF type to make
processing faster.

Signed-off-by: Jarno Rajahalme <ja...@ovn.org>
---
 include/openvswitch/meta-flow.h |  6 ++++--
 include/openvswitch/ofp-util.h  |  3 +++
 lib/meta-flow.c                 | 23 +++++++++++++++++++-
 lib/nx-match.c                  | 32 ++++++++++++++++-----------
 lib/ofp-util.c                  | 16 ++++++++++++++
 ofproto/ofproto-dpif-xlate.c    | 48 +++++++++++++++++++++--------------------
 ofproto/ofproto.c               |  9 ++++++--
 7 files changed, 96 insertions(+), 41 deletions(-)

diff --git a/include/openvswitch/meta-flow.h b/include/openvswitch/meta-flow.h
index d8c5dd8..aaf7da1 100644
--- a/include/openvswitch/meta-flow.h
+++ b/include/openvswitch/meta-flow.h
@@ -2035,10 +2035,12 @@ int mf_subvalue_width(const union mf_subvalue *);
 void mf_subvalue_shift(union mf_subvalue *, int n);
 void mf_subvalue_format(const union mf_subvalue *, struct ds *);
 
-/* An array of fields with values */
+/* Set of field values. 'values' only includes the actual data bytes for each
+ * field for which is used, as marked by 1-bits in 'used'. */
 struct field_array {
     struct mf_bitmap used;
-    union mf_value value[MFF_N_IDS];
+    size_t values_size;      /* Number of bytes currently in 'values'. */
+    uint8_t *values;     /* Dynamically allocated to the correct size. */
 };
 
 /* Finding mf_fields. */
diff --git a/include/openvswitch/ofp-util.h b/include/openvswitch/ofp-util.h
index 7a5c905..fecdb43 100644
--- a/include/openvswitch/ofp-util.h
+++ b/include/openvswitch/ofp-util.h
@@ -1262,6 +1262,9 @@ struct ofputil_group_desc {
     struct ofputil_group_props props; /* Group properties. */
 };
 
+void ofputil_group_properties_destroy(struct ofputil_group_props *);
+void ofputil_group_properties_copy(struct ofputil_group_props *to,
+                                   const struct ofputil_group_props *from);
 void ofputil_bucket_list_destroy(struct ovs_list *buckets);
 void ofputil_bucket_clone_list(struct ovs_list *dest,
                                const struct ovs_list *src,
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
index c44dd2a..2c89613 100644
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -2515,7 +2515,28 @@ void
 field_array_set(enum mf_field_id id, const union mf_value *value,
                 struct field_array *fa)
 {
+    size_t i, offset = 0;
+
     ovs_assert(id < MFF_N_IDS);
+
+    /* Find the spot for 'id'. */
+    BITMAP_FOR_EACH_1 (i, id, fa->used.bm) {
+        offset += mf_from_id(i)->n_bytes;
+    }
+
+    size_t value_size = mf_from_id(id)->n_bytes;
+
+    /* make room if necessary. */
+    if (!bitmap_is_set(fa->used.bm, id)) {
+        fa->values = xrealloc(fa->values, fa->values_size + value_size);
+        /* Move remainder forward, if any. */
+        if (offset < fa->values_size) {
+            memmove(fa->values + offset + value_size, fa->values + offset,
+                    fa->values_size - offset);
+        }
+        fa->values_size += value_size;
+    }
     bitmap_set1(fa->used.bm, id);
-    fa->value[id] = *value;
+
+    memcpy(fa->values + offset, value, value_size);
 }
diff --git a/lib/nx-match.c b/lib/nx-match.c
index 297e361..7e324e4 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -1178,12 +1178,15 @@ void
 oxm_format_field_array(struct ds *ds, const struct field_array *fa)
 {
     size_t start_len = ds->length;
-    int i;
+    size_t i, offset = 0;
 
-    for (i = 0; i < MFF_N_IDS; i++) {
-        if (bitmap_is_set(fa->used.bm, i)) {
-            nx_format_mask_tlv(ds, i, &fa->value[i]);
-        }
+    BITMAP_FOR_EACH_1 (i, MFF_N_IDS, fa->used.bm) {
+        const struct mf_field *mf = mf_from_id(i);
+        union mf_value value;
+
+        memcpy(&value, fa->values + offset, mf->n_bytes);
+        nx_format_mask_tlv(ds, i, &value);
+        offset += mf->n_bytes;
     }
 
     if (ds->length > start_len) {
@@ -1205,7 +1208,6 @@ oxm_put_field_array(struct ofpbuf *b, const struct 
field_array *fa,
                     enum ofp_version version)
 {
     size_t start_len = b->size;
-    int i;
 
     /* Field arrays are only used with the group selection method
      * property and group properties are only available in OpenFlow 1.5+.
@@ -1220,13 +1222,17 @@ oxm_put_field_array(struct ofpbuf *b, const struct 
field_array *fa,
      */
     ovs_assert(version >= OFP15_VERSION);
 
-    for (i = 0; i < MFF_N_IDS; i++) {
-        if (bitmap_is_set(fa->used.bm, i)) {
-            int len = mf_field_len(mf_from_id(i), &fa->value[i], NULL, NULL);
-            nxm_put__(b, i, version,
-                      &fa->value[i].u8 + mf_from_id(i)->n_bytes - len, NULL,
-                      len);
-        }
+    size_t i, offset = 0;
+
+    BITMAP_FOR_EACH_1 (i, MFF_N_IDS, fa->used.bm) {
+        const struct mf_field *mf = mf_from_id(i);
+        union mf_value value;
+
+        memcpy(&value, fa->values + offset, mf->n_bytes);
+
+        int len = mf_field_len(mf, &value, NULL, NULL);
+        nxm_put__(b, i, version, &value + mf->n_bytes - len, NULL, len);
+        offset += mf->n_bytes;
     }
 
     return b->size - start_len;
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 175ae2d..c677ba4 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -8205,6 +8205,7 @@ void
 ofputil_uninit_group_desc(struct ofputil_group_desc *gd)
 {
     ofputil_bucket_list_destroy(&gd->buckets);
+    ofputil_group_properties_destroy(&gd->props);
 }
 
 /* Decodes the OpenFlow group description request in 'oh', returning the group
@@ -8870,6 +8871,20 @@ ofputil_init_group_properties(struct ofputil_group_props 
*gp)
     memset(gp, 0, sizeof *gp);
 }
 
+void
+ofputil_group_properties_copy(struct ofputil_group_props *to,
+                              const struct ofputil_group_props *from)
+{
+    *to = *from;
+    to->fields.values = xmemdup(from->fields.values, from->fields.values_size);
+}
+
+void
+ofputil_group_properties_destroy(struct ofputil_group_props *gp)
+{
+    free(gp->fields.values);
+}
+
 static enum ofperr
 parse_group_prop_ntr_selection_method(struct ofpbuf *payload,
                                       enum ofp11_group_type group_type,
@@ -9128,6 +9143,7 @@ void
 ofputil_uninit_group_mod(struct ofputil_group_mod *gm)
 {
     ofputil_bucket_list_destroy(&gm->buckets);
+    ofputil_group_properties_destroy(&gm->props);
 }
 
 static struct ofpbuf *
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 3efba3a..0a1e2c4 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -3492,39 +3492,41 @@ xlate_hash_fields_select_group(struct xlate_ctx *ctx, 
struct group_dpif *group)
 {
     const struct field_array *fields;
     struct ofputil_bucket *bucket;
+    const uint8_t *mask_values;
     uint32_t basis;
-    int i;
+    size_t i;
 
     fields = group_dpif_get_fields(group);
+    mask_values = fields->values;
     basis = hash_uint64(group_dpif_get_selection_method_param(group));
 
-    for (i = 0; i < MFF_N_IDS; i++) {
-        if (bitmap_is_set(fields->used.bm, i)) {
-            const struct mf_field *mf = mf_from_id(i);
+    BITMAP_FOR_EACH_1 (i, MFF_N_IDS, fields->used.bm) {
+        const struct mf_field *mf = mf_from_id(i);
 
-            /* Skip fields for which prerequisities are not met. */
-            if (!mf_are_prereqs_ok(mf, &ctx->xin->flow, ctx->wc)) {
-                continue;
-            }
+        /* Skip fields for which prerequisities are not met. */
+        if (!mf_are_prereqs_ok(mf, &ctx->xin->flow, ctx->wc)) {
+            /* Skip the mask bytes for this field. */
+            mask_values += mf->n_bytes;
+            continue;
+        }
 
-            union mf_value value;
-            union mf_value mask;
+        union mf_value value;
+        union mf_value mask;
 
-            mf_get_value(mf, &ctx->xin->flow, &value);
-            /* This seems inefficient but so does apply_mask() */
-            for (int j = 0; j < mf->n_bytes; j++) {
-                mask.b[j] = fields->value[i].b[j];
-                value.b[j] &= mask.b[j];
-            }
-            basis = hash_bytes(&value, mf->n_bytes, basis);
-
-            /* For tunnels, hash in whether the field is present. */
-            if (mf_is_tun_metadata(mf)) {
-                basis = hash_boolean(mf_is_set(mf, &ctx->xin->flow), basis);
-            }
+        mf_get_value(mf, &ctx->xin->flow, &value);
+        /* Mask the value. */
+        for (int j = 0; j < mf->n_bytes; j++) {
+            mask.b[j] = *mask_values++;
+            value.b[j] &= mask.b[j];
+        }
+        basis = hash_bytes(&value, mf->n_bytes, basis);
 
-            mf_mask_field_masked(mf, &mask, ctx->wc);
+        /* For tunnels, hash in whether the field is present. */
+        if (mf_is_tun_metadata(mf)) {
+            basis = hash_boolean(mf_is_set(mf, &ctx->xin->flow), basis);
         }
+
+        mf_mask_field_masked(mf, &mask, ctx->wc);
     }
 
     bucket = group_best_live_bucket(ctx, group, basis);
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index cd0c90f..408e026 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -2979,6 +2979,8 @@ static void
 group_destroy_cb(struct ofgroup *group)
 {
     group->ofproto->ofproto_class->group_destruct(group);
+    ofputil_group_properties_destroy(CONST_CAST(struct ofputil_group_props *,
+                                                &group->props));
     ofputil_bucket_list_destroy(&group->buckets);
     group->ofproto->ofproto_class->group_dealloc(group);
 }
@@ -6570,8 +6572,9 @@ init_group(struct ofproto *ofproto, const struct 
ofputil_group_mod *gm,
     *CONST_CAST(uint32_t *, &(*ofgroup)->n_buckets) =
         ovs_list_size(&(*ofgroup)->buckets);
 
-    memcpy(CONST_CAST(struct ofputil_group_props *, &(*ofgroup)->props),
-           &gm->props, sizeof (struct ofputil_group_props));
+    ofputil_group_properties_copy(CONST_CAST(struct ofputil_group_props *,
+                                             &(*ofgroup)->props),
+                                  &gm->props);
     rule_collection_init(&(*ofgroup)->rules);
 
     /* Make group visible from 'version'. */
@@ -6581,6 +6584,8 @@ init_group(struct ofproto *ofproto, const struct 
ofputil_group_mod *gm,
     /* Construct called BEFORE any locks are held. */
     error = ofproto->ofproto_class->group_construct(*ofgroup);
     if (error) {
+        ofputil_group_properties_destroy(CONST_CAST(struct ofputil_group_props 
*,
+                                                    &(*ofgroup)->props));
         ofputil_bucket_list_destroy(&(*ofgroup)->buckets);
         ofproto->ofproto_class->group_dealloc(*ofgroup);
     }
-- 
2.1.4

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to