X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=ofproto%2Fofproto-dpif-rid.c;h=84c997ccdd1feb104b27c94d1d8435922640301d;hb=600766e877efa2713b9c87d127f7190d8ab48da9;hp=e2867b737b5799bbe4cfa165c25710d361114412;hpb=2082425c2c95431a2f8f5d3f6b1d0ef8f242c186;p=cascardo%2Fovs.git diff --git a/ofproto/ofproto-dpif-rid.c b/ofproto/ofproto-dpif-rid.c index e2867b737..84c997ccd 100644 --- a/ofproto/ofproto-dpif-rid.c +++ b/ofproto/ofproto-dpif-rid.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015 Nicira, Inc. + * Copyright (c) 2014, 2015, 2016 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,6 +36,8 @@ static uint32_t next_id OVS_GUARDED_BY(mutex); /* Possible next free id. */ #define RECIRC_POOL_STATIC_IDS 1024 +static void recirc_id_node_free(struct recirc_id_node *); + void recirc_init(void) { @@ -88,7 +90,7 @@ recirc_run(void) * finished. */ LIST_FOR_EACH_POP (node, exp_node, &expired) { cmap_remove(&id_map, &node->id_node, node->id); - ovsrcu_postpone(free, node); + ovsrcu_postpone(recirc_id_node_free, node); } if (!list_is_empty(&expiring)) { @@ -124,52 +126,66 @@ recirc_id_node_find(uint32_t id) } static uint32_t -recirc_metadata_hash(const struct recirc_state *state) +frozen_state_hash(const struct frozen_state *state) { uint32_t hash; - hash = hash_pointer(state->ofproto, 0); + hash = uuid_hash(&state->ofproto_uuid); hash = hash_int(state->table_id, hash); - hash = hash_words64((const uint64_t *) &state->metadata, - sizeof state->metadata / sizeof(uint64_t), + if (flow_tnl_dst_is_set(state->metadata.tunnel)) { + /* We may leave remainder bytes unhashed, but that is unlikely as + * the tunnel is not in the datapath format. */ + hash = hash_bytes64((const uint64_t *) state->metadata.tunnel, + flow_tnl_size(state->metadata.tunnel), hash); + } + hash = hash_boolean(state->conntracked, hash); + hash = hash_bytes64((const uint64_t *) &state->metadata.metadata, + sizeof state->metadata - sizeof state->metadata.tunnel, hash); - if (state->stack && state->stack->size != 0) { - hash = hash_words64((const uint64_t *) state->stack->data, - state->stack->size / sizeof(uint64_t), hash); + if (state->stack && state->n_stack) { + hash = hash_bytes64((const uint64_t *) state->stack, + state->n_stack * sizeof *state->stack, hash); } + hash = hash_int(state->mirrors, hash); hash = hash_int(state->action_set_len, hash); + if (state->action_set_len) { + hash = hash_bytes64(ALIGNED_CAST(const uint64_t *, state->action_set), + 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); + hash = hash_bytes64(ALIGNED_CAST(const uint64_t *, state->ofpacts), + state->ofpacts_len, hash); } return hash; } static bool -recirc_metadata_equal(const struct recirc_state *a, - const struct recirc_state *b) +frozen_state_equal(const struct frozen_state *a, const struct frozen_state *b) { 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 + && uuid_equals(&a->ofproto_uuid, &b->ofproto_uuid) + && flow_tnl_equal(a->metadata.tunnel, b->metadata.tunnel) + && !memcmp(&a->metadata.metadata, &b->metadata.metadata, + sizeof a->metadata - sizeof a->metadata.tunnel) + && a->n_stack == b->n_stack + && !memcmp(a->stack, b->stack, a->n_stack * sizeof *a->stack) + && a->mirrors == b->mirrors + && a->conntracked == b->conntracked && ofpacts_equal(a->ofpacts, a->ofpacts_len, - b->ofpacts, b->ofpacts_len)); + b->ofpacts, b->ofpacts_len) + && ofpacts_equal(a->action_set, a->action_set_len, + b->action_set, b->action_set_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(const struct recirc_state *target, uint32_t hash) +recirc_find_equal(const struct frozen_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->state, target)) { + if (frozen_state_equal(&node->state, target)) { return node; } } @@ -177,7 +193,7 @@ recirc_find_equal(const struct recirc_state *target, uint32_t hash) } static struct recirc_id_node * -recirc_ref_equal(const struct recirc_state *target, uint32_t hash) +recirc_ref_equal(const struct frozen_state *target, uint32_t hash) { struct recirc_id_node *node; @@ -191,17 +207,30 @@ recirc_ref_equal(const struct recirc_state *target, uint32_t hash) } static void -recirc_state_clone(struct recirc_state *new, const struct recirc_state *old) +frozen_state_clone(struct frozen_state *new, const struct frozen_state *old, + struct flow_tnl *tunnel) { *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); - } + flow_tnl_copy__(tunnel, old->metadata.tunnel); + new->metadata.tunnel = tunnel; + + new->stack = (new->n_stack + ? xmemdup(new->stack, new->n_stack * sizeof *new->stack) + : NULL); + new->ofpacts = (new->ofpacts_len + ? xmemdup(new->ofpacts, new->ofpacts_len) + : NULL); + new->action_set = (new->action_set_len + ? xmemdup(new->action_set, new->action_set_len) + : NULL); +} + +static void +frozen_state_free(struct frozen_state *state) +{ + free(state->stack); + free(state->ofpacts); + free(state->action_set); } /* Allocate a unique recirculation id for the given set of flow metadata. @@ -209,14 +238,16 @@ recirc_state_clone(struct recirc_state *new, const struct recirc_state *old) * 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__(const struct recirc_state *state, uint32_t hash) +recirc_alloc_id__(const struct frozen_state *state, uint32_t hash) { 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); - recirc_state_clone(CONST_CAST(struct recirc_state *, &node->state), state); + frozen_state_clone(CONST_CAST(struct frozen_state *, &node->state), state, + &node->state_metadata_tunnel); ovs_mutex_lock(&mutex); for (;;) { @@ -243,9 +274,9 @@ recirc_alloc_id__(const struct recirc_state *state, uint32_t hash) /* Look up an existing ID for the given flow's metadata and optional actions. */ uint32_t -recirc_find_id(const struct recirc_state *target) +recirc_find_id(const struct frozen_state *target) { - uint32_t hash = recirc_metadata_hash(target); + uint32_t hash = frozen_state_hash(target); struct recirc_id_node *node = recirc_find_equal(target, hash); return node ? node->id : 0; } @@ -253,9 +284,9 @@ recirc_find_id(const struct recirc_state *target) /* Allocate a unique recirculation id for the given set of flow metadata and optional actions. */ uint32_t -recirc_alloc_id_ctx(const struct recirc_state *state) +recirc_alloc_id_ctx(const struct frozen_state *state) { - uint32_t hash = recirc_metadata_hash(state); + uint32_t hash = frozen_state_hash(state); struct recirc_id_node *node = recirc_ref_equal(state, hash); if (!node) { node = recirc_alloc_id__(state, hash); @@ -267,12 +298,22 @@ recirc_alloc_id_ctx(const struct recirc_state *state) uint32_t recirc_alloc_id(struct ofproto_dpif *ofproto) { - struct recirc_state state = { + struct flow_tnl tunnel; + tunnel.ip_dst = htonl(0); + tunnel.ipv6_dst = in6addr_any; + struct frozen_state state = { .table_id = TBL_INTERNAL, - .ofproto = ofproto, - .metadata = { .in_port = OFPP_NONE }, + .ofproto_uuid = *ofproto_dpif_get_uuid(ofproto), + .metadata = { .tunnel = &tunnel, .in_port = OFPP_NONE }, }; - return recirc_alloc_id__(&state, recirc_metadata_hash(&state))->id; + return recirc_alloc_id__(&state, frozen_state_hash(&state))->id; +} + +static void +recirc_id_node_free(struct recirc_id_node *node) +{ + frozen_state_free(CONST_CAST(struct frozen_state *, &node->state)); + free(node); } void @@ -315,8 +356,9 @@ recirc_free_ofproto(struct ofproto_dpif *ofproto, const char *ofproto_name) { struct recirc_id_node *n; + const struct uuid *ofproto_uuid = ofproto_dpif_get_uuid(ofproto); CMAP_FOR_EACH (n, metadata_node, &metadata_map) { - if (n->state.ofproto == ofproto) { + if (uuid_equals(&n->state.ofproto_uuid, ofproto_uuid)) { VLOG_ERR("recirc_id %"PRIu32 " left allocated when ofproto (%s)" " is destructed", n->id, ofproto_name);