Store and restore the stack when recirculating.

Signed-off-by: Jarno Rajahalme <[email protected]>
Signed-off-by: Jarno Rajahalme <[email protected]>
---
 ofproto/ofproto-dpif-rid.c   |   50 ++++++++++++++++++++++++++++--------------
 ofproto/ofproto-dpif-rid.h   |    5 ++++-
 ofproto/ofproto-dpif-xlate.c |   10 ++++++---
 tests/mpls-xlate.at          |    2 +-
 4 files changed, 45 insertions(+), 22 deletions(-)

diff --git a/ofproto/ofproto-dpif-rid.c b/ofproto/ofproto-dpif-rid.c
index b9adf88..2ffdba7 100644
--- a/ofproto/ofproto-dpif-rid.c
+++ b/ofproto/ofproto-dpif-rid.c
@@ -16,6 +16,7 @@
 
 #include <config.h>
 
+#include "ofpbuf.h"
 #include "ofproto-dpif.h"
 #include "ofproto-dpif-rid.h"
 #include "ofproto-provider.h"
@@ -125,7 +126,7 @@ recirc_id_node_find(uint32_t id)
 
 static uint32_t
 recirc_metadata_hash(uint32_t action_set_len, uint32_t ofpacts_len,
-                     const struct ofpact *ofpacts)
+                     const struct ofpact *ofpacts, struct ofpbuf *stack)
 {
     uint32_t hash;
 
@@ -133,31 +134,38 @@ recirc_metadata_hash(uint32_t action_set_len, uint32_t 
ofpacts_len,
 
     hash = hash_int(action_set_len, 0);
     hash = hash_words64((const uint64_t *)ofpacts,
-                        OFPACT_ALIGN(ofpacts_len) / OFPACT_ALIGNTO, hash);
+                        OFPACT_ALIGN(ofpacts_len) / sizeof(uint64_t), hash);
+    if (stack && stack->size != 0) {
+        hash = hash_words64((const uint64_t *)stack->data,
+                            stack->size / sizeof(uint64_t), hash);
+    }
     return hash;
 }
 
 static bool
 recirc_metadata_equal(const struct recirc_id_node *node,
                       uint32_t action_set_len, uint32_t ofpacts_len,
-                      const struct ofpact *ofpacts)
+                      const struct ofpact *ofpacts, struct ofpbuf *stack)
 {
     return node->action_set_len == action_set_len
         && node->ofpacts_len == ofpacts_len
-        && !memcmp(node->ofpacts, ofpacts, ofpacts_len);
+        && !memcmp(node->ofpacts, ofpacts, ofpacts_len)
+        && ((!node->stack && (!stack || stack->size == 0))
+            || (node->stack && stack && ofpbuf_equal(node->stack, stack)));
 }
 
 /* Lockless RCU protected lookup.  If node is needed accross RCU quiescent
  * state, caller should take a reference. */
 static struct recirc_id_node *
 recirc_find_equal(uint32_t action_set_len, uint32_t ofpacts_len,
-                  const struct ofpact *ofpacts, uint32_t hash)
+                  const struct ofpact *ofpacts, struct ofpbuf *stack,
+                  uint32_t hash)
 {
     struct recirc_id_node *node;
 
     CMAP_FOR_EACH_WITH_HASH(node, metadata_node, hash, &metadata_map) {
         if (recirc_metadata_equal(node, action_set_len, ofpacts_len,
-                                  ofpacts)) {
+                                  ofpacts, stack)) {
             return node;
         }
     }
@@ -166,12 +174,14 @@ recirc_find_equal(uint32_t action_set_len, uint32_t 
ofpacts_len,
 
 static struct recirc_id_node *
 recirc_ref_equal(uint32_t action_set_len, uint32_t ofpacts_len,
-                 const struct ofpact *ofpacts, uint32_t hash)
+                 const struct ofpact *ofpacts, struct ofpbuf *stack,
+                 uint32_t hash)
 {
     struct recirc_id_node *node;
 
     do {
-        node = recirc_find_equal(action_set_len, ofpacts_len, ofpacts, hash);
+        node = recirc_find_equal(action_set_len, ofpacts_len, ofpacts, stack,
+                                 hash);
 
         /* Try again if the node was released before we get the reference. */
     } while (node && !ovs_refcount_try_ref_rcu(&node->refcount));
@@ -185,7 +195,8 @@ recirc_ref_equal(uint32_t action_set_len, uint32_t 
ofpacts_len,
  * hash is recomputed if it is passed in as 0. */
 static struct recirc_id_node *
 recirc_alloc_id__(uint32_t action_set_len, uint32_t ofpacts_len,
-                  const struct ofpact *ofpacts, uint32_t hash)
+                  const struct ofpact *ofpacts, struct ofpbuf *stack,
+                  uint32_t hash)
 {
     struct recirc_id_node *node = xzalloc(sizeof *node +
                                           OFPACT_ALIGN(ofpacts_len));
@@ -198,6 +209,8 @@ recirc_alloc_id__(uint32_t action_set_len, uint32_t 
ofpacts_len,
     node->ofpacts_len = ofpacts_len;
     memcpy(node->ofpacts, ofpacts, ofpacts_len);
 
+    node->stack = (stack && stack->size) ? ofpbuf_clone(stack) : NULL;
+
     node->hash = hash;
     ovs_mutex_lock(&mutex);
     for (;;) {
@@ -231,8 +244,8 @@ recirc_find_id(uint32_t action_set_len, uint32_t 
ofpacts_len,
     struct recirc_id_node *node;
     uint32_t hash;
 
-    hash = recirc_metadata_hash(action_set_len, ofpacts_len, ofpacts);
-    node = recirc_find_equal(action_set_len, ofpacts_len, ofpacts, hash);
+    hash = recirc_metadata_hash(action_set_len, ofpacts_len, ofpacts, NULL);
+    node = recirc_find_equal(action_set_len, ofpacts_len, ofpacts, NULL, hash);
 
     return node ? node->id : 0;
 }
@@ -241,20 +254,21 @@ recirc_find_id(uint32_t action_set_len, uint32_t 
ofpacts_len,
    optional actions. */
 uint32_t
 recirc_alloc_id_ctx(uint32_t action_set_len, uint32_t ofpacts_len,
-                    const struct ofpact *ofpacts)
+                    const struct ofpact *ofpacts, struct ofpbuf *stack)
 {
     struct recirc_id_node *node;
     uint32_t hash;
 
     /* Look up an existing ID. */
-    hash = recirc_metadata_hash(action_set_len, ofpacts_len, ofpacts);
-    node = recirc_ref_equal(action_set_len, ofpacts_len, ofpacts, hash);
+    hash = recirc_metadata_hash(action_set_len, ofpacts_len, ofpacts, stack);
+    node = recirc_ref_equal(action_set_len, ofpacts_len, ofpacts, stack, hash);
 
     /* Allocate a new recirc ID if needed. */
     if (!node) {
         ovs_assert(action_set_len <= ofpacts_len);
 
-        node = recirc_alloc_id__(action_set_len, ofpacts_len, ofpacts, hash);
+        node = recirc_alloc_id__(action_set_len, ofpacts_len, ofpacts, stack,
+                                 hash);
     }
 
     return node->id;
@@ -279,8 +293,10 @@ recirc_alloc_id(struct ofproto_dpif *ofproto)
                 sizeof ofpacts.goto_table);
     ofpacts.goto_table.table_id = TBL_INTERNAL;
 
-    hash = recirc_metadata_hash(0, sizeof ofpacts, &ofpacts.unroll.ofpact);
-    node = recirc_alloc_id__(0, sizeof ofpacts, &ofpacts.unroll.ofpact, hash);
+    hash = recirc_metadata_hash(0, sizeof ofpacts, &ofpacts.unroll.ofpact,
+                                NULL);
+    node = recirc_alloc_id__(0, sizeof ofpacts, &ofpacts.unroll.ofpact, NULL,
+                             hash);
 
     return node->id;
 }
diff --git a/ofproto/ofproto-dpif-rid.h b/ofproto/ofproto-dpif-rid.h
index 3c90b8a..69fb0cb 100644
--- a/ofproto/ofproto-dpif-rid.h
+++ b/ofproto/ofproto-dpif-rid.h
@@ -99,6 +99,8 @@ struct recirc_id_node {
     uint32_t hash;
     struct ovs_refcount refcount;
 
+    struct ofpbuf *stack;         /* Stack if any. */
+
     /* Actions to be translated on recirculation. */
     uint32_t action_set_len;      /* How much of 'ofpacts' consists of an
                                    * action set? */
@@ -113,7 +115,8 @@ void recirc_init(void);
 uint32_t recirc_alloc_id(struct ofproto_dpif *);
 
 uint32_t recirc_alloc_id_ctx(uint32_t action_set_len, uint32_t ofpacts_len,
-                             const struct ofpact *ofpacts);
+                             const struct ofpact *ofpacts,
+                             struct ofpbuf *stack);
 uint32_t recirc_find_id(uint32_t action_set_len, uint32_t ofpacts_len,
                         const struct ofpact *ofpacts);
 void recirc_free_id(uint32_t recirc_id);
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index eb2669b..b196543 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -3379,7 +3379,8 @@ compose_recirculate_action(struct xlate_ctx *ctx)
          * flow.  The life-cycle of this recirc id is managed by associating it
          * with the udpif key ('ukey') created for each new datapath flow. */
         id = recirc_alloc_id_ctx(ctx->recirc_action_offset,
-                                 ctx->action_set.size, ctx->action_set.data);
+                                 ctx->action_set.size, ctx->action_set.data,
+                                 &ctx->stack);
         if (!id) {
             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
             VLOG_ERR_RL(&rl, "Failed to allocate recirculation id");
@@ -4729,6 +4730,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out 
*xout)
     ctx.action_set_has_group = false;
     ofpbuf_use_stub(&ctx.action_set,
                     ctx.action_set_stub, sizeof ctx.action_set_stub);
+    ofpbuf_use_stub(&ctx.stack, ctx.init_stack, sizeof ctx.init_stack);
 
     if (xin->recirc) {
         const struct recirc_id_node *recirc = xin->recirc;
@@ -4764,6 +4766,10 @@ xlate_actions(struct xlate_in *xin, struct xlate_out 
*xout)
             xin->ofpacts = recirc->ofpacts +
                 recirc->action_set_len / sizeof *recirc->ofpacts;
         }
+        /* Restore stack, if any. */
+        if (recirc->stack) {
+            ofpbuf_put(&ctx.stack, recirc->stack->data, recirc->stack->size);
+        }
     }
 
     if (!xin->ofpacts && !ctx.rule) {
@@ -4801,8 +4807,6 @@ xlate_actions(struct xlate_in *xin, struct xlate_out 
*xout)
         OVS_NOT_REACHED();
     }
 
-    ofpbuf_use_stub(&ctx.stack, ctx.init_stack, sizeof ctx.init_stack);
-
     if (mbridge_has_mirrors(ctx.xbridge->mbridge)) {
         /* Do this conditionally because the copy is expensive enough that it
          * shows up in profiles. */
diff --git a/tests/mpls-xlate.at b/tests/mpls-xlate.at
index c293db7..571b8ce 100644
--- a/tests/mpls-xlate.at
+++ b/tests/mpls-xlate.at
@@ -36,7 +36,7 @@ AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 
in_port=local,dl_type=0x0800,acti
 AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 
cookie=0xa,table=0,dl_type=0x8847,in_port=1,mpls_label=60,action=set_field:10-\>reg0,pop_mpls:0x8847,goto_table:1])
 # The pop_mpls below recirculates from within a resubmit
 # After recirculation the (restored) register value is moved to IP ttl.
-AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 
cookie=0xb,table=1,dl_type=0x8847,in_port=1,mpls_label=50,action=pop_mpls:0x0800,move:NXM_NX_REG0[[0..7]]-\>NXM_NX_IP_TTL[[]],output:LOCAL])
+AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 
cookie=0xb,table=1,dl_type=0x8847,in_port=1,mpls_label=50,action=push:NXM_NX_REG0[[0..7]],pop_mpls:0x0800,set_field:0-\>nw_ttl,pop:NXM_NX_REG1[[0..7]],move:NXM_NX_REG1[[0..7]]-\>NXM_NX_IP_TTL[[]],output:LOCAL])
 
 dnl Double MPLS push
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 
'in_port(100),eth(src=f8:bc:12:44:34:b6,dst=f8:bc:12:46:58:e0),eth_type(0x0800),ipv4(src=1.1.2.92,dst=1.1.2.88,proto=47,tos=0,ttl=64,frag=no)'],
 [0], [stdout])
-- 
1.7.10.4

_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev

Reply via email to