]>
Commit | Line | Data |
---|---|---|
f5374617 | 1 | /* |
290835f9 | 2 | * Copyright (c) 2014, 2015, 2016 Nicira, Inc. |
f5374617 AZ |
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 | ||
e672ff9b | 23 | #include "cmap.h" |
29bae541 | 24 | #include "ofproto-dpif-mirror.h" |
b598f214 BW |
25 | #include "openvswitch/list.h" |
26 | #include "openvswitch/ofp-actions.h" | |
e672ff9b | 27 | #include "ovs-thread.h" |
290835f9 | 28 | #include "uuid.h" |
e672ff9b JR |
29 | |
30 | struct ofproto_dpif; | |
31 | struct rule; | |
f5374617 AZ |
32 | |
33 | /* | |
1d361a81 BP |
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. | |
e672ff9b | 45 | * |
e672ff9b JR |
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 | |
59781952 JR |
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. | |
e672ff9b | 55 | * |
59781952 JR |
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. | |
e672ff9b JR |
63 | * |
64 | * The RECIRC action sets the recirc_id field and then reprocesses the packet | |
59781952 JR |
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. | |
e672ff9b JR |
70 | * |
71 | * User space recirculation context | |
72 | * --------------------------------- | |
f5374617 | 73 | * |
59781952 JR |
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 | |
e672ff9b JR |
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. | |
f5374617 | 81 | * |
e672ff9b JR |
82 | * Recirculation ID pool |
83 | * ---------------------- | |
f5374617 | 84 | * |
59781952 JR |
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. | |
e672ff9b JR |
89 | * |
90 | * A Recirculation ID can be any uint32_t value, except for that the value 0 is | |
91 | * reserved for 'no recirculation' case. | |
f5374617 AZ |
92 | * |
93 | * Thread-safety | |
e672ff9b | 94 | * -------------- |
f5374617 AZ |
95 | * |
96 | * All APIs are thread safe. | |
f5374617 | 97 | */ |
e672ff9b JR |
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. */ | |
2482b0b0 | 102 | BUILD_ASSERT_DECL(FLOW_WC_SEQ == 39); |
e672ff9b | 103 | |
1d361a81 | 104 | struct frozen_metadata { |
e672ff9b | 105 | /* Metadata in struct flow. */ |
59781952 | 106 | const struct flow_tnl *tunnel; /* Encapsulating tunnel parameters. */ |
e672ff9b JR |
107 | ovs_be64 metadata; /* OpenFlow Metadata. */ |
108 | uint64_t regs[FLOW_N_XREGS]; /* Registers. */ | |
109 | ofp_port_t in_port; /* Incoming port. */ | |
e672ff9b JR |
110 | }; |
111 | ||
112 | static inline void | |
1d361a81 | 113 | frozen_metadata_from_flow(struct frozen_metadata *md, |
e672ff9b JR |
114 | const struct flow *flow) |
115 | { | |
116 | memset(md, 0, sizeof *md); | |
59781952 | 117 | md->tunnel = &flow->tunnel; |
e672ff9b JR |
118 | md->metadata = flow->metadata; |
119 | memcpy(md->regs, flow->regs, sizeof md->regs); | |
120 | md->in_port = flow->in_port.ofp_port; | |
e672ff9b JR |
121 | } |
122 | ||
123 | static inline void | |
1d361a81 | 124 | frozen_metadata_to_flow(const struct frozen_metadata *md, |
e672ff9b JR |
125 | struct flow *flow) |
126 | { | |
ffe4c74f | 127 | if (md->tunnel && flow_tnl_dst_is_set(md->tunnel)) { |
59781952 JR |
128 | flow->tunnel = *md->tunnel; |
129 | } else { | |
130 | memset(&flow->tunnel, 0, sizeof flow->tunnel); | |
131 | } | |
e672ff9b JR |
132 | flow->metadata = md->metadata; |
133 | memcpy(flow->regs, md->regs, sizeof flow->regs); | |
134 | flow->in_port.ofp_port = md->in_port; | |
e672ff9b JR |
135 | } |
136 | ||
1d361a81 BP |
137 | /* State that flow translation can save, to restore when translation |
138 | * resumes. */ | |
139 | struct frozen_state { | |
140 | /* Initial table for processing when thawing. */ | |
e672ff9b JR |
141 | uint8_t table_id; |
142 | ||
1d361a81 BP |
143 | /* Pipeline context for processing when thawing. */ |
144 | struct uuid ofproto_uuid; /* Bridge to resume from. */ | |
145 | struct frozen_metadata metadata; /* Flow metadata. */ | |
84cf3c1f JR |
146 | uint8_t *stack; /* Stack if any. */ |
147 | size_t stack_size; | |
29bae541 | 148 | mirror_mask_t mirrors; /* Mirrors already output. */ |
1d361a81 | 149 | bool conntracked; /* Conntrack occurred prior to freeze. */ |
e672ff9b | 150 | |
1d361a81 | 151 | /* Actions to be translated when thawing. */ |
417509fa BP |
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. */ | |
2082425c BP |
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. */ | |
1d361a81 | 173 | const struct frozen_state state; |
59781952 JR |
174 | |
175 | /* Storage for tunnel metadata. */ | |
176 | struct flow_tnl state_metadata_tunnel; | |
e672ff9b JR |
177 | }; |
178 | ||
e672ff9b JR |
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 | ||
1d361a81 BP |
183 | uint32_t recirc_alloc_id_ctx(const struct frozen_state *); |
184 | uint32_t recirc_find_id(const struct frozen_state *); | |
e672ff9b JR |
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); | |
e6bc8e74 | 189 | bool recirc_id_node_find_and_ref(uint32_t id); |
e672ff9b | 190 | |
29b1ea3f | 191 | static inline struct recirc_id_node * |
1d361a81 | 192 | recirc_id_node_from_state(const struct frozen_state *state) |
29b1ea3f BP |
193 | { |
194 | return CONTAINER_OF(state, struct recirc_id_node, state); | |
195 | } | |
196 | ||
e672ff9b JR |
197 | static inline bool recirc_id_node_try_ref_rcu(const struct recirc_id_node *n_) |
198 | { | |
199 | struct recirc_id_node *node = CONST_CAST(struct recirc_id_node *, n_); | |
200 | ||
201 | return node ? ovs_refcount_try_ref_rcu(&node->refcount) : false; | |
202 | } | |
203 | ||
204 | void recirc_id_node_unref(const struct recirc_id_node *); | |
205 | ||
206 | void recirc_run(void); | |
207 | ||
fbf5d6ec JR |
208 | /* Recirculation IDs on which references are held. */ |
209 | struct recirc_refs { | |
210 | unsigned n_recircs; | |
211 | union { | |
212 | uint32_t recirc[2]; /* When n_recircs == 1 or 2 */ | |
213 | uint32_t *recircs; /* When 'n_recircs' > 2 */ | |
214 | }; | |
215 | }; | |
216 | ||
217 | #define RECIRC_REFS_EMPTY_INITIALIZER ((struct recirc_refs) \ | |
218 | { 0, { { 0, 0 } } }) | |
219 | /* Helpers to abstract the recirculation union away. */ | |
220 | static inline void | |
221 | recirc_refs_init(struct recirc_refs *rr) | |
222 | { | |
223 | *rr = RECIRC_REFS_EMPTY_INITIALIZER; | |
224 | } | |
225 | ||
226 | static inline void | |
227 | recirc_refs_add(struct recirc_refs *rr, uint32_t id) | |
228 | { | |
229 | if (OVS_LIKELY(rr->n_recircs < ARRAY_SIZE(rr->recirc))) { | |
230 | rr->recirc[rr->n_recircs++] = id; | |
231 | } else { | |
232 | if (rr->n_recircs == ARRAY_SIZE(rr->recirc)) { | |
233 | uint32_t *recircs = xmalloc(sizeof rr->recirc + sizeof id); | |
234 | ||
235 | memcpy(recircs, rr->recirc, sizeof rr->recirc); | |
236 | rr->recircs = recircs; | |
237 | } else { | |
238 | rr->recircs = xrealloc(rr->recircs, | |
239 | (rr->n_recircs + 1) * sizeof id); | |
240 | } | |
241 | rr->recircs[rr->n_recircs++] = id; | |
242 | } | |
243 | } | |
244 | ||
245 | static inline void | |
246 | recirc_refs_swap(struct recirc_refs *a, struct recirc_refs *b) | |
247 | { | |
248 | struct recirc_refs tmp; | |
249 | ||
250 | tmp = *a; | |
251 | *a = *b; | |
252 | *b = tmp; | |
253 | } | |
254 | ||
255 | static inline void | |
256 | recirc_refs_unref(struct recirc_refs *rr) | |
257 | { | |
258 | if (OVS_LIKELY(rr->n_recircs <= ARRAY_SIZE(rr->recirc))) { | |
259 | for (int i = 0; i < rr->n_recircs; i++) { | |
260 | recirc_free_id(rr->recirc[i]); | |
261 | } | |
262 | } else { | |
263 | for (int i = 0; i < rr->n_recircs; i++) { | |
264 | recirc_free_id(rr->recircs[i]); | |
265 | } | |
266 | free(rr->recircs); | |
267 | } | |
268 | rr->n_recircs = 0; | |
269 | } | |
270 | ||
f5374617 | 271 | #endif |