1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
|
/*
* Copyright (c) 2014, 2015, 2016, 2017 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef OFPROTO_DPIF_RID_H
#define OFPROTO_DPIF_RID_H
#include <stddef.h>
#include <stdint.h>
#include "cmap.h"
#include "ofproto-dpif-mirror.h"
#include "ofproto/ofproto-provider.h"
#include "openvswitch/list.h"
#include "openvswitch/ofp-actions.h"
#include "ovs-thread.h"
#include "uuid.h"
struct ofproto_dpif;
struct rule;
/*
* 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
* member interface 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 pool
* ----------------------
*
* 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.
*
* 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.
*/
/* 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 == 42);
struct frozen_metadata {
/* Metadata in struct flow. */
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;
/* It is unsafe for frozen_state to reference tun_table because
* tun_table is protected by RCU while the lifecycle of frozen_state
* can span several RCU quiesce states.
*
* The latest valid tun_table can be found by ofproto_get_tun_tab()
* efficiently. */
md->tunnel.metadata.tab = NULL;
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(struct ofproto *ofproto,
const struct frozen_metadata *md,
struct flow *flow)
{
flow->tunnel = md->tunnel;
flow->tunnel.metadata.tab = ofproto_get_tun_tab(ofproto);
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. */
uint8_t *stack; /* Stack if any. */
size_t stack_size;
mirror_mask_t mirrors; /* Mirrors already output. */
bool conntracked; /* Conntrack occurred prior to freeze. */
bool was_mpls; /* MPLS packet */
struct uuid xport_uuid; /* UUID of 1st port packet received on. */
/* 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. */
/* User data for controller userspace cookie. */
uint8_t *userdata;
size_t userdata_len;
};
/* 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;
};
/* 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);
bool recirc_id_node_find_and_ref(uint32_t 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
|