2 * Copyright (c) 2014, 2015, 2016 Nicira, Inc.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #ifndef OFPROTO_DPIF_RID_H
18 #define OFPROTO_DPIF_RID_H
24 #include "ofproto-dpif-mirror.h"
25 #include "openvswitch/list.h"
26 #include "openvswitch/ofp-actions.h"
27 #include "ovs-thread.h"
34 * Freezing and recirculation
35 * ==========================
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".
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.
47 * Data path and user space interface
48 * -----------------------------------
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.
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.
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.
71 * User space recirculation context
72 * ---------------------------------
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.
82 * Recirculation ID pool
83 * ----------------------
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
90 * A Recirculation ID can be any uint32_t value, except for that the value 0 is
91 * reserved for 'no recirculation' case.
96 * All APIs are thread safe.
99 /* Metadata for restoring pipeline context after recirculation. Helpers
100 * are inlined below to keep them together with the definition for easier
102 BUILD_ASSERT_DECL(FLOW_WC_SEQ
== 39);
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. */
113 frozen_metadata_from_flow(struct frozen_metadata
*md
,
114 const struct flow
*flow
)
116 memset(md
, 0, sizeof *md
);
117 md
->tunnel
= &flow
->tunnel
;
118 md
->metadata
= flow
->metadata
;
119 memcpy(md
->regs
, flow
->regs
, sizeof md
->regs
);
120 md
->in_port
= flow
->in_port
.ofp_port
;
124 frozen_metadata_to_flow(const struct frozen_metadata
*md
,
127 if (md
->tunnel
&& flow_tnl_dst_is_set(md
->tunnel
)) {
128 flow
->tunnel
= *md
->tunnel
;
130 memset(&flow
->tunnel
, 0, sizeof flow
->tunnel
);
132 flow
->metadata
= md
->metadata
;
133 memcpy(flow
->regs
, md
->regs
, sizeof flow
->regs
);
134 flow
->in_port
.ofp_port
= md
->in_port
;
137 /* State that flow translation can save, to restore when translation
139 struct frozen_state
{
140 /* Initial table for processing when thawing. */
143 /* Pipeline context for processing when thawing. */
144 struct uuid ofproto_uuid
; /* Bridge to resume from. */
145 struct frozen_metadata metadata
; /* Flow metadata. */
146 uint8_t *stack
; /* Stack if any. */
148 mirror_mask_t mirrors
; /* Mirrors already output. */
149 bool conntracked
; /* Conntrack occurred prior to freeze. */
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. */
158 /* This maps a recirculation ID to saved state that flow translation can
159 * restore when recirculation occurs. */
160 struct recirc_id_node
{
162 struct ovs_list exp_node OVS_GUARDED
;
163 struct cmap_node id_node
;
164 struct cmap_node metadata_node
;
167 struct ovs_refcount refcount
;
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
;
175 /* Storage for tunnel metadata. */
176 struct flow_tnl state_metadata_tunnel
;
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
*);
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
);
188 const struct recirc_id_node
*recirc_id_node_find(uint32_t recirc_id
);
190 static inline struct recirc_id_node
*
191 recirc_id_node_from_state(const struct frozen_state
*state
)
193 return CONTAINER_OF(state
, struct recirc_id_node
, state
);
196 static inline bool recirc_id_node_try_ref_rcu(const struct recirc_id_node
*n_
)
198 struct recirc_id_node
*node
= CONST_CAST(struct recirc_id_node
*, n_
);
200 return node
? ovs_refcount_try_ref_rcu(&node
->refcount
) : false;
203 void recirc_id_node_unref(const struct recirc_id_node
*);
205 void recirc_run(void);
207 /* Recirculation IDs on which references are held. */
211 uint32_t recirc
[2]; /* When n_recircs == 1 or 2 */
212 uint32_t *recircs
; /* When 'n_recircs' > 2 */
216 #define RECIRC_REFS_EMPTY_INITIALIZER ((struct recirc_refs) \
218 /* Helpers to abstract the recirculation union away. */
220 recirc_refs_init(struct recirc_refs
*rr
)
222 *rr
= RECIRC_REFS_EMPTY_INITIALIZER
;
226 recirc_refs_add(struct recirc_refs
*rr
, uint32_t id
)
228 if (OVS_LIKELY(rr
->n_recircs
< ARRAY_SIZE(rr
->recirc
))) {
229 rr
->recirc
[rr
->n_recircs
++] = id
;
231 if (rr
->n_recircs
== ARRAY_SIZE(rr
->recirc
)) {
232 uint32_t *recircs
= xmalloc(sizeof rr
->recirc
+ sizeof id
);
234 memcpy(recircs
, rr
->recirc
, sizeof rr
->recirc
);
235 rr
->recircs
= recircs
;
237 rr
->recircs
= xrealloc(rr
->recircs
,
238 (rr
->n_recircs
+ 1) * sizeof id
);
240 rr
->recircs
[rr
->n_recircs
++] = id
;
245 recirc_refs_swap(struct recirc_refs
*a
, struct recirc_refs
*b
)
247 struct recirc_refs tmp
;
255 recirc_refs_unref(struct recirc_refs
*rr
)
257 if (OVS_LIKELY(rr
->n_recircs
<= ARRAY_SIZE(rr
->recirc
))) {
258 for (int i
= 0; i
< rr
->n_recircs
; i
++) {
259 recirc_free_id(rr
->recirc
[i
]);
262 for (int i
= 0; i
< rr
->n_recircs
; i
++) {
263 recirc_free_id(rr
->recircs
[i
]);