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