[ovs-dev] [PATCH] lib: Build action_set in one scan of action_list

Kyle Simpson kyleandrew.simpson at gmail.com
Wed Jun 6 14:17:59 UTC 2018


The previous implementation scans the action set of each WRITE_ACTIONS
command 13--17 times when moving the actions over. This change builds
up the list as a single scan, which should be more efficient.

Signed-off-by: Kyle Simpson <kyleandrew.simpson at gmail.com>
---
 lib/ofp-actions.c | 110 +++++++++++++++++++++++++++-------------------
 1 file changed, 65 insertions(+), 45 deletions(-)

diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index 87797bc9a..6400aabf4 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -7116,40 +7116,43 @@ ofpact_copy(struct ofpbuf *out, const struct ofpact *a)
     ofpbuf_put(out, a, OFPACT_ALIGN(a->len));
 }

-/* Copies the last ofpact whose type is 'filter' from 'in' to 'out'. */
-static bool
-ofpacts_copy_last(struct ofpbuf *out, const struct ofpbuf *in,
-                  enum ofpact_type filter)
-{
-    const struct ofpact *target;
-    const struct ofpact *a;
-
-    target = NULL;
-    OFPACT_FOR_EACH (a, in->data, in->size) {
-        if (a->type == filter) {
-            target = a;
-        }
-    }
-    if (target) {
-        ofpact_copy(out, target);
-    }
-    return target != NULL;
-}
-
-/* Append all ofpacts, for which 'filter' returns true, from 'in' to 'out'.
+/* Append all ofpacts, from 'in' to 'out'.
  * The order of appended ofpacts is preserved between 'in' and 'out' */
 static void
-ofpacts_copy_all(struct ofpbuf *out, const struct ofpbuf *in,
-                 bool (*filter)(const struct ofpact *))
+ofpacts_copy_all(struct ofpbuf *out, const struct ofpbuf *in)
 {
     const struct ofpact *a;

     OFPACT_FOR_EACH (a, in->data, in->size) {
-        if (filter(a)) {
-            ofpact_copy(out, a);
-        }
-    }
-}
+        ofpact_copy(out, a);
+    }
+}
+
+#define ACTION_SET_MISC_POSITION 10
+#define ACTION_SET_COUNT ACTION_SET_MISC_POSITION + 6
+
+/* 1-indexed lookup table for constructing the action set.
+ * The OpenFlow spec "Action Set" section specifies this order.
+ * 0 (implicit from partial initialisation) means ignore, unless
+ * action is a "set_or_move" (and should be copied to another list) */
+static const unsigned int ofpact_action_set_order[N_OFPACTS] = {
+    [OFPACT_STRIP_VLAN]     = 1,
+    [OFPACT_POP_MPLS]       = 2,
+    [OFPACT_DECAP]          = 3,
+    [OFPACT_ENCAP]          = 4,
+    [OFPACT_PUSH_MPLS]      = 5,
+    [OFPACT_PUSH_VLAN]      = 6,
+    [OFPACT_DEC_TTL]        = 7,
+    [OFPACT_DEC_MPLS_TTL]   = 8,
+    [OFPACT_DEC_NSH_TTL]    = 9,
+    /* Space reserved for set_or_move action list. */
+    [OFPACT_SET_QUEUE]      = ACTION_SET_MISC_POSITION + 1,
+    [OFPACT_GROUP]          = ACTION_SET_MISC_POSITION + 2,
+    [OFPACT_OUTPUT]         = ACTION_SET_MISC_POSITION + 3,
+    [OFPACT_RESUBMIT]       = ACTION_SET_MISC_POSITION + 4,
+    [OFPACT_CT_CLEAR]       = ACTION_SET_MISC_POSITION + 5,
+    [OFPACT_CT]             = ACTION_SET_MISC_POSITION + 6,
+};

 /* Reads 'action_set', which contains ofpacts accumulated by
  * OFPACT_WRITE_ACTIONS instructions, and writes equivalent actions to be
@@ -7172,18 +7175,32 @@ void
 ofpacts_execute_action_set(struct ofpbuf *action_list,
                            const struct ofpbuf *action_set)
 {
-    /* The OpenFlow spec "Action Set" section specifies this order. */
-    ofpacts_copy_last(action_list, action_set, OFPACT_STRIP_VLAN);
-    ofpacts_copy_last(action_list, action_set, OFPACT_POP_MPLS);
-    ofpacts_copy_last(action_list, action_set, OFPACT_DECAP);
-    ofpacts_copy_last(action_list, action_set, OFPACT_ENCAP);
-    ofpacts_copy_last(action_list, action_set, OFPACT_PUSH_MPLS);
-    ofpacts_copy_last(action_list, action_set, OFPACT_PUSH_VLAN);
-    ofpacts_copy_last(action_list, action_set, OFPACT_DEC_TTL);
-    ofpacts_copy_last(action_list, action_set, OFPACT_DEC_MPLS_TTL);
-    ofpacts_copy_last(action_list, action_set, OFPACT_DEC_NSH_TTL);
-    ofpacts_copy_all(action_list, action_set, ofpact_is_set_or_move_action);
-    ofpacts_copy_last(action_list, action_set, OFPACT_SET_QUEUE);
+    const struct ofpact *actions[ACTION_SET_COUNT] = {NULL,};
+    struct ofpbuf set_or_move_action_list;
+    ofpbuf_init(&set_or_move_action_list, 0);
+
+    const struct ofpact *cursor;
+
+    OFPACT_FOR_EACH (cursor, action_set->data, action_set->size) {
+        unsigned int loc = ofpact_action_set_order[cursor->type];
+
+        if (loc) {
+            actions[loc-1] = cursor;
+        } else if (ofpact_is_set_or_move_action(cursor)) {
+            ofpact_copy(&set_or_move_action_list, cursor);
+        }
+    }
+
+    /* Copy up to OFPACT_SET_QUEUE. */
+    for (int i = 0; i < ACTION_SET_MISC_POSITION + 1; ++i) {
+        if (i == ACTION_SET_MISC_POSITION - 1) {
+            ofpacts_copy_all(action_list, &set_or_move_action_list);
+        } else if (actions[i]) {
+            ofpact_copy(action_list, actions[i]);
+        }
+    }
+
+    ofpbuf_uninit(&set_or_move_action_list);

     /* If both OFPACT_GROUP and OFPACT_OUTPUT are present, OpenFlow says that
      * we should execute only OFPACT_GROUP.
@@ -7191,12 +7208,15 @@ ofpacts_execute_action_set(struct ofpbuf *action_list,
      * If neither OFPACT_GROUP nor OFPACT_OUTPUT is present, then we can drop
      * all the actions because there's no point in modifying a packet that will
      * not be sent anywhere. */
-    if (!ofpacts_copy_last(action_list, action_set, OFPACT_GROUP) &&
-        !ofpacts_copy_last(action_list, action_set, OFPACT_OUTPUT) &&
-        !ofpacts_copy_last(action_list, action_set, OFPACT_RESUBMIT) &&
-        !ofpacts_copy_last(action_list, action_set, OFPACT_CT_CLEAR) &&
-        !ofpacts_copy_last(action_list, action_set, OFPACT_CT)) {
+    const struct ofpact *final_action = NULL;
+    for (int i = ACTION_SET_MISC_POSITION + 1; !final_action && i <
ACTION_SET_COUNT; ++i) {
+        final_action = actions[i];
+    }
+
+    if (!final_action) {
         ofpbuf_clear(action_list);
+    } else {
+        ofpact_copy(action_list, final_action);
     }
 }

-- 
2.17.1


More information about the dev mailing list