It’s almost like having named function arguments in C! Acked-by: Jarno Rajahalme <jrajaha...@nicira.com>
> On Jul 29, 2015, at 11:42 PM, Ben Pfaff <b...@nicira.com> wrote: > > This greatly reduces the number of arguments to many of the functions > involved in recirculation, which to my eye makes the code clearer. It > will also make it easier to add new recirculation state in an upcoming > commit. > > Signed-off-by: Ben Pfaff <b...@nicira.com> > --- > ofproto/ofproto-dpif-rid.c | 162 ++++++++++++++++--------------------------- > ofproto/ofproto-dpif-rid.h | 43 +++++++----- > ofproto/ofproto-dpif-xlate.c | 57 ++++++++------- > 3 files changed, 117 insertions(+), 145 deletions(-) > > diff --git a/ofproto/ofproto-dpif-rid.c b/ofproto/ofproto-dpif-rid.c > index f1b3bdc..e2867b7 100644 > --- a/ofproto/ofproto-dpif-rid.c > +++ b/ofproto/ofproto-dpif-rid.c > @@ -124,62 +124,52 @@ recirc_id_node_find(uint32_t id) > } > > static uint32_t > -recirc_metadata_hash(struct ofproto_dpif *ofproto, uint8_t table_id, > - struct recirc_metadata *md, struct ofpbuf *stack, > - uint32_t action_set_len, uint32_t ofpacts_len, > - const struct ofpact *ofpacts) > +recirc_metadata_hash(const struct recirc_state *state) > { > uint32_t hash; > > - BUILD_ASSERT(OFPACT_ALIGNTO == sizeof(uint64_t)); > - > - hash = hash_pointer(ofproto, 0); > - hash = hash_int(table_id, hash); > - hash = hash_words64((const uint64_t *)md, sizeof *md / sizeof(uint64_t), > + hash = hash_pointer(state->ofproto, 0); > + hash = hash_int(state->table_id, hash); > + hash = hash_words64((const uint64_t *) &state->metadata, > + sizeof state->metadata / sizeof(uint64_t), > hash); > - if (stack && stack->size != 0) { > - hash = hash_words64((const uint64_t *)stack->data, > - stack->size / sizeof(uint64_t), hash); > + if (state->stack && state->stack->size != 0) { > + hash = hash_words64((const uint64_t *) state->stack->data, > + state->stack->size / sizeof(uint64_t), hash); > } > - hash = hash_int(action_set_len, hash); > - if (ofpacts_len) { > - hash = hash_words64(ALIGNED_CAST(const uint64_t *, ofpacts), > - OFPACT_ALIGN(ofpacts_len) / sizeof(uint64_t), > + hash = hash_int(state->action_set_len, hash); > + if (state->ofpacts_len) { > + hash = hash_words64(ALIGNED_CAST(const uint64_t *, state->ofpacts), > + state->ofpacts_len / sizeof(uint64_t), > hash); > } > return hash; > } > > static bool > -recirc_metadata_equal(const struct recirc_id_node *node, > - struct ofproto_dpif *ofproto, uint8_t table_id, > - struct recirc_metadata *md, struct ofpbuf *stack, > - uint32_t action_set_len, uint32_t ofpacts_len, > - const struct ofpact *ofpacts) > +recirc_metadata_equal(const struct recirc_state *a, > + const struct recirc_state *b) > { > - return node->ofproto == ofproto > - && node->table_id == table_id > - && !memcmp(&node->metadata, md, sizeof *md) > - && ((!node->stack && (!stack || stack->size == 0)) > - || (node->stack && stack && ofpbuf_equal(node->stack, stack))) > - && node->action_set_len == action_set_len > - && node->ofpacts_len == ofpacts_len > - && (ofpacts_len == 0 || !memcmp(node->ofpacts, ofpacts, > ofpacts_len)); > + return (a->table_id == b->table_id > + && a->ofproto == b->ofproto > + && !memcmp(&a->metadata, &b->metadata, sizeof a->metadata) > + && (((!a->stack || !a->stack->size) && > + (!b->stack || !b->stack->size)) > + || (a->stack && b->stack && ofpbuf_equal(a->stack, > b->stack))) > + && a->action_set_len == b->action_set_len > + && ofpacts_equal(a->ofpacts, a->ofpacts_len, > + b->ofpacts, b->ofpacts_len)); > } > > /* 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(struct ofproto_dpif *ofproto, uint8_t table_id, > - struct recirc_metadata *md, struct ofpbuf *stack, > - uint32_t action_set_len, uint32_t ofpacts_len, > - const struct ofpact *ofpacts, uint32_t hash) > +recirc_find_equal(const struct recirc_state *target, uint32_t hash) > { > struct recirc_id_node *node; > > - CMAP_FOR_EACH_WITH_HASH(node, metadata_node, hash, &metadata_map) { > - if (recirc_metadata_equal(node, ofproto, table_id, md, stack, > - action_set_len, ofpacts_len, ofpacts)) { > + CMAP_FOR_EACH_WITH_HASH (node, metadata_node, hash, &metadata_map) { > + if (recirc_metadata_equal(&node->state, target)) { > return node; > } > } > @@ -187,16 +177,12 @@ recirc_find_equal(struct ofproto_dpif *ofproto, uint8_t > table_id, > } > > static struct recirc_id_node * > -recirc_ref_equal(struct ofproto_dpif *ofproto, uint8_t table_id, > - struct recirc_metadata *md, struct ofpbuf *stack, > - uint32_t action_set_len, uint32_t ofpacts_len, > - const struct ofpact *ofpacts, uint32_t hash) > +recirc_ref_equal(const struct recirc_state *target, uint32_t hash) > { > struct recirc_id_node *node; > > do { > - node = recirc_find_equal(ofproto, table_id, md, stack, > action_set_len, > - ofpacts_len, ofpacts, hash); > + node = recirc_find_equal(target, hash); > > /* Try again if the node was released before we get the reference. */ > } while (node && !ovs_refcount_try_ref_rcu(&node->refcount)); > @@ -204,30 +190,33 @@ recirc_ref_equal(struct ofproto_dpif *ofproto, uint8_t > table_id, > return node; > } > > +static void > +recirc_state_clone(struct recirc_state *new, const struct recirc_state *old) > +{ > + *new = *old; > + if (new->stack) { > + new->stack = new->stack->size ? ofpbuf_clone(new->stack) : NULL; > + } > + if (new->ofpacts) { > + new->ofpacts = (new->ofpacts_len > + ? xmemdup(new->ofpacts, new->ofpacts_len) > + : NULL); > + } > +} > + > /* Allocate a unique recirculation id for the given set of flow metadata. > * The ID space is 2^^32, so there should never be a situation in which all > * the IDs are used up. We loop until we find a free one. > * hash is recomputed if it is passed in as 0. */ > static struct recirc_id_node * > -recirc_alloc_id__(struct ofproto_dpif *ofproto, uint8_t table_id, > - struct recirc_metadata *md, struct ofpbuf *stack, > - uint32_t action_set_len, uint32_t ofpacts_len, > - const struct ofpact *ofpacts, uint32_t hash) > +recirc_alloc_id__(const struct recirc_state *state, uint32_t hash) > { > - struct recirc_id_node *node = xzalloc(sizeof *node + > - OFPACT_ALIGN(ofpacts_len)); > + ovs_assert(state->action_set_len <= state->ofpacts_len); > + > + struct recirc_id_node *node = xzalloc(sizeof *node); > node->hash = hash; > ovs_refcount_init(&node->refcount); > - > - node->ofproto = ofproto; > - node->table_id = table_id; > - memcpy(&node->metadata, md, sizeof node->metadata); > - node->stack = (stack && stack->size) ? ofpbuf_clone(stack) : NULL; > - node->action_set_len = action_set_len; > - node->ofpacts_len = ofpacts_len; > - if (ofpacts_len) { > - memcpy(node->ofpacts, ofpacts, ofpacts_len); > - } > + recirc_state_clone(CONST_CAST(struct recirc_state *, &node->state), > state); > > ovs_mutex_lock(&mutex); > for (;;) { > @@ -254,48 +243,23 @@ recirc_alloc_id__(struct ofproto_dpif *ofproto, uint8_t > table_id, > /* Look up an existing ID for the given flow's metadata and optional actions. > */ > uint32_t > -recirc_find_id(struct ofproto_dpif *ofproto, uint8_t table_id, > - struct recirc_metadata *md, struct ofpbuf *stack, > - uint32_t action_set_len, uint32_t ofpacts_len, > - const struct ofpact *ofpacts) > +recirc_find_id(const struct recirc_state *target) > { > - /* Check if an ID with the given metadata already exists. */ > - struct recirc_id_node *node; > - uint32_t hash; > - > - hash = recirc_metadata_hash(ofproto, table_id, md, stack, action_set_len, > - ofpacts_len, ofpacts); > - node = recirc_find_equal(ofproto, table_id, md, stack, action_set_len, > - ofpacts_len, ofpacts, hash); > - > + uint32_t hash = recirc_metadata_hash(target); > + struct recirc_id_node *node = recirc_find_equal(target, hash); > return node ? node->id : 0; > } > > /* Allocate a unique recirculation id for the given set of flow metadata and > optional actions. */ > uint32_t > -recirc_alloc_id_ctx(struct ofproto_dpif *ofproto, uint8_t table_id, > - struct recirc_metadata *md, struct ofpbuf *stack, > - uint32_t action_set_len, uint32_t ofpacts_len, > - const struct ofpact *ofpacts) > +recirc_alloc_id_ctx(const struct recirc_state *state) > { > - struct recirc_id_node *node; > - uint32_t hash; > - > - /* Look up an existing ID. */ > - hash = recirc_metadata_hash(ofproto, table_id, md, stack, action_set_len, > - ofpacts_len, ofpacts); > - node = recirc_ref_equal(ofproto, table_id, md, stack, action_set_len, > - ofpacts_len, ofpacts, hash); > - > - /* Allocate a new recirc ID if needed. */ > + uint32_t hash = recirc_metadata_hash(state); > + struct recirc_id_node *node = recirc_ref_equal(state, hash); > if (!node) { > - ovs_assert(action_set_len <= ofpacts_len); > - > - node = recirc_alloc_id__(ofproto, table_id, md, stack, > action_set_len, > - ofpacts_len, ofpacts, hash); > + node = recirc_alloc_id__(state, hash); > } > - > return node->id; > } > > @@ -303,16 +267,12 @@ recirc_alloc_id_ctx(struct ofproto_dpif *ofproto, > uint8_t table_id, > uint32_t > recirc_alloc_id(struct ofproto_dpif *ofproto) > { > - struct recirc_metadata md; > - struct recirc_id_node *node; > - uint32_t hash; > - > - memset(&md, 0, sizeof md); > - md.in_port = OFPP_NONE; > - hash = recirc_metadata_hash(ofproto, TBL_INTERNAL, &md, NULL, 0, 0, > NULL); > - node = recirc_alloc_id__(ofproto, TBL_INTERNAL, &md, NULL, 0, 0, NULL, > - hash); > - return node->id; > + struct recirc_state state = { > + .table_id = TBL_INTERNAL, > + .ofproto = ofproto, > + .metadata = { .in_port = OFPP_NONE }, > + }; > + return recirc_alloc_id__(&state, recirc_metadata_hash(&state))->id; > } > > void > @@ -356,7 +316,7 @@ recirc_free_ofproto(struct ofproto_dpif *ofproto, const > char *ofproto_name) > struct recirc_id_node *n; > > CMAP_FOR_EACH (n, metadata_node, &metadata_map) { > - if (n->ofproto == ofproto) { > + if (n->state.ofproto == ofproto) { > VLOG_ERR("recirc_id %"PRIu32 > " left allocated when ofproto (%s)" > " is destructed", n->id, ofproto_name); > diff --git a/ofproto/ofproto-dpif-rid.h b/ofproto/ofproto-dpif-rid.h > index a614a4d..9caa662 100644 > --- a/ofproto/ofproto-dpif-rid.h > +++ b/ofproto/ofproto-dpif-rid.h > @@ -125,16 +125,9 @@ recirc_metadata_to_flow(const struct recirc_metadata *md, > flow->actset_output = md->actset_output; > } > > -/* Pool node fields should NOT be modified after placing the node in the > pool. > - */ > -struct recirc_id_node { > - struct ovs_list exp_node OVS_GUARDED; > - struct cmap_node id_node; > - struct cmap_node metadata_node; > - uint32_t id; > - uint32_t hash; > - struct ovs_refcount refcount; > - > +/* State that flow translation can save, to restore when recirculation > + * occurs. */ > +struct recirc_state { > /* Initial table for post-recirculation processing. */ > uint8_t table_id; > > @@ -147,7 +140,25 @@ struct recirc_id_node { > uint32_t action_set_len; /* How much of 'ofpacts' consists of an > * action set? */ > uint32_t ofpacts_len; /* Size of 'ofpacts', in bytes. */ > - struct ofpact ofpacts[]; /* Sequence of "struct ofpacts". */ > + struct ofpact *ofpacts; /* Sequence of "struct ofpacts". */ > +}; > + > +/* This maps a recirculation ID to saved state that flow translation can > + * restore when recirculation occurs. */ > +struct recirc_id_node { > + /* Index data. */ > + struct ovs_list exp_node OVS_GUARDED; > + struct cmap_node id_node; > + struct cmap_node metadata_node; > + uint32_t id; > + uint32_t hash; > + struct ovs_refcount refcount; > + > + /* Saved state. > + * > + * This state should not be modified after inserting a node in the pool, > + * hence the 'const' to emphasize that. */ > + const struct recirc_state state; > }; > > void recirc_init(void); > @@ -156,14 +167,8 @@ void recirc_init(void); > * updated to use this mechanism instead of internal rules. */ > uint32_t recirc_alloc_id(struct ofproto_dpif *); > > -uint32_t recirc_alloc_id_ctx(struct ofproto_dpif *, uint8_t table_id, > - struct recirc_metadata *, struct ofpbuf *stack, > - uint32_t action_set_len, uint32_t ofpacts_len, > - const struct ofpact *); > -uint32_t recirc_find_id(struct ofproto_dpif *, uint8_t table_id, > - struct recirc_metadata *, struct ofpbuf *stack, > - uint32_t action_set_len, uint32_t ofpacts_len, > - const struct ofpact *); > +uint32_t recirc_alloc_id_ctx(const struct recirc_state *); > +uint32_t recirc_find_id(const struct recirc_state *); > void recirc_free_id(uint32_t recirc_id); > void recirc_free_ofproto(struct ofproto_dpif *, const char *ofproto_name); > > diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c > index cbcd2a3..4315e30 100644 > --- a/ofproto/ofproto-dpif-xlate.c > +++ b/ofproto/ofproto-dpif-xlate.c > @@ -3505,14 +3505,22 @@ compose_recirculate_action(struct xlate_ctx *ctx) > > ovs_assert(ctx->recirc_action_offset >= 0); > > + struct recirc_state state = { > + .table_id = 0, > + .ofproto = ctx->xbridge->ofproto, > + .metadata = md, > + .stack = &ctx->stack, > + .action_set_len = ctx->recirc_action_offset, > + .ofpacts_len = ctx->action_set.size, > + .ofpacts = ctx->action_set.data, > + }; > + > /* Only allocate recirculation ID if we have a packet. */ > if (ctx->xin->packet) { > /* Allocate a unique recirc id for the given metadata state in the > * 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->xbridge->ofproto, 0, &md, &ctx->stack, > - ctx->recirc_action_offset, > - ctx->action_set.size, ctx->action_set.data); > + id = recirc_alloc_id_ctx(&state); > if (!id) { > static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > VLOG_ERR_RL(&rl, "Failed to allocate recirculation id"); > @@ -3522,12 +3530,12 @@ compose_recirculate_action(struct xlate_ctx *ctx) > } else { > /* Look up an existing recirc id for the given metadata state in the > * flow. No new reference is taken, as the ID is RCU protected and is > - * only required temporarily for verification. */ > - id = recirc_find_id(ctx->xbridge->ofproto, 0, &md, &ctx->stack, > - ctx->recirc_action_offset, > - ctx->action_set.size, ctx->action_set.data); > - /* We let zero 'id' to be used in the RECIRC action below, which will > - * fail all revalidations as zero is not a valid recirculation ID. */ > + * only required temporarily for verification. > + * > + * This might fail and return 0. We let zero 'id' to be used in the > + * RECIRC action below, which will fail all revalidations as zero is > + * not a valid recirculation ID. */ > + id = recirc_find_id(&state); > } > > nl_msg_put_u32(ctx->odp_actions, OVS_ACTION_ATTR_RECIRC, id); > @@ -4798,7 +4806,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out > *xout) > COVERAGE_INC(xlate_actions); > > if (xin->recirc) { > - const struct recirc_id_node *recirc = xin->recirc; > + const struct recirc_state *state = &xin->recirc->state; > > if (xin->ofpacts_len > 0 || ctx.rule) { > static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); > @@ -4811,10 +4819,10 @@ xlate_actions(struct xlate_in *xin, struct xlate_out > *xout) > } > > /* Set the bridge for post-recirculation processing if needed. */ > - if (ctx.xbridge->ofproto != recirc->ofproto) { > + if (ctx.xbridge->ofproto != state->ofproto) { > struct xlate_cfg *xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp); > - const struct xbridge *new_bridge = xbridge_lookup(xcfg, > - > recirc->ofproto); > + const struct xbridge *new_bridge > + = xbridge_lookup(xcfg, state->ofproto); > > if (OVS_UNLIKELY(!new_bridge)) { > /* Drop the packet if the bridge cannot be found. */ > @@ -4827,26 +4835,25 @@ xlate_actions(struct xlate_in *xin, struct xlate_out > *xout) > > /* Set the post-recirculation table id. Note: A table lookup is done > * only if there are no post-recirculation actions. */ > - ctx.table_id = recirc->table_id; > + ctx.table_id = state->table_id; > > /* Restore pipeline metadata. May change flow's in_port and other > * metadata to the values that existed when recirculation was > * triggered. */ > - recirc_metadata_to_flow(&recirc->metadata, flow); > + recirc_metadata_to_flow(&state->metadata, flow); > > /* Restore stack, if any. */ > - if (recirc->stack) { > - ofpbuf_put(&ctx.stack, recirc->stack->data, recirc->stack->size); > + if (state->stack) { > + ofpbuf_put(&ctx.stack, state->stack->data, state->stack->size); > } > > /* Restore action set, if any. */ > - if (recirc->action_set_len) { > + if (state->action_set_len) { > const struct ofpact *a; > > - ofpbuf_put(&ctx.action_set, recirc->ofpacts, > - recirc->action_set_len); > + ofpbuf_put(&ctx.action_set, state->ofpacts, > state->action_set_len); > > - OFPACT_FOR_EACH(a, recirc->ofpacts, recirc->action_set_len) { > + OFPACT_FOR_EACH(a, state->ofpacts, state->action_set_len) { > if (a->type == OFPACT_GROUP) { > ctx.action_set_has_group = true; > break; > @@ -4856,10 +4863,10 @@ xlate_actions(struct xlate_in *xin, struct xlate_out > *xout) > > /* Restore recirculation actions. If there are no actions, processing > * will start with a lookup in the table set above. */ > - if (recirc->ofpacts_len > recirc->action_set_len) { > - xin->ofpacts_len = recirc->ofpacts_len - recirc->action_set_len; > - xin->ofpacts = recirc->ofpacts + > - recirc->action_set_len / sizeof *recirc->ofpacts; > + if (state->ofpacts_len > state->action_set_len) { > + xin->ofpacts_len = state->ofpacts_len - state->action_set_len; > + xin->ofpacts = state->ofpacts + > + state->action_set_len / sizeof *state->ofpacts; > } > } else if (OVS_UNLIKELY(flow->recirc_id)) { > static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); > -- > 2.1.3 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev