X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=ofproto%2Fofproto-dpif-rid.h;h=8ada5328c8173d4f87d2f043196597dd7efe6983;hb=6c6eedc5d6730835a0d9724e2e8cfe9cdf03b07d;hp=3344e2a53573dd0f4238d6ccb08b64a37c42606f;hpb=f537461746b9a605972fbddab66f092d96e65732;p=cascardo%2Fovs.git diff --git a/ofproto/ofproto-dpif-rid.h b/ofproto/ofproto-dpif-rid.h index 3344e2a53..8ada5328c 100644 --- a/ofproto/ofproto-dpif-rid.h +++ b/ofproto/ofproto-dpif-rid.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 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. @@ -20,29 +20,253 @@ #include #include -struct recirc_id_pool; +#include "cmap.h" +#include "list.h" +#include "ofp-actions.h" +#include "ofproto-dpif-mirror.h" +#include "ovs-thread.h" +#include "uuid.h" + +struct ofproto_dpif; +struct rule; /* - * Recirculation ID pool. - * ====================== + * Freezing and recirculation + * ========================== + * + * Freezing is a technique for halting and checkpointing packet translation in + * a way that it can be restarted again later. This file has a couple of data + * structures related to freezing in general; their names begin with "frozen". + * + * Recirculation is the use of freezing to allow a frame to re-enter the + * datapath packet processing path to achieve more flexible packet processing, + * such as modifying header fields after MPLS POP action and selecting a slave + * port for bond ports. + * + * + * Data path and user space interface + * ----------------------------------- + * + * Recirculation uses two uint32_t fields, recirc_id and dp_hash, and a RECIRC + * action. recirc_id is used to select the next packet processing steps among + * multiple instances of recirculation. When a packet initially enters the + * datapath it is assigned with recirc_id 0, which indicates no recirculation. + * Recirc_ids are managed by the user space, opaque to the datapath. + * + * On the other hand, dp_hash can only be computed by the datapath, opaque to + * the user space, as the datapath is free to choose the hashing algorithm + * without informing user space about it. The dp_hash value should be + * wildcarded for newly received packets. HASH action specifies whether the + * hash is computed, and if computed, how many fields are to be included in the + * hash computation. The computed hash value is stored into the dp_hash field + * prior to recirculation. + * + * The RECIRC action sets the recirc_id field and then reprocesses the packet + * as if it was received again on the same input port. RECIRC action works + * like a function call; actions listed after the RECIRC action will be + * executed after recirculation. RECIRC action can be nested, but datapath + * implementation limits the number of nested recirculations to prevent + * unreasonable nesting depth or infinite loop. + * + * User space recirculation context + * --------------------------------- + * + * Recirculation is usually hidden from the OpenFlow controllers. Action + * translation code deduces when recirculation is necessary and issues a + * datapath recirculation action. All OpenFlow actions to be performed after + * recirculation are derived from the OpenFlow pipeline and are stored with the + * recirculation ID. When the OpenFlow tables are changed in a way affecting + * the recirculation flows, new recirculation ID with new metadata and actions + * is allocated and the old one is timed out. * - * Recirculation ID needs to be unique for each datapath. Recirculation - * ID pool keeps track recirculation ids. + * Recirculation ID pool + * ---------------------- * - * Typically, there is one recirculation ID pool for each backer. + * Recirculation ID needs to be unique for all datapaths. Recirculation ID + * pool keeps track of recirculation ids and stores OpenFlow pipeline + * translation context so that flow processing may continue after + * recirculation. * - * In theory, Recirculation ID can be any uint32_t value, except 0. - * The implementation usually limits it to a smaller range to ease - * debugging. + * A Recirculation ID can be any uint32_t value, except for that the value 0 is + * reserved for 'no recirculation' case. * * Thread-safety - * ============= + * -------------- * * All APIs are thread safe. - * */ -struct recirc_id_pool *recirc_id_pool_create(void); -void recirc_id_pool_destroy(struct recirc_id_pool *pool); -uint32_t recirc_id_alloc(struct recirc_id_pool *pool); -void recirc_id_free(struct recirc_id_pool *pool, uint32_t recirc_id); + +/* Metadata for restoring pipeline context after recirculation. Helpers + * are inlined below to keep them together with the definition for easier + * updates. */ +BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35); + +struct frozen_metadata { + /* Metadata in struct flow. */ + const struct flow_tnl *tunnel; /* Encapsulating tunnel parameters. */ + ovs_be64 metadata; /* OpenFlow Metadata. */ + uint64_t regs[FLOW_N_XREGS]; /* Registers. */ + ofp_port_t in_port; /* Incoming port. */ +}; + +static inline void +frozen_metadata_from_flow(struct frozen_metadata *md, + const struct flow *flow) +{ + memset(md, 0, sizeof *md); + md->tunnel = &flow->tunnel; + md->metadata = flow->metadata; + memcpy(md->regs, flow->regs, sizeof md->regs); + md->in_port = flow->in_port.ofp_port; +} + +static inline void +frozen_metadata_to_flow(const struct frozen_metadata *md, + struct flow *flow) +{ + if (md->tunnel && flow_tnl_dst_is_set(md->tunnel)) { + flow->tunnel = *md->tunnel; + } else { + memset(&flow->tunnel, 0, sizeof flow->tunnel); + } + flow->metadata = md->metadata; + memcpy(flow->regs, md->regs, sizeof flow->regs); + flow->in_port.ofp_port = md->in_port; +} + +/* State that flow translation can save, to restore when translation + * resumes. */ +struct frozen_state { + /* Initial table for processing when thawing. */ + uint8_t table_id; + + /* Pipeline context for processing when thawing. */ + struct uuid ofproto_uuid; /* Bridge to resume from. */ + struct frozen_metadata metadata; /* Flow metadata. */ + union mf_subvalue *stack; /* Stack if any. */ + size_t n_stack; + mirror_mask_t mirrors; /* Mirrors already output. */ + bool conntracked; /* Conntrack occurred prior to freeze. */ + + /* Actions to be translated when thawing. */ + struct ofpact *ofpacts; + size_t ofpacts_len; /* Size of 'ofpacts', in bytes. */ + struct ofpact *action_set; + size_t action_set_len; /* Size of 'action_set', in bytes. */ +}; + +/* 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 frozen_state state; + + /* Storage for tunnel metadata. */ + struct flow_tnl state_metadata_tunnel; +}; + +void recirc_init(void); + +/* This is only used for bonds and will go away when bonds implementation is + * updated to use this mechanism instead of internal rules. */ +uint32_t recirc_alloc_id(struct ofproto_dpif *); + +uint32_t recirc_alloc_id_ctx(const struct frozen_state *); +uint32_t recirc_find_id(const struct frozen_state *); +void recirc_free_id(uint32_t recirc_id); +void recirc_free_ofproto(struct ofproto_dpif *, const char *ofproto_name); + +const struct recirc_id_node *recirc_id_node_find(uint32_t recirc_id); + +static inline struct recirc_id_node * +recirc_id_node_from_state(const struct frozen_state *state) +{ + return CONTAINER_OF(state, struct recirc_id_node, state); +} + +static inline bool recirc_id_node_try_ref_rcu(const struct recirc_id_node *n_) +{ + struct recirc_id_node *node = CONST_CAST(struct recirc_id_node *, n_); + + return node ? ovs_refcount_try_ref_rcu(&node->refcount) : false; +} + +void recirc_id_node_unref(const struct recirc_id_node *); + +void recirc_run(void); + +/* Recirculation IDs on which references are held. */ +struct recirc_refs { + unsigned n_recircs; + union { + uint32_t recirc[2]; /* When n_recircs == 1 or 2 */ + uint32_t *recircs; /* When 'n_recircs' > 2 */ + }; +}; + +#define RECIRC_REFS_EMPTY_INITIALIZER ((struct recirc_refs) \ + { 0, { { 0, 0 } } }) +/* Helpers to abstract the recirculation union away. */ +static inline void +recirc_refs_init(struct recirc_refs *rr) +{ + *rr = RECIRC_REFS_EMPTY_INITIALIZER; +} + +static inline void +recirc_refs_add(struct recirc_refs *rr, uint32_t id) +{ + if (OVS_LIKELY(rr->n_recircs < ARRAY_SIZE(rr->recirc))) { + rr->recirc[rr->n_recircs++] = id; + } else { + if (rr->n_recircs == ARRAY_SIZE(rr->recirc)) { + uint32_t *recircs = xmalloc(sizeof rr->recirc + sizeof id); + + memcpy(recircs, rr->recirc, sizeof rr->recirc); + rr->recircs = recircs; + } else { + rr->recircs = xrealloc(rr->recircs, + (rr->n_recircs + 1) * sizeof id); + } + rr->recircs[rr->n_recircs++] = id; + } +} + +static inline void +recirc_refs_swap(struct recirc_refs *a, struct recirc_refs *b) +{ + struct recirc_refs tmp; + + tmp = *a; + *a = *b; + *b = tmp; +} + +static inline void +recirc_refs_unref(struct recirc_refs *rr) +{ + if (OVS_LIKELY(rr->n_recircs <= ARRAY_SIZE(rr->recirc))) { + for (int i = 0; i < rr->n_recircs; i++) { + recirc_free_id(rr->recirc[i]); + } + } else { + for (int i = 0; i < rr->n_recircs; i++) { + recirc_free_id(rr->recircs[i]); + } + free(rr->recircs); + } + rr->n_recircs = 0; +} + #endif