Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2014, 2015, 2016 Nicira, Inc.
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License");
5 : : * you may not use this file except in compliance with the License.
6 : : * You may obtain a copy of the License at:
7 : : *
8 : : * http://www.apache.org/licenses/LICENSE-2.0
9 : : *
10 : : * Unless required by applicable law or agreed to in writing, software
11 : : * distributed under the License is distributed on an "AS IS" BASIS,
12 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : : * See the License for the specific language governing permissions and
14 : : * limitations under the License.
15 : : */
16 : :
17 : : #ifndef OFPROTO_DPIF_RID_H
18 : : #define OFPROTO_DPIF_RID_H
19 : :
20 : : #include <stddef.h>
21 : : #include <stdint.h>
22 : :
23 : : #include "cmap.h"
24 : : #include "ofproto-dpif-mirror.h"
25 : : #include "openvswitch/list.h"
26 : : #include "openvswitch/ofp-actions.h"
27 : : #include "ovs-thread.h"
28 : : #include "uuid.h"
29 : :
30 : : struct ofproto_dpif;
31 : : struct rule;
32 : :
33 : : /*
34 : : * Freezing and recirculation
35 : : * ==========================
36 : : *
37 : : * Freezing is a technique for halting and checkpointing packet translation in
38 : : * a way that it can be restarted again later. This file has a couple of data
39 : : * structures related to freezing in general; their names begin with "frozen".
40 : : *
41 : : * Recirculation is the use of freezing to allow a frame to re-enter the
42 : : * datapath packet processing path to achieve more flexible packet processing,
43 : : * such as modifying header fields after MPLS POP action and selecting a slave
44 : : * port for bond ports.
45 : : *
46 : : *
47 : : * Data path and user space interface
48 : : * -----------------------------------
49 : : *
50 : : * Recirculation uses two uint32_t fields, recirc_id and dp_hash, and a RECIRC
51 : : * action. recirc_id is used to select the next packet processing steps among
52 : : * multiple instances of recirculation. When a packet initially enters the
53 : : * datapath it is assigned with recirc_id 0, which indicates no recirculation.
54 : : * Recirc_ids are managed by the user space, opaque to the datapath.
55 : : *
56 : : * On the other hand, dp_hash can only be computed by the datapath, opaque to
57 : : * the user space, as the datapath is free to choose the hashing algorithm
58 : : * without informing user space about it. The dp_hash value should be
59 : : * wildcarded for newly received packets. HASH action specifies whether the
60 : : * hash is computed, and if computed, how many fields are to be included in the
61 : : * hash computation. The computed hash value is stored into the dp_hash field
62 : : * prior to recirculation.
63 : : *
64 : : * The RECIRC action sets the recirc_id field and then reprocesses the packet
65 : : * as if it was received again on the same input port. RECIRC action works
66 : : * like a function call; actions listed after the RECIRC action will be
67 : : * executed after recirculation. RECIRC action can be nested, but datapath
68 : : * implementation limits the number of nested recirculations to prevent
69 : : * unreasonable nesting depth or infinite loop.
70 : : *
71 : : * User space recirculation context
72 : : * ---------------------------------
73 : : *
74 : : * Recirculation is usually hidden from the OpenFlow controllers. Action
75 : : * translation code deduces when recirculation is necessary and issues a
76 : : * datapath recirculation action. All OpenFlow actions to be performed after
77 : : * recirculation are derived from the OpenFlow pipeline and are stored with the
78 : : * recirculation ID. When the OpenFlow tables are changed in a way affecting
79 : : * the recirculation flows, new recirculation ID with new metadata and actions
80 : : * is allocated and the old one is timed out.
81 : : *
82 : : * Recirculation ID pool
83 : : * ----------------------
84 : : *
85 : : * Recirculation ID needs to be unique for all datapaths. Recirculation ID
86 : : * pool keeps track of recirculation ids and stores OpenFlow pipeline
87 : : * translation context so that flow processing may continue after
88 : : * recirculation.
89 : : *
90 : : * A Recirculation ID can be any uint32_t value, except for that the value 0 is
91 : : * reserved for 'no recirculation' case.
92 : : *
93 : : * Thread-safety
94 : : * --------------
95 : : *
96 : : * All APIs are thread safe.
97 : : */
98 : :
99 : : /* Metadata for restoring pipeline context after recirculation. Helpers
100 : : * are inlined below to keep them together with the definition for easier
101 : : * updates. */
102 : : BUILD_ASSERT_DECL(FLOW_WC_SEQ == 36);
103 : :
104 : : struct frozen_metadata {
105 : : /* Metadata in struct flow. */
106 : : const struct flow_tnl *tunnel; /* Encapsulating tunnel parameters. */
107 : : ovs_be64 metadata; /* OpenFlow Metadata. */
108 : : uint64_t regs[FLOW_N_XREGS]; /* Registers. */
109 : : ofp_port_t in_port; /* Incoming port. */
110 : : };
111 : :
112 : : static inline void
113 : 1419 : frozen_metadata_from_flow(struct frozen_metadata *md,
114 : : const struct flow *flow)
115 : : {
116 : 1419 : memset(md, 0, sizeof *md);
117 : 1419 : md->tunnel = &flow->tunnel;
118 : 1419 : md->metadata = flow->metadata;
119 : 1419 : memcpy(md->regs, flow->regs, sizeof md->regs);
120 : 1419 : md->in_port = flow->in_port.ofp_port;
121 : 1419 : }
122 : :
123 : : static inline void
124 : 1503 : frozen_metadata_to_flow(const struct frozen_metadata *md,
125 : : struct flow *flow)
126 : : {
127 [ + - ][ - + ]: 1503 : if (md->tunnel && flow_tnl_dst_is_set(md->tunnel)) {
128 : 0 : flow->tunnel = *md->tunnel;
129 : : } else {
130 : 1503 : memset(&flow->tunnel, 0, sizeof flow->tunnel);
131 : : }
132 : 1503 : flow->metadata = md->metadata;
133 : 1503 : memcpy(flow->regs, md->regs, sizeof flow->regs);
134 : 1503 : flow->in_port.ofp_port = md->in_port;
135 : 1503 : }
136 : :
137 : : /* State that flow translation can save, to restore when translation
138 : : * resumes. */
139 : : struct frozen_state {
140 : : /* Initial table for processing when thawing. */
141 : : uint8_t table_id;
142 : :
143 : : /* Pipeline context for processing when thawing. */
144 : : struct uuid ofproto_uuid; /* Bridge to resume from. */
145 : : struct frozen_metadata metadata; /* Flow metadata. */
146 : : union mf_subvalue *stack; /* Stack if any. */
147 : : size_t n_stack;
148 : : mirror_mask_t mirrors; /* Mirrors already output. */
149 : : bool conntracked; /* Conntrack occurred prior to freeze. */
150 : :
151 : : /* Actions to be translated when thawing. */
152 : : struct ofpact *ofpacts;
153 : : size_t ofpacts_len; /* Size of 'ofpacts', in bytes. */
154 : : struct ofpact *action_set;
155 : : size_t action_set_len; /* Size of 'action_set', in bytes. */
156 : : };
157 : :
158 : : /* This maps a recirculation ID to saved state that flow translation can
159 : : * restore when recirculation occurs. */
160 : : struct recirc_id_node {
161 : : /* Index data. */
162 : : struct ovs_list exp_node OVS_GUARDED;
163 : : struct cmap_node id_node;
164 : : struct cmap_node metadata_node;
165 : : uint32_t id;
166 : : uint32_t hash;
167 : : struct ovs_refcount refcount;
168 : :
169 : : /* Saved state.
170 : : *
171 : : * This state should not be modified after inserting a node in the pool,
172 : : * hence the 'const' to emphasize that. */
173 : : const struct frozen_state state;
174 : :
175 : : /* Storage for tunnel metadata. */
176 : : struct flow_tnl state_metadata_tunnel;
177 : : };
178 : :
179 : : /* This is only used for bonds and will go away when bonds implementation is
180 : : * updated to use this mechanism instead of internal rules. */
181 : : uint32_t recirc_alloc_id(struct ofproto_dpif *);
182 : :
183 : : uint32_t recirc_alloc_id_ctx(const struct frozen_state *);
184 : : uint32_t recirc_find_id(const struct frozen_state *);
185 : : void recirc_free_id(uint32_t recirc_id);
186 : : void recirc_free_ofproto(struct ofproto_dpif *, const char *ofproto_name);
187 : :
188 : : const struct recirc_id_node *recirc_id_node_find(uint32_t recirc_id);
189 : :
190 : : static inline struct recirc_id_node *
191 : 771 : recirc_id_node_from_state(const struct frozen_state *state)
192 : : {
193 : 771 : return CONTAINER_OF(state, struct recirc_id_node, state);
194 : : }
195 : :
196 : 771 : static inline bool recirc_id_node_try_ref_rcu(const struct recirc_id_node *n_)
197 : : {
198 : 771 : struct recirc_id_node *node = CONST_CAST(struct recirc_id_node *, n_);
199 : :
200 [ + - ][ + + ]: 771 : return node ? ovs_refcount_try_ref_rcu(&node->refcount) : false;
201 : : }
202 : :
203 : : void recirc_id_node_unref(const struct recirc_id_node *);
204 : :
205 : : void recirc_run(void);
206 : :
207 : : /* Recirculation IDs on which references are held. */
208 : : struct recirc_refs {
209 : : unsigned n_recircs;
210 : : union {
211 : : uint32_t recirc[2]; /* When n_recircs == 1 or 2 */
212 : : uint32_t *recircs; /* When 'n_recircs' > 2 */
213 : : };
214 : : };
215 : :
216 : : #define RECIRC_REFS_EMPTY_INITIALIZER ((struct recirc_refs) \
217 : : { 0, { { 0, 0 } } })
218 : : /* Helpers to abstract the recirculation union away. */
219 : : static inline void
220 : 6744 : recirc_refs_init(struct recirc_refs *rr)
221 : : {
222 : 6744 : *rr = RECIRC_REFS_EMPTY_INITIALIZER;
223 : 6744 : }
224 : :
225 : : static inline void
226 : 947 : recirc_refs_add(struct recirc_refs *rr, uint32_t id)
227 : : {
228 [ + + ]: 947 : if (OVS_LIKELY(rr->n_recircs < ARRAY_SIZE(rr->recirc))) {
229 : 907 : rr->recirc[rr->n_recircs++] = id;
230 : : } else {
231 [ + + ]: 40 : if (rr->n_recircs == ARRAY_SIZE(rr->recirc)) {
232 : 20 : uint32_t *recircs = xmalloc(sizeof rr->recirc + sizeof id);
233 : :
234 : 20 : memcpy(recircs, rr->recirc, sizeof rr->recirc);
235 : 20 : rr->recircs = recircs;
236 : : } else {
237 : 20 : rr->recircs = xrealloc(rr->recircs,
238 : 20 : (rr->n_recircs + 1) * sizeof id);
239 : : }
240 : 40 : rr->recircs[rr->n_recircs++] = id;
241 : : }
242 : 947 : }
243 : :
244 : : static inline void
245 : 7539 : recirc_refs_swap(struct recirc_refs *a, struct recirc_refs *b)
246 : : {
247 : : struct recirc_refs tmp;
248 : :
249 : 7539 : tmp = *a;
250 : 7539 : *a = *b;
251 : 7539 : *b = tmp;
252 : 7539 : }
253 : :
254 : : static inline void
255 : 91781 : recirc_refs_unref(struct recirc_refs *rr)
256 : : {
257 [ + + ]: 91781 : if (OVS_LIKELY(rr->n_recircs <= ARRAY_SIZE(rr->recirc))) {
258 [ + + ]: 92626 : for (int i = 0; i < rr->n_recircs; i++) {
259 : 865 : recirc_free_id(rr->recirc[i]);
260 : : }
261 : : } else {
262 [ + + ]: 100 : for (int i = 0; i < rr->n_recircs; i++) {
263 : 80 : recirc_free_id(rr->recircs[i]);
264 : : }
265 : 20 : free(rr->recircs);
266 : : }
267 : 91781 : rr->n_recircs = 0;
268 : 91781 : }
269 : :
270 : : #endif
|