X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=ofproto%2Fofproto-dpif-rid.c;h=84c997ccdd1feb104b27c94d1d8435922640301d;hb=8f79bb4d3999d993424e9578342b4130d10a556c;hp=17bcede6244b4e7aad27e2407cb401053df87031;hpb=e672ff9b4d224f4d7ef12b289811b0759a333e48;p=cascardo%2Fovs.git diff --git a/ofproto/ofproto-dpif-rid.c b/ofproto/ofproto-dpif-rid.c index 17bcede62..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) { @@ -67,7 +69,7 @@ recirc_run(void) /* Do maintenance at most 4 times / sec. */ ovs_mutex_lock(&mutex); if (now - last > 250) { - struct recirc_id_node *node, *next; + struct recirc_id_node *node; last = now; @@ -86,10 +88,9 @@ recirc_run(void) /* Delete the expired. These have been lingering for at least 250 ms, * which should be enough for any ongoing recirculations to be * finished. */ - LIST_FOR_EACH_SAFE (node, next, exp_node, &expired) { - list_remove(&node->exp_node); + 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)) { @@ -125,62 +126,66 @@ 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) +frozen_state_hash(const struct frozen_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 = uuid_hash(&state->ofproto_uuid); + hash = hash_int(state->table_id, hash); + 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 (stack && stack->size != 0) { - hash = hash_words64((const uint64_t *)stack->data, - 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); } - 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); + if (state->ofpacts_len) { + hash = hash_bytes64(ALIGNED_CAST(const uint64_t *, state->ofpacts), + state->ofpacts_len, 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) +frozen_state_equal(const struct frozen_state *a, const struct frozen_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 + && 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) + && 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(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 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, ofproto, table_id, md, stack, - action_set_len, ofpacts_len, ofpacts)) { + CMAP_FOR_EACH_WITH_HASH (node, metadata_node, hash, &metadata_map) { + if (frozen_state_equal(&node->state, target)) { return node; } } @@ -188,16 +193,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 frozen_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)); @@ -205,30 +206,48 @@ recirc_ref_equal(struct ofproto_dpif *ofproto, uint8_t table_id, return node; } +static void +frozen_state_clone(struct frozen_state *new, const struct frozen_state *old, + struct flow_tnl *tunnel) +{ + *new = *old; + 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. * 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 frozen_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); - } + frozen_state_clone(CONST_CAST(struct frozen_state *, &node->state), state, + &node->state_metadata_tunnel); ovs_mutex_lock(&mutex); for (;;) { @@ -255,48 +274,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 frozen_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 = frozen_state_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 frozen_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 = frozen_state_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; } @@ -304,16 +298,22 @@ 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; + struct flow_tnl tunnel; + tunnel.ip_dst = htonl(0); + tunnel.ipv6_dst = in6addr_any; + struct frozen_state state = { + .table_id = TBL_INTERNAL, + .ofproto_uuid = *ofproto_dpif_get_uuid(ofproto), + .metadata = { .tunnel = &tunnel, .in_port = OFPP_NONE }, + }; + return recirc_alloc_id__(&state, frozen_state_hash(&state))->id; +} - 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; +static void +recirc_id_node_free(struct recirc_id_node *node) +{ + frozen_state_free(CONST_CAST(struct frozen_state *, &node->state)); + free(node); } void @@ -356,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->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);