/src/openvswitch/lib/ofp-actions.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2008-2017, 2019-2020 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 | | #include <config.h> |
18 | | |
19 | | #include <sys/types.h> |
20 | | #include <netinet/in.h> |
21 | | |
22 | | #include "bundle.h" |
23 | | #include "byte-order.h" |
24 | | #include "colors.h" |
25 | | #include "compiler.h" |
26 | | #include "dummy.h" |
27 | | #include "openvswitch/hmap.h" |
28 | | #include "learn.h" |
29 | | #include "multipath.h" |
30 | | #include "nx-match.h" |
31 | | #include "odp-netlink.h" |
32 | | #include "openvswitch/dynamic-string.h" |
33 | | #include "openvswitch/meta-flow.h" |
34 | | #include "openvswitch/ofp-actions.h" |
35 | | #include "openvswitch/ofp-packet.h" |
36 | | #include "openvswitch/ofp-parse.h" |
37 | | #include "openvswitch/ofp-port.h" |
38 | | #include "openvswitch/ofp-prop.h" |
39 | | #include "openvswitch/ofp-table.h" |
40 | | #include "openvswitch/ofpbuf.h" |
41 | | #include "openvswitch/vlog.h" |
42 | | #include "unaligned.h" |
43 | | #include "util.h" |
44 | | #include "vl-mff-map.h" |
45 | | |
46 | | VLOG_DEFINE_THIS_MODULE(ofp_actions); |
47 | | |
48 | | static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); |
49 | | |
50 | | struct ofp_action_header; |
51 | | |
52 | | /* Header for Open vSwitch and ONF vendor extension actions. |
53 | | * |
54 | | * This is the entire header for a few Open vSwitch vendor extension actions, |
55 | | * the ones that either have no arguments or for which variable-length |
56 | | * arguments follow the header. |
57 | | * |
58 | | * This cannot be used as an entirely generic vendor extension action header, |
59 | | * because OpenFlow does not specify the location or size of the action |
60 | | * subtype; it just happens that ONF extensions and Nicira extensions share |
61 | | * this format. */ |
62 | | struct ext_action_header { |
63 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
64 | | ovs_be16 len; /* At least 16. */ |
65 | | ovs_be32 vendor; /* NX_VENDOR_ID or ONF_VENDOR_ID. */ |
66 | | ovs_be16 subtype; /* See enum ofp_raw_action_type. */ |
67 | | uint8_t pad[6]; |
68 | | }; |
69 | | OFP_ASSERT(sizeof(struct ext_action_header) == 16); |
70 | | |
71 | | /* Raw identifiers for OpenFlow actions. |
72 | | * |
73 | | * Decoding and encoding OpenFlow actions across multiple versions is difficult |
74 | | * to do in a clean, consistent way. This enumeration lays out all of the |
75 | | * forms of actions that Open vSwitch supports. |
76 | | * |
77 | | * The comments here must follow a stylized form because the |
78 | | * "extract-ofp-actions" program parses them at build time to generate data |
79 | | * tables. |
80 | | * |
81 | | * - The first part of each comment specifies the vendor, OpenFlow versions, |
82 | | * and type for each protocol that supports the action: |
83 | | * |
84 | | * # The vendor is OF for standard OpenFlow actions, NX for Nicira |
85 | | * extension actions. (Support for other vendors can be added, but |
86 | | * it can't be done just based on a vendor ID definition alone |
87 | | * because OpenFlow doesn't define a standard way to specify a |
88 | | * subtype for vendor actions, so other vendors might do it different |
89 | | * from Nicira.) |
90 | | * |
91 | | * # The version can specify a specific OpenFlow version, a version |
92 | | * range delimited by "-", or an open-ended range with "+". |
93 | | * |
94 | | * # The type, in parentheses, is the action type number (for standard |
95 | | * OpenFlow actions) or subtype (for vendor extension actions). |
96 | | * |
97 | | * # Optionally one may add "is deprecated" followed by a |
98 | | * human-readable reason in parentheses (which will be used in log |
99 | | * messages), if a particular action should no longer be used. |
100 | | * |
101 | | * Multiple such specifications may be separated by commas. |
102 | | * |
103 | | * - The second part describes the action's wire format. It may be: |
104 | | * |
105 | | * # "struct <name>": The struct fully specifies the wire format. The |
106 | | * action is exactly the size of the struct. (Thus, the struct must |
107 | | * be an exact multiple of 8 bytes in size.) |
108 | | * |
109 | | * # "struct <name>, ...": The struct specifies the beginning of the |
110 | | * wire format. An instance of the action is either the struct's |
111 | | * exact size, or a multiple of 8 bytes longer. |
112 | | * |
113 | | * # "uint<N>_t" or "ovs_be<N>": The action consists of a (standard or |
114 | | * vendor extension) header, followed by 0 or more pad bytes to align |
115 | | * to a multiple of <N> bits, followed by an argument of the given |
116 | | * type, followed by 0 or more pad bytes to bring the total action up |
117 | | * to a multiple of 8 bytes. |
118 | | * |
119 | | * # "void": The action is just a (standard or vendor extension) |
120 | | * header. |
121 | | * |
122 | | * # Optionally, one may add "VLMFF" in the end of the second part if |
123 | | * the Openflow action may use a variable length meta-flow field |
124 | | * (i.e. tun_metadata). Adding "VLMFF" will pass the per-switch based |
125 | | * variable length meta-flow field mapping map (struct vl_mff_map) to |
126 | | * the corresponding action decoding function. |
127 | | * |
128 | | * - Optional additional text enclosed in square brackets is commentary for |
129 | | * the human reader. |
130 | | */ |
131 | | enum ofp_raw_action_type { |
132 | | /* ## ----------------- ## */ |
133 | | /* ## Standard actions. ## */ |
134 | | /* ## ----------------- ## */ |
135 | | |
136 | | /* OF1.0(0): struct ofp10_action_output. */ |
137 | | OFPAT_RAW10_OUTPUT, |
138 | | /* OF1.1+(0): struct ofp11_action_output. */ |
139 | | OFPAT_RAW11_OUTPUT, |
140 | | |
141 | | /* OF1.0(1): uint16_t. */ |
142 | | OFPAT_RAW10_SET_VLAN_VID, |
143 | | /* OF1.0(2): uint8_t. */ |
144 | | OFPAT_RAW10_SET_VLAN_PCP, |
145 | | |
146 | | /* OF1.1(1), OF1.2+(1) is deprecated (use Set-Field): uint16_t. |
147 | | * |
148 | | * [Semantics differ slightly between the 1.0 and 1.1 versions of the VLAN |
149 | | * modification actions: the 1.0 versions push a VLAN header if none is |
150 | | * present, but the 1.1 versions do not. That is the only reason that we |
151 | | * distinguish their raw action types.] */ |
152 | | OFPAT_RAW11_SET_VLAN_VID, |
153 | | /* OF1.1(2), OF1.2+(2) is deprecated (use Set-Field): uint8_t. */ |
154 | | OFPAT_RAW11_SET_VLAN_PCP, |
155 | | |
156 | | /* OF1.1+(17): ovs_be16. |
157 | | * |
158 | | * [The argument is the Ethertype, e.g. ETH_TYPE_VLAN_8021Q, not the VID or |
159 | | * TCI.] */ |
160 | | OFPAT_RAW11_PUSH_VLAN, |
161 | | |
162 | | /* OF1.0(3): void. */ |
163 | | OFPAT_RAW10_STRIP_VLAN, |
164 | | /* OF1.1+(18): void. */ |
165 | | OFPAT_RAW11_POP_VLAN, |
166 | | |
167 | | /* OF1.0(4), OF1.1(3), OF1.2+(3) is deprecated (use Set-Field): struct |
168 | | * ofp_action_dl_addr. */ |
169 | | OFPAT_RAW_SET_DL_SRC, |
170 | | |
171 | | /* OF1.0(5), OF1.1(4), OF1.2+(4) is deprecated (use Set-Field): struct |
172 | | * ofp_action_dl_addr. */ |
173 | | OFPAT_RAW_SET_DL_DST, |
174 | | |
175 | | /* OF1.0(6), OF1.1(5), OF1.2+(5) is deprecated (use Set-Field): |
176 | | * ovs_be32. */ |
177 | | OFPAT_RAW_SET_NW_SRC, |
178 | | |
179 | | /* OF1.0(7), OF1.1(6), OF1.2+(6) is deprecated (use Set-Field): |
180 | | * ovs_be32. */ |
181 | | OFPAT_RAW_SET_NW_DST, |
182 | | |
183 | | /* OF1.0(8), OF1.1(7), OF1.2+(7) is deprecated (use Set-Field): uint8_t. */ |
184 | | OFPAT_RAW_SET_NW_TOS, |
185 | | |
186 | | /* OF1.1(8), OF1.2+(8) is deprecated (use Set-Field): uint8_t. */ |
187 | | OFPAT_RAW11_SET_NW_ECN, |
188 | | |
189 | | /* OF1.0(9), OF1.1(9), OF1.2+(9) is deprecated (use Set-Field): |
190 | | * ovs_be16. */ |
191 | | OFPAT_RAW_SET_TP_SRC, |
192 | | |
193 | | /* OF1.0(10), OF1.1(10), OF1.2+(10) is deprecated (use Set-Field): |
194 | | * ovs_be16. */ |
195 | | OFPAT_RAW_SET_TP_DST, |
196 | | |
197 | | /* OF1.0(11): struct ofp10_action_enqueue. */ |
198 | | OFPAT_RAW10_ENQUEUE, |
199 | | |
200 | | /* NX1.0(30), OF1.1(13), OF1.2+(13) is deprecated (use Set-Field): |
201 | | * ovs_be32. */ |
202 | | OFPAT_RAW_SET_MPLS_LABEL, |
203 | | |
204 | | /* NX1.0(31), OF1.1(14), OF1.2+(14) is deprecated (use Set-Field): |
205 | | * uint8_t. */ |
206 | | OFPAT_RAW_SET_MPLS_TC, |
207 | | |
208 | | /* NX1.0(25), OF1.1(15), OF1.2+(15) is deprecated (use Set-Field): |
209 | | * uint8_t. */ |
210 | | OFPAT_RAW_SET_MPLS_TTL, |
211 | | |
212 | | /* NX1.0(26), OF1.1+(16): void. */ |
213 | | OFPAT_RAW_DEC_MPLS_TTL, |
214 | | |
215 | | /* NX1.0(23), OF1.1+(19): ovs_be16. |
216 | | * |
217 | | * [The argument is the Ethertype, e.g. ETH_TYPE_MPLS, not the label.] */ |
218 | | OFPAT_RAW_PUSH_MPLS, |
219 | | |
220 | | /* NX1.0(24), OF1.1+(20): ovs_be16. |
221 | | * |
222 | | * [The argument is the Ethertype, e.g. ETH_TYPE_IPV4 if at BoS or |
223 | | * ETH_TYPE_MPLS otherwise, not the label.] */ |
224 | | OFPAT_RAW_POP_MPLS, |
225 | | |
226 | | /* NX1.0(4), OF1.1+(21): uint32_t. */ |
227 | | OFPAT_RAW_SET_QUEUE, |
228 | | |
229 | | /* NX1.0(40), OF1.1+(22): uint32_t. */ |
230 | | OFPAT_RAW_GROUP, |
231 | | |
232 | | /* OF1.1+(23): uint8_t. */ |
233 | | OFPAT_RAW11_SET_NW_TTL, |
234 | | |
235 | | /* NX1.0(18), OF1.1+(24): void. */ |
236 | | OFPAT_RAW_DEC_NW_TTL, |
237 | | /* NX1.0+(21): struct nx_action_cnt_ids, ... */ |
238 | | NXAST_RAW_DEC_TTL_CNT_IDS, |
239 | | |
240 | | /* OF1.2-1.4(25): struct ofp12_action_set_field, ... VLMFF */ |
241 | | OFPAT_RAW12_SET_FIELD, |
242 | | /* OF1.5+(25): struct ofp12_action_set_field, ... VLMFF */ |
243 | | OFPAT_RAW15_SET_FIELD, |
244 | | /* NX1.0-1.4(7): struct nx_action_reg_load. VLMFF |
245 | | * |
246 | | * [In OpenFlow 1.5, set_field is a superset of reg_load functionality, so |
247 | | * we drop reg_load.] */ |
248 | | NXAST_RAW_REG_LOAD, |
249 | | /* NX1.0-1.4(33): struct ext_action_header, ... VLMFF |
250 | | * |
251 | | * [In OpenFlow 1.5, set_field is a superset of reg_load2 functionality, so |
252 | | * we drop reg_load2.] */ |
253 | | NXAST_RAW_REG_LOAD2, |
254 | | |
255 | | /* OF1.5+(28): struct ofp15_action_copy_field, ... VLMFF */ |
256 | | OFPAT_RAW15_COPY_FIELD, |
257 | | /* ONF1.3-1.4(3200): struct onf_action_copy_field, ... VLMFF */ |
258 | | ONFACT_RAW13_COPY_FIELD, |
259 | | /* NX1.0-1.4(6): struct nx_action_reg_move, ... VLMFF */ |
260 | | NXAST_RAW_REG_MOVE, |
261 | | |
262 | | /* OF1.5+(29): uint32_t. */ |
263 | | OFPAT_RAW15_METER, |
264 | | |
265 | | /* ## ------------------------- ## */ |
266 | | /* ## Nicira extension actions. ## */ |
267 | | /* ## ------------------------- ## */ |
268 | | |
269 | | /* Actions similar to standard actions are listed with the standard actions. */ |
270 | | |
271 | | /* NX1.0+(1): uint16_t. */ |
272 | | NXAST_RAW_RESUBMIT, |
273 | | /* NX1.0+(14): struct nx_action_resubmit. */ |
274 | | NXAST_RAW_RESUBMIT_TABLE, |
275 | | /* NX1.0+(44): struct nx_action_resubmit. */ |
276 | | NXAST_RAW_RESUBMIT_TABLE_CT, |
277 | | |
278 | | /* NX1.0+(2): uint32_t. */ |
279 | | NXAST_RAW_SET_TUNNEL, |
280 | | /* NX1.0+(9): uint64_t. */ |
281 | | NXAST_RAW_SET_TUNNEL64, |
282 | | |
283 | | /* NX1.0+(5): void. */ |
284 | | NXAST_RAW_POP_QUEUE, |
285 | | |
286 | | /* NX1.0+(8): struct nx_action_note, ... */ |
287 | | NXAST_RAW_NOTE, |
288 | | |
289 | | /* NX1.0+(10): struct nx_action_multipath. VLMFF */ |
290 | | NXAST_RAW_MULTIPATH, |
291 | | |
292 | | /* NX1.0+(12): struct nx_action_bundle, ... */ |
293 | | NXAST_RAW_BUNDLE, |
294 | | /* NX1.0+(13): struct nx_action_bundle, ... VLMFF */ |
295 | | NXAST_RAW_BUNDLE_LOAD, |
296 | | |
297 | | /* NX1.0+(15): struct nx_action_output_reg. VLMFF */ |
298 | | NXAST_RAW_OUTPUT_REG, |
299 | | /* NX1.0+(32): struct nx_action_output_reg2. VLMFF */ |
300 | | NXAST_RAW_OUTPUT_REG2, |
301 | | |
302 | | /* NX1.0+(16): struct nx_action_learn, ... VLMFF */ |
303 | | NXAST_RAW_LEARN, |
304 | | /* NX1.0+(45): struct nx_action_learn2, ... VLMFF */ |
305 | | NXAST_RAW_LEARN2, |
306 | | |
307 | | /* NX1.0+(17): void. */ |
308 | | NXAST_RAW_EXIT, |
309 | | |
310 | | /* NX1.0+(19): struct nx_action_fin_timeout. */ |
311 | | NXAST_RAW_FIN_TIMEOUT, |
312 | | |
313 | | /* NX1.0+(20): struct nx_action_controller. */ |
314 | | NXAST_RAW_CONTROLLER, |
315 | | /* NX1.0+(37): struct ext_action_header, ... */ |
316 | | NXAST_RAW_CONTROLLER2, |
317 | | |
318 | | /* NX1.0+(22): struct nx_action_write_metadata. */ |
319 | | NXAST_RAW_WRITE_METADATA, |
320 | | |
321 | | /* NX1.0+(27): struct nx_action_stack. VLMFF */ |
322 | | NXAST_RAW_STACK_PUSH, |
323 | | |
324 | | /* NX1.0+(28): struct nx_action_stack. VLMFF */ |
325 | | NXAST_RAW_STACK_POP, |
326 | | |
327 | | /* NX1.0+(29): struct nx_action_sample. */ |
328 | | NXAST_RAW_SAMPLE, |
329 | | /* NX1.0+(38): struct nx_action_sample2. */ |
330 | | NXAST_RAW_SAMPLE2, |
331 | | /* NX1.0+(41): struct nx_action_sample2. */ |
332 | | NXAST_RAW_SAMPLE3, |
333 | | /* NX1.0+(51): struct nx_action_sample4. VLMFF */ |
334 | | NXAST_RAW_SAMPLE4, |
335 | | |
336 | | /* NX1.0+(34): struct nx_action_conjunction. */ |
337 | | NXAST_RAW_CONJUNCTION, |
338 | | |
339 | | /* NX1.0+(35): struct nx_action_conntrack, ... VLMFF */ |
340 | | NXAST_RAW_CT, |
341 | | |
342 | | /* NX1.0+(36): struct nx_action_nat, ... */ |
343 | | NXAST_RAW_NAT, |
344 | | |
345 | | /* NX1.0+(39): struct nx_action_output_trunc. */ |
346 | | NXAST_RAW_OUTPUT_TRUNC, |
347 | | |
348 | | /* NX1.0+(42): struct ext_action_header, ... VLMFF */ |
349 | | NXAST_RAW_CLONE, |
350 | | |
351 | | /* NX1.0+(43): void. */ |
352 | | NXAST_RAW_CT_CLEAR, |
353 | | |
354 | | /* NX1.3+(46): struct nx_action_encap, ... */ |
355 | | NXAST_RAW_ENCAP, |
356 | | |
357 | | /* NX1.3+(47): struct nx_action_decap, ... */ |
358 | | NXAST_RAW_DECAP, |
359 | | |
360 | | /* NX1.3+(48): void. */ |
361 | | NXAST_RAW_DEC_NSH_TTL, |
362 | | |
363 | | /* NX1.0+(49): struct nx_action_check_pkt_larger, ... VLMFF */ |
364 | | NXAST_RAW_CHECK_PKT_LARGER, |
365 | | |
366 | | /* NX1.0+(50): struct nx_action_delete_field. VLMFF */ |
367 | | NXAST_RAW_DELETE_FIELD, |
368 | | |
369 | | /* ## ------------------ ## */ |
370 | | /* ## Debugging actions. ## */ |
371 | | /* ## ------------------ ## */ |
372 | | |
373 | | /* These are intentionally undocumented, subject to change, and ovs-vswitchd */ |
374 | | /* accepts them only if started with --enable-dummy. */ |
375 | | |
376 | | /* NX1.0+(254): void. */ |
377 | | NXAST_RAW_DEBUG_SLOW, |
378 | | |
379 | | /* NX1.0+(255): void. */ |
380 | | NXAST_RAW_DEBUG_RECIRC, |
381 | | }; |
382 | | |
383 | | /* OpenFlow actions are always a multiple of 8 bytes in length. */ |
384 | 236k | #define OFP_ACTION_ALIGN 8 |
385 | | |
386 | | /* Define a few functions for working with instructions. */ |
387 | | #define DEFINE_INST(ENUM, STRUCT, EXTENSIBLE, NAME) \ |
388 | | static inline const struct STRUCT * OVS_UNUSED \ |
389 | | instruction_get_##ENUM(const struct ofp11_instruction *inst)\ |
390 | 145 | { \ |
391 | 145 | ovs_assert(inst->type == htons(ENUM)); \ |
392 | 145 | return ALIGNED_CAST(struct STRUCT *, inst); \ |
393 | 145 | } \ ofp-actions.c:instruction_get_OFPIT11_CLEAR_ACTIONS Line | Count | Source | 390 | 77 | { \ | 391 | 77 | ovs_assert(inst->type == htons(ENUM)); \ | 392 | 77 | return ALIGNED_CAST(struct STRUCT *, inst); \ | 393 | 77 | } \ |
ofp-actions.c:instruction_get_OFPIT11_GOTO_TABLE Line | Count | Source | 390 | 68 | { \ | 391 | 68 | ovs_assert(inst->type == htons(ENUM)); \ | 392 | 68 | return ALIGNED_CAST(struct STRUCT *, inst); \ | 393 | 68 | } \ |
Unexecuted instantiation: ofp-actions.c:instruction_get_OFPIT13_METER Unexecuted instantiation: ofp-actions.c:instruction_get_OFPIT11_APPLY_ACTIONS Unexecuted instantiation: ofp-actions.c:instruction_get_OFPIT11_WRITE_ACTIONS Unexecuted instantiation: ofp-actions.c:instruction_get_OFPIT11_WRITE_METADATA |
394 | | \ |
395 | | static inline void OVS_UNUSED \ |
396 | | instruction_init_##ENUM(struct STRUCT *s) \ |
397 | 0 | { \ |
398 | 0 | memset(s, 0, sizeof *s); \ |
399 | 0 | s->type = htons(ENUM); \ |
400 | 0 | s->len = htons(sizeof *s); \ |
401 | 0 | } \ Unexecuted instantiation: ofp-actions.c:instruction_init_OFPIT13_METER Unexecuted instantiation: ofp-actions.c:instruction_init_OFPIT11_CLEAR_ACTIONS Unexecuted instantiation: ofp-actions.c:instruction_init_OFPIT11_WRITE_ACTIONS Unexecuted instantiation: ofp-actions.c:instruction_init_OFPIT11_WRITE_METADATA Unexecuted instantiation: ofp-actions.c:instruction_init_OFPIT11_GOTO_TABLE Unexecuted instantiation: ofp-actions.c:instruction_init_OFPIT11_APPLY_ACTIONS |
402 | | \ |
403 | | static inline struct STRUCT * OVS_UNUSED \ |
404 | | instruction_put_##ENUM(struct ofpbuf *buf) \ |
405 | 0 | { \ |
406 | 0 | struct STRUCT *s = ofpbuf_put_uninit(buf, sizeof *s); \ |
407 | 0 | instruction_init_##ENUM(s); \ |
408 | 0 | return s; \ |
409 | 0 | } Unexecuted instantiation: ofp-actions.c:instruction_put_OFPIT13_METER Unexecuted instantiation: ofp-actions.c:instruction_put_OFPIT11_CLEAR_ACTIONS Unexecuted instantiation: ofp-actions.c:instruction_put_OFPIT11_WRITE_ACTIONS Unexecuted instantiation: ofp-actions.c:instruction_put_OFPIT11_WRITE_METADATA Unexecuted instantiation: ofp-actions.c:instruction_put_OFPIT11_GOTO_TABLE Unexecuted instantiation: ofp-actions.c:instruction_put_OFPIT11_APPLY_ACTIONS |
410 | | OVS_INSTRUCTIONS |
411 | | #undef DEFINE_INST |
412 | | |
413 | | static void ofpacts_update_instruction_actions(struct ofpbuf *openflow, |
414 | | size_t ofs); |
415 | | static void pad_ofpat(struct ofpbuf *openflow, size_t start_ofs); |
416 | | |
417 | | static enum ofperr ofpacts_verify(const struct ofpact[], size_t ofpacts_len, |
418 | | enum ofp_version, uint32_t allowed_ovsinsts, |
419 | | enum ofpact_type outer_action, |
420 | | char **errorp); |
421 | | |
422 | | static void put_set_field(struct ofpbuf *openflow, enum ofp_version, |
423 | | enum mf_field_id, uint64_t value); |
424 | | |
425 | | static void put_reg_load(struct ofpbuf *openflow, |
426 | | const struct mf_subfield *, uint64_t value); |
427 | | |
428 | | static enum ofperr ofpact_pull_raw(struct ofpbuf *, enum ofp_version, |
429 | | enum ofp_raw_action_type *, uint64_t *arg, |
430 | | size_t *raw_len); |
431 | | static void *ofpact_put_raw(struct ofpbuf *, enum ofp_version, |
432 | | enum ofp_raw_action_type, uint64_t arg); |
433 | | |
434 | | static char *OVS_WARN_UNUSED_RESULT ofpacts_parse( |
435 | | char *str, const struct ofpact_parse_params *pp, |
436 | | bool allow_instructions, enum ofpact_type outer_action); |
437 | | static enum ofperr ofpacts_pull_openflow_actions__( |
438 | | struct ofpbuf *openflow, unsigned int actions_len, |
439 | | enum ofp_version version, uint32_t allowed_ovsinsts, |
440 | | struct ofpbuf *ofpacts, enum ofpact_type outer_action, |
441 | | const struct vl_mff_map *vl_mff_map, uint64_t *ofpacts_tlv_bitmap); |
442 | | static char * OVS_WARN_UNUSED_RESULT ofpacts_parse_copy( |
443 | | const char *s_, const struct ofpact_parse_params *pp, |
444 | | bool allow_instructions, enum ofpact_type outer_action); |
445 | | |
446 | | static void inconsistent_match(enum ofputil_protocol *usable_protocols); |
447 | | |
448 | | /* Returns the ofpact following 'ofpact', except that if 'ofpact' contains |
449 | | * nested ofpacts it returns the first one. */ |
450 | | struct ofpact * |
451 | | ofpact_next_flattened(const struct ofpact *ofpact) |
452 | 0 | { |
453 | 0 | switch (ofpact->type) { |
454 | 0 | case OFPACT_OUTPUT: |
455 | 0 | case OFPACT_GROUP: |
456 | 0 | case OFPACT_CONTROLLER: |
457 | 0 | case OFPACT_ENQUEUE: |
458 | 0 | case OFPACT_OUTPUT_REG: |
459 | 0 | case OFPACT_OUTPUT_TRUNC: |
460 | 0 | case OFPACT_BUNDLE: |
461 | 0 | case OFPACT_SET_FIELD: |
462 | 0 | case OFPACT_SET_VLAN_VID: |
463 | 0 | case OFPACT_SET_VLAN_PCP: |
464 | 0 | case OFPACT_STRIP_VLAN: |
465 | 0 | case OFPACT_PUSH_VLAN: |
466 | 0 | case OFPACT_SET_ETH_SRC: |
467 | 0 | case OFPACT_SET_ETH_DST: |
468 | 0 | case OFPACT_SET_IPV4_SRC: |
469 | 0 | case OFPACT_SET_IPV4_DST: |
470 | 0 | case OFPACT_SET_IP_DSCP: |
471 | 0 | case OFPACT_SET_IP_ECN: |
472 | 0 | case OFPACT_SET_IP_TTL: |
473 | 0 | case OFPACT_SET_L4_SRC_PORT: |
474 | 0 | case OFPACT_SET_L4_DST_PORT: |
475 | 0 | case OFPACT_REG_MOVE: |
476 | 0 | case OFPACT_STACK_PUSH: |
477 | 0 | case OFPACT_STACK_POP: |
478 | 0 | case OFPACT_DEC_TTL: |
479 | 0 | case OFPACT_SET_MPLS_LABEL: |
480 | 0 | case OFPACT_SET_MPLS_TC: |
481 | 0 | case OFPACT_SET_MPLS_TTL: |
482 | 0 | case OFPACT_DEC_MPLS_TTL: |
483 | 0 | case OFPACT_PUSH_MPLS: |
484 | 0 | case OFPACT_POP_MPLS: |
485 | 0 | case OFPACT_SET_TUNNEL: |
486 | 0 | case OFPACT_SET_QUEUE: |
487 | 0 | case OFPACT_POP_QUEUE: |
488 | 0 | case OFPACT_FIN_TIMEOUT: |
489 | 0 | case OFPACT_RESUBMIT: |
490 | 0 | case OFPACT_LEARN: |
491 | 0 | case OFPACT_CONJUNCTION: |
492 | 0 | case OFPACT_MULTIPATH: |
493 | 0 | case OFPACT_NOTE: |
494 | 0 | case OFPACT_EXIT: |
495 | 0 | case OFPACT_SAMPLE: |
496 | 0 | case OFPACT_UNROLL_XLATE: |
497 | 0 | case OFPACT_CT_CLEAR: |
498 | 0 | case OFPACT_DEBUG_RECIRC: |
499 | 0 | case OFPACT_DEBUG_SLOW: |
500 | 0 | case OFPACT_METER: |
501 | 0 | case OFPACT_CLEAR_ACTIONS: |
502 | 0 | case OFPACT_WRITE_METADATA: |
503 | 0 | case OFPACT_GOTO_TABLE: |
504 | 0 | case OFPACT_NAT: |
505 | 0 | case OFPACT_ENCAP: |
506 | 0 | case OFPACT_DECAP: |
507 | 0 | case OFPACT_DEC_NSH_TTL: |
508 | 0 | case OFPACT_CHECK_PKT_LARGER: |
509 | 0 | case OFPACT_DELETE_FIELD: |
510 | 0 | return ofpact_next(ofpact); |
511 | | |
512 | 0 | case OFPACT_CLONE: |
513 | 0 | return ofpact_get_CLONE(ofpact)->actions; |
514 | | |
515 | 0 | case OFPACT_CT: |
516 | 0 | return ofpact_get_CT(ofpact)->actions; |
517 | | |
518 | 0 | case OFPACT_WRITE_ACTIONS: |
519 | 0 | return ofpact_get_WRITE_ACTIONS(ofpact)->actions; |
520 | 0 | } |
521 | | |
522 | 0 | OVS_NOT_REACHED(); |
523 | 0 | } |
524 | | |
525 | | /* Pull off existing actions or instructions. Used by nesting actions to keep |
526 | | * ofpacts_parse() oblivious of actions nesting. |
527 | | * |
528 | | * Push the actions back on after nested parsing, e.g.: |
529 | | * |
530 | | * size_t ofs = ofpacts_pull(ofpacts); |
531 | | * ...nested parsing... |
532 | | * ofpbuf_push_uninit(ofpacts, ofs); |
533 | | */ |
534 | | static size_t |
535 | | ofpacts_pull(struct ofpbuf *ofpacts) |
536 | 14.9k | { |
537 | 14.9k | size_t ofs; |
538 | | |
539 | 14.9k | ofs = ofpacts->size; |
540 | 14.9k | ofpbuf_pull(ofpacts, ofs); |
541 | | |
542 | 14.9k | return ofs; |
543 | 14.9k | } |
544 | | |
545 | | #include "ofp-actions.inc1" |
546 | | |
547 | | /* Output actions. */ |
548 | | |
549 | | /* Action structure for OFPAT10_OUTPUT, which sends packets out 'port'. |
550 | | * When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max |
551 | | * number of bytes to send. A 'max_len' of zero means no bytes of the |
552 | | * packet should be sent. */ |
553 | | struct ofp10_action_output { |
554 | | ovs_be16 type; /* OFPAT10_OUTPUT. */ |
555 | | ovs_be16 len; /* Length is 8. */ |
556 | | ovs_be16 port; /* Output port. */ |
557 | | ovs_be16 max_len; /* Max length to send to controller. */ |
558 | | }; |
559 | | OFP_ASSERT(sizeof(struct ofp10_action_output) == 8); |
560 | | |
561 | | /* Action structure for OFPAT_OUTPUT, which sends packets out 'port'. |
562 | | * When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max |
563 | | * number of bytes to send. A 'max_len' of zero means no bytes of the |
564 | | * packet should be sent.*/ |
565 | | struct ofp11_action_output { |
566 | | ovs_be16 type; /* OFPAT11_OUTPUT. */ |
567 | | ovs_be16 len; /* Length is 16. */ |
568 | | ovs_be32 port; /* Output port. */ |
569 | | ovs_be16 max_len; /* Max length to send to controller. */ |
570 | | uint8_t pad[6]; /* Pad to 64 bits. */ |
571 | | }; |
572 | | OFP_ASSERT(sizeof(struct ofp11_action_output) == 16); |
573 | | |
574 | | static enum ofperr |
575 | | decode_OFPAT_RAW10_OUTPUT(const struct ofp10_action_output *oao, |
576 | | enum ofp_version ofp_version OVS_UNUSED, |
577 | | struct ofpbuf *out) |
578 | 23.8k | { |
579 | 23.8k | struct ofpact_output *output; |
580 | | |
581 | 23.8k | output = ofpact_put_OUTPUT(out); |
582 | 23.8k | output->port = u16_to_ofp(ntohs(oao->port)); |
583 | 23.8k | output->max_len = ntohs(oao->max_len); |
584 | | |
585 | 23.8k | return ofpact_check_output_port(output->port, OFPP_MAX); |
586 | 23.8k | } |
587 | | |
588 | | static enum ofperr |
589 | | decode_OFPAT_RAW11_OUTPUT(const struct ofp11_action_output *oao, |
590 | | enum ofp_version ofp_version OVS_UNUSED, |
591 | | struct ofpbuf *out) |
592 | 2.73k | { |
593 | 2.73k | struct ofpact_output *output; |
594 | 2.73k | enum ofperr error; |
595 | | |
596 | 2.73k | output = ofpact_put_OUTPUT(out); |
597 | 2.73k | output->max_len = ntohs(oao->max_len); |
598 | | |
599 | 2.73k | error = ofputil_port_from_ofp11(oao->port, &output->port); |
600 | 2.73k | if (error) { |
601 | 140 | return error; |
602 | 140 | } |
603 | | |
604 | 2.59k | return ofpact_check_output_port(output->port, OFPP_MAX); |
605 | 2.73k | } |
606 | | |
607 | | static void |
608 | | encode_OUTPUT(const struct ofpact_output *output, |
609 | | enum ofp_version ofp_version, struct ofpbuf *out) |
610 | 0 | { |
611 | 0 | if (ofp_version == OFP10_VERSION) { |
612 | 0 | struct ofp10_action_output *oao; |
613 | |
|
614 | 0 | oao = put_OFPAT10_OUTPUT(out); |
615 | 0 | oao->port = htons(ofp_to_u16(output->port)); |
616 | 0 | oao->max_len = htons(output->max_len); |
617 | 0 | } else { |
618 | 0 | struct ofp11_action_output *oao; |
619 | |
|
620 | 0 | oao = put_OFPAT11_OUTPUT(out); |
621 | 0 | oao->port = ofputil_port_to_ofp11(output->port); |
622 | 0 | oao->max_len = htons(output->max_len); |
623 | 0 | } |
624 | 0 | } |
625 | | |
626 | | static char * OVS_WARN_UNUSED_RESULT |
627 | | parse_truncate_subfield(const char *arg_, |
628 | | const struct ofpact_parse_params *pp, |
629 | | struct ofpact_output_trunc *output_trunc) |
630 | 0 | { |
631 | 0 | char *key, *value; |
632 | 0 | char *arg = CONST_CAST(char *, arg_); |
633 | |
|
634 | 0 | while (ofputil_parse_key_value(&arg, &key, &value)) { |
635 | 0 | if (!strcmp(key, "port")) { |
636 | 0 | if (!ofputil_port_from_string(value, pp->port_map, |
637 | 0 | &output_trunc->port)) { |
638 | 0 | return xasprintf("output to unknown truncate port: %s", |
639 | 0 | value); |
640 | 0 | } |
641 | 0 | if (ofp_to_u16(output_trunc->port) > ofp_to_u16(OFPP_MAX)) { |
642 | 0 | if (output_trunc->port != OFPP_LOCAL && |
643 | 0 | output_trunc->port != OFPP_IN_PORT) |
644 | 0 | return xasprintf("output to unsupported truncate port: %s", |
645 | 0 | value); |
646 | 0 | } |
647 | 0 | } else if (!strcmp(key, "max_len")) { |
648 | 0 | char *err; |
649 | |
|
650 | 0 | err = str_to_u32(value, &output_trunc->max_len); |
651 | 0 | if (err) { |
652 | 0 | return err; |
653 | 0 | } |
654 | | |
655 | 0 | if (output_trunc->max_len < ETH_HEADER_LEN) { |
656 | 0 | return xasprintf("max_len %"PRIu32" is less than the minimum " |
657 | 0 | "value %d", |
658 | 0 | output_trunc->max_len, ETH_HEADER_LEN); |
659 | 0 | } |
660 | 0 | } else { |
661 | 0 | return xasprintf("invalid key '%s' in output_trunc argument", |
662 | 0 | key); |
663 | 0 | } |
664 | 0 | } |
665 | 0 | return NULL; |
666 | 0 | } |
667 | | |
668 | | static char * OVS_WARN_UNUSED_RESULT |
669 | | parse_OUTPUT(const char *arg, const struct ofpact_parse_params *pp) |
670 | 0 | { |
671 | 0 | if (strstr(arg, "port") && strstr(arg, "max_len")) { |
672 | 0 | struct ofpact_output_trunc *output_trunc; |
673 | |
|
674 | 0 | output_trunc = ofpact_put_OUTPUT_TRUNC(pp->ofpacts); |
675 | 0 | return parse_truncate_subfield(arg, pp, output_trunc); |
676 | 0 | } |
677 | | |
678 | 0 | ofp_port_t port; |
679 | 0 | if (ofputil_port_from_string(arg, pp->port_map, &port)) { |
680 | 0 | struct ofpact_output *output = ofpact_put_OUTPUT(pp->ofpacts); |
681 | 0 | output->port = port; |
682 | 0 | output->max_len = output->port == OFPP_CONTROLLER ? UINT16_MAX : 0; |
683 | 0 | return NULL; |
684 | 0 | } |
685 | | |
686 | 0 | struct mf_subfield src; |
687 | 0 | char *error = mf_parse_subfield(&src, arg); |
688 | 0 | if (!error) { |
689 | 0 | struct ofpact_output_reg *output_reg; |
690 | |
|
691 | 0 | output_reg = ofpact_put_OUTPUT_REG(pp->ofpacts); |
692 | 0 | output_reg->max_len = UINT16_MAX; |
693 | 0 | output_reg->src = src; |
694 | 0 | return NULL; |
695 | 0 | } |
696 | 0 | free(error); |
697 | |
|
698 | 0 | return xasprintf("%s: output to unknown port", arg); |
699 | 0 | } |
700 | | |
701 | | static void |
702 | | format_OUTPUT(const struct ofpact_output *a, |
703 | | const struct ofpact_format_params *fp) |
704 | 16.9k | { |
705 | 16.9k | if (ofp_to_u16(a->port) < ofp_to_u16(OFPP_MAX)) { |
706 | 8.66k | ds_put_format(fp->s, "%soutput:%s", colors.special, colors.end); |
707 | 8.66k | } |
708 | 16.9k | ofputil_format_port(a->port, fp->port_map, fp->s); |
709 | 16.9k | if (a->port == OFPP_CONTROLLER) { |
710 | 915 | ds_put_format(fp->s, ":%"PRIu16, a->max_len); |
711 | 915 | } |
712 | 16.9k | } |
713 | | |
714 | | static enum ofperr |
715 | | check_OUTPUT(const struct ofpact_output *a, |
716 | | const struct ofpact_check_params *cp) |
717 | 16.3k | { |
718 | 16.3k | return ofpact_check_output_port(a->port, cp->max_ports); |
719 | 16.3k | } |
720 | | |
721 | | /* Group actions. */ |
722 | | |
723 | | static enum ofperr |
724 | | decode_OFPAT_RAW_GROUP(uint32_t group_id, |
725 | | enum ofp_version ofp_version OVS_UNUSED, |
726 | | struct ofpbuf *out) |
727 | 1.94k | { |
728 | 1.94k | ofpact_put_GROUP(out)->group_id = group_id; |
729 | 1.94k | return 0; |
730 | 1.94k | } |
731 | | |
732 | | static void |
733 | | encode_GROUP(const struct ofpact_group *group, |
734 | | enum ofp_version ofp_version, struct ofpbuf *out) |
735 | 0 | { |
736 | 0 | put_OFPAT_GROUP(out, ofp_version, group->group_id); |
737 | 0 | } |
738 | | |
739 | | static char * OVS_WARN_UNUSED_RESULT |
740 | | parse_GROUP(char *arg, const struct ofpact_parse_params *pp) |
741 | 0 | { |
742 | 0 | return str_to_u32(arg, &ofpact_put_GROUP(pp->ofpacts)->group_id); |
743 | 0 | } |
744 | | |
745 | | static void |
746 | | format_GROUP(const struct ofpact_group *a, |
747 | | const struct ofpact_format_params *fp) |
748 | 1.33k | { |
749 | 1.33k | ds_put_format(fp->s, "%sgroup:%s%"PRIu32, |
750 | 1.33k | colors.special, colors.end, a->group_id); |
751 | 1.33k | } |
752 | | |
753 | | static enum ofperr |
754 | | check_GROUP(const struct ofpact_group *a OVS_UNUSED, |
755 | | const struct ofpact_check_params *cp OVS_UNUSED) |
756 | 1.17k | { |
757 | 1.17k | return 0; |
758 | 1.17k | } |
759 | | |
760 | | /* Action structure for NXAST_CONTROLLER. |
761 | | * |
762 | | * This generalizes using OFPAT_OUTPUT to send a packet to OFPP_CONTROLLER. In |
763 | | * addition to the 'max_len' that OFPAT_OUTPUT supports, it also allows |
764 | | * specifying: |
765 | | * |
766 | | * - 'reason': The reason code to use in the ofp_packet_in or nx_packet_in. |
767 | | * |
768 | | * - 'controller_id': The ID of the controller connection to which the |
769 | | * ofp_packet_in should be sent. The ofp_packet_in or nx_packet_in is |
770 | | * sent only to controllers that have the specified controller connection |
771 | | * ID. See "struct nx_controller_id" for more information. */ |
772 | | struct nx_action_controller { |
773 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
774 | | ovs_be16 len; /* Length is 16. */ |
775 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
776 | | ovs_be16 subtype; /* NXAST_CONTROLLER. */ |
777 | | ovs_be16 max_len; /* Maximum length to send to controller. */ |
778 | | ovs_be16 controller_id; /* Controller ID to send packet-in. */ |
779 | | uint8_t reason; /* enum ofp_packet_in_reason (OFPR_*). */ |
780 | | uint8_t zero; /* Must be zero. */ |
781 | | }; |
782 | | OFP_ASSERT(sizeof(struct nx_action_controller) == 16); |
783 | | |
784 | | /* Properties for NXAST_CONTROLLER2. |
785 | | * |
786 | | * For more information on the effect of NXAC2PT_PAUSE, see the large comment |
787 | | * on NXT_PACKET_IN2 in nicira-ext.h */ |
788 | | enum nx_action_controller2_prop_type { |
789 | | NXAC2PT_MAX_LEN, /* ovs_be16 max bytes to send (default all). */ |
790 | | NXAC2PT_CONTROLLER_ID, /* ovs_be16 dest controller ID (default 0). */ |
791 | | NXAC2PT_REASON, /* uint8_t reason (OFPR_*), default 0. */ |
792 | | NXAC2PT_USERDATA, /* Data to copy into NXPINT_USERDATA. */ |
793 | | NXAC2PT_PAUSE, /* Flag to pause pipeline to resume later. */ |
794 | | NXAC2PT_METER_ID, /* ovs_b32 meter (default NX_CTLR_NO_METER). */ |
795 | | }; |
796 | | |
797 | | /* The action structure for NXAST_CONTROLLER2 is "struct ext_action_header", |
798 | | * followed by NXAC2PT_* properties. */ |
799 | | |
800 | | static enum ofperr |
801 | | decode_NXAST_RAW_CONTROLLER(const struct nx_action_controller *nac, |
802 | | enum ofp_version ofp_version OVS_UNUSED, |
803 | | struct ofpbuf *out) |
804 | 1.76k | { |
805 | 1.76k | struct ofpact_controller *oc; |
806 | | |
807 | 1.76k | oc = ofpact_put_CONTROLLER(out); |
808 | 1.76k | oc->ofpact.raw = NXAST_RAW_CONTROLLER; |
809 | 1.76k | oc->max_len = ntohs(nac->max_len); |
810 | 1.76k | oc->controller_id = ntohs(nac->controller_id); |
811 | 1.76k | oc->reason = nac->reason; |
812 | 1.76k | oc->meter_id = NX_CTLR_NO_METER; |
813 | 1.76k | ofpact_finish_CONTROLLER(out, &oc); |
814 | | |
815 | 1.76k | return 0; |
816 | 1.76k | } |
817 | | |
818 | | static enum ofperr |
819 | | decode_NXAST_RAW_CONTROLLER2(const struct ext_action_header *eah, |
820 | | enum ofp_version ofp_version OVS_UNUSED, |
821 | | struct ofpbuf *out) |
822 | 1.81k | { |
823 | 1.81k | if (!is_all_zeros(eah->pad, sizeof eah->pad)) { |
824 | 304 | return OFPERR_NXBRC_MUST_BE_ZERO; |
825 | 304 | } |
826 | | |
827 | 1.50k | size_t start_ofs = out->size; |
828 | 1.50k | struct ofpact_controller *oc = ofpact_put_CONTROLLER(out); |
829 | 1.50k | oc->ofpact.raw = NXAST_RAW_CONTROLLER2; |
830 | 1.50k | oc->max_len = UINT16_MAX; |
831 | 1.50k | oc->reason = OFPR_ACTION; |
832 | 1.50k | oc->meter_id = NX_CTLR_NO_METER; |
833 | | |
834 | 1.50k | struct ofpbuf properties; |
835 | 1.50k | ofpbuf_use_const(&properties, eah, ntohs(eah->len)); |
836 | 1.50k | ofpbuf_pull(&properties, sizeof *eah); |
837 | | |
838 | 2.79k | while (properties.size > 0) { |
839 | 1.84k | struct ofpbuf payload; |
840 | 1.84k | uint64_t type; |
841 | | |
842 | 1.84k | enum ofperr error = ofpprop_pull(&properties, &payload, &type); |
843 | 1.84k | if (error) { |
844 | 466 | return error; |
845 | 466 | } |
846 | | |
847 | 1.38k | switch (type) { |
848 | 180 | case NXAC2PT_MAX_LEN: |
849 | 180 | error = ofpprop_parse_u16(&payload, &oc->max_len); |
850 | 180 | break; |
851 | | |
852 | 34 | case NXAC2PT_CONTROLLER_ID: |
853 | 34 | error = ofpprop_parse_u16(&payload, &oc->controller_id); |
854 | 34 | break; |
855 | | |
856 | 116 | case NXAC2PT_REASON: { |
857 | 116 | uint8_t u8; |
858 | 116 | error = ofpprop_parse_u8(&payload, &u8); |
859 | 116 | if (!error) { |
860 | 106 | oc->reason = u8; |
861 | 106 | } |
862 | 116 | break; |
863 | 0 | } |
864 | | |
865 | 744 | case NXAC2PT_USERDATA: |
866 | 744 | out->size = start_ofs + sizeof(struct ofpact_controller); |
867 | 744 | ofpbuf_put(out, payload.msg, ofpbuf_msgsize(&payload)); |
868 | 744 | oc = ofpbuf_at_assert(out, start_ofs, sizeof *oc); |
869 | 744 | oc->userdata_len = ofpbuf_msgsize(&payload); |
870 | 744 | break; |
871 | | |
872 | 180 | case NXAC2PT_PAUSE: |
873 | 180 | oc->pause = true; |
874 | 180 | break; |
875 | | |
876 | 44 | case NXAC2PT_METER_ID: |
877 | 44 | error = ofpprop_parse_u32(&payload, &oc->meter_id); |
878 | 44 | break; |
879 | | |
880 | 85 | default: |
881 | 85 | error = OFPPROP_UNKNOWN(false, "NXAST_RAW_CONTROLLER2", type); |
882 | 85 | break; |
883 | 1.38k | } |
884 | 1.38k | if (error) { |
885 | 95 | return error; |
886 | 95 | } |
887 | 1.38k | } |
888 | | |
889 | 945 | ofpact_finish_CONTROLLER(out, &oc); |
890 | | |
891 | 945 | return 0; |
892 | 1.50k | } |
893 | | |
894 | | static void |
895 | | encode_CONTROLLER(const struct ofpact_controller *controller, |
896 | | enum ofp_version ofp_version OVS_UNUSED, |
897 | | struct ofpbuf *out) |
898 | 0 | { |
899 | 0 | if (controller->userdata_len |
900 | 0 | || controller->pause |
901 | 0 | || controller->meter_id != NX_CTLR_NO_METER |
902 | 0 | || controller->ofpact.raw == NXAST_RAW_CONTROLLER2) { |
903 | 0 | size_t start_ofs = out->size; |
904 | 0 | put_NXAST_CONTROLLER2(out); |
905 | 0 | if (controller->max_len != UINT16_MAX) { |
906 | 0 | ofpprop_put_u16(out, NXAC2PT_MAX_LEN, controller->max_len); |
907 | 0 | } |
908 | 0 | if (controller->controller_id != 0) { |
909 | 0 | ofpprop_put_u16(out, NXAC2PT_CONTROLLER_ID, |
910 | 0 | controller->controller_id); |
911 | 0 | } |
912 | 0 | if (controller->reason != OFPR_ACTION) { |
913 | 0 | ofpprop_put_u8(out, NXAC2PT_REASON, controller->reason); |
914 | 0 | } |
915 | 0 | if (controller->userdata_len != 0) { |
916 | 0 | ofpprop_put(out, NXAC2PT_USERDATA, controller->userdata, |
917 | 0 | controller->userdata_len); |
918 | 0 | } |
919 | 0 | if (controller->pause) { |
920 | 0 | ofpprop_put_flag(out, NXAC2PT_PAUSE); |
921 | 0 | } |
922 | 0 | if (controller->meter_id != NX_CTLR_NO_METER) { |
923 | 0 | ofpprop_put_u32(out, NXAC2PT_METER_ID, controller->meter_id); |
924 | 0 | } |
925 | 0 | pad_ofpat(out, start_ofs); |
926 | 0 | } else { |
927 | 0 | struct nx_action_controller *nac; |
928 | |
|
929 | 0 | nac = put_NXAST_CONTROLLER(out); |
930 | 0 | nac->max_len = htons(controller->max_len); |
931 | 0 | nac->controller_id = htons(controller->controller_id); |
932 | 0 | nac->reason = controller->reason; |
933 | 0 | } |
934 | 0 | } |
935 | | |
936 | | static char * OVS_WARN_UNUSED_RESULT |
937 | | parse_CONTROLLER(char *arg, const struct ofpact_parse_params *pp) |
938 | 0 | { |
939 | 0 | enum ofp_packet_in_reason reason = OFPR_ACTION; |
940 | 0 | uint16_t controller_id = 0; |
941 | 0 | uint16_t max_len = UINT16_MAX; |
942 | 0 | uint32_t meter_id = NX_CTLR_NO_METER; |
943 | 0 | const char *userdata = NULL; |
944 | 0 | bool pause = false; |
945 | |
|
946 | 0 | if (!arg[0]) { |
947 | | /* Use defaults. */ |
948 | 0 | } else if (strspn(arg, "0123456789") == strlen(arg)) { |
949 | 0 | char *error = str_to_u16(arg, "max_len", &max_len); |
950 | 0 | if (error) { |
951 | 0 | return error; |
952 | 0 | } |
953 | 0 | } else { |
954 | 0 | char *name, *value; |
955 | |
|
956 | 0 | while (ofputil_parse_key_value(&arg, &name, &value)) { |
957 | 0 | if (!strcmp(name, "reason")) { |
958 | 0 | if (!ofputil_packet_in_reason_from_string(value, &reason)) { |
959 | 0 | return xasprintf("unknown reason \"%s\"", value); |
960 | 0 | } |
961 | 0 | } else if (!strcmp(name, "max_len")) { |
962 | 0 | char *error = str_to_u16(value, "max_len", &max_len); |
963 | 0 | if (error) { |
964 | 0 | return error; |
965 | 0 | } |
966 | 0 | } else if (!strcmp(name, "id")) { |
967 | 0 | char *error = str_to_u16(value, "id", &controller_id); |
968 | 0 | if (error) { |
969 | 0 | return error; |
970 | 0 | } |
971 | 0 | } else if (!strcmp(name, "userdata")) { |
972 | 0 | userdata = value; |
973 | 0 | } else if (!strcmp(name, "pause")) { |
974 | 0 | pause = true; |
975 | 0 | } else if (!strcmp(name, "meter_id")) { |
976 | 0 | char *error = str_to_u32(value, &meter_id); |
977 | 0 | if (error) { |
978 | 0 | return error; |
979 | 0 | } |
980 | 0 | } else { |
981 | 0 | return xasprintf("unknown key \"%s\" parsing controller " |
982 | 0 | "action", name); |
983 | 0 | } |
984 | 0 | } |
985 | 0 | } |
986 | | |
987 | 0 | if (reason == OFPR_ACTION && controller_id == 0 && !userdata && !pause |
988 | 0 | && meter_id == NX_CTLR_NO_METER) { |
989 | 0 | struct ofpact_output *output; |
990 | |
|
991 | 0 | output = ofpact_put_OUTPUT(pp->ofpacts); |
992 | 0 | output->port = OFPP_CONTROLLER; |
993 | 0 | output->max_len = max_len; |
994 | 0 | } else { |
995 | 0 | struct ofpact_controller *controller; |
996 | |
|
997 | 0 | controller = ofpact_put_CONTROLLER(pp->ofpacts); |
998 | 0 | controller->max_len = max_len; |
999 | 0 | controller->reason = reason; |
1000 | 0 | controller->controller_id = controller_id; |
1001 | 0 | controller->pause = pause; |
1002 | 0 | controller->meter_id = meter_id; |
1003 | |
|
1004 | 0 | if (userdata) { |
1005 | 0 | size_t start_ofs = pp->ofpacts->size; |
1006 | 0 | const char *end = ofpbuf_put_hex(pp->ofpacts, userdata, NULL); |
1007 | 0 | if (*end) { |
1008 | 0 | return xstrdup("bad hex digit in `controller' " |
1009 | 0 | "action `userdata'"); |
1010 | 0 | } |
1011 | 0 | size_t userdata_len = pp->ofpacts->size - start_ofs; |
1012 | 0 | controller = pp->ofpacts->header; |
1013 | 0 | controller->userdata_len = userdata_len; |
1014 | 0 | } |
1015 | | |
1016 | 0 | if (ofpbuf_oversized(pp->ofpacts)) { |
1017 | 0 | return xasprintf("input too big"); |
1018 | 0 | } |
1019 | | |
1020 | 0 | ofpact_finish_CONTROLLER(pp->ofpacts, &controller); |
1021 | 0 | } |
1022 | | |
1023 | 0 | return NULL; |
1024 | 0 | } |
1025 | | |
1026 | | static void |
1027 | | format_CONTROLLER(const struct ofpact_controller *a, |
1028 | | const struct ofpact_format_params *fp) |
1029 | 2.62k | { |
1030 | 2.62k | if (a->reason == OFPR_ACTION && !a->controller_id && !a->userdata_len |
1031 | 2.62k | && !a->pause && a->meter_id == NX_CTLR_NO_METER) { |
1032 | 12 | ds_put_format(fp->s, "%sCONTROLLER:%s%"PRIu16, |
1033 | 12 | colors.special, colors.end, a->max_len); |
1034 | 2.61k | } else { |
1035 | 2.61k | enum ofp_packet_in_reason reason = a->reason; |
1036 | | |
1037 | 2.61k | ds_put_format(fp->s, "%scontroller(%s", colors.paren, colors.end); |
1038 | 2.61k | if (reason != OFPR_ACTION) { |
1039 | 1.55k | char reasonbuf[OFPUTIL_PACKET_IN_REASON_BUFSIZE]; |
1040 | | |
1041 | 1.55k | ds_put_format(fp->s, "%sreason=%s%s,", colors.param, colors.end, |
1042 | 1.55k | ofputil_packet_in_reason_to_string( |
1043 | 1.55k | reason, reasonbuf, sizeof reasonbuf)); |
1044 | 1.55k | } |
1045 | 2.61k | if (a->max_len != UINT16_MAX) { |
1046 | 1.75k | ds_put_format(fp->s, "%smax_len=%s%"PRIu16",", |
1047 | 1.75k | colors.param, colors.end, a->max_len); |
1048 | 1.75k | } |
1049 | 2.61k | if (a->controller_id != 0) { |
1050 | 1.41k | ds_put_format(fp->s, "%sid=%s%"PRIu16",", |
1051 | 1.41k | colors.param, colors.end, a->controller_id); |
1052 | 1.41k | } |
1053 | 2.61k | if (a->userdata_len) { |
1054 | 741 | ds_put_format(fp->s, "%suserdata=%s", colors.param, colors.end); |
1055 | 741 | ds_put_hex_with_delimiter(fp->s, a->userdata, a->userdata_len, |
1056 | 741 | "."); |
1057 | 741 | ds_put_char(fp->s, ','); |
1058 | 741 | } |
1059 | 2.61k | if (a->pause) { |
1060 | 120 | ds_put_format(fp->s, "%spause%s,", colors.value, colors.end); |
1061 | 120 | } |
1062 | 2.61k | if (a->meter_id != NX_CTLR_NO_METER) { |
1063 | 44 | ds_put_format(fp->s, "%smeter_id=%s%"PRIu32",", |
1064 | 44 | colors.param, colors.end, a->meter_id); |
1065 | 44 | } |
1066 | 2.61k | ds_chomp(fp->s, ','); |
1067 | 2.61k | ds_put_format(fp->s, "%s)%s", colors.paren, colors.end); |
1068 | 2.61k | } |
1069 | 2.62k | } |
1070 | | |
1071 | | static enum ofperr |
1072 | | check_CONTROLLER(const struct ofpact_controller *a OVS_UNUSED, |
1073 | | const struct ofpact_check_params *cp OVS_UNUSED) |
1074 | 19 | { |
1075 | 19 | return 0; |
1076 | 19 | } |
1077 | | |
1078 | | /* Enqueue action. */ |
1079 | | struct ofp10_action_enqueue { |
1080 | | ovs_be16 type; /* OFPAT10_ENQUEUE. */ |
1081 | | ovs_be16 len; /* Len is 16. */ |
1082 | | ovs_be16 port; /* Port that queue belongs. Should |
1083 | | refer to a valid physical port |
1084 | | (i.e. < OFPP_MAX) or OFPP_IN_PORT. */ |
1085 | | uint8_t pad[6]; /* Pad for 64-bit alignment. */ |
1086 | | ovs_be32 queue_id; /* Where to enqueue the packets. */ |
1087 | | }; |
1088 | | OFP_ASSERT(sizeof(struct ofp10_action_enqueue) == 16); |
1089 | | |
1090 | | static enum ofperr |
1091 | | decode_OFPAT_RAW10_ENQUEUE(const struct ofp10_action_enqueue *oae, |
1092 | | enum ofp_version ofp_version OVS_UNUSED, |
1093 | | struct ofpbuf *out) |
1094 | 193 | { |
1095 | 193 | struct ofpact_enqueue *enqueue; |
1096 | | |
1097 | 193 | enqueue = ofpact_put_ENQUEUE(out); |
1098 | 193 | enqueue->port = u16_to_ofp(ntohs(oae->port)); |
1099 | 193 | enqueue->queue = ntohl(oae->queue_id); |
1100 | 193 | if (ofp_to_u16(enqueue->port) >= ofp_to_u16(OFPP_MAX) |
1101 | 193 | && enqueue->port != OFPP_IN_PORT |
1102 | 193 | && enqueue->port != OFPP_LOCAL) { |
1103 | 23 | return OFPERR_OFPBAC_BAD_OUT_PORT; |
1104 | 23 | } |
1105 | 170 | return 0; |
1106 | 193 | } |
1107 | | |
1108 | | static void |
1109 | | encode_ENQUEUE(const struct ofpact_enqueue *enqueue, |
1110 | | enum ofp_version ofp_version, struct ofpbuf *out) |
1111 | 0 | { |
1112 | 0 | if (ofp_version == OFP10_VERSION) { |
1113 | 0 | struct ofp10_action_enqueue *oae; |
1114 | |
|
1115 | 0 | oae = put_OFPAT10_ENQUEUE(out); |
1116 | 0 | oae->port = htons(ofp_to_u16(enqueue->port)); |
1117 | 0 | oae->queue_id = htonl(enqueue->queue); |
1118 | 0 | } else { |
1119 | 0 | put_OFPAT_SET_QUEUE(out, ofp_version, enqueue->queue); |
1120 | |
|
1121 | 0 | struct ofp11_action_output *oao = put_OFPAT11_OUTPUT(out); |
1122 | 0 | oao->port = ofputil_port_to_ofp11(enqueue->port); |
1123 | 0 | oao->max_len = OVS_BE16_MAX; |
1124 | |
|
1125 | 0 | put_NXAST_POP_QUEUE(out); |
1126 | 0 | } |
1127 | 0 | } |
1128 | | |
1129 | | static char * OVS_WARN_UNUSED_RESULT |
1130 | | parse_ENQUEUE(char *arg, const struct ofpact_parse_params *pp) |
1131 | 0 | { |
1132 | 0 | char *sp = NULL; |
1133 | 0 | char *port = strtok_r(arg, ":q,", &sp); |
1134 | 0 | char *queue = strtok_r(NULL, "", &sp); |
1135 | 0 | struct ofpact_enqueue *enqueue; |
1136 | |
|
1137 | 0 | if (port == NULL || queue == NULL) { |
1138 | 0 | return xstrdup("\"enqueue\" syntax is \"enqueue:PORT:QUEUE\" or " |
1139 | 0 | "\"enqueue(PORT,QUEUE)\""); |
1140 | 0 | } |
1141 | | |
1142 | 0 | enqueue = ofpact_put_ENQUEUE(pp->ofpacts); |
1143 | 0 | if (!ofputil_port_from_string(port, pp->port_map, &enqueue->port)) { |
1144 | 0 | return xasprintf("%s: enqueue to unknown port", port); |
1145 | 0 | } |
1146 | 0 | return str_to_u32(queue, &enqueue->queue); |
1147 | 0 | } |
1148 | | |
1149 | | static void |
1150 | | format_ENQUEUE(const struct ofpact_enqueue *a, |
1151 | | const struct ofpact_format_params *fp) |
1152 | 170 | { |
1153 | 170 | ds_put_format(fp->s, "%senqueue:%s", colors.param, colors.end); |
1154 | 170 | ofputil_format_port(a->port, fp->port_map, fp->s); |
1155 | 170 | ds_put_format(fp->s, ":%"PRIu32, a->queue); |
1156 | 170 | } |
1157 | | |
1158 | | static enum ofperr |
1159 | | check_ENQUEUE(const struct ofpact_enqueue *a, |
1160 | | const struct ofpact_check_params *cp) |
1161 | 55 | { |
1162 | 55 | if (ofp_to_u16(a->port) >= ofp_to_u16(cp->max_ports) |
1163 | 55 | && a->port != OFPP_IN_PORT |
1164 | 55 | && a->port != OFPP_LOCAL) { |
1165 | 0 | return OFPERR_OFPBAC_BAD_OUT_PORT; |
1166 | 0 | } |
1167 | 55 | return 0; |
1168 | 55 | } |
1169 | | |
1170 | | /* Action structure for NXAST_OUTPUT_REG. |
1171 | | * |
1172 | | * Outputs to the OpenFlow port number written to src[ofs:ofs+nbits]. |
1173 | | * |
1174 | | * The format and semantics of 'src' and 'ofs_nbits' are similar to those for |
1175 | | * the NXAST_REG_LOAD action. |
1176 | | * |
1177 | | * The acceptable nxm_header values for 'src' are the same as the acceptable |
1178 | | * nxm_header values for the 'src' field of NXAST_REG_MOVE. |
1179 | | * |
1180 | | * The 'max_len' field indicates the number of bytes to send when the chosen |
1181 | | * port is OFPP_CONTROLLER. Its semantics are equivalent to the 'max_len' |
1182 | | * field of OFPAT_OUTPUT. |
1183 | | * |
1184 | | * The 'zero' field is required to be zeroed for forward compatibility. */ |
1185 | | struct nx_action_output_reg { |
1186 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
1187 | | ovs_be16 len; /* 24. */ |
1188 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
1189 | | ovs_be16 subtype; /* NXAST_OUTPUT_REG. */ |
1190 | | |
1191 | | ovs_be16 ofs_nbits; /* (ofs << 6) | (n_bits - 1). */ |
1192 | | ovs_be32 src; /* Source. */ |
1193 | | |
1194 | | ovs_be16 max_len; /* Max length to send to controller. */ |
1195 | | |
1196 | | uint8_t zero[6]; /* Reserved, must be zero. */ |
1197 | | }; |
1198 | | OFP_ASSERT(sizeof(struct nx_action_output_reg) == 24); |
1199 | | |
1200 | | /* Action structure for NXAST_OUTPUT_REG2. |
1201 | | * |
1202 | | * Like the NXAST_OUTPUT_REG but organized so that there is room for a 64-bit |
1203 | | * experimenter OXM as 'src'. |
1204 | | */ |
1205 | | struct nx_action_output_reg2 { |
1206 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
1207 | | ovs_be16 len; /* 24. */ |
1208 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
1209 | | ovs_be16 subtype; /* NXAST_OUTPUT_REG2. */ |
1210 | | |
1211 | | ovs_be16 ofs_nbits; /* (ofs << 6) | (n_bits - 1). */ |
1212 | | ovs_be16 max_len; /* Max length to send to controller. */ |
1213 | | |
1214 | | /* Followed by: |
1215 | | * - 'src', as an OXM/NXM header (either 4 or 8 bytes). |
1216 | | * - Enough 0-bytes to pad the action out to 24 bytes. */ |
1217 | | uint8_t pad[10]; |
1218 | | }; |
1219 | | OFP_ASSERT(sizeof(struct nx_action_output_reg2) == 24); |
1220 | | |
1221 | | static enum ofperr |
1222 | | decode_NXAST_RAW_OUTPUT_REG(const struct nx_action_output_reg *naor, |
1223 | | enum ofp_version ofp_version OVS_UNUSED, |
1224 | | const struct vl_mff_map *vl_mff_map, |
1225 | | uint64_t *tlv_bitmap, struct ofpbuf *out) |
1226 | 443 | { |
1227 | 443 | struct ofpact_output_reg *output_reg; |
1228 | 443 | enum ofperr error; |
1229 | | |
1230 | 443 | if (!is_all_zeros(naor->zero, sizeof naor->zero)) { |
1231 | 79 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
1232 | 79 | } |
1233 | | |
1234 | 364 | output_reg = ofpact_put_OUTPUT_REG(out); |
1235 | 364 | output_reg->ofpact.raw = NXAST_RAW_OUTPUT_REG; |
1236 | 364 | output_reg->src.ofs = nxm_decode_ofs(naor->ofs_nbits); |
1237 | 364 | output_reg->src.n_bits = nxm_decode_n_bits(naor->ofs_nbits); |
1238 | 364 | output_reg->max_len = ntohs(naor->max_len); |
1239 | 364 | error = mf_vl_mff_mf_from_nxm_header(ntohl(naor->src), vl_mff_map, |
1240 | 364 | &output_reg->src.field, tlv_bitmap); |
1241 | 364 | if (error) { |
1242 | 50 | return error; |
1243 | 50 | } |
1244 | | |
1245 | 314 | return mf_check_src(&output_reg->src, NULL); |
1246 | 364 | } |
1247 | | |
1248 | | static enum ofperr |
1249 | | decode_NXAST_RAW_OUTPUT_REG2(const struct nx_action_output_reg2 *naor, |
1250 | | enum ofp_version ofp_version OVS_UNUSED, |
1251 | | const struct vl_mff_map *vl_mff_map, |
1252 | | uint64_t *tlv_bitmap, struct ofpbuf *out) |
1253 | 511 | { |
1254 | 511 | struct ofpact_output_reg *output_reg; |
1255 | 511 | enum ofperr error; |
1256 | | |
1257 | 511 | output_reg = ofpact_put_OUTPUT_REG(out); |
1258 | 511 | output_reg->ofpact.raw = NXAST_RAW_OUTPUT_REG2; |
1259 | 511 | output_reg->src.ofs = nxm_decode_ofs(naor->ofs_nbits); |
1260 | 511 | output_reg->src.n_bits = nxm_decode_n_bits(naor->ofs_nbits); |
1261 | 511 | output_reg->max_len = ntohs(naor->max_len); |
1262 | | |
1263 | 511 | struct ofpbuf b = ofpbuf_const_initializer(naor, ntohs(naor->len)); |
1264 | 511 | ofpbuf_pull(&b, OBJECT_OFFSETOF(naor, pad)); |
1265 | | |
1266 | 511 | error = mf_vl_mff_nx_pull_header(&b, vl_mff_map, &output_reg->src.field, |
1267 | 511 | NULL, tlv_bitmap); |
1268 | 511 | if (error) { |
1269 | 215 | return error; |
1270 | 215 | } |
1271 | | |
1272 | 296 | if (!is_all_zeros(b.data, b.size)) { |
1273 | 10 | return OFPERR_NXBRC_MUST_BE_ZERO; |
1274 | 10 | } |
1275 | | |
1276 | 286 | return mf_check_src(&output_reg->src, NULL); |
1277 | 296 | } |
1278 | | |
1279 | | static void |
1280 | | encode_OUTPUT_REG(const struct ofpact_output_reg *output_reg, |
1281 | | enum ofp_version ofp_version OVS_UNUSED, |
1282 | | struct ofpbuf *out) |
1283 | 0 | { |
1284 | | /* If 'output_reg' came in as an NXAST_RAW_OUTPUT_REG2 action, or if it |
1285 | | * cannot be encoded in the older form, encode it as |
1286 | | * NXAST_RAW_OUTPUT_REG2. */ |
1287 | 0 | if (output_reg->ofpact.raw == NXAST_RAW_OUTPUT_REG2 |
1288 | 0 | || !mf_nxm_header(output_reg->src.field->id)) { |
1289 | 0 | struct nx_action_output_reg2 *naor = put_NXAST_OUTPUT_REG2(out); |
1290 | 0 | size_t size = out->size; |
1291 | |
|
1292 | 0 | naor->ofs_nbits = nxm_encode_ofs_nbits(output_reg->src.ofs, |
1293 | 0 | output_reg->src.n_bits); |
1294 | 0 | naor->max_len = htons(output_reg->max_len); |
1295 | |
|
1296 | 0 | out->size = size - sizeof naor->pad; |
1297 | 0 | nx_put_mff_header(out, output_reg->src.field, 0, false); |
1298 | 0 | out->size = size; |
1299 | 0 | } else { |
1300 | 0 | struct nx_action_output_reg *naor = put_NXAST_OUTPUT_REG(out); |
1301 | |
|
1302 | 0 | naor->ofs_nbits = nxm_encode_ofs_nbits(output_reg->src.ofs, |
1303 | 0 | output_reg->src.n_bits); |
1304 | 0 | naor->src = htonl(nxm_header_from_mff(output_reg->src.field)); |
1305 | 0 | naor->max_len = htons(output_reg->max_len); |
1306 | 0 | } |
1307 | 0 | } |
1308 | | |
1309 | | static char * OVS_WARN_UNUSED_RESULT |
1310 | | parse_OUTPUT_REG(const char *arg, const struct ofpact_parse_params *pp) |
1311 | 0 | { |
1312 | 0 | return parse_OUTPUT(arg, pp); |
1313 | 0 | } |
1314 | | |
1315 | | static void |
1316 | | format_OUTPUT_REG(const struct ofpact_output_reg *a, |
1317 | | const struct ofpact_format_params *fp) |
1318 | 379 | { |
1319 | 379 | ds_put_format(fp->s, "%soutput:%s", colors.special, colors.end); |
1320 | 379 | mf_format_subfield(&a->src, fp->s); |
1321 | 379 | } |
1322 | | |
1323 | | static enum ofperr |
1324 | | check_OUTPUT_REG(const struct ofpact_output_reg *a, |
1325 | | const struct ofpact_check_params *cp) |
1326 | 293 | { |
1327 | 293 | return mf_check_src(&a->src, cp->match); |
1328 | 293 | } |
1329 | | |
1330 | | /* Action structure for NXAST_BUNDLE and NXAST_BUNDLE_LOAD. |
1331 | | * |
1332 | | * The bundle actions choose a member from a supplied list of options. |
1333 | | * NXAST_BUNDLE outputs to its selection. NXAST_BUNDLE_LOAD writes its |
1334 | | * selection to a register. |
1335 | | * |
1336 | | * The list of possible members follows the nx_action_bundle structure. The |
1337 | | * size of each member is governed by its type as indicated by the |
1338 | | * 'member_type' parameter. The list of members should be padded at its end |
1339 | | * with zeros to make the total length of the action a multiple of 8. |
1340 | | * |
1341 | | * Switches infer from the 'member_type' parameter the size of each member. |
1342 | | * All implementations must support the NXM_OF_IN_PORT 'member_type' which |
1343 | | * indicates that the members are OpenFlow port numbers with |
1344 | | * NXM_LENGTH(NXM_OF_IN_PORT) == 2 byte width. Switches should reject actions |
1345 | | * which indicate unknown or unsupported member types. |
1346 | | * |
1347 | | * Switches use a strategy dictated by the 'algorithm' parameter to choose a |
1348 | | * member. If the switch does not support the specified 'algorithm' parameter, |
1349 | | * it should reject the action. |
1350 | | * |
1351 | | * Several algorithms take into account liveness when selecting members. The |
1352 | | * liveness of a member is implementation defined (with one exception), but |
1353 | | * will generally take into account things like its carrier status and the |
1354 | | * results of any link monitoring protocols which happen to be running on it. |
1355 | | * In order to give controllers a place-holder value, the OFPP_NONE port is |
1356 | | * always considered live, that is, NXAST_BUNDLE_LOAD stores OFPP_NONE in the |
1357 | | * output register if no member is live. |
1358 | | * |
1359 | | * Some member selection strategies require the use of a hash function, in |
1360 | | * which case the 'fields' and 'basis' parameters should be populated. The |
1361 | | * 'fields' parameter (one of NX_HASH_FIELDS_*) designates which parts of the |
1362 | | * flow to hash. Refer to the definition of "enum nx_hash_fields" for details. |
1363 | | * The 'basis' parameter is used as a universal hash parameter. Different |
1364 | | * values of 'basis' yield different hash results. |
1365 | | * |
1366 | | * The 'zero' parameter at the end of the action structure is reserved for |
1367 | | * future use. Switches are required to reject actions which have nonzero |
1368 | | * bytes in the 'zero' field. |
1369 | | * |
1370 | | * NXAST_BUNDLE actions should have 'ofs_nbits' and 'dst' zeroed. Switches |
1371 | | * should reject actions which have nonzero bytes in either of these fields. |
1372 | | * |
1373 | | * NXAST_BUNDLE_LOAD stores the OpenFlow port number of the selected member in |
1374 | | * dst[ofs:ofs+n_bits]. The format and semantics of 'dst' and 'ofs_nbits' are |
1375 | | * similar to those for the NXAST_REG_LOAD action. */ |
1376 | | struct nx_action_bundle { |
1377 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
1378 | | ovs_be16 len; /* Length including members. */ |
1379 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
1380 | | ovs_be16 subtype; /* NXAST_BUNDLE or NXAST_BUNDLE_LOAD. */ |
1381 | | |
1382 | | /* Member choice algorithm to apply to hash value. */ |
1383 | | ovs_be16 algorithm; /* One of NX_BD_ALG_*. */ |
1384 | | |
1385 | | /* What fields to hash and how. */ |
1386 | | ovs_be16 fields; /* One of NX_HASH_FIELDS_*. */ |
1387 | | ovs_be16 basis; /* Universal hash parameter. */ |
1388 | | |
1389 | | ovs_be32 member_type; /* NXM_OF_IN_PORT. */ |
1390 | | ovs_be16 n_members; /* Number of members. */ |
1391 | | |
1392 | | ovs_be16 ofs_nbits; /* (ofs << 6) | (n_bits - 1). */ |
1393 | | ovs_be32 dst; /* Destination. */ |
1394 | | |
1395 | | uint8_t zero[4]; /* Reserved. Must be zero. */ |
1396 | | }; |
1397 | | OFP_ASSERT(sizeof(struct nx_action_bundle) == 32); |
1398 | | |
1399 | | static enum ofperr |
1400 | | decode_bundle(bool load, const struct nx_action_bundle *nab, |
1401 | | const struct vl_mff_map *vl_mff_map, uint64_t *tlv_bitmap, |
1402 | | struct ofpbuf *ofpacts) |
1403 | 3.41k | { |
1404 | 3.41k | static struct vlog_rate_limit rll = VLOG_RATE_LIMIT_INIT(1, 5); |
1405 | 3.41k | struct ofpact_bundle *bundle; |
1406 | 3.41k | uint32_t member_type; |
1407 | 3.41k | size_t members_size, i; |
1408 | 3.41k | enum ofperr error; |
1409 | | |
1410 | 3.41k | bundle = ofpact_put_BUNDLE(ofpacts); |
1411 | | |
1412 | 3.41k | bundle->n_members = ntohs(nab->n_members); |
1413 | 3.41k | bundle->basis = ntohs(nab->basis); |
1414 | 3.41k | bundle->fields = ntohs(nab->fields); |
1415 | 3.41k | bundle->algorithm = ntohs(nab->algorithm); |
1416 | 3.41k | member_type = ntohl(nab->member_type); |
1417 | 3.41k | members_size = ntohs(nab->len) - sizeof *nab; |
1418 | | |
1419 | 3.41k | error = OFPERR_OFPBAC_BAD_ARGUMENT; |
1420 | 3.41k | if (!flow_hash_fields_valid(bundle->fields)) { |
1421 | 421 | VLOG_WARN_RL(&rll, "unsupported fields %d", (int) bundle->fields); |
1422 | 2.99k | } else if (bundle->n_members > BUNDLE_MAX_MEMBERS) { |
1423 | 225 | VLOG_WARN_RL(&rll, "too many members"); |
1424 | 2.76k | } else if (bundle->algorithm != NX_BD_ALG_HRW |
1425 | 2.76k | && bundle->algorithm != NX_BD_ALG_ACTIVE_BACKUP) { |
1426 | 339 | VLOG_WARN_RL(&rll, "unsupported algorithm %d", (int) bundle->algorithm); |
1427 | 2.42k | } else if (member_type != mf_nxm_header(MFF_IN_PORT)) { |
1428 | 982 | VLOG_WARN_RL(&rll, "unsupported member type %"PRIu32, member_type); |
1429 | 1.44k | } else { |
1430 | 1.44k | error = 0; |
1431 | 1.44k | } |
1432 | | |
1433 | 3.41k | if (!is_all_zeros(nab->zero, sizeof nab->zero)) { |
1434 | 1.95k | VLOG_WARN_RL(&rll, "reserved field is nonzero"); |
1435 | 1.95k | error = OFPERR_OFPBAC_BAD_ARGUMENT; |
1436 | 1.95k | } |
1437 | | |
1438 | 3.41k | if (load) { |
1439 | 954 | bundle->dst.ofs = nxm_decode_ofs(nab->ofs_nbits); |
1440 | 954 | bundle->dst.n_bits = nxm_decode_n_bits(nab->ofs_nbits); |
1441 | 954 | error = mf_vl_mff_mf_from_nxm_header(ntohl(nab->dst), vl_mff_map, |
1442 | 954 | &bundle->dst.field, tlv_bitmap); |
1443 | 954 | if (error) { |
1444 | 296 | return error; |
1445 | 296 | } |
1446 | | |
1447 | 658 | if (bundle->dst.n_bits < 16) { |
1448 | 39 | VLOG_WARN_RL(&rll, "bundle_load action requires at least 16 bit " |
1449 | 39 | "destination."); |
1450 | 39 | error = OFPERR_OFPBAC_BAD_ARGUMENT; |
1451 | 39 | } |
1452 | 2.45k | } else { |
1453 | 2.45k | if (nab->ofs_nbits || nab->dst) { |
1454 | 1.07k | VLOG_WARN_RL(&rll, "bundle action has nonzero reserved fields"); |
1455 | 1.07k | error = OFPERR_OFPBAC_BAD_ARGUMENT; |
1456 | 1.07k | } |
1457 | 2.45k | } |
1458 | | |
1459 | 3.11k | if (members_size < bundle->n_members * sizeof(ovs_be16)) { |
1460 | 900 | VLOG_WARN_RL(&rll, "Nicira action %s only has %"PRIuSIZE" bytes " |
1461 | 900 | "allocated for members. %"PRIuSIZE" bytes are " |
1462 | 900 | "required for %u members.", |
1463 | 900 | load ? "bundle_load" : "bundle", members_size, |
1464 | 900 | bundle->n_members * sizeof(ovs_be16), bundle->n_members); |
1465 | 900 | error = OFPERR_OFPBAC_BAD_LEN; |
1466 | 2.21k | } else { |
1467 | 16.9k | for (i = 0; i < bundle->n_members; i++) { |
1468 | 14.7k | ofp_port_t ofp_port |
1469 | 14.7k | = u16_to_ofp(ntohs(((ovs_be16 *)(nab + 1))[i])); |
1470 | 14.7k | ofpbuf_put(ofpacts, &ofp_port, sizeof ofp_port); |
1471 | 14.7k | bundle = ofpacts->header; |
1472 | 14.7k | } |
1473 | 2.21k | } |
1474 | | |
1475 | 3.11k | ofpact_finish_BUNDLE(ofpacts, &bundle); |
1476 | 3.11k | if (!error) { |
1477 | 1.74k | error = bundle_check(bundle, OFPP_MAX, NULL); |
1478 | 1.74k | } |
1479 | 3.11k | return error; |
1480 | 3.41k | } |
1481 | | |
1482 | | static enum ofperr |
1483 | | decode_NXAST_RAW_BUNDLE(const struct nx_action_bundle *nab, |
1484 | | enum ofp_version ofp_version OVS_UNUSED, |
1485 | | struct ofpbuf *out) |
1486 | 2.45k | { |
1487 | 2.45k | return decode_bundle(false, nab, NULL, NULL, out); |
1488 | 2.45k | } |
1489 | | |
1490 | | static enum ofperr |
1491 | | decode_NXAST_RAW_BUNDLE_LOAD(const struct nx_action_bundle *nab, |
1492 | | enum ofp_version ofp_version OVS_UNUSED, |
1493 | | const struct vl_mff_map *vl_mff_map, |
1494 | | uint64_t *tlv_bitmap, struct ofpbuf *out) |
1495 | 954 | { |
1496 | 954 | return decode_bundle(true, nab, vl_mff_map, tlv_bitmap, out); |
1497 | 954 | } |
1498 | | |
1499 | | static void |
1500 | | encode_BUNDLE(const struct ofpact_bundle *bundle, |
1501 | | enum ofp_version ofp_version OVS_UNUSED, |
1502 | | struct ofpbuf *out) |
1503 | 0 | { |
1504 | 0 | int members_len = ROUND_UP(2 * bundle->n_members, OFP_ACTION_ALIGN); |
1505 | 0 | struct nx_action_bundle *nab; |
1506 | 0 | ovs_be16 *members; |
1507 | 0 | size_t i; |
1508 | |
|
1509 | 0 | nab = (bundle->dst.field |
1510 | 0 | ? put_NXAST_BUNDLE_LOAD(out) |
1511 | 0 | : put_NXAST_BUNDLE(out)); |
1512 | 0 | nab->len = htons(ntohs(nab->len) + members_len); |
1513 | 0 | nab->algorithm = htons(bundle->algorithm); |
1514 | 0 | nab->fields = htons(bundle->fields); |
1515 | 0 | nab->basis = htons(bundle->basis); |
1516 | 0 | nab->member_type = htonl(mf_nxm_header(MFF_IN_PORT)); |
1517 | 0 | nab->n_members = htons(bundle->n_members); |
1518 | 0 | if (bundle->dst.field) { |
1519 | 0 | nab->ofs_nbits = nxm_encode_ofs_nbits(bundle->dst.ofs, |
1520 | 0 | bundle->dst.n_bits); |
1521 | 0 | nab->dst = htonl(nxm_header_from_mff(bundle->dst.field)); |
1522 | 0 | } |
1523 | |
|
1524 | 0 | members = ofpbuf_put_zeros(out, members_len); |
1525 | 0 | for (i = 0; i < bundle->n_members; i++) { |
1526 | 0 | members[i] = htons(ofp_to_u16(bundle->members[i])); |
1527 | 0 | } |
1528 | 0 | } |
1529 | | |
1530 | | static char * OVS_WARN_UNUSED_RESULT |
1531 | | parse_BUNDLE(const char *arg, const struct ofpact_parse_params *pp) |
1532 | 0 | { |
1533 | 0 | return bundle_parse(arg, pp->port_map, pp->ofpacts); |
1534 | 0 | } |
1535 | | |
1536 | | static char * OVS_WARN_UNUSED_RESULT |
1537 | | parse_bundle_load(const char *arg, const struct ofpact_parse_params *pp) |
1538 | 0 | { |
1539 | 0 | return bundle_parse_load(arg, pp->port_map, pp->ofpacts); |
1540 | 0 | } |
1541 | | |
1542 | | static void |
1543 | | format_BUNDLE(const struct ofpact_bundle *a, |
1544 | | const struct ofpact_format_params *fp) |
1545 | 1.27k | { |
1546 | 1.27k | bundle_format(a, fp->port_map, fp->s); |
1547 | 1.27k | } |
1548 | | |
1549 | | static enum ofperr |
1550 | | check_BUNDLE(const struct ofpact_bundle *a, |
1551 | | const struct ofpact_check_params *cp) |
1552 | 741 | { |
1553 | 741 | return bundle_check(a, cp->max_ports, cp->match); |
1554 | 741 | } |
1555 | | |
1556 | | /* Set VLAN actions. */ |
1557 | | |
1558 | | static enum ofperr |
1559 | | decode_set_vlan_vid(uint16_t vid, bool push_vlan_if_needed, struct ofpbuf *out) |
1560 | 13.1k | { |
1561 | 13.1k | if (vid & ~0xfff) { |
1562 | 99 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
1563 | 13.0k | } else { |
1564 | 13.0k | struct ofpact_vlan_vid *vlan_vid = ofpact_put_SET_VLAN_VID(out); |
1565 | 13.0k | vlan_vid->vlan_vid = vid; |
1566 | 13.0k | vlan_vid->push_vlan_if_needed = push_vlan_if_needed; |
1567 | 13.0k | return 0; |
1568 | 13.0k | } |
1569 | 13.1k | } |
1570 | | |
1571 | | static enum ofperr |
1572 | | decode_OFPAT_RAW10_SET_VLAN_VID(uint16_t vid, |
1573 | | enum ofp_version ofp_version OVS_UNUSED, |
1574 | | struct ofpbuf *out) |
1575 | 11.5k | { |
1576 | 11.5k | return decode_set_vlan_vid(vid, true, out); |
1577 | 11.5k | } |
1578 | | |
1579 | | static enum ofperr |
1580 | | decode_OFPAT_RAW11_SET_VLAN_VID(uint16_t vid, |
1581 | | enum ofp_version ofp_version OVS_UNUSED, |
1582 | | struct ofpbuf *out) |
1583 | 1.65k | { |
1584 | 1.65k | return decode_set_vlan_vid(vid, false, out); |
1585 | 1.65k | } |
1586 | | |
1587 | | static void |
1588 | | encode_SET_VLAN_VID(const struct ofpact_vlan_vid *vlan_vid, |
1589 | | enum ofp_version ofp_version, struct ofpbuf *out) |
1590 | 0 | { |
1591 | 0 | uint16_t vid = vlan_vid->vlan_vid; |
1592 | | |
1593 | | /* Push a VLAN tag, if none is present and this form of the action calls |
1594 | | * for such a feature. */ |
1595 | 0 | if (ofp_version > OFP10_VERSION |
1596 | 0 | && vlan_vid->push_vlan_if_needed |
1597 | 0 | && !vlan_vid->flow_has_vlan) { |
1598 | 0 | put_OFPAT11_PUSH_VLAN(out, htons(ETH_TYPE_VLAN_8021Q)); |
1599 | 0 | } |
1600 | |
|
1601 | 0 | if (ofp_version == OFP10_VERSION) { |
1602 | 0 | put_OFPAT10_SET_VLAN_VID(out, vid); |
1603 | 0 | } else if (ofp_version == OFP11_VERSION) { |
1604 | 0 | put_OFPAT11_SET_VLAN_VID(out, vid); |
1605 | 0 | } else { |
1606 | 0 | put_set_field(out, ofp_version, MFF_VLAN_VID, vid | OFPVID12_PRESENT); |
1607 | 0 | } |
1608 | 0 | } |
1609 | | |
1610 | | static char * OVS_WARN_UNUSED_RESULT |
1611 | | parse_set_vlan_vid(char *arg, bool push_vlan_if_needed, |
1612 | | const struct ofpact_parse_params *pp) |
1613 | 0 | { |
1614 | 0 | struct ofpact_vlan_vid *vlan_vid; |
1615 | 0 | uint16_t vid; |
1616 | 0 | char *error; |
1617 | |
|
1618 | 0 | error = str_to_u16(arg, "VLAN VID", &vid); |
1619 | 0 | if (error) { |
1620 | 0 | return error; |
1621 | 0 | } |
1622 | | |
1623 | 0 | if (vid & ~VLAN_VID_MASK) { |
1624 | 0 | return xasprintf("%s: not a valid VLAN VID", arg); |
1625 | 0 | } |
1626 | 0 | vlan_vid = ofpact_put_SET_VLAN_VID(pp->ofpacts); |
1627 | 0 | vlan_vid->vlan_vid = vid; |
1628 | 0 | vlan_vid->push_vlan_if_needed = push_vlan_if_needed; |
1629 | 0 | return NULL; |
1630 | 0 | } |
1631 | | |
1632 | | static char * OVS_WARN_UNUSED_RESULT |
1633 | | parse_SET_VLAN_VID(char *arg, const struct ofpact_parse_params *pp) |
1634 | 0 | { |
1635 | 0 | return parse_set_vlan_vid(arg, false, pp); |
1636 | 0 | } |
1637 | | |
1638 | | static void |
1639 | | format_SET_VLAN_VID(const struct ofpact_vlan_vid *a, |
1640 | | const struct ofpact_format_params *fp) |
1641 | 8.22k | { |
1642 | 8.22k | ds_put_format(fp->s, "%s%s:%s%"PRIu16, colors.param, |
1643 | 8.22k | a->push_vlan_if_needed ? "mod_vlan_vid" : "set_vlan_vid", |
1644 | 8.22k | colors.end, a->vlan_vid); |
1645 | 8.22k | } |
1646 | | |
1647 | | static enum ofperr |
1648 | | check_SET_VLAN_VID(struct ofpact_vlan_vid *a, struct ofpact_check_params *cp) |
1649 | 7.54k | { |
1650 | | /* Remember if we saw a vlan tag in the flow to aid translating to OpenFlow |
1651 | | * 1.1+ if need be. */ |
1652 | 7.54k | ovs_be16 *tci = &cp->match->flow.vlans[0].tci; |
1653 | 7.54k | a->flow_has_vlan = (*tci & htons(VLAN_CFI)) != 0; |
1654 | 7.54k | if (!a->flow_has_vlan && !a->push_vlan_if_needed) { |
1655 | 519 | inconsistent_match(&cp->usable_protocols); |
1656 | 519 | } |
1657 | | |
1658 | | /* Temporarily mark that we have a vlan tag. */ |
1659 | 7.54k | *tci |= htons(VLAN_CFI); |
1660 | | |
1661 | 7.54k | return 0; |
1662 | 7.54k | } |
1663 | | |
1664 | | /* Set PCP actions. */ |
1665 | | |
1666 | | static enum ofperr |
1667 | | decode_set_vlan_pcp(uint8_t pcp, bool push_vlan_if_needed, struct ofpbuf *out) |
1668 | 8.27k | { |
1669 | 8.27k | if (pcp & ~7) { |
1670 | 122 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
1671 | 8.15k | } else { |
1672 | 8.15k | struct ofpact_vlan_pcp *vlan_pcp = ofpact_put_SET_VLAN_PCP(out); |
1673 | 8.15k | vlan_pcp->vlan_pcp = pcp; |
1674 | 8.15k | vlan_pcp->push_vlan_if_needed = push_vlan_if_needed; |
1675 | 8.15k | return 0; |
1676 | 8.15k | } |
1677 | 8.27k | } |
1678 | | |
1679 | | static enum ofperr |
1680 | | decode_OFPAT_RAW10_SET_VLAN_PCP(uint8_t pcp, |
1681 | | enum ofp_version ofp_version OVS_UNUSED, |
1682 | | struct ofpbuf *out) |
1683 | 7.08k | { |
1684 | 7.08k | return decode_set_vlan_pcp(pcp, true, out); |
1685 | 7.08k | } |
1686 | | |
1687 | | static enum ofperr |
1688 | | decode_OFPAT_RAW11_SET_VLAN_PCP(uint8_t pcp, |
1689 | | enum ofp_version ofp_version OVS_UNUSED, |
1690 | | struct ofpbuf *out) |
1691 | 1.19k | { |
1692 | 1.19k | return decode_set_vlan_pcp(pcp, false, out); |
1693 | 1.19k | } |
1694 | | |
1695 | | static void |
1696 | | encode_SET_VLAN_PCP(const struct ofpact_vlan_pcp *vlan_pcp, |
1697 | | enum ofp_version ofp_version, struct ofpbuf *out) |
1698 | 0 | { |
1699 | 0 | uint8_t pcp = vlan_pcp->vlan_pcp; |
1700 | | |
1701 | | /* Push a VLAN tag, if none is present and this form of the action calls |
1702 | | * for such a feature. */ |
1703 | 0 | if (ofp_version > OFP10_VERSION |
1704 | 0 | && vlan_pcp->push_vlan_if_needed |
1705 | 0 | && !vlan_pcp->flow_has_vlan) { |
1706 | 0 | put_OFPAT11_PUSH_VLAN(out, htons(ETH_TYPE_VLAN_8021Q)); |
1707 | 0 | } |
1708 | |
|
1709 | 0 | if (ofp_version == OFP10_VERSION) { |
1710 | 0 | put_OFPAT10_SET_VLAN_PCP(out, pcp); |
1711 | 0 | } else if (ofp_version == OFP11_VERSION) { |
1712 | 0 | put_OFPAT11_SET_VLAN_PCP(out, pcp); |
1713 | 0 | } else { |
1714 | 0 | put_set_field(out, ofp_version, MFF_VLAN_PCP, pcp); |
1715 | 0 | } |
1716 | 0 | } |
1717 | | |
1718 | | static char * OVS_WARN_UNUSED_RESULT |
1719 | | parse_set_vlan_pcp(char *arg, bool push_vlan_if_needed, |
1720 | | const struct ofpact_parse_params *pp) |
1721 | 0 | { |
1722 | 0 | struct ofpact_vlan_pcp *vlan_pcp; |
1723 | 0 | uint8_t pcp; |
1724 | 0 | char *error; |
1725 | |
|
1726 | 0 | error = str_to_u8(arg, "VLAN PCP", &pcp); |
1727 | 0 | if (error) { |
1728 | 0 | return error; |
1729 | 0 | } |
1730 | | |
1731 | 0 | if (pcp & ~7) { |
1732 | 0 | return xasprintf("%s: not a valid VLAN PCP", arg); |
1733 | 0 | } |
1734 | 0 | vlan_pcp = ofpact_put_SET_VLAN_PCP(pp->ofpacts); |
1735 | 0 | vlan_pcp->vlan_pcp = pcp; |
1736 | 0 | vlan_pcp->push_vlan_if_needed = push_vlan_if_needed; |
1737 | 0 | return NULL; |
1738 | 0 | } |
1739 | | |
1740 | | static char * OVS_WARN_UNUSED_RESULT |
1741 | | parse_SET_VLAN_PCP(char *arg, const struct ofpact_parse_params *pp) |
1742 | 0 | { |
1743 | 0 | return parse_set_vlan_pcp(arg, false, pp); |
1744 | 0 | } |
1745 | | |
1746 | | static void |
1747 | | format_SET_VLAN_PCP(const struct ofpact_vlan_pcp *a, |
1748 | | const struct ofpact_format_params *fp) |
1749 | 4.01k | { |
1750 | 4.01k | ds_put_format(fp->s, "%s%s:%s%"PRIu8, colors.param, |
1751 | 4.01k | a->push_vlan_if_needed ? "mod_vlan_pcp" : "set_vlan_pcp", |
1752 | 4.01k | colors.end, a->vlan_pcp); |
1753 | 4.01k | } |
1754 | | |
1755 | | static enum ofperr |
1756 | | check_SET_VLAN_PCP(struct ofpact_vlan_pcp *a, struct ofpact_check_params *cp) |
1757 | 4.50k | { |
1758 | | /* Remember if we saw a vlan tag in the flow to aid translating to OpenFlow |
1759 | | * 1.1+ if need be. */ |
1760 | 4.50k | ovs_be16 *tci = &cp->match->flow.vlans[0].tci; |
1761 | 4.50k | a->flow_has_vlan = (*tci & htons(VLAN_CFI)) != 0; |
1762 | 4.50k | if (!a->flow_has_vlan && !a->push_vlan_if_needed) { |
1763 | 37 | inconsistent_match(&cp->usable_protocols); |
1764 | 37 | } |
1765 | | |
1766 | | /* Temporarily mark that we have a vlan tag. */ |
1767 | 4.50k | *tci |= htons(VLAN_CFI); |
1768 | | |
1769 | 4.50k | return 0; |
1770 | 4.50k | } |
1771 | | |
1772 | | /* Strip VLAN actions. */ |
1773 | | |
1774 | | static enum ofperr |
1775 | | decode_OFPAT_RAW10_STRIP_VLAN(struct ofpbuf *out) |
1776 | 13.8k | { |
1777 | 13.8k | ofpact_put_STRIP_VLAN(out)->ofpact.raw = OFPAT_RAW10_STRIP_VLAN; |
1778 | 13.8k | return 0; |
1779 | 13.8k | } |
1780 | | |
1781 | | static enum ofperr |
1782 | | decode_OFPAT_RAW11_POP_VLAN(struct ofpbuf *out) |
1783 | 1.93k | { |
1784 | 1.93k | ofpact_put_STRIP_VLAN(out)->ofpact.raw = OFPAT_RAW11_POP_VLAN; |
1785 | 1.93k | return 0; |
1786 | 1.93k | } |
1787 | | |
1788 | | static void |
1789 | | encode_STRIP_VLAN(const struct ofpact_null *null OVS_UNUSED, |
1790 | | enum ofp_version ofp_version, struct ofpbuf *out) |
1791 | 0 | { |
1792 | 0 | if (ofp_version == OFP10_VERSION) { |
1793 | 0 | put_OFPAT10_STRIP_VLAN(out); |
1794 | 0 | } else { |
1795 | 0 | put_OFPAT11_POP_VLAN(out); |
1796 | 0 | } |
1797 | 0 | } |
1798 | | |
1799 | | static char * OVS_WARN_UNUSED_RESULT |
1800 | | parse_STRIP_VLAN(char *arg OVS_UNUSED, const struct ofpact_parse_params *pp) |
1801 | 0 | { |
1802 | 0 | ofpact_put_STRIP_VLAN(pp->ofpacts)->ofpact.raw = OFPAT_RAW10_STRIP_VLAN; |
1803 | 0 | return NULL; |
1804 | 0 | } |
1805 | | |
1806 | | static char * OVS_WARN_UNUSED_RESULT |
1807 | | parse_pop_vlan(const struct ofpact_parse_params *pp) |
1808 | 0 | { |
1809 | 0 | ofpact_put_STRIP_VLAN(pp->ofpacts)->ofpact.raw = OFPAT_RAW11_POP_VLAN; |
1810 | 0 | return NULL; |
1811 | 0 | } |
1812 | | |
1813 | | static void |
1814 | | format_STRIP_VLAN(const struct ofpact_null *a, |
1815 | | const struct ofpact_format_params *fp) |
1816 | 8.76k | { |
1817 | 8.76k | ds_put_format(fp->s, (a->ofpact.raw == OFPAT_RAW11_POP_VLAN |
1818 | 8.76k | ? "%spop_vlan%s" |
1819 | 8.76k | : "%sstrip_vlan%s"), |
1820 | 8.76k | colors.value, colors.end); |
1821 | 8.76k | } |
1822 | | |
1823 | | static enum ofperr |
1824 | | check_STRIP_VLAN(const struct ofpact_null *a OVS_UNUSED, |
1825 | | struct ofpact_check_params *cp) |
1826 | 8.90k | { |
1827 | 8.90k | if (!(cp->match->flow.vlans[0].tci & htons(VLAN_CFI))) { |
1828 | 2.25k | inconsistent_match(&cp->usable_protocols); |
1829 | 2.25k | } |
1830 | 8.90k | flow_pop_vlan(&cp->match->flow, NULL); |
1831 | 8.90k | return 0; |
1832 | 8.90k | } |
1833 | | |
1834 | | /* Push VLAN action. */ |
1835 | | |
1836 | | static enum ofperr |
1837 | | decode_OFPAT_RAW11_PUSH_VLAN(ovs_be16 eth_type, |
1838 | | enum ofp_version ofp_version OVS_UNUSED, |
1839 | | struct ofpbuf *out) |
1840 | 3.99k | { |
1841 | 3.99k | struct ofpact_push_vlan *push_vlan; |
1842 | 3.99k | if (!eth_type_vlan(eth_type)) { |
1843 | 268 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
1844 | 268 | } |
1845 | 3.72k | push_vlan = ofpact_put_PUSH_VLAN(out); |
1846 | 3.72k | push_vlan->ethertype = eth_type; |
1847 | 3.72k | return 0; |
1848 | 3.99k | } |
1849 | | |
1850 | | static void |
1851 | | encode_PUSH_VLAN(const struct ofpact_push_vlan *push_vlan, |
1852 | | enum ofp_version ofp_version, struct ofpbuf *out) |
1853 | 0 | { |
1854 | 0 | if (ofp_version == OFP10_VERSION) { |
1855 | | /* PUSH is a side effect of a SET_VLAN_VID/PCP, which should |
1856 | | * follow this action. */ |
1857 | 0 | } else { |
1858 | 0 | put_OFPAT11_PUSH_VLAN(out, push_vlan->ethertype); |
1859 | 0 | } |
1860 | 0 | } |
1861 | | |
1862 | | static char * OVS_WARN_UNUSED_RESULT |
1863 | | parse_PUSH_VLAN(char *arg, const struct ofpact_parse_params *pp) |
1864 | 0 | { |
1865 | 0 | struct ofpact_push_vlan *push_vlan; |
1866 | 0 | uint16_t ethertype; |
1867 | 0 | char *error; |
1868 | |
|
1869 | 0 | *pp->usable_protocols &= OFPUTIL_P_OF11_UP; |
1870 | 0 | error = str_to_u16(arg, "ethertype", ðertype); |
1871 | 0 | if (error) { |
1872 | 0 | return error; |
1873 | 0 | } |
1874 | | |
1875 | 0 | if (!eth_type_vlan(htons(ethertype))) { |
1876 | 0 | return xasprintf("%s: not a valid VLAN ethertype", arg); |
1877 | 0 | } |
1878 | 0 | push_vlan = ofpact_put_PUSH_VLAN(pp->ofpacts); |
1879 | 0 | push_vlan->ethertype = htons(ethertype); |
1880 | 0 | return NULL; |
1881 | 0 | } |
1882 | | |
1883 | | static void |
1884 | | format_PUSH_VLAN(const struct ofpact_push_vlan *push_vlan, |
1885 | | const struct ofpact_format_params *fp) |
1886 | 1.60k | { |
1887 | 1.60k | ds_put_format(fp->s, "%spush_vlan:%s%#"PRIx16, |
1888 | 1.60k | colors.param, colors.end, ntohs(push_vlan->ethertype)); |
1889 | 1.60k | } |
1890 | | |
1891 | | static enum ofperr |
1892 | | check_PUSH_VLAN(const struct ofpact_push_vlan *a OVS_UNUSED, |
1893 | | struct ofpact_check_params *cp) |
1894 | 2.95k | { |
1895 | 2.95k | struct flow *flow = &cp->match->flow; |
1896 | 2.95k | if (flow->vlans[FLOW_MAX_VLAN_HEADERS - 1].tci & htons(VLAN_CFI)) { |
1897 | | /* Support maximum (FLOW_MAX_VLAN_HEADERS) VLAN headers. */ |
1898 | 489 | return OFPERR_OFPBAC_BAD_TAG; |
1899 | 489 | } |
1900 | | /* Temporary mark that we have a vlan tag. */ |
1901 | 2.46k | flow_push_vlan_uninit(flow, NULL); |
1902 | 2.46k | flow->vlans[0].tci |= htons(VLAN_CFI); |
1903 | 2.46k | return 0; |
1904 | 2.95k | } |
1905 | | |
1906 | | /* Action structure for OFPAT10_SET_DL_SRC/DST and OFPAT11_SET_DL_SRC/DST. */ |
1907 | | struct ofp_action_dl_addr { |
1908 | | ovs_be16 type; /* Type. */ |
1909 | | ovs_be16 len; /* Length is 16. */ |
1910 | | struct eth_addr dl_addr; /* Ethernet address. */ |
1911 | | uint8_t pad[6]; |
1912 | | }; |
1913 | | OFP_ASSERT(sizeof(struct ofp_action_dl_addr) == 16); |
1914 | | |
1915 | | static enum ofperr |
1916 | | decode_OFPAT_RAW_SET_DL_SRC(const struct ofp_action_dl_addr *a, |
1917 | | enum ofp_version ofp_version OVS_UNUSED, |
1918 | | struct ofpbuf *out) |
1919 | 49 | { |
1920 | 49 | ofpact_put_SET_ETH_SRC(out)->mac = a->dl_addr; |
1921 | 49 | return 0; |
1922 | 49 | } |
1923 | | |
1924 | | static enum ofperr |
1925 | | decode_OFPAT_RAW_SET_DL_DST(const struct ofp_action_dl_addr *a, |
1926 | | enum ofp_version ofp_version OVS_UNUSED, |
1927 | | struct ofpbuf *out) |
1928 | 238 | { |
1929 | 238 | ofpact_put_SET_ETH_DST(out)->mac = a->dl_addr; |
1930 | 238 | return 0; |
1931 | 238 | } |
1932 | | |
1933 | | static void |
1934 | | encode_SET_ETH_addr(const struct ofpact_mac *mac, enum ofp_version ofp_version, |
1935 | | enum ofp_raw_action_type raw, enum mf_field_id field, |
1936 | | struct ofpbuf *out) |
1937 | 0 | { |
1938 | 0 | if (ofp_version < OFP12_VERSION) { |
1939 | 0 | struct ofp_action_dl_addr *oada; |
1940 | |
|
1941 | 0 | oada = ofpact_put_raw(out, ofp_version, raw, 0); |
1942 | 0 | oada->dl_addr = mac->mac; |
1943 | 0 | } else { |
1944 | 0 | put_set_field(out, ofp_version, field, eth_addr_to_uint64(mac->mac)); |
1945 | 0 | } |
1946 | 0 | } |
1947 | | |
1948 | | static void |
1949 | | encode_SET_ETH_SRC(const struct ofpact_mac *mac, enum ofp_version ofp_version, |
1950 | | struct ofpbuf *out) |
1951 | 0 | { |
1952 | 0 | encode_SET_ETH_addr(mac, ofp_version, OFPAT_RAW_SET_DL_SRC, MFF_ETH_SRC, |
1953 | 0 | out); |
1954 | |
|
1955 | 0 | } |
1956 | | |
1957 | | static void |
1958 | | encode_SET_ETH_DST(const struct ofpact_mac *mac, |
1959 | | enum ofp_version ofp_version, |
1960 | | struct ofpbuf *out) |
1961 | 0 | { |
1962 | 0 | encode_SET_ETH_addr(mac, ofp_version, OFPAT_RAW_SET_DL_DST, MFF_ETH_DST, |
1963 | 0 | out); |
1964 | |
|
1965 | 0 | } |
1966 | | |
1967 | | static char * OVS_WARN_UNUSED_RESULT |
1968 | | parse_SET_ETH_SRC(char *arg, const struct ofpact_parse_params *pp) |
1969 | 0 | { |
1970 | 0 | return str_to_mac(arg, &ofpact_put_SET_ETH_SRC(pp->ofpacts)->mac); |
1971 | 0 | } |
1972 | | |
1973 | | static char * OVS_WARN_UNUSED_RESULT |
1974 | | parse_SET_ETH_DST(char *arg, const struct ofpact_parse_params *pp) |
1975 | 0 | { |
1976 | 0 | return str_to_mac(arg, &ofpact_put_SET_ETH_DST(pp->ofpacts)->mac); |
1977 | 0 | } |
1978 | | |
1979 | | static void |
1980 | | format_SET_ETH_SRC(const struct ofpact_mac *a, |
1981 | | const struct ofpact_format_params *fp) |
1982 | 44 | { |
1983 | 44 | ds_put_format(fp->s, "%smod_dl_src:%s"ETH_ADDR_FMT, |
1984 | 44 | colors.param, colors.end, ETH_ADDR_ARGS(a->mac)); |
1985 | 44 | } |
1986 | | |
1987 | | static void |
1988 | | format_SET_ETH_DST(const struct ofpact_mac *a, |
1989 | | const struct ofpact_format_params *fp) |
1990 | 162 | { |
1991 | 162 | ds_put_format(fp->s, "%smod_dl_dst:%s"ETH_ADDR_FMT, |
1992 | 162 | colors.param, colors.end, ETH_ADDR_ARGS(a->mac)); |
1993 | 162 | } |
1994 | | |
1995 | | static enum ofperr |
1996 | | check_SET_ETH_SRC(const struct ofpact_mac *a OVS_UNUSED, |
1997 | | const struct ofpact_check_params *cp OVS_UNUSED) |
1998 | 35 | { |
1999 | 35 | return 0; |
2000 | 35 | } |
2001 | | |
2002 | | static enum ofperr |
2003 | | check_SET_ETH_DST(const struct ofpact_mac *a OVS_UNUSED, |
2004 | | const struct ofpact_check_params *cp OVS_UNUSED) |
2005 | 148 | { |
2006 | 148 | return 0; |
2007 | 148 | } |
2008 | | |
2009 | | /* Set IPv4 address actions. */ |
2010 | | |
2011 | | static enum ofperr |
2012 | | decode_OFPAT_RAW_SET_NW_SRC(ovs_be32 ipv4, |
2013 | | enum ofp_version ofp_version OVS_UNUSED, |
2014 | | struct ofpbuf *out) |
2015 | 5.96k | { |
2016 | 5.96k | ofpact_put_SET_IPV4_SRC(out)->ipv4 = ipv4; |
2017 | 5.96k | return 0; |
2018 | 5.96k | } |
2019 | | |
2020 | | static enum ofperr |
2021 | | decode_OFPAT_RAW_SET_NW_DST(ovs_be32 ipv4, |
2022 | | enum ofp_version ofp_version OVS_UNUSED, |
2023 | | struct ofpbuf *out) |
2024 | 11.1k | { |
2025 | 11.1k | ofpact_put_SET_IPV4_DST(out)->ipv4 = ipv4; |
2026 | 11.1k | return 0; |
2027 | 11.1k | } |
2028 | | |
2029 | | static void |
2030 | | encode_SET_IPV4_addr(const struct ofpact_ipv4 *ipv4, |
2031 | | enum ofp_version ofp_version, |
2032 | | enum ofp_raw_action_type raw, enum mf_field_id field, |
2033 | | struct ofpbuf *out) |
2034 | 0 | { |
2035 | 0 | ovs_be32 addr = ipv4->ipv4; |
2036 | 0 | if (ofp_version < OFP12_VERSION) { |
2037 | 0 | ofpact_put_raw(out, ofp_version, raw, ntohl(addr)); |
2038 | 0 | } else { |
2039 | 0 | put_set_field(out, ofp_version, field, ntohl(addr)); |
2040 | 0 | } |
2041 | 0 | } |
2042 | | |
2043 | | static void |
2044 | | encode_SET_IPV4_SRC(const struct ofpact_ipv4 *ipv4, |
2045 | | enum ofp_version ofp_version, struct ofpbuf *out) |
2046 | 0 | { |
2047 | 0 | encode_SET_IPV4_addr(ipv4, ofp_version, OFPAT_RAW_SET_NW_SRC, MFF_IPV4_SRC, |
2048 | 0 | out); |
2049 | 0 | } |
2050 | | |
2051 | | static void |
2052 | | encode_SET_IPV4_DST(const struct ofpact_ipv4 *ipv4, |
2053 | | enum ofp_version ofp_version, struct ofpbuf *out) |
2054 | 0 | { |
2055 | 0 | encode_SET_IPV4_addr(ipv4, ofp_version, OFPAT_RAW_SET_NW_DST, MFF_IPV4_DST, |
2056 | 0 | out); |
2057 | 0 | } |
2058 | | |
2059 | | static char * OVS_WARN_UNUSED_RESULT |
2060 | | parse_SET_IPV4_SRC(char *arg, const struct ofpact_parse_params *pp) |
2061 | 0 | { |
2062 | 0 | return str_to_ip(arg, &ofpact_put_SET_IPV4_SRC(pp->ofpacts)->ipv4); |
2063 | 0 | } |
2064 | | |
2065 | | static char * OVS_WARN_UNUSED_RESULT |
2066 | | parse_SET_IPV4_DST(char *arg, const struct ofpact_parse_params *pp) |
2067 | 0 | { |
2068 | 0 | return str_to_ip(arg, &ofpact_put_SET_IPV4_DST(pp->ofpacts)->ipv4); |
2069 | 0 | } |
2070 | | |
2071 | | static void |
2072 | | format_SET_IPV4_SRC(const struct ofpact_ipv4 *a, |
2073 | | const struct ofpact_format_params *fp) |
2074 | 3.55k | { |
2075 | 3.55k | ds_put_format(fp->s, "%smod_nw_src:%s"IP_FMT, |
2076 | 3.55k | colors.param, colors.end, IP_ARGS(a->ipv4)); |
2077 | 3.55k | } |
2078 | | |
2079 | | static void |
2080 | | format_SET_IPV4_DST(const struct ofpact_ipv4 *a, |
2081 | | const struct ofpact_format_params *fp) |
2082 | 4.87k | { |
2083 | 4.87k | ds_put_format(fp->s, "%smod_nw_dst:%s"IP_FMT, |
2084 | 4.87k | colors.param, colors.end, IP_ARGS(a->ipv4)); |
2085 | 4.87k | } |
2086 | | |
2087 | | static enum ofperr |
2088 | | check_set_ipv4(struct ofpact_check_params *cp) |
2089 | 10.3k | { |
2090 | 10.3k | ovs_be16 dl_type = get_dl_type(&cp->match->flow); |
2091 | 10.3k | if (dl_type != htons(ETH_TYPE_IP)) { |
2092 | 5.91k | inconsistent_match(&cp->usable_protocols); |
2093 | 5.91k | } |
2094 | 10.3k | return 0; |
2095 | 10.3k | } |
2096 | | |
2097 | | static enum ofperr |
2098 | | check_SET_IPV4_SRC(const struct ofpact_ipv4 *a OVS_UNUSED, |
2099 | | struct ofpact_check_params *cp) |
2100 | 4.19k | { |
2101 | 4.19k | return check_set_ipv4(cp); |
2102 | 4.19k | } |
2103 | | |
2104 | | static enum ofperr |
2105 | | check_SET_IPV4_DST(const struct ofpact_ipv4 *a OVS_UNUSED, |
2106 | | struct ofpact_check_params *cp) |
2107 | 6.13k | { |
2108 | 6.13k | return check_set_ipv4(cp); |
2109 | 6.13k | } |
2110 | | |
2111 | | /* Set IPv4/v6 TOS actions. */ |
2112 | | |
2113 | | static enum ofperr |
2114 | | decode_OFPAT_RAW_SET_NW_TOS(uint8_t dscp, |
2115 | | enum ofp_version ofp_version OVS_UNUSED, |
2116 | | struct ofpbuf *out) |
2117 | 13.0k | { |
2118 | 13.0k | if (dscp & ~IP_DSCP_MASK) { |
2119 | 118 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
2120 | 12.8k | } else { |
2121 | 12.8k | ofpact_put_SET_IP_DSCP(out)->dscp = dscp; |
2122 | 12.8k | return 0; |
2123 | 12.8k | } |
2124 | 13.0k | } |
2125 | | |
2126 | | static void |
2127 | | encode_SET_IP_DSCP(const struct ofpact_dscp *dscp, |
2128 | | enum ofp_version ofp_version, struct ofpbuf *out) |
2129 | 0 | { |
2130 | 0 | if (ofp_version < OFP12_VERSION) { |
2131 | 0 | put_OFPAT_SET_NW_TOS(out, ofp_version, dscp->dscp); |
2132 | 0 | } else { |
2133 | 0 | put_set_field(out, ofp_version, MFF_IP_DSCP_SHIFTED, dscp->dscp >> 2); |
2134 | 0 | } |
2135 | 0 | } |
2136 | | |
2137 | | static char * OVS_WARN_UNUSED_RESULT |
2138 | | parse_SET_IP_DSCP(char *arg, const struct ofpact_parse_params *pp) |
2139 | | |
2140 | 0 | { |
2141 | 0 | uint8_t tos; |
2142 | 0 | char *error; |
2143 | |
|
2144 | 0 | error = str_to_u8(arg, "TOS", &tos); |
2145 | 0 | if (error) { |
2146 | 0 | return error; |
2147 | 0 | } |
2148 | | |
2149 | 0 | if (tos & ~IP_DSCP_MASK) { |
2150 | 0 | return xasprintf("%s: not a valid TOS", arg); |
2151 | 0 | } |
2152 | 0 | ofpact_put_SET_IP_DSCP(pp->ofpacts)->dscp = tos; |
2153 | 0 | return NULL; |
2154 | 0 | } |
2155 | | |
2156 | | static void |
2157 | | format_SET_IP_DSCP(const struct ofpact_dscp *a, |
2158 | | const struct ofpact_format_params *fp) |
2159 | 7.61k | { |
2160 | 7.61k | ds_put_format(fp->s, "%smod_nw_tos:%s%d", |
2161 | 7.61k | colors.param, colors.end, a->dscp); |
2162 | 7.61k | } |
2163 | | |
2164 | | static enum ofperr |
2165 | | check_set_ip(struct ofpact_check_params *cp) |
2166 | 15.3k | { |
2167 | 15.3k | if (!is_ip_any(&cp->match->flow)) { |
2168 | 10.0k | inconsistent_match(&cp->usable_protocols); |
2169 | 10.0k | } |
2170 | 15.3k | return 0; |
2171 | 15.3k | } |
2172 | | |
2173 | | static enum ofperr |
2174 | | check_SET_IP_DSCP(const struct ofpact_dscp *a OVS_UNUSED, |
2175 | | struct ofpact_check_params *cp) |
2176 | 7.52k | { |
2177 | 7.52k | return check_set_ip(cp); |
2178 | 7.52k | } |
2179 | | |
2180 | | /* Set IPv4/v6 ECN actions. */ |
2181 | | |
2182 | | static enum ofperr |
2183 | | decode_OFPAT_RAW11_SET_NW_ECN(uint8_t ecn, |
2184 | | enum ofp_version ofp_version OVS_UNUSED, |
2185 | | struct ofpbuf *out) |
2186 | 1.84k | { |
2187 | 1.84k | if (ecn & ~IP_ECN_MASK) { |
2188 | 983 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
2189 | 983 | } else { |
2190 | 866 | ofpact_put_SET_IP_ECN(out)->ecn = ecn; |
2191 | 866 | return 0; |
2192 | 866 | } |
2193 | 1.84k | } |
2194 | | |
2195 | | static void |
2196 | | encode_SET_IP_ECN(const struct ofpact_ecn *ip_ecn, |
2197 | | enum ofp_version ofp_version, struct ofpbuf *out) |
2198 | 0 | { |
2199 | 0 | uint8_t ecn = ip_ecn->ecn; |
2200 | 0 | if (ofp_version == OFP10_VERSION) { |
2201 | 0 | struct mf_subfield dst = { .field = mf_from_id(MFF_IP_ECN), |
2202 | 0 | .ofs = 0, .n_bits = 2 }; |
2203 | 0 | put_reg_load(out, &dst, ecn); |
2204 | 0 | } else if (ofp_version == OFP11_VERSION) { |
2205 | 0 | put_OFPAT11_SET_NW_ECN(out, ecn); |
2206 | 0 | } else { |
2207 | 0 | put_set_field(out, ofp_version, MFF_IP_ECN, ecn); |
2208 | 0 | } |
2209 | 0 | } |
2210 | | |
2211 | | static char * OVS_WARN_UNUSED_RESULT |
2212 | | parse_SET_IP_ECN(char *arg, const struct ofpact_parse_params *pp) |
2213 | 0 | { |
2214 | 0 | uint8_t ecn; |
2215 | 0 | char *error; |
2216 | |
|
2217 | 0 | error = str_to_u8(arg, "ECN", &ecn); |
2218 | 0 | if (error) { |
2219 | 0 | return error; |
2220 | 0 | } |
2221 | | |
2222 | 0 | if (ecn & ~IP_ECN_MASK) { |
2223 | 0 | return xasprintf("%s: not a valid ECN", arg); |
2224 | 0 | } |
2225 | 0 | ofpact_put_SET_IP_ECN(pp->ofpacts)->ecn = ecn; |
2226 | 0 | return NULL; |
2227 | 0 | } |
2228 | | |
2229 | | static void |
2230 | | format_SET_IP_ECN(const struct ofpact_ecn *a, |
2231 | | const struct ofpact_format_params *fp) |
2232 | 702 | { |
2233 | 702 | ds_put_format(fp->s, "%smod_nw_ecn:%s%d", |
2234 | 702 | colors.param, colors.end, a->ecn); |
2235 | 702 | } |
2236 | | |
2237 | | static enum ofperr |
2238 | | check_SET_IP_ECN(const struct ofpact_ecn *a OVS_UNUSED, |
2239 | | struct ofpact_check_params *cp) |
2240 | 256 | { |
2241 | 256 | return check_set_ip(cp); |
2242 | 256 | } |
2243 | | |
2244 | | /* Set IPv4/v6 TTL actions. */ |
2245 | | |
2246 | | static enum ofperr |
2247 | | decode_OFPAT_RAW11_SET_NW_TTL(uint8_t ttl, |
2248 | | enum ofp_version ofp_version OVS_UNUSED, |
2249 | | struct ofpbuf *out) |
2250 | 512 | { |
2251 | 512 | ofpact_put_SET_IP_TTL(out)->ttl = ttl; |
2252 | 512 | return 0; |
2253 | 512 | } |
2254 | | |
2255 | | static void |
2256 | | encode_SET_IP_TTL(const struct ofpact_ip_ttl *ttl, |
2257 | | enum ofp_version ofp_version, struct ofpbuf *out) |
2258 | 0 | { |
2259 | 0 | if (ofp_version >= OFP11_VERSION) { |
2260 | 0 | put_OFPAT11_SET_NW_TTL(out, ttl->ttl); |
2261 | 0 | } else { |
2262 | 0 | struct mf_subfield dst = { .field = mf_from_id(MFF_IP_TTL), |
2263 | 0 | .ofs = 0, .n_bits = 8 }; |
2264 | 0 | put_reg_load(out, &dst, ttl->ttl); |
2265 | 0 | } |
2266 | 0 | } |
2267 | | |
2268 | | static char * OVS_WARN_UNUSED_RESULT |
2269 | | parse_SET_IP_TTL(char *arg, const struct ofpact_parse_params *pp) |
2270 | | |
2271 | 0 | { |
2272 | 0 | uint8_t ttl; |
2273 | 0 | char *error; |
2274 | |
|
2275 | 0 | error = str_to_u8(arg, "TTL", &ttl); |
2276 | 0 | if (error) { |
2277 | 0 | return error; |
2278 | 0 | } |
2279 | | |
2280 | 0 | ofpact_put_SET_IP_TTL(pp->ofpacts)->ttl = ttl; |
2281 | 0 | return NULL; |
2282 | 0 | } |
2283 | | |
2284 | | static void |
2285 | | format_SET_IP_TTL(const struct ofpact_ip_ttl *a, |
2286 | | const struct ofpact_format_params *fp) |
2287 | 453 | { |
2288 | 453 | ds_put_format(fp->s, "%smod_nw_ttl:%s%d", |
2289 | 453 | colors.param, colors.end, a->ttl); |
2290 | 453 | } |
2291 | | |
2292 | | static enum ofperr |
2293 | | check_SET_IP_TTL(const struct ofpact_ip_ttl *a OVS_UNUSED, |
2294 | | struct ofpact_check_params *cp) |
2295 | 459 | { |
2296 | 459 | return check_set_ip(cp); |
2297 | 459 | } |
2298 | | |
2299 | | /* Set TCP/UDP/SCTP port actions. */ |
2300 | | |
2301 | | static enum ofperr |
2302 | | decode_OFPAT_RAW_SET_TP_SRC(ovs_be16 port, |
2303 | | enum ofp_version ofp_version OVS_UNUSED, |
2304 | | struct ofpbuf *out) |
2305 | 10.8k | { |
2306 | 10.8k | ofpact_put_SET_L4_SRC_PORT(out)->port = ntohs(port); |
2307 | 10.8k | return 0; |
2308 | 10.8k | } |
2309 | | |
2310 | | static enum ofperr |
2311 | | decode_OFPAT_RAW_SET_TP_DST(ovs_be16 port, |
2312 | | enum ofp_version ofp_version OVS_UNUSED, |
2313 | | struct ofpbuf *out) |
2314 | 19.4k | { |
2315 | 19.4k | ofpact_put_SET_L4_DST_PORT(out)->port = ntohs(port); |
2316 | 19.4k | return 0; |
2317 | 19.4k | } |
2318 | | |
2319 | | static void |
2320 | | encode_SET_L4_port(const struct ofpact_l4_port *l4_port, |
2321 | | enum ofp_version ofp_version, enum ofp_raw_action_type raw, |
2322 | | enum mf_field_id field, struct ofpbuf *out) |
2323 | 0 | { |
2324 | 0 | uint16_t port = l4_port->port; |
2325 | |
|
2326 | 0 | if (ofp_version >= OFP12_VERSION && field != MFF_N_IDS) { |
2327 | 0 | put_set_field(out, ofp_version, field, port); |
2328 | 0 | } else { |
2329 | 0 | ofpact_put_raw(out, ofp_version, raw, port); |
2330 | 0 | } |
2331 | 0 | } |
2332 | | |
2333 | | static void |
2334 | | encode_SET_L4_SRC_PORT(const struct ofpact_l4_port *l4_port, |
2335 | | enum ofp_version ofp_version, struct ofpbuf *out) |
2336 | 0 | { |
2337 | 0 | uint8_t proto = l4_port->flow_ip_proto; |
2338 | 0 | enum mf_field_id field = (proto == IPPROTO_TCP ? MFF_TCP_SRC |
2339 | 0 | : proto == IPPROTO_UDP ? MFF_UDP_SRC |
2340 | 0 | : proto == IPPROTO_SCTP ? MFF_SCTP_SRC |
2341 | 0 | : MFF_N_IDS); |
2342 | |
|
2343 | 0 | encode_SET_L4_port(l4_port, ofp_version, OFPAT_RAW_SET_TP_SRC, field, out); |
2344 | 0 | } |
2345 | | |
2346 | | static void |
2347 | | encode_SET_L4_DST_PORT(const struct ofpact_l4_port *l4_port, |
2348 | | enum ofp_version ofp_version, |
2349 | | struct ofpbuf *out) |
2350 | 0 | { |
2351 | 0 | uint8_t proto = l4_port->flow_ip_proto; |
2352 | 0 | enum mf_field_id field = (proto == IPPROTO_TCP ? MFF_TCP_DST |
2353 | 0 | : proto == IPPROTO_UDP ? MFF_UDP_DST |
2354 | 0 | : proto == IPPROTO_SCTP ? MFF_SCTP_DST |
2355 | 0 | : MFF_N_IDS); |
2356 | |
|
2357 | 0 | encode_SET_L4_port(l4_port, ofp_version, OFPAT_RAW_SET_TP_DST, field, out); |
2358 | 0 | } |
2359 | | |
2360 | | static char * OVS_WARN_UNUSED_RESULT |
2361 | | parse_SET_L4_SRC_PORT(char *arg, const struct ofpact_parse_params *pp) |
2362 | 0 | { |
2363 | 0 | return str_to_u16(arg, "source port", |
2364 | 0 | &ofpact_put_SET_L4_SRC_PORT(pp->ofpacts)->port); |
2365 | 0 | } |
2366 | | |
2367 | | static char * OVS_WARN_UNUSED_RESULT |
2368 | | parse_SET_L4_DST_PORT(char *arg, const struct ofpact_parse_params *pp) |
2369 | 0 | { |
2370 | 0 | return str_to_u16(arg, "destination port", |
2371 | 0 | &ofpact_put_SET_L4_DST_PORT(pp->ofpacts)->port); |
2372 | 0 | } |
2373 | | |
2374 | | static void |
2375 | | format_SET_L4_SRC_PORT(const struct ofpact_l4_port *a, |
2376 | | const struct ofpact_format_params *fp) |
2377 | 6.48k | { |
2378 | 6.48k | ds_put_format(fp->s, "%smod_tp_src:%s%d", |
2379 | 6.48k | colors.param, colors.end, a->port); |
2380 | 6.48k | } |
2381 | | |
2382 | | static void |
2383 | | format_SET_L4_DST_PORT(const struct ofpact_l4_port *a, |
2384 | | const struct ofpact_format_params *fp) |
2385 | 14.0k | { |
2386 | 14.0k | ds_put_format(fp->s, "%smod_tp_dst:%s%d", |
2387 | 14.0k | colors.param, colors.end, a->port); |
2388 | 14.0k | } |
2389 | | |
2390 | | static enum ofperr |
2391 | | check_set_l4_port(struct ofpact_l4_port *a, struct ofpact_check_params *cp) |
2392 | 19.2k | { |
2393 | 19.2k | const struct flow *flow = &cp->match->flow; |
2394 | 19.2k | if (!is_ip_any(flow) |
2395 | 19.2k | || flow->nw_frag & FLOW_NW_FRAG_LATER |
2396 | 19.2k | || (flow->nw_proto != IPPROTO_TCP && |
2397 | 16.0k | flow->nw_proto != IPPROTO_UDP && |
2398 | 16.0k | flow->nw_proto != IPPROTO_SCTP)) { |
2399 | 6.25k | inconsistent_match(&cp->usable_protocols); |
2400 | 6.25k | } |
2401 | | |
2402 | | /* Note the transport protocol in use, to allow this action to be converted |
2403 | | * to an OF1.2 set_field action later if necessary. */ |
2404 | 19.2k | a->flow_ip_proto = flow->nw_proto; |
2405 | | |
2406 | 19.2k | return 0; |
2407 | 19.2k | } |
2408 | | |
2409 | | static enum ofperr |
2410 | | check_SET_L4_SRC_PORT(struct ofpact_l4_port *a, struct ofpact_check_params *cp) |
2411 | 5.24k | { |
2412 | 5.24k | return check_set_l4_port(a, cp); |
2413 | 5.24k | } |
2414 | | |
2415 | | static enum ofperr |
2416 | | check_SET_L4_DST_PORT(struct ofpact_l4_port *a, struct ofpact_check_params *cp) |
2417 | 14.0k | { |
2418 | 14.0k | return check_set_l4_port(a, cp); |
2419 | 14.0k | } |
2420 | | |
2421 | | /* Action structure for OFPAT_COPY_FIELD. */ |
2422 | | struct ofp15_action_copy_field { |
2423 | | ovs_be16 type; /* OFPAT_COPY_FIELD. */ |
2424 | | ovs_be16 len; /* Length is padded to 64 bits. */ |
2425 | | ovs_be16 n_bits; /* Number of bits to copy. */ |
2426 | | ovs_be16 src_offset; /* Starting bit offset in source. */ |
2427 | | ovs_be16 dst_offset; /* Starting bit offset in destination. */ |
2428 | | uint8_t pad[2]; |
2429 | | /* Followed by: |
2430 | | * - OXM header for source field. |
2431 | | * - OXM header for destination field. |
2432 | | * - Padding with 0-bytes to a multiple of 8 bytes. |
2433 | | * The "pad2" member is the beginning of the above. */ |
2434 | | uint8_t pad2[4]; |
2435 | | }; |
2436 | | OFP_ASSERT(sizeof(struct ofp15_action_copy_field) == 16); |
2437 | | |
2438 | | /* Action structure for OpenFlow 1.3 extension copy-field action.. */ |
2439 | | struct onf_action_copy_field { |
2440 | | ovs_be16 type; /* OFPAT_EXPERIMENTER. */ |
2441 | | ovs_be16 len; /* Length is padded to 64 bits. */ |
2442 | | ovs_be32 experimenter; /* ONF_VENDOR_ID. */ |
2443 | | ovs_be16 exp_type; /* 3200. */ |
2444 | | uint8_t pad[2]; /* Not used. */ |
2445 | | ovs_be16 n_bits; /* Number of bits to copy. */ |
2446 | | ovs_be16 src_offset; /* Starting bit offset in source. */ |
2447 | | ovs_be16 dst_offset; /* Starting bit offset in destination. */ |
2448 | | uint8_t pad2[2]; /* Not used. */ |
2449 | | /* Followed by: |
2450 | | * - OXM header for source field. |
2451 | | * - OXM header for destination field. |
2452 | | * - Padding with 0-bytes (either 0 or 4 of them) to a multiple of 8 bytes. |
2453 | | * The "pad3" member is the beginning of the above. */ |
2454 | | uint8_t pad3[4]; /* Not used. */ |
2455 | | }; |
2456 | | OFP_ASSERT(sizeof(struct onf_action_copy_field) == 24); |
2457 | | |
2458 | | /* Action structure for NXAST_REG_MOVE. |
2459 | | * |
2460 | | * Copies src[src_ofs:src_ofs+n_bits] to dst[dst_ofs:dst_ofs+n_bits], where |
2461 | | * a[b:c] denotes the bits within 'a' numbered 'b' through 'c' (not including |
2462 | | * bit 'c'). Bit numbering starts at 0 for the least-significant bit, 1 for |
2463 | | * the next most significant bit, and so on. |
2464 | | * |
2465 | | * 'src' and 'dst' are nxm_header values with nxm_hasmask=0. (It doesn't make |
2466 | | * sense to use nxm_hasmask=1 because the action does not do any kind of |
2467 | | * matching; it uses the actual value of a field.) |
2468 | | * |
2469 | | * The following nxm_header values are potentially acceptable as 'src': |
2470 | | * |
2471 | | * - NXM_OF_IN_PORT |
2472 | | * - NXM_OF_ETH_DST |
2473 | | * - NXM_OF_ETH_SRC |
2474 | | * - NXM_OF_ETH_TYPE |
2475 | | * - NXM_OF_VLAN_TCI |
2476 | | * - NXM_OF_IP_TOS |
2477 | | * - NXM_OF_IP_PROTO |
2478 | | * - NXM_OF_IP_SRC |
2479 | | * - NXM_OF_IP_DST |
2480 | | * - NXM_OF_TCP_SRC |
2481 | | * - NXM_OF_TCP_DST |
2482 | | * - NXM_OF_UDP_SRC |
2483 | | * - NXM_OF_UDP_DST |
2484 | | * - NXM_OF_ICMP_TYPE |
2485 | | * - NXM_OF_ICMP_CODE |
2486 | | * - NXM_OF_ARP_OP |
2487 | | * - NXM_OF_ARP_SPA |
2488 | | * - NXM_OF_ARP_TPA |
2489 | | * - NXM_NX_TUN_ID |
2490 | | * - NXM_NX_ARP_SHA |
2491 | | * - NXM_NX_ARP_THA |
2492 | | * - NXM_NX_ICMPV6_TYPE |
2493 | | * - NXM_NX_ICMPV6_CODE |
2494 | | * - NXM_NX_ND_SLL |
2495 | | * - NXM_NX_ND_TLL |
2496 | | * - NXM_NX_REG(idx) for idx in the switch's accepted range. |
2497 | | * - NXM_NX_PKT_MARK |
2498 | | * - NXM_NX_TUN_IPV4_SRC |
2499 | | * - NXM_NX_TUN_IPV4_DST |
2500 | | * |
2501 | | * The following nxm_header values are potentially acceptable as 'dst': |
2502 | | * |
2503 | | * - NXM_OF_ETH_DST |
2504 | | * - NXM_OF_ETH_SRC |
2505 | | * - NXM_OF_IP_TOS |
2506 | | * - NXM_OF_IP_SRC |
2507 | | * - NXM_OF_IP_DST |
2508 | | * - NXM_OF_TCP_SRC |
2509 | | * - NXM_OF_TCP_DST |
2510 | | * - NXM_OF_UDP_SRC |
2511 | | * - NXM_OF_UDP_DST |
2512 | | * - NXM_OF_ICMP_TYPE |
2513 | | * - NXM_OF_ICMP_CODE |
2514 | | * - NXM_NX_ICMPV6_TYPE |
2515 | | * - NXM_NX_ICMPV6_CODE |
2516 | | * - NXM_NX_ARP_SHA |
2517 | | * - NXM_NX_ARP_THA |
2518 | | * - NXM_OF_ARP_OP |
2519 | | * - NXM_OF_ARP_SPA |
2520 | | * - NXM_OF_ARP_TPA |
2521 | | * Modifying any of the above fields changes the corresponding packet |
2522 | | * header. |
2523 | | * |
2524 | | * - NXM_OF_IN_PORT |
2525 | | * |
2526 | | * - NXM_NX_REG(idx) for idx in the switch's accepted range. |
2527 | | * |
2528 | | * - NXM_NX_PKT_MARK |
2529 | | * |
2530 | | * - NXM_OF_VLAN_TCI. Modifying this field's value has side effects on the |
2531 | | * packet's 802.1Q header. Setting a value with CFI=0 removes the 802.1Q |
2532 | | * header (if any), ignoring the other bits. Setting a value with CFI=1 |
2533 | | * adds or modifies the 802.1Q header appropriately, setting the TCI field |
2534 | | * to the field's new value (with the CFI bit masked out). |
2535 | | * |
2536 | | * - NXM_NX_TUN_ID, NXM_NX_TUN_IPV4_SRC, NXM_NX_TUN_IPV4_DST. Modifying |
2537 | | * any of these values modifies the corresponding tunnel header field used |
2538 | | * for the packet's next tunnel encapsulation, if allowed by the |
2539 | | * configuration of the output tunnel port. |
2540 | | * |
2541 | | * A given nxm_header value may be used as 'src' or 'dst' only on a flow whose |
2542 | | * nx_match satisfies its prerequisites. For example, NXM_OF_IP_TOS may be |
2543 | | * used only if the flow's nx_match includes an nxm_entry that specifies |
2544 | | * nxm_type=NXM_OF_ETH_TYPE, nxm_hasmask=0, and nxm_value=0x0800. |
2545 | | * |
2546 | | * The switch will reject actions for which src_ofs+n_bits is greater than the |
2547 | | * width of 'src' or dst_ofs+n_bits is greater than the width of 'dst' with |
2548 | | * error type OFPET_BAD_ACTION, code OFPBAC_BAD_ARGUMENT. |
2549 | | * |
2550 | | * This action behaves properly when 'src' overlaps with 'dst', that is, it |
2551 | | * behaves as if 'src' were copied out to a temporary buffer, then the |
2552 | | * temporary buffer copied to 'dst'. |
2553 | | */ |
2554 | | struct nx_action_reg_move { |
2555 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
2556 | | ovs_be16 len; /* Length is 24. */ |
2557 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
2558 | | ovs_be16 subtype; /* NXAST_REG_MOVE. */ |
2559 | | ovs_be16 n_bits; /* Number of bits. */ |
2560 | | ovs_be16 src_ofs; /* Starting bit offset in source. */ |
2561 | | ovs_be16 dst_ofs; /* Starting bit offset in destination. */ |
2562 | | /* Followed by: |
2563 | | * - OXM/NXM header for source field (4 or 8 bytes). |
2564 | | * - OXM/NXM header for destination field (4 or 8 bytes). |
2565 | | * - Padding with 0-bytes to a multiple of 8 bytes, if necessary. */ |
2566 | | }; |
2567 | | OFP_ASSERT(sizeof(struct nx_action_reg_move) == 16); |
2568 | | |
2569 | | static enum ofperr |
2570 | | decode_copy_field__(ovs_be16 src_offset, ovs_be16 dst_offset, ovs_be16 n_bits, |
2571 | | const void *action, ovs_be16 action_len, size_t oxm_offset, |
2572 | | const struct vl_mff_map *vl_mff_map, |
2573 | | uint64_t *tlv_bitmap, struct ofpbuf *ofpacts) |
2574 | 107 | { |
2575 | 107 | struct ofpact_reg_move *move = ofpact_put_REG_MOVE(ofpacts); |
2576 | 107 | enum ofperr error; |
2577 | | |
2578 | 107 | move->ofpact.raw = ONFACT_RAW13_COPY_FIELD; |
2579 | 107 | move->src.ofs = ntohs(src_offset); |
2580 | 107 | move->src.n_bits = ntohs(n_bits); |
2581 | 107 | move->dst.ofs = ntohs(dst_offset); |
2582 | 107 | move->dst.n_bits = ntohs(n_bits); |
2583 | | |
2584 | 107 | struct ofpbuf b = ofpbuf_const_initializer(action, ntohs(action_len)); |
2585 | 107 | ofpbuf_pull(&b, oxm_offset); |
2586 | | |
2587 | 107 | error = mf_vl_mff_nx_pull_header(&b, vl_mff_map, &move->src.field, NULL, |
2588 | 107 | tlv_bitmap); |
2589 | 107 | if (error) { |
2590 | 27 | return error; |
2591 | 27 | } |
2592 | 80 | error = mf_vl_mff_nx_pull_header(&b, vl_mff_map, &move->dst.field, NULL, |
2593 | 80 | tlv_bitmap); |
2594 | 80 | if (error) { |
2595 | 52 | return error; |
2596 | 52 | } |
2597 | | |
2598 | 28 | if (!is_all_zeros(b.data, b.size)) { |
2599 | 10 | return OFPERR_NXBRC_MUST_BE_ZERO; |
2600 | 10 | } |
2601 | | |
2602 | 18 | return nxm_reg_move_check(move, NULL); |
2603 | 28 | } |
2604 | | |
2605 | | static enum ofperr |
2606 | | decode_OFPAT_RAW15_COPY_FIELD(const struct ofp15_action_copy_field *oacf, |
2607 | | enum ofp_version ofp_version OVS_UNUSED, |
2608 | | const struct vl_mff_map *vl_mff_map, |
2609 | | uint64_t *tlv_bitmap, struct ofpbuf *ofpacts) |
2610 | 97 | { |
2611 | 97 | return decode_copy_field__(oacf->src_offset, oacf->dst_offset, |
2612 | 97 | oacf->n_bits, oacf, oacf->len, |
2613 | 97 | OBJECT_OFFSETOF(oacf, pad2), vl_mff_map, |
2614 | 97 | tlv_bitmap, ofpacts); |
2615 | 97 | } |
2616 | | |
2617 | | static enum ofperr |
2618 | | decode_ONFACT_RAW13_COPY_FIELD(const struct onf_action_copy_field *oacf, |
2619 | | enum ofp_version ofp_version OVS_UNUSED, |
2620 | | const struct vl_mff_map *vl_mff_map, |
2621 | | uint64_t *tlv_bitmap, struct ofpbuf *ofpacts) |
2622 | 10 | { |
2623 | 10 | return decode_copy_field__(oacf->src_offset, oacf->dst_offset, |
2624 | 10 | oacf->n_bits, oacf, oacf->len, |
2625 | 10 | OBJECT_OFFSETOF(oacf, pad3), vl_mff_map, |
2626 | 10 | tlv_bitmap, ofpacts); |
2627 | 10 | } |
2628 | | |
2629 | | static enum ofperr |
2630 | | decode_NXAST_RAW_REG_MOVE(const struct nx_action_reg_move *narm, |
2631 | | enum ofp_version ofp_version OVS_UNUSED, |
2632 | | const struct vl_mff_map *vl_mff_map, |
2633 | | uint64_t *tlv_bitmap, struct ofpbuf *ofpacts) |
2634 | 1.29k | { |
2635 | 1.29k | struct ofpact_reg_move *move = ofpact_put_REG_MOVE(ofpacts); |
2636 | 1.29k | enum ofperr error; |
2637 | | |
2638 | 1.29k | move->ofpact.raw = NXAST_RAW_REG_MOVE; |
2639 | 1.29k | move->src.ofs = ntohs(narm->src_ofs); |
2640 | 1.29k | move->src.n_bits = ntohs(narm->n_bits); |
2641 | 1.29k | move->dst.ofs = ntohs(narm->dst_ofs); |
2642 | 1.29k | move->dst.n_bits = ntohs(narm->n_bits); |
2643 | | |
2644 | 1.29k | struct ofpbuf b = ofpbuf_const_initializer(narm, ntohs(narm->len)); |
2645 | 1.29k | ofpbuf_pull(&b, sizeof *narm); |
2646 | | |
2647 | 1.29k | error = mf_vl_mff_nx_pull_header(&b, vl_mff_map, &move->src.field, NULL, |
2648 | 1.29k | tlv_bitmap); |
2649 | 1.29k | if (error) { |
2650 | 327 | return error; |
2651 | 327 | } |
2652 | | |
2653 | 972 | error = mf_vl_mff_nx_pull_header(&b, vl_mff_map, &move->dst.field, NULL, |
2654 | 972 | tlv_bitmap); |
2655 | 972 | if (error) { |
2656 | 217 | return error; |
2657 | 217 | } |
2658 | | |
2659 | 755 | if (!is_all_zeros(b.data, b.size)) { |
2660 | 10 | return OFPERR_NXBRC_MUST_BE_ZERO; |
2661 | 10 | } |
2662 | | |
2663 | 745 | return nxm_reg_move_check(move, NULL); |
2664 | 755 | } |
2665 | | |
2666 | | static void |
2667 | | encode_REG_MOVE(const struct ofpact_reg_move *move, |
2668 | | enum ofp_version ofp_version, struct ofpbuf *out) |
2669 | 0 | { |
2670 | | /* For OpenFlow 1.3, the choice of ONFACT_RAW13_COPY_FIELD versus |
2671 | | * NXAST_RAW_REG_MOVE is somewhat difficult. Neither one is guaranteed to |
2672 | | * be supported by every OpenFlow 1.3 implementation. It would be ideal to |
2673 | | * probe for support. Until we have that ability, we currently prefer |
2674 | | * NXAST_RAW_REG_MOVE for backward compatibility with older Open vSwitch |
2675 | | * versions. */ |
2676 | 0 | size_t start_ofs = out->size; |
2677 | 0 | if (ofp_version >= OFP15_VERSION) { |
2678 | 0 | struct ofp15_action_copy_field *copy = put_OFPAT15_COPY_FIELD(out); |
2679 | 0 | copy->n_bits = htons(move->dst.n_bits); |
2680 | 0 | copy->src_offset = htons(move->src.ofs); |
2681 | 0 | copy->dst_offset = htons(move->dst.ofs); |
2682 | 0 | out->size = out->size - sizeof copy->pad2; |
2683 | 0 | nx_put_mff_header(out, move->src.field, ofp_version, false); |
2684 | 0 | nx_put_mff_header(out, move->dst.field, ofp_version, false); |
2685 | 0 | } else if (ofp_version == OFP13_VERSION |
2686 | 0 | && move->ofpact.raw == ONFACT_RAW13_COPY_FIELD) { |
2687 | 0 | struct onf_action_copy_field *copy = put_ONFACT13_COPY_FIELD(out); |
2688 | 0 | copy->n_bits = htons(move->dst.n_bits); |
2689 | 0 | copy->src_offset = htons(move->src.ofs); |
2690 | 0 | copy->dst_offset = htons(move->dst.ofs); |
2691 | 0 | out->size = out->size - sizeof copy->pad3; |
2692 | 0 | nx_put_mff_header(out, move->src.field, ofp_version, false); |
2693 | 0 | nx_put_mff_header(out, move->dst.field, ofp_version, false); |
2694 | 0 | } else { |
2695 | 0 | struct nx_action_reg_move *narm = put_NXAST_REG_MOVE(out); |
2696 | 0 | narm->n_bits = htons(move->dst.n_bits); |
2697 | 0 | narm->src_ofs = htons(move->src.ofs); |
2698 | 0 | narm->dst_ofs = htons(move->dst.ofs); |
2699 | 0 | nx_put_mff_header(out, move->src.field, 0, false); |
2700 | 0 | nx_put_mff_header(out, move->dst.field, 0, false); |
2701 | 0 | } |
2702 | 0 | pad_ofpat(out, start_ofs); |
2703 | 0 | } |
2704 | | |
2705 | | static char * OVS_WARN_UNUSED_RESULT |
2706 | | parse_REG_MOVE(const char *arg, const struct ofpact_parse_params *pp) |
2707 | 0 | { |
2708 | 0 | struct ofpact_reg_move *move = ofpact_put_REG_MOVE(pp->ofpacts); |
2709 | 0 | return nxm_parse_reg_move(move, arg); |
2710 | 0 | } |
2711 | | |
2712 | | static void |
2713 | | format_REG_MOVE(const struct ofpact_reg_move *a, |
2714 | | const struct ofpact_format_params *fp) |
2715 | 275 | { |
2716 | 275 | nxm_format_reg_move(a, fp->s); |
2717 | 275 | } |
2718 | | |
2719 | | static enum ofperr |
2720 | | check_REG_MOVE(const struct ofpact_reg_move *a, |
2721 | | const struct ofpact_check_params *cp) |
2722 | 38 | { |
2723 | 38 | return nxm_reg_move_check(a, cp->match); |
2724 | 38 | } |
2725 | | |
2726 | | /* Action structure for OFPAT12_SET_FIELD. */ |
2727 | | struct ofp12_action_set_field { |
2728 | | ovs_be16 type; /* OFPAT12_SET_FIELD. */ |
2729 | | ovs_be16 len; /* Length is padded to 64 bits. */ |
2730 | | |
2731 | | /* Followed by: |
2732 | | * - An OXM header, value, and (in OpenFlow 1.5+) optionally a mask. |
2733 | | * - Enough 0-bytes to pad out to a multiple of 64 bits. |
2734 | | * |
2735 | | * The "pad" member is the beginning of the above. */ |
2736 | | uint8_t pad[4]; |
2737 | | }; |
2738 | | OFP_ASSERT(sizeof(struct ofp12_action_set_field) == 8); |
2739 | | |
2740 | | /* Action structure for NXAST_REG_LOAD. |
2741 | | * |
2742 | | * Copies value[0:n_bits] to dst[ofs:ofs+n_bits], where a[b:c] denotes the bits |
2743 | | * within 'a' numbered 'b' through 'c' (not including bit 'c'). Bit numbering |
2744 | | * starts at 0 for the least-significant bit, 1 for the next most significant |
2745 | | * bit, and so on. |
2746 | | * |
2747 | | * 'dst' is an nxm_header with nxm_hasmask=0. See the documentation for |
2748 | | * NXAST_REG_MOVE, above, for the permitted fields and for the side effects of |
2749 | | * loading them. |
2750 | | * |
2751 | | * The 'ofs' and 'n_bits' fields are combined into a single 'ofs_nbits' field |
2752 | | * to avoid enlarging the structure by another 8 bytes. To allow 'n_bits' to |
2753 | | * take a value between 1 and 64 (inclusive) while taking up only 6 bits, it is |
2754 | | * also stored as one less than its true value: |
2755 | | * |
2756 | | * 15 6 5 0 |
2757 | | * +------------------------------+------------------+ |
2758 | | * | ofs | n_bits - 1 | |
2759 | | * +------------------------------+------------------+ |
2760 | | * |
2761 | | * The switch will reject actions for which ofs+n_bits is greater than the |
2762 | | * width of 'dst', or in which any bits in 'value' with value 2**n_bits or |
2763 | | * greater are set to 1, with error type OFPET_BAD_ACTION, code |
2764 | | * OFPBAC_BAD_ARGUMENT. |
2765 | | */ |
2766 | | struct nx_action_reg_load { |
2767 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
2768 | | ovs_be16 len; /* Length is 24. */ |
2769 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
2770 | | ovs_be16 subtype; /* NXAST_REG_LOAD. */ |
2771 | | ovs_be16 ofs_nbits; /* (ofs << 6) | (n_bits - 1). */ |
2772 | | ovs_be32 dst; /* Destination register. */ |
2773 | | ovs_be64 value; /* Immediate value. */ |
2774 | | }; |
2775 | | OFP_ASSERT(sizeof(struct nx_action_reg_load) == 24); |
2776 | | |
2777 | | /* The NXAST_REG_LOAD2 action structure is "struct ext_action_header", |
2778 | | * followed by: |
2779 | | * |
2780 | | * - An NXM/OXM header, value, and optionally a mask. |
2781 | | * - Enough 0-bytes to pad out to a multiple of 64 bits. |
2782 | | * |
2783 | | * The "pad" member is the beginning of the above. */ |
2784 | | |
2785 | | static enum ofperr |
2786 | | decode_ofpat_set_field(const struct ofp12_action_set_field *oasf, |
2787 | | bool may_mask, const struct vl_mff_map *vl_mff_map, |
2788 | | uint64_t *tlv_bitmap, struct ofpbuf *ofpacts) |
2789 | 12.7k | { |
2790 | 12.7k | struct ofpbuf b = ofpbuf_const_initializer(oasf, ntohs(oasf->len)); |
2791 | 12.7k | ofpbuf_pull(&b, OBJECT_OFFSETOF(oasf, pad)); |
2792 | | |
2793 | 12.7k | union mf_value value, mask; |
2794 | 12.7k | const struct mf_field *field; |
2795 | 12.7k | enum ofperr error; |
2796 | 12.7k | error = mf_vl_mff_nx_pull_entry(&b, vl_mff_map, &field, &value, |
2797 | 12.7k | may_mask ? &mask : NULL, tlv_bitmap); |
2798 | 12.7k | if (error) { |
2799 | 2.63k | return (error == OFPERR_OFPBMC_BAD_MASK |
2800 | 2.63k | ? OFPERR_OFPBAC_BAD_SET_MASK |
2801 | 2.63k | : error); |
2802 | 2.63k | } |
2803 | | |
2804 | 10.1k | if (!may_mask) { |
2805 | 9.21k | memset(&mask, 0xff, field->n_bytes); |
2806 | 9.21k | } |
2807 | | |
2808 | 10.1k | if (!is_all_zeros(b.data, b.size)) { |
2809 | 779 | return OFPERR_OFPBAC_BAD_SET_ARGUMENT; |
2810 | 779 | } |
2811 | | |
2812 | | /* OpenFlow says specifically that one may not set OXM_OF_IN_PORT via |
2813 | | * Set-Field. */ |
2814 | 9.33k | if (field->id == MFF_IN_PORT_OXM) { |
2815 | 18 | return OFPERR_OFPBAC_BAD_SET_ARGUMENT; |
2816 | 18 | } |
2817 | | |
2818 | | /* oxm_length is now validated to be compatible with mf_value. */ |
2819 | 9.32k | if (!field->writable) { |
2820 | 10 | VLOG_WARN_RL(&rl, "destination field %s is not writable", |
2821 | 10 | field->name); |
2822 | 10 | return OFPERR_OFPBAC_BAD_SET_ARGUMENT; |
2823 | 10 | } |
2824 | | |
2825 | | /* The value must be valid for match. OpenFlow 1.5 also says, |
2826 | | * "In an OXM_OF_VLAN_VID set-field action, the OFPVID_PRESENT bit must be |
2827 | | * a 1-bit in oxm_value and in oxm_mask." */ |
2828 | 9.31k | if (!mf_is_value_valid(field, &value) |
2829 | 9.31k | || (field->id == MFF_VLAN_VID |
2830 | 9.22k | && (!(mask.be16 & htons(OFPVID12_PRESENT)) |
2831 | 950 | || !(value.be16 & htons(OFPVID12_PRESENT))))) { |
2832 | 950 | struct ds ds = DS_EMPTY_INITIALIZER; |
2833 | 950 | mf_format(field, &value, NULL, NULL, &ds); |
2834 | 950 | VLOG_WARN_RL(&rl, "Invalid value for set field %s: %s", |
2835 | 950 | field->name, ds_cstr(&ds)); |
2836 | 950 | ds_destroy(&ds); |
2837 | | |
2838 | 950 | return OFPERR_OFPBAC_BAD_SET_ARGUMENT; |
2839 | 950 | } |
2840 | | |
2841 | 8.36k | ofpact_put_set_field(ofpacts, field, &value, &mask); |
2842 | 8.36k | return 0; |
2843 | 9.31k | } |
2844 | | |
2845 | | static enum ofperr |
2846 | | decode_OFPAT_RAW12_SET_FIELD(const struct ofp12_action_set_field *oasf, |
2847 | | enum ofp_version ofp_version OVS_UNUSED, |
2848 | | const struct vl_mff_map *vl_mff_map, |
2849 | | uint64_t *tlv_bitmap, struct ofpbuf *ofpacts) |
2850 | 11.5k | { |
2851 | 11.5k | return decode_ofpat_set_field(oasf, false, vl_mff_map, tlv_bitmap, |
2852 | 11.5k | ofpacts); |
2853 | 11.5k | } |
2854 | | |
2855 | | static enum ofperr |
2856 | | decode_OFPAT_RAW15_SET_FIELD(const struct ofp12_action_set_field *oasf, |
2857 | | enum ofp_version ofp_version OVS_UNUSED, |
2858 | | const struct vl_mff_map *vl_mff_map, |
2859 | | uint64_t *tlv_bitmap, struct ofpbuf *ofpacts) |
2860 | 1.21k | { |
2861 | 1.21k | return decode_ofpat_set_field(oasf, true, vl_mff_map, tlv_bitmap, ofpacts); |
2862 | 1.21k | } |
2863 | | |
2864 | | static enum ofperr |
2865 | | decode_NXAST_RAW_REG_LOAD(const struct nx_action_reg_load *narl, |
2866 | | enum ofp_version ofp_version OVS_UNUSED, |
2867 | | const struct vl_mff_map *vl_mff_map, |
2868 | | uint64_t *tlv_bitmap, struct ofpbuf *out) |
2869 | 4.14k | { |
2870 | 4.14k | struct mf_subfield dst; |
2871 | 4.14k | enum ofperr error; |
2872 | | |
2873 | 4.14k | dst.ofs = nxm_decode_ofs(narl->ofs_nbits); |
2874 | 4.14k | dst.n_bits = nxm_decode_n_bits(narl->ofs_nbits); |
2875 | 4.14k | error = mf_vl_mff_mf_from_nxm_header(ntohl(narl->dst), vl_mff_map, |
2876 | 4.14k | &dst.field, tlv_bitmap); |
2877 | 4.14k | if (error) { |
2878 | 133 | return error; |
2879 | 133 | } |
2880 | | |
2881 | 4.01k | error = mf_check_dst(&dst, NULL); |
2882 | 4.01k | if (error) { |
2883 | 235 | return error; |
2884 | 235 | } |
2885 | | |
2886 | | /* Reject 'narl' if a bit numbered 'n_bits' or higher is set to 1 in |
2887 | | * narl->value. */ |
2888 | 3.77k | if (dst.n_bits < 64 && ntohll(narl->value) >> dst.n_bits) { |
2889 | 351 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
2890 | 351 | } |
2891 | | |
2892 | 3.42k | struct ofpact_set_field *sf = ofpact_put_reg_load(out, dst.field, NULL, |
2893 | 3.42k | NULL); |
2894 | 3.42k | bitwise_put(ntohll(narl->value), |
2895 | 3.42k | sf->value, dst.field->n_bytes, dst.ofs, |
2896 | 3.42k | dst.n_bits); |
2897 | 3.42k | bitwise_put(UINT64_MAX, |
2898 | 3.42k | ofpact_set_field_mask(sf), dst.field->n_bytes, dst.ofs, |
2899 | 3.42k | dst.n_bits); |
2900 | 3.42k | return 0; |
2901 | 3.77k | } |
2902 | | |
2903 | | static enum ofperr |
2904 | | decode_NXAST_RAW_REG_LOAD2(const struct ext_action_header *eah, |
2905 | | enum ofp_version ofp_version OVS_UNUSED, |
2906 | | const struct vl_mff_map *vl_mff_map, |
2907 | | uint64_t *tlv_bitmap, struct ofpbuf *out) |
2908 | 9.79k | { |
2909 | 9.79k | struct ofpbuf b = ofpbuf_const_initializer(eah, ntohs(eah->len)); |
2910 | 9.79k | ofpbuf_pull(&b, OBJECT_OFFSETOF(eah, pad)); |
2911 | | |
2912 | 9.79k | union mf_value value, mask; |
2913 | 9.79k | const struct mf_field *field; |
2914 | 9.79k | enum ofperr error; |
2915 | 9.79k | error = mf_vl_mff_nx_pull_entry(&b, vl_mff_map, &field, &value, &mask, |
2916 | 9.79k | tlv_bitmap); |
2917 | 9.79k | if (error) { |
2918 | 1.21k | return error; |
2919 | 1.21k | } |
2920 | | |
2921 | 8.58k | if (!is_all_zeros(b.data, b.size)) { |
2922 | 34 | return OFPERR_OFPBAC_BAD_SET_ARGUMENT; |
2923 | 34 | } |
2924 | | |
2925 | 8.54k | if (!field->writable) { |
2926 | 3 | VLOG_WARN_RL(&rl, "destination field %s is not writable", field->name); |
2927 | 3 | return OFPERR_OFPBAC_BAD_SET_ARGUMENT; |
2928 | 3 | } |
2929 | | |
2930 | | /* Put value and mask. */ |
2931 | 8.54k | ofpact_put_reg_load2(out, field, &value, &mask); |
2932 | 8.54k | return 0; |
2933 | 8.54k | } |
2934 | | |
2935 | | static void |
2936 | | put_set_field(struct ofpbuf *openflow, enum ofp_version ofp_version, |
2937 | | enum mf_field_id field, uint64_t value_) |
2938 | 0 | { |
2939 | 0 | struct ofp12_action_set_field *oasf OVS_UNUSED; |
2940 | 0 | int n_bytes = mf_from_id(field)->n_bytes; |
2941 | 0 | size_t start_ofs = openflow->size; |
2942 | 0 | union mf_value value; |
2943 | |
|
2944 | 0 | value.be64 = htonll(value_ << (8 * (8 - n_bytes))); |
2945 | |
|
2946 | 0 | oasf = put_OFPAT12_SET_FIELD(openflow); |
2947 | 0 | openflow->size = openflow->size - sizeof oasf->pad; |
2948 | 0 | nx_put_entry(openflow, mf_from_id(field), ofp_version, &value, NULL); |
2949 | 0 | pad_ofpat(openflow, start_ofs); |
2950 | 0 | } |
2951 | | |
2952 | | static void |
2953 | | put_reg_load(struct ofpbuf *openflow, |
2954 | | const struct mf_subfield *dst, uint64_t value) |
2955 | 0 | { |
2956 | 0 | ovs_assert(dst->n_bits <= 64); |
2957 | |
|
2958 | 0 | struct nx_action_reg_load *narl = put_NXAST_REG_LOAD(openflow); |
2959 | 0 | narl->ofs_nbits = nxm_encode_ofs_nbits(dst->ofs, dst->n_bits); |
2960 | 0 | narl->dst = htonl(nxm_header_from_mff(dst->field)); |
2961 | 0 | narl->value = htonll(value); |
2962 | 0 | } |
2963 | | |
2964 | | static bool |
2965 | | next_load_segment(const struct ofpact_set_field *sf, |
2966 | | struct mf_subfield *dst, uint64_t *value) |
2967 | 6.06k | { |
2968 | 6.06k | int n_bits = sf->field->n_bits; |
2969 | 6.06k | int n_bytes = sf->field->n_bytes; |
2970 | 6.06k | int start = dst->ofs + dst->n_bits; |
2971 | | |
2972 | 6.06k | if (start < n_bits) { |
2973 | 4.89k | dst->field = sf->field; |
2974 | 4.89k | dst->ofs = bitwise_scan(ofpact_set_field_mask(sf), n_bytes, 1, start, |
2975 | 4.89k | n_bits); |
2976 | 4.89k | if (dst->ofs < n_bits) { |
2977 | 3.03k | dst->n_bits = bitwise_scan(ofpact_set_field_mask(sf), n_bytes, 0, |
2978 | 3.03k | dst->ofs + 1, |
2979 | 3.03k | MIN(dst->ofs + 64, n_bits)) - dst->ofs; |
2980 | 3.03k | *value = bitwise_get(sf->value, n_bytes, dst->ofs, dst->n_bits); |
2981 | 3.03k | return true; |
2982 | 3.03k | } |
2983 | 4.89k | } |
2984 | 3.03k | return false; |
2985 | 6.06k | } |
2986 | | |
2987 | | /* Convert 'sf' to a series of REG_LOADs. */ |
2988 | | static void |
2989 | | set_field_to_nxast(const struct ofpact_set_field *sf, struct ofpbuf *openflow) |
2990 | 0 | { |
2991 | | /* If 'sf' cannot be encoded as NXAST_REG_LOAD because it requires an |
2992 | | * experimenter OXM or is variable length (or if it came in as |
2993 | | * NXAST_REG_LOAD2), encode as NXAST_REG_LOAD2. Otherwise use |
2994 | | * NXAST_REG_LOAD, which is backward compatible. */ |
2995 | 0 | if (sf->ofpact.raw == NXAST_RAW_REG_LOAD2 |
2996 | 0 | || !mf_nxm_header(sf->field->id) || sf->field->variable_len) { |
2997 | 0 | struct ext_action_header *eah OVS_UNUSED; |
2998 | 0 | size_t start_ofs = openflow->size; |
2999 | |
|
3000 | 0 | eah = put_NXAST_REG_LOAD2(openflow); |
3001 | 0 | openflow->size = openflow->size - sizeof eah->pad; |
3002 | 0 | nx_put_entry(openflow, sf->field, 0, sf->value, |
3003 | 0 | ofpact_set_field_mask(sf)); |
3004 | 0 | pad_ofpat(openflow, start_ofs); |
3005 | 0 | } else { |
3006 | 0 | struct mf_subfield dst; |
3007 | 0 | uint64_t value; |
3008 | |
|
3009 | 0 | dst.ofs = dst.n_bits = 0; |
3010 | 0 | while (next_load_segment(sf, &dst, &value)) { |
3011 | 0 | put_reg_load(openflow, &dst, value); |
3012 | 0 | } |
3013 | 0 | } |
3014 | 0 | } |
3015 | | |
3016 | | /* Convert 'sf', which must set an entire field, to standard OpenFlow 1.0/1.1 |
3017 | | * actions, if we can, falling back to Nicira extensions if we must. |
3018 | | * |
3019 | | * We check only meta-flow types that can appear within set field actions and |
3020 | | * that have a mapping to compatible action types. These struct mf_field |
3021 | | * definitions have a defined OXM or NXM header value and specify the field as |
3022 | | * writable. */ |
3023 | | static void |
3024 | | set_field_to_legacy_openflow(const struct ofpact_set_field *sf, |
3025 | | enum ofp_version ofp_version, |
3026 | | struct ofpbuf *out) |
3027 | 0 | { |
3028 | 0 | switch ((int) sf->field->id) { |
3029 | 0 | case MFF_VLAN_TCI: { |
3030 | 0 | ovs_be16 tci = sf->value->be16; |
3031 | 0 | bool cfi = (tci & htons(VLAN_CFI)) != 0; |
3032 | 0 | uint16_t vid = vlan_tci_to_vid(tci); |
3033 | 0 | uint8_t pcp = vlan_tci_to_pcp(tci); |
3034 | |
|
3035 | 0 | if (ofp_version < OFP11_VERSION) { |
3036 | | /* NXM_OF_VLAN_TCI to OpenFlow 1.0 mapping: |
3037 | | * |
3038 | | * If CFI=1, Add or modify VLAN VID & PCP. |
3039 | | * If CFI=0, strip VLAN header, if any. |
3040 | | */ |
3041 | 0 | if (cfi) { |
3042 | 0 | put_OFPAT10_SET_VLAN_VID(out, vid); |
3043 | 0 | put_OFPAT10_SET_VLAN_PCP(out, pcp); |
3044 | 0 | } else { |
3045 | 0 | put_OFPAT10_STRIP_VLAN(out); |
3046 | 0 | } |
3047 | 0 | } else { |
3048 | | /* NXM_OF_VLAN_TCI to OpenFlow 1.1 mapping: |
3049 | | * |
3050 | | * If CFI=1, Add or modify VLAN VID & PCP. |
3051 | | * OpenFlow 1.1 set actions only apply if the packet |
3052 | | * already has VLAN tags. To be sure that is the case |
3053 | | * we have to push a VLAN header. As we do not support |
3054 | | * multiple layers of VLANs, this is a no-op, if a VLAN |
3055 | | * header already exists. This may backfire, however, |
3056 | | * when we start supporting multiple layers of VLANs. |
3057 | | * If CFI=0, strip VLAN header, if any. |
3058 | | */ |
3059 | 0 | if (cfi) { |
3060 | | /* Push a VLAN tag, if one was not seen at action validation |
3061 | | * time. */ |
3062 | 0 | if (!sf->flow_has_vlan) { |
3063 | 0 | put_OFPAT11_PUSH_VLAN(out, htons(ETH_TYPE_VLAN_8021Q)); |
3064 | 0 | } |
3065 | 0 | put_OFPAT11_SET_VLAN_VID(out, vid); |
3066 | 0 | put_OFPAT11_SET_VLAN_PCP(out, pcp); |
3067 | 0 | } else { |
3068 | | /* If the flow did not match on vlan, we have no way of |
3069 | | * knowing if the vlan tag exists, so we must POP just to be |
3070 | | * sure. */ |
3071 | 0 | put_OFPAT11_POP_VLAN(out); |
3072 | 0 | } |
3073 | 0 | } |
3074 | 0 | break; |
3075 | 0 | } |
3076 | | |
3077 | 0 | case MFF_VLAN_VID: { |
3078 | 0 | uint16_t vid = ntohs(sf->value->be16) & VLAN_VID_MASK; |
3079 | 0 | if (ofp_version == OFP10_VERSION) { |
3080 | 0 | put_OFPAT10_SET_VLAN_VID(out, vid); |
3081 | 0 | } else { |
3082 | 0 | put_OFPAT11_SET_VLAN_VID(out, vid); |
3083 | 0 | } |
3084 | 0 | break; |
3085 | 0 | } |
3086 | | |
3087 | 0 | case MFF_VLAN_PCP: |
3088 | 0 | if (ofp_version == OFP10_VERSION) { |
3089 | 0 | put_OFPAT10_SET_VLAN_PCP(out, sf->value->u8); |
3090 | 0 | } else { |
3091 | 0 | put_OFPAT11_SET_VLAN_PCP(out, sf->value->u8); |
3092 | 0 | } |
3093 | 0 | break; |
3094 | | |
3095 | 0 | case MFF_ETH_SRC: |
3096 | 0 | put_OFPAT_SET_DL_SRC(out, ofp_version)->dl_addr = sf->value->mac; |
3097 | 0 | break; |
3098 | | |
3099 | 0 | case MFF_ETH_DST: |
3100 | 0 | put_OFPAT_SET_DL_DST(out, ofp_version)->dl_addr = sf->value->mac; |
3101 | 0 | break; |
3102 | | |
3103 | 0 | case MFF_IPV4_SRC: |
3104 | 0 | put_OFPAT_SET_NW_SRC(out, ofp_version, sf->value->be32); |
3105 | 0 | break; |
3106 | | |
3107 | 0 | case MFF_IPV4_DST: |
3108 | 0 | put_OFPAT_SET_NW_DST(out, ofp_version, sf->value->be32); |
3109 | 0 | break; |
3110 | | |
3111 | 0 | case MFF_IP_DSCP: |
3112 | 0 | put_OFPAT_SET_NW_TOS(out, ofp_version, sf->value->u8); |
3113 | 0 | break; |
3114 | | |
3115 | 0 | case MFF_IP_DSCP_SHIFTED: |
3116 | 0 | put_OFPAT_SET_NW_TOS(out, ofp_version, sf->value->u8 << 2); |
3117 | 0 | break; |
3118 | | |
3119 | 0 | case MFF_IP_ECN: { |
3120 | 0 | struct ofpact_ecn ip_ecn = { .ecn = sf->value->u8 }; |
3121 | 0 | encode_SET_IP_ECN(&ip_ecn, ofp_version, out); |
3122 | 0 | break; |
3123 | 0 | } |
3124 | | |
3125 | 0 | case MFF_TCP_SRC: |
3126 | 0 | case MFF_UDP_SRC: |
3127 | 0 | put_OFPAT_SET_TP_SRC(out, sf->value->be16); |
3128 | 0 | break; |
3129 | | |
3130 | 0 | case MFF_TCP_DST: |
3131 | 0 | case MFF_UDP_DST: |
3132 | 0 | put_OFPAT_SET_TP_DST(out, sf->value->be16); |
3133 | 0 | break; |
3134 | | |
3135 | 0 | default: |
3136 | 0 | set_field_to_nxast(sf, out); |
3137 | 0 | break; |
3138 | 0 | } |
3139 | 0 | } |
3140 | | |
3141 | | static void |
3142 | | set_field_to_set_field(const struct ofpact_set_field *sf, |
3143 | | enum ofp_version ofp_version, struct ofpbuf *out) |
3144 | 0 | { |
3145 | 0 | struct ofp12_action_set_field *oasf OVS_UNUSED; |
3146 | 0 | size_t start_ofs = out->size; |
3147 | |
|
3148 | 0 | oasf = put_OFPAT12_SET_FIELD(out); |
3149 | 0 | out->size = out->size - sizeof oasf->pad; |
3150 | 0 | nx_put_entry(out, sf->field, ofp_version, sf->value, |
3151 | 0 | ofpact_set_field_mask(sf)); |
3152 | 0 | pad_ofpat(out, start_ofs); |
3153 | 0 | } |
3154 | | |
3155 | | static void |
3156 | | encode_SET_FIELD(const struct ofpact_set_field *sf, |
3157 | | enum ofp_version ofp_version, struct ofpbuf *out) |
3158 | 0 | { |
3159 | 0 | if (ofp_version >= OFP15_VERSION) { |
3160 | | /* OF1.5+ only has Set-Field (reg_load is redundant so we drop it |
3161 | | * entirely). */ |
3162 | 0 | set_field_to_set_field(sf, ofp_version, out); |
3163 | 0 | } else if (sf->ofpact.raw == NXAST_RAW_REG_LOAD || |
3164 | 0 | sf->ofpact.raw == NXAST_RAW_REG_LOAD2) { |
3165 | | /* It came in as reg_load, send it out the same way. */ |
3166 | 0 | set_field_to_nxast(sf, out); |
3167 | 0 | } else if (ofp_version < OFP12_VERSION) { |
3168 | | /* OpenFlow 1.0 and 1.1 don't have Set-Field. */ |
3169 | 0 | set_field_to_legacy_openflow(sf, ofp_version, out); |
3170 | 0 | } else if (is_all_ones(ofpact_set_field_mask(sf), sf->field->n_bytes)) { |
3171 | | /* We're encoding to OpenFlow 1.2, 1.3, or 1.4. The action sets an |
3172 | | * entire field, so encode it as OFPAT_SET_FIELD. */ |
3173 | 0 | set_field_to_set_field(sf, ofp_version, out); |
3174 | 0 | } else { |
3175 | | /* We're encoding to OpenFlow 1.2, 1.3, or 1.4. The action cannot be |
3176 | | * encoded as OFPAT_SET_FIELD because it does not set an entire field, |
3177 | | * so encode it as reg_load. */ |
3178 | 0 | set_field_to_nxast(sf, out); |
3179 | 0 | } |
3180 | 0 | } |
3181 | | |
3182 | | /* Parses the input argument 'arg' into the key, value, and delimiter |
3183 | | * components that are common across the reg_load and set_field action format. |
3184 | | * |
3185 | | * With an argument like "1->metadata", sets the following pointers to |
3186 | | * point within 'arg': |
3187 | | * key: "metadata" |
3188 | | * value: "1" |
3189 | | * delim: "->" |
3190 | | * |
3191 | | * Returns NULL if successful, otherwise a malloc()'d string describing the |
3192 | | * error. The caller is responsible for freeing the returned string. */ |
3193 | | static char * OVS_WARN_UNUSED_RESULT |
3194 | | set_field_split_str(char *arg, char **key, char **value, char **delim) |
3195 | 0 | { |
3196 | 0 | char *value_end; |
3197 | |
|
3198 | 0 | *key = NULL; |
3199 | 0 | *value = arg; |
3200 | 0 | if (delim) { |
3201 | 0 | *delim = NULL; |
3202 | 0 | } |
3203 | |
|
3204 | 0 | value_end = strstr(arg, "->"); |
3205 | 0 | if (!value_end) { |
3206 | 0 | return xasprintf("%s: missing `->'", arg); |
3207 | 0 | } |
3208 | | |
3209 | 0 | *key = value_end + strlen("->"); |
3210 | 0 | if (delim) { |
3211 | 0 | *delim = value_end; |
3212 | 0 | } |
3213 | 0 | if (strlen(value_end) <= strlen("->")) { |
3214 | 0 | return xasprintf("%s: missing field name following `->'", arg); |
3215 | 0 | } |
3216 | | |
3217 | 0 | return NULL; |
3218 | 0 | } |
3219 | | |
3220 | | /* Parses a "set_field" action with argument 'arg', appending the parsed |
3221 | | * action to 'pp->ofpacts'. |
3222 | | * |
3223 | | * Returns NULL if successful, otherwise a malloc()'d string describing the |
3224 | | * error. The caller is responsible for freeing the returned string. */ |
3225 | | static char * OVS_WARN_UNUSED_RESULT |
3226 | | set_field_parse__(char *arg, const struct ofpact_parse_params *pp) |
3227 | 0 | { |
3228 | 0 | char *value; |
3229 | 0 | char *delim; |
3230 | 0 | char *key; |
3231 | 0 | const struct mf_field *mf; |
3232 | 0 | union mf_value sf_value, sf_mask; |
3233 | 0 | char *error; |
3234 | |
|
3235 | 0 | error = set_field_split_str(arg, &key, &value, &delim); |
3236 | 0 | if (error) { |
3237 | 0 | return error; |
3238 | 0 | } |
3239 | | |
3240 | 0 | mf = mf_from_name(key); |
3241 | 0 | if (!mf) { |
3242 | 0 | return xasprintf("%s is not a valid OXM field name", key); |
3243 | 0 | } |
3244 | 0 | if (!mf->writable) { |
3245 | 0 | return xasprintf("%s is read-only", key); |
3246 | 0 | } |
3247 | | |
3248 | 0 | delim[0] = '\0'; |
3249 | 0 | error = mf_parse(mf, value, pp->port_map, &sf_value, &sf_mask); |
3250 | 0 | if (error) { |
3251 | 0 | return error; |
3252 | 0 | } |
3253 | | |
3254 | 0 | if (!mf_is_value_valid(mf, &sf_value)) { |
3255 | 0 | return xasprintf("%s is not a valid value for field %s", value, key); |
3256 | 0 | } |
3257 | | |
3258 | 0 | *pp->usable_protocols &= mf->usable_protocols_exact; |
3259 | |
|
3260 | 0 | ofpact_put_set_field(pp->ofpacts, mf, &sf_value, &sf_mask); |
3261 | 0 | return NULL; |
3262 | 0 | } |
3263 | | |
3264 | | /* Parses 'arg' as the argument to a "set_field" action, and appends such an |
3265 | | * action to 'pp->ofpacts'. |
3266 | | * |
3267 | | * Returns NULL if successful, otherwise a malloc()'d string describing the |
3268 | | * error. The caller is responsible for freeing the returned string. */ |
3269 | | static char * OVS_WARN_UNUSED_RESULT |
3270 | | parse_SET_FIELD(const char *arg, const struct ofpact_parse_params *pp) |
3271 | 0 | { |
3272 | 0 | char *copy = xstrdup(arg); |
3273 | 0 | char *error = set_field_parse__(copy, pp); |
3274 | 0 | free(copy); |
3275 | 0 | return error; |
3276 | 0 | } |
3277 | | |
3278 | | static char * OVS_WARN_UNUSED_RESULT |
3279 | | parse_reg_load(char *arg, const struct ofpact_parse_params *pp) |
3280 | 0 | { |
3281 | 0 | struct mf_subfield dst; |
3282 | 0 | char *key, *value_str; |
3283 | 0 | union mf_value value; |
3284 | 0 | char *error; |
3285 | |
|
3286 | 0 | error = set_field_split_str(arg, &key, &value_str, NULL); |
3287 | 0 | if (error) { |
3288 | 0 | return error; |
3289 | 0 | } |
3290 | | |
3291 | 0 | error = mf_parse_subfield(&dst, key); |
3292 | 0 | if (error) { |
3293 | 0 | return error; |
3294 | 0 | } |
3295 | | |
3296 | 0 | if (parse_int_string(value_str, (uint8_t *)&value, dst.field->n_bytes, |
3297 | 0 | &key)) { |
3298 | 0 | return xasprintf("%s: cannot parse integer value", arg); |
3299 | 0 | } |
3300 | | |
3301 | 0 | if (!bitwise_is_all_zeros(&value, dst.field->n_bytes, dst.n_bits, |
3302 | 0 | dst.field->n_bytes * 8 - dst.n_bits)) { |
3303 | 0 | struct ds ds; |
3304 | |
|
3305 | 0 | ds_init(&ds); |
3306 | 0 | mf_format(dst.field, &value, NULL, NULL, &ds); |
3307 | 0 | error = xasprintf("%s: value %s does not fit into %d bits", |
3308 | 0 | arg, ds_cstr(&ds), dst.n_bits); |
3309 | 0 | ds_destroy(&ds); |
3310 | 0 | return error; |
3311 | 0 | } |
3312 | | |
3313 | 0 | struct ofpact_set_field *sf = ofpact_put_reg_load(pp->ofpacts, dst.field, |
3314 | 0 | NULL, NULL); |
3315 | |
|
3316 | 0 | bitwise_copy(&value, dst.field->n_bytes, 0, sf->value, |
3317 | 0 | dst.field->n_bytes, dst.ofs, dst.n_bits); |
3318 | 0 | bitwise_one(ofpact_set_field_mask(sf), dst.field->n_bytes, dst.ofs, |
3319 | 0 | dst.n_bits); |
3320 | 0 | return NULL; |
3321 | 0 | } |
3322 | | |
3323 | | static void |
3324 | | format_SET_FIELD(const struct ofpact_set_field *a, |
3325 | | const struct ofpact_format_params *fp) |
3326 | 11.4k | { |
3327 | 11.4k | if (a->ofpact.raw == NXAST_RAW_REG_LOAD) { |
3328 | 3.03k | struct mf_subfield dst; |
3329 | 3.03k | uint64_t value; |
3330 | | |
3331 | 3.03k | dst.ofs = dst.n_bits = 0; |
3332 | 6.06k | while (next_load_segment(a, &dst, &value)) { |
3333 | 3.03k | ds_put_format(fp->s, "%sload:%s%#"PRIx64"%s->%s", |
3334 | 3.03k | colors.special, colors.end, value, |
3335 | 3.03k | colors.special, colors.end); |
3336 | 3.03k | mf_format_subfield(&dst, fp->s); |
3337 | 3.03k | ds_put_char(fp->s, ','); |
3338 | 3.03k | } |
3339 | 3.03k | ds_chomp(fp->s, ','); |
3340 | 8.40k | } else { |
3341 | 8.40k | ds_put_format(fp->s, "%sset_field:%s", colors.special, colors.end); |
3342 | 8.40k | mf_format(a->field, a->value, ofpact_set_field_mask(a), |
3343 | 8.40k | fp->port_map, fp->s); |
3344 | 8.40k | ds_put_format(fp->s, "%s->%s%s", |
3345 | 8.40k | colors.special, colors.end, a->field->name); |
3346 | 8.40k | } |
3347 | 11.4k | } |
3348 | | |
3349 | | static enum ofperr |
3350 | | check_SET_FIELD(struct ofpact_set_field *a, |
3351 | | const struct ofpact_check_params *cp) |
3352 | 8.24k | { |
3353 | 8.24k | const struct mf_field *mf = a->field; |
3354 | 8.24k | struct flow *flow = &cp->match->flow; |
3355 | 8.24k | ovs_be16 *tci = &flow->vlans[0].tci; |
3356 | | |
3357 | | /* Require OXM_OF_VLAN_VID to have an existing VLAN header. */ |
3358 | 8.24k | if (!mf_are_prereqs_ok(mf, flow, NULL) |
3359 | 8.24k | || (mf->id == MFF_VLAN_VID && !(*tci & htons(VLAN_CFI)))) { |
3360 | 918 | VLOG_WARN_RL(&rl, "set_field %s lacks correct prerequisites", |
3361 | 918 | mf->name); |
3362 | 918 | return OFPERR_OFPBAC_MATCH_INCONSISTENT; |
3363 | 918 | } |
3364 | | |
3365 | | /* Remember if we saw a VLAN tag in the flow, to aid translating to |
3366 | | * OpenFlow 1.1 if need be. */ |
3367 | 7.32k | a->flow_has_vlan = (*tci & htons(VLAN_CFI)) != 0; |
3368 | 7.32k | if (mf->id == MFF_VLAN_TCI) { |
3369 | | /* The set field may add or remove the VLAN tag, |
3370 | | * Mark the status temporarily. */ |
3371 | 6 | *tci = a->value->be16; |
3372 | 6 | } |
3373 | | |
3374 | 7.32k | return 0; |
3375 | 8.24k | } |
3376 | | |
3377 | | /* Appends an OFPACT_SET_FIELD ofpact with enough space for the value and a |
3378 | | * properly aligned mask for the 'field' to 'ofpacts' and returns it. Fills |
3379 | | * in the value from 'value', if non-NULL, and mask from 'mask' if non-NULL. |
3380 | | * If 'value' is non-NULL and 'mask' is NULL, an all-ones mask will be |
3381 | | * filled in. */ |
3382 | | struct ofpact_set_field * |
3383 | | ofpact_put_set_field(struct ofpbuf *ofpacts, const struct mf_field *field, |
3384 | | const void *value, const void *mask) |
3385 | 20.3k | { |
3386 | | /* Ensure there's enough space for: |
3387 | | * - value (8-byte aligned) |
3388 | | * - mask (8-byte aligned) |
3389 | | * - padding (to make the whole ofpact_set_field 8-byte aligned) |
3390 | | */ |
3391 | 20.3k | size_t total_size = 2 * ROUND_UP(field->n_bytes, OFPACT_ALIGNTO); |
3392 | 20.3k | struct ofpact_set_field *sf = ofpact_put_SET_FIELD(ofpacts); |
3393 | 20.3k | sf->field = field; |
3394 | | |
3395 | | /* Fill with all zeroes to make sure the padding is initialized. */ |
3396 | 20.3k | ofpbuf_put_zeros(ofpacts, total_size); |
3397 | 20.3k | sf = ofpacts->header; |
3398 | | |
3399 | | /* Fill in the value and mask if given, otherwise keep the zeroes |
3400 | | * so that the caller may fill in the value and mask itself. */ |
3401 | 20.3k | if (value) { |
3402 | 16.9k | memcpy(sf->value, value, field->n_bytes); |
3403 | 16.9k | if (mask) { |
3404 | 16.9k | memcpy(ofpact_set_field_mask(sf), mask, field->n_bytes); |
3405 | 16.9k | } else { |
3406 | 0 | memset(ofpact_set_field_mask(sf), 0xff, field->n_bytes); |
3407 | 0 | } |
3408 | 16.9k | } |
3409 | | |
3410 | | /* Update length. */ |
3411 | 20.3k | ofpact_finish_SET_FIELD(ofpacts, &sf); |
3412 | | |
3413 | 20.3k | return sf; |
3414 | 20.3k | } |
3415 | | |
3416 | | /* Appends an OFPACT_SET_FIELD ofpact to 'ofpacts' and returns it. The ofpact |
3417 | | * is marked such that, if possible, it will be translated to OpenFlow as |
3418 | | * NXAST_REG_LOAD extension actions rather than OFPAT_SET_FIELD, either because |
3419 | | * that was the way that the action was expressed when it came into OVS or for |
3420 | | * backward compatibility. */ |
3421 | | struct ofpact_set_field * |
3422 | | ofpact_put_reg_load(struct ofpbuf *ofpacts, const struct mf_field *field, |
3423 | | const void *value, const void *mask) |
3424 | 3.42k | { |
3425 | 3.42k | struct ofpact_set_field *sf = ofpact_put_set_field(ofpacts, field, value, |
3426 | 3.42k | mask); |
3427 | 3.42k | sf->ofpact.raw = NXAST_RAW_REG_LOAD; |
3428 | | |
3429 | 3.42k | return sf; |
3430 | 3.42k | } |
3431 | | |
3432 | | struct ofpact_set_field * |
3433 | | ofpact_put_reg_load2(struct ofpbuf *ofpacts, const struct mf_field *field, |
3434 | | const void *value, const void *mask) |
3435 | 8.54k | { |
3436 | 8.54k | struct ofpact_set_field *sf = ofpact_put_set_field(ofpacts, field, value, |
3437 | 8.54k | mask); |
3438 | 8.54k | sf->ofpact.raw = NXAST_RAW_REG_LOAD2; |
3439 | | |
3440 | 8.54k | return sf; |
3441 | 8.54k | } |
3442 | | |
3443 | | |
3444 | | /* Action structure for NXAST_STACK_PUSH and NXAST_STACK_POP. |
3445 | | * |
3446 | | * Pushes (or pops) field[offset: offset + n_bits] to (or from) |
3447 | | * top of the stack. |
3448 | | */ |
3449 | | struct nx_action_stack { |
3450 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
3451 | | ovs_be16 len; /* Length is 16. */ |
3452 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
3453 | | ovs_be16 subtype; /* NXAST_STACK_PUSH or NXAST_STACK_POP. */ |
3454 | | ovs_be16 offset; /* Bit offset into the field. */ |
3455 | | /* Followed by: |
3456 | | * - OXM/NXM header for field to push or pop (4 or 8 bytes). |
3457 | | * - ovs_be16 'n_bits', the number of bits to extract from the field. |
3458 | | * - Enough 0-bytes to pad out the action to 24 bytes. */ |
3459 | | uint8_t pad[12]; /* See above. */ |
3460 | | }; |
3461 | | OFP_ASSERT(sizeof(struct nx_action_stack) == 24); |
3462 | | |
3463 | | static enum ofperr |
3464 | | decode_stack_action(const struct nx_action_stack *nasp, |
3465 | | const struct vl_mff_map *vl_mff_map, uint64_t *tlv_bitmap, |
3466 | | struct ofpact_stack *stack_action) |
3467 | 3.92k | { |
3468 | 3.92k | enum ofperr error; |
3469 | 3.92k | stack_action->subfield.ofs = ntohs(nasp->offset); |
3470 | | |
3471 | 3.92k | struct ofpbuf b = ofpbuf_const_initializer(nasp, sizeof *nasp); |
3472 | 3.92k | ofpbuf_pull(&b, OBJECT_OFFSETOF(nasp, pad)); |
3473 | 3.92k | error = mf_vl_mff_nx_pull_header(&b, vl_mff_map, |
3474 | 3.92k | &stack_action->subfield.field, NULL, |
3475 | 3.92k | tlv_bitmap); |
3476 | 3.92k | if (error) { |
3477 | 772 | return error; |
3478 | 772 | } |
3479 | | |
3480 | 3.15k | stack_action->subfield.n_bits = ntohs(*(const ovs_be16 *) b.data); |
3481 | 3.15k | ofpbuf_pull(&b, 2); |
3482 | 3.15k | if (!is_all_zeros(b.data, b.size)) { |
3483 | 575 | return OFPERR_NXBRC_MUST_BE_ZERO; |
3484 | 575 | } |
3485 | | |
3486 | 2.57k | return 0; |
3487 | 3.15k | } |
3488 | | |
3489 | | static enum ofperr |
3490 | | decode_NXAST_RAW_STACK_PUSH(const struct nx_action_stack *nasp, |
3491 | | enum ofp_version ofp_version OVS_UNUSED, |
3492 | | const struct vl_mff_map *vl_mff_map, |
3493 | | uint64_t *tlv_bitmap, struct ofpbuf *ofpacts) |
3494 | 1.14k | { |
3495 | 1.14k | struct ofpact_stack *push = ofpact_put_STACK_PUSH(ofpacts); |
3496 | 1.14k | enum ofperr error = decode_stack_action(nasp, vl_mff_map, tlv_bitmap, |
3497 | 1.14k | push); |
3498 | 1.14k | return error ? error : nxm_stack_push_check(push, NULL); |
3499 | 1.14k | } |
3500 | | |
3501 | | static enum ofperr |
3502 | | decode_NXAST_RAW_STACK_POP(const struct nx_action_stack *nasp, |
3503 | | enum ofp_version ofp_version OVS_UNUSED, |
3504 | | const struct vl_mff_map *vl_mff_map, |
3505 | | uint64_t *tlv_bitmap, struct ofpbuf *ofpacts) |
3506 | 2.77k | { |
3507 | 2.77k | struct ofpact_stack *pop = ofpact_put_STACK_POP(ofpacts); |
3508 | 2.77k | enum ofperr error = decode_stack_action(nasp, vl_mff_map, tlv_bitmap, |
3509 | 2.77k | pop); |
3510 | 2.77k | return error ? error : nxm_stack_pop_check(pop, NULL); |
3511 | 2.77k | } |
3512 | | |
3513 | | static void |
3514 | | encode_STACK_op(const struct ofpact_stack *stack_action, |
3515 | | struct nx_action_stack *nasp) |
3516 | 0 | { |
3517 | 0 | struct ofpbuf b; |
3518 | 0 | ovs_be16 n_bits; |
3519 | |
|
3520 | 0 | nasp->offset = htons(stack_action->subfield.ofs); |
3521 | |
|
3522 | 0 | ofpbuf_use_stack(&b, nasp, ntohs(nasp->len)); |
3523 | 0 | ofpbuf_put_uninit(&b, OBJECT_OFFSETOF(nasp, pad)); |
3524 | 0 | nx_put_mff_header(&b, stack_action->subfield.field, 0, false); |
3525 | 0 | n_bits = htons(stack_action->subfield.n_bits); |
3526 | 0 | ofpbuf_put(&b, &n_bits, sizeof n_bits); |
3527 | 0 | } |
3528 | | |
3529 | | static void |
3530 | | encode_STACK_PUSH(const struct ofpact_stack *stack, |
3531 | | enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out) |
3532 | 0 | { |
3533 | 0 | encode_STACK_op(stack, put_NXAST_STACK_PUSH(out)); |
3534 | 0 | } |
3535 | | |
3536 | | static void |
3537 | | encode_STACK_POP(const struct ofpact_stack *stack, |
3538 | | enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out) |
3539 | 0 | { |
3540 | 0 | encode_STACK_op(stack, put_NXAST_STACK_POP(out)); |
3541 | 0 | } |
3542 | | |
3543 | | static char * OVS_WARN_UNUSED_RESULT |
3544 | | parse_STACK_PUSH(char *arg, const struct ofpact_parse_params *pp) |
3545 | 0 | { |
3546 | 0 | return nxm_parse_stack_action(ofpact_put_STACK_PUSH(pp->ofpacts), arg); |
3547 | 0 | } |
3548 | | |
3549 | | static char * OVS_WARN_UNUSED_RESULT |
3550 | | parse_STACK_POP(char *arg, const struct ofpact_parse_params *pp) |
3551 | 0 | { |
3552 | 0 | return nxm_parse_stack_action(ofpact_put_STACK_POP(pp->ofpacts), arg); |
3553 | 0 | } |
3554 | | |
3555 | | static void |
3556 | | format_STACK_PUSH(const struct ofpact_stack *a, |
3557 | | const struct ofpact_format_params *fp) |
3558 | 1 | { |
3559 | 1 | nxm_format_stack_push(a, fp->s); |
3560 | 1 | } |
3561 | | |
3562 | | static void |
3563 | | format_STACK_POP(const struct ofpact_stack *a, |
3564 | | const struct ofpact_format_params *fp) |
3565 | 753 | { |
3566 | 753 | nxm_format_stack_pop(a, fp->s); |
3567 | 753 | } |
3568 | | |
3569 | | static enum ofperr |
3570 | | check_STACK_PUSH(const struct ofpact_stack *a, |
3571 | | const struct ofpact_check_params *cp) |
3572 | 5 | { |
3573 | 5 | return nxm_stack_push_check(a, cp->match); |
3574 | 5 | } |
3575 | | |
3576 | | static enum ofperr |
3577 | | check_STACK_POP(const struct ofpact_stack *a, |
3578 | | const struct ofpact_check_params *cp) |
3579 | 898 | { |
3580 | 898 | return nxm_stack_pop_check(a, cp->match); |
3581 | 898 | } |
3582 | | |
3583 | | /* Action structure for NXAST_DEC_TTL_CNT_IDS. |
3584 | | * |
3585 | | * If the packet is not IPv4 or IPv6, does nothing. For IPv4 or IPv6, if the |
3586 | | * TTL or hop limit is at least 2, decrements it by 1. Otherwise, if TTL or |
3587 | | * hop limit is 0 or 1, sends a packet-in to the controllers with each of the |
3588 | | * 'n_controllers' controller IDs specified in 'cnt_ids'. |
3589 | | * |
3590 | | * (This differs from NXAST_DEC_TTL in that for NXAST_DEC_TTL the packet-in is |
3591 | | * sent only to controllers with id 0.) |
3592 | | */ |
3593 | | struct nx_action_cnt_ids { |
3594 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
3595 | | ovs_be16 len; /* Length including cnt_ids. */ |
3596 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
3597 | | ovs_be16 subtype; /* NXAST_DEC_TTL_CNT_IDS. */ |
3598 | | |
3599 | | ovs_be16 n_controllers; /* Number of controllers. */ |
3600 | | uint8_t zeros[4]; /* Must be zero. */ |
3601 | | |
3602 | | /* Followed by 1 or more controller ids: |
3603 | | * |
3604 | | * uint16_t cnt_ids[]; -- Controller ids. |
3605 | | * uint8_t pad[]; -- Must be 0 to 8-byte align cnt_ids[]. |
3606 | | */ |
3607 | | }; |
3608 | | OFP_ASSERT(sizeof(struct nx_action_cnt_ids) == 16); |
3609 | | |
3610 | | static enum ofperr |
3611 | | decode_OFPAT_RAW_DEC_NW_TTL(struct ofpbuf *out) |
3612 | 11.0k | { |
3613 | 11.0k | uint16_t id = 0; |
3614 | 11.0k | struct ofpact_cnt_ids *ids; |
3615 | 11.0k | enum ofperr error = 0; |
3616 | | |
3617 | 11.0k | ids = ofpact_put_DEC_TTL(out); |
3618 | 11.0k | ids->n_controllers = 1; |
3619 | 11.0k | ofpbuf_put(out, &id, sizeof id); |
3620 | 11.0k | ids = out->header; |
3621 | 11.0k | ofpact_finish_DEC_TTL(out, &ids); |
3622 | 11.0k | return error; |
3623 | 11.0k | } |
3624 | | |
3625 | | static enum ofperr |
3626 | | decode_NXAST_RAW_DEC_TTL_CNT_IDS(const struct nx_action_cnt_ids *nac_ids, |
3627 | | enum ofp_version ofp_version OVS_UNUSED, |
3628 | | struct ofpbuf *out) |
3629 | 11.8k | { |
3630 | 11.8k | struct ofpact_cnt_ids *ids; |
3631 | 11.8k | size_t ids_size; |
3632 | 11.8k | int i; |
3633 | | |
3634 | 11.8k | ids = ofpact_put_DEC_TTL(out); |
3635 | 11.8k | ids->ofpact.raw = NXAST_RAW_DEC_TTL_CNT_IDS; |
3636 | 11.8k | ids->n_controllers = ntohs(nac_ids->n_controllers); |
3637 | 11.8k | ids_size = ntohs(nac_ids->len) - sizeof *nac_ids; |
3638 | | |
3639 | 11.8k | if (!is_all_zeros(nac_ids->zeros, sizeof nac_ids->zeros)) { |
3640 | 1.36k | return OFPERR_NXBRC_MUST_BE_ZERO; |
3641 | 1.36k | } |
3642 | | |
3643 | 10.4k | if (ids_size < ids->n_controllers * sizeof(ovs_be16)) { |
3644 | 698 | VLOG_WARN_RL(&rl, "Nicira action dec_ttl_cnt_ids only has %"PRIuSIZE" " |
3645 | 698 | "bytes allocated for controller ids. %"PRIuSIZE" bytes " |
3646 | 698 | "are required for %u controllers.", |
3647 | 698 | ids_size, ids->n_controllers * sizeof(ovs_be16), |
3648 | 698 | ids->n_controllers); |
3649 | 698 | return OFPERR_OFPBAC_BAD_LEN; |
3650 | 698 | } |
3651 | | |
3652 | 33.6k | for (i = 0; i < ids->n_controllers; i++) { |
3653 | 23.8k | uint16_t id = ntohs(((ovs_be16 *)(nac_ids + 1))[i]); |
3654 | 23.8k | ofpbuf_put(out, &id, sizeof id); |
3655 | 23.8k | ids = out->header; |
3656 | 23.8k | } |
3657 | | |
3658 | 9.78k | ofpact_finish_DEC_TTL(out, &ids); |
3659 | | |
3660 | 9.78k | return 0; |
3661 | 10.4k | } |
3662 | | |
3663 | | static void |
3664 | | encode_DEC_TTL(const struct ofpact_cnt_ids *dec_ttl, |
3665 | | enum ofp_version ofp_version, struct ofpbuf *out) |
3666 | 0 | { |
3667 | 0 | if (dec_ttl->ofpact.raw == NXAST_RAW_DEC_TTL_CNT_IDS |
3668 | 0 | || dec_ttl->n_controllers != 1 |
3669 | 0 | || dec_ttl->cnt_ids[0] != 0) { |
3670 | 0 | struct nx_action_cnt_ids *nac_ids = put_NXAST_DEC_TTL_CNT_IDS(out); |
3671 | 0 | int ids_len = ROUND_UP(2 * dec_ttl->n_controllers, OFP_ACTION_ALIGN); |
3672 | 0 | ovs_be16 *ids; |
3673 | 0 | size_t i; |
3674 | |
|
3675 | 0 | nac_ids->len = htons(ntohs(nac_ids->len) + ids_len); |
3676 | 0 | nac_ids->n_controllers = htons(dec_ttl->n_controllers); |
3677 | |
|
3678 | 0 | ids = ofpbuf_put_zeros(out, ids_len); |
3679 | 0 | for (i = 0; i < dec_ttl->n_controllers; i++) { |
3680 | 0 | ids[i] = htons(dec_ttl->cnt_ids[i]); |
3681 | 0 | } |
3682 | 0 | } else { |
3683 | 0 | put_OFPAT_DEC_NW_TTL(out, ofp_version); |
3684 | 0 | } |
3685 | 0 | } |
3686 | | |
3687 | | static void |
3688 | | parse_noargs_dec_ttl(const struct ofpact_parse_params *pp) |
3689 | 0 | { |
3690 | 0 | struct ofpact_cnt_ids *ids; |
3691 | 0 | uint16_t id = 0; |
3692 | |
|
3693 | 0 | ofpact_put_DEC_TTL(pp->ofpacts); |
3694 | 0 | ofpbuf_put(pp->ofpacts, &id, sizeof id); |
3695 | 0 | ids = pp->ofpacts->header; |
3696 | 0 | ids->n_controllers++; |
3697 | 0 | ofpact_finish_DEC_TTL(pp->ofpacts, &ids); |
3698 | 0 | } |
3699 | | |
3700 | | static char * OVS_WARN_UNUSED_RESULT |
3701 | | parse_DEC_TTL(char *arg, const struct ofpact_parse_params *pp) |
3702 | 0 | { |
3703 | 0 | if (*arg == '\0') { |
3704 | 0 | parse_noargs_dec_ttl(pp); |
3705 | 0 | } else { |
3706 | 0 | struct ofpact_cnt_ids *ids; |
3707 | 0 | char *cntr; |
3708 | |
|
3709 | 0 | ids = ofpact_put_DEC_TTL(pp->ofpacts); |
3710 | 0 | ids->ofpact.raw = NXAST_RAW_DEC_TTL_CNT_IDS; |
3711 | 0 | for (cntr = strtok_r(arg, ", ", &arg); cntr != NULL; |
3712 | 0 | cntr = strtok_r(NULL, ", ", &arg)) { |
3713 | 0 | uint16_t id = atoi(cntr); |
3714 | |
|
3715 | 0 | ofpbuf_put(pp->ofpacts, &id, sizeof id); |
3716 | 0 | ids = pp->ofpacts->header; |
3717 | 0 | ids->n_controllers++; |
3718 | 0 | } |
3719 | 0 | if (!ids->n_controllers) { |
3720 | 0 | return xstrdup("dec_ttl_cnt_ids: expected at least one controller " |
3721 | 0 | "id."); |
3722 | 0 | } |
3723 | | |
3724 | 0 | if (ofpbuf_oversized(pp->ofpacts)) { |
3725 | 0 | return xasprintf("input too big"); |
3726 | 0 | } |
3727 | | |
3728 | 0 | ofpact_finish_DEC_TTL(pp->ofpacts, &ids); |
3729 | 0 | } |
3730 | 0 | return NULL; |
3731 | 0 | } |
3732 | | |
3733 | | static void |
3734 | | format_DEC_TTL(const struct ofpact_cnt_ids *a, |
3735 | | const struct ofpact_format_params *fp) |
3736 | 11.4k | { |
3737 | 11.4k | size_t i; |
3738 | | |
3739 | 11.4k | ds_put_format(fp->s, "%sdec_ttl%s", colors.paren, colors.end); |
3740 | 11.4k | if (a->ofpact.raw == NXAST_RAW_DEC_TTL_CNT_IDS) { |
3741 | 4.28k | ds_put_format(fp->s, "%s(%s", colors.paren, colors.end); |
3742 | 17.1k | for (i = 0; i < a->n_controllers; i++) { |
3743 | 12.8k | if (i) { |
3744 | 8.57k | ds_put_cstr(fp->s, ","); |
3745 | 8.57k | } |
3746 | 12.8k | ds_put_format(fp->s, "%"PRIu16, a->cnt_ids[i]); |
3747 | 12.8k | } |
3748 | 4.28k | ds_put_format(fp->s, "%s)%s", colors.paren, colors.end); |
3749 | 4.28k | } |
3750 | 11.4k | } |
3751 | | |
3752 | | static enum ofperr |
3753 | | check_DEC_TTL(const struct ofpact_cnt_ids *a OVS_UNUSED, |
3754 | | struct ofpact_check_params *cp) |
3755 | 7.12k | { |
3756 | 7.12k | return check_set_ip(cp); |
3757 | 7.12k | } |
3758 | | |
3759 | | /* Set MPLS label actions. */ |
3760 | | |
3761 | | static enum ofperr |
3762 | | decode_OFPAT_RAW_SET_MPLS_LABEL(ovs_be32 label, |
3763 | | enum ofp_version ofp_version OVS_UNUSED, |
3764 | | struct ofpbuf *out) |
3765 | 1.85k | { |
3766 | 1.85k | ofpact_put_SET_MPLS_LABEL(out)->label = label; |
3767 | 1.85k | return 0; |
3768 | 1.85k | } |
3769 | | |
3770 | | static void |
3771 | | encode_SET_MPLS_LABEL(const struct ofpact_mpls_label *label, |
3772 | | enum ofp_version ofp_version, |
3773 | | struct ofpbuf *out) |
3774 | 0 | { |
3775 | 0 | if (ofp_version < OFP12_VERSION) { |
3776 | 0 | put_OFPAT_SET_MPLS_LABEL(out, ofp_version, label->label); |
3777 | 0 | } else { |
3778 | 0 | put_set_field(out, ofp_version, MFF_MPLS_LABEL, ntohl(label->label)); |
3779 | 0 | } |
3780 | 0 | } |
3781 | | |
3782 | | static char * OVS_WARN_UNUSED_RESULT |
3783 | | parse_SET_MPLS_LABEL(char *arg, const struct ofpact_parse_params *pp) |
3784 | 0 | { |
3785 | 0 | struct ofpact_mpls_label *mpls_label |
3786 | 0 | = ofpact_put_SET_MPLS_LABEL(pp->ofpacts); |
3787 | 0 | uint32_t label; |
3788 | 0 | char *error; |
3789 | |
|
3790 | 0 | if (*arg == '\0') { |
3791 | 0 | return xstrdup("set_mpls_label: expected label."); |
3792 | 0 | } |
3793 | | |
3794 | 0 | error = str_to_u32(arg, &label); |
3795 | 0 | if (error) { |
3796 | 0 | return error; |
3797 | 0 | } |
3798 | | |
3799 | 0 | if (label & ~0xfffff) { |
3800 | 0 | return xasprintf("%s: not a valid MPLS label", arg); |
3801 | 0 | } |
3802 | 0 | mpls_label->label = htonl(label); |
3803 | 0 | return NULL; |
3804 | 0 | } |
3805 | | |
3806 | | static void |
3807 | | format_SET_MPLS_LABEL(const struct ofpact_mpls_label *a, |
3808 | | const struct ofpact_format_params *fp) |
3809 | 176 | { |
3810 | 176 | ds_put_format(fp->s, "%sset_mpls_label(%s%"PRIu32"%s)%s", |
3811 | 176 | colors.paren, colors.end, ntohl(a->label), |
3812 | 176 | colors.paren, colors.end); |
3813 | 176 | } |
3814 | | |
3815 | | static enum ofperr |
3816 | | check_set_mpls(struct ofpact_check_params *cp) |
3817 | 4.62k | { |
3818 | 4.62k | ovs_be16 dl_type = get_dl_type(&cp->match->flow); |
3819 | 4.62k | if (!eth_type_mpls(dl_type)) { |
3820 | 3.63k | inconsistent_match(&cp->usable_protocols); |
3821 | 3.63k | } |
3822 | 4.62k | return 0; |
3823 | 4.62k | } |
3824 | | |
3825 | | static enum ofperr |
3826 | | check_SET_MPLS_LABEL(const struct ofpact_mpls_label *a OVS_UNUSED, |
3827 | | struct ofpact_check_params *cp) |
3828 | 1.77k | { |
3829 | 1.77k | return check_set_mpls(cp); |
3830 | 1.77k | } |
3831 | | |
3832 | | /* Set MPLS TC actions. */ |
3833 | | |
3834 | | static enum ofperr |
3835 | | decode_OFPAT_RAW_SET_MPLS_TC(uint8_t tc, |
3836 | | enum ofp_version ofp_version OVS_UNUSED, |
3837 | | struct ofpbuf *out) |
3838 | 496 | { |
3839 | 496 | ofpact_put_SET_MPLS_TC(out)->tc = tc; |
3840 | 496 | return 0; |
3841 | 496 | } |
3842 | | |
3843 | | static void |
3844 | | encode_SET_MPLS_TC(const struct ofpact_mpls_tc *tc, |
3845 | | enum ofp_version ofp_version, struct ofpbuf *out) |
3846 | 0 | { |
3847 | 0 | if (ofp_version < OFP12_VERSION) { |
3848 | 0 | put_OFPAT_SET_MPLS_TC(out, ofp_version, tc->tc); |
3849 | 0 | } else { |
3850 | 0 | put_set_field(out, ofp_version, MFF_MPLS_TC, tc->tc); |
3851 | 0 | } |
3852 | 0 | } |
3853 | | |
3854 | | static char * OVS_WARN_UNUSED_RESULT |
3855 | | parse_SET_MPLS_TC(char *arg, const struct ofpact_parse_params *pp) |
3856 | 0 | { |
3857 | 0 | struct ofpact_mpls_tc *mpls_tc = ofpact_put_SET_MPLS_TC(pp->ofpacts); |
3858 | 0 | uint8_t tc; |
3859 | 0 | char *error; |
3860 | |
|
3861 | 0 | if (*arg == '\0') { |
3862 | 0 | return xstrdup("set_mpls_tc: expected tc."); |
3863 | 0 | } |
3864 | | |
3865 | 0 | error = str_to_u8(arg, "MPLS TC", &tc); |
3866 | 0 | if (error) { |
3867 | 0 | return error; |
3868 | 0 | } |
3869 | | |
3870 | 0 | if (tc & ~7) { |
3871 | 0 | return xasprintf("%s: not a valid MPLS TC", arg); |
3872 | 0 | } |
3873 | 0 | mpls_tc->tc = tc; |
3874 | 0 | return NULL; |
3875 | 0 | } |
3876 | | |
3877 | | static void |
3878 | | format_SET_MPLS_TC(const struct ofpact_mpls_tc *a, |
3879 | | const struct ofpact_format_params *fp) |
3880 | 485 | { |
3881 | 485 | ds_put_format(fp->s, "%sset_mpls_tc(%s%"PRIu8"%s)%s", |
3882 | 485 | colors.paren, colors.end, a->tc, |
3883 | 485 | colors.paren, colors.end); |
3884 | 485 | } |
3885 | | |
3886 | | static enum ofperr |
3887 | | check_SET_MPLS_TC(const struct ofpact_mpls_tc *a OVS_UNUSED, |
3888 | | struct ofpact_check_params *cp) |
3889 | 364 | { |
3890 | 364 | return check_set_mpls(cp); |
3891 | 364 | } |
3892 | | |
3893 | | /* Set MPLS TTL actions. */ |
3894 | | |
3895 | | static enum ofperr |
3896 | | decode_OFPAT_RAW_SET_MPLS_TTL(uint8_t ttl, |
3897 | | enum ofp_version ofp_version OVS_UNUSED, |
3898 | | struct ofpbuf *out) |
3899 | 684 | { |
3900 | 684 | ofpact_put_SET_MPLS_TTL(out)->ttl = ttl; |
3901 | 684 | return 0; |
3902 | 684 | } |
3903 | | |
3904 | | static void |
3905 | | encode_SET_MPLS_TTL(const struct ofpact_mpls_ttl *ttl, |
3906 | | enum ofp_version ofp_version, struct ofpbuf *out) |
3907 | 0 | { |
3908 | 0 | put_OFPAT_SET_MPLS_TTL(out, ofp_version, ttl->ttl); |
3909 | 0 | } |
3910 | | |
3911 | | /* Parses 'arg' as the argument to a "set_mpls_ttl" action, and appends such an |
3912 | | * action to 'pp->ofpacts'. |
3913 | | * |
3914 | | * Returns NULL if successful, otherwise a malloc()'d string describing the |
3915 | | * error. The caller is responsible for freeing the returned string. */ |
3916 | | static char * OVS_WARN_UNUSED_RESULT |
3917 | | parse_SET_MPLS_TTL(char *arg, const struct ofpact_parse_params *pp) |
3918 | 0 | { |
3919 | 0 | struct ofpact_mpls_ttl *mpls_ttl = ofpact_put_SET_MPLS_TTL(pp->ofpacts); |
3920 | 0 | uint8_t ttl; |
3921 | 0 | char *error; |
3922 | |
|
3923 | 0 | if (*arg == '\0') { |
3924 | 0 | return xstrdup("set_mpls_ttl: expected ttl."); |
3925 | 0 | } |
3926 | | |
3927 | 0 | error = str_to_u8(arg, "MPLS TTL", &ttl); |
3928 | 0 | if (error) { |
3929 | 0 | return error; |
3930 | 0 | } |
3931 | 0 | mpls_ttl->ttl = ttl; |
3932 | 0 | return NULL; |
3933 | 0 | } |
3934 | | |
3935 | | static void |
3936 | | format_SET_MPLS_TTL(const struct ofpact_mpls_ttl *a, |
3937 | | const struct ofpact_format_params *fp) |
3938 | 450 | { |
3939 | 450 | ds_put_format(fp->s, "%sset_mpls_ttl(%s%"PRIu8"%s)%s", |
3940 | 450 | colors.paren, colors.end, a->ttl, |
3941 | 450 | colors.paren, colors.end); |
3942 | 450 | } |
3943 | | |
3944 | | static enum ofperr |
3945 | | check_SET_MPLS_TTL(const struct ofpact_mpls_ttl *a OVS_UNUSED, |
3946 | | struct ofpact_check_params *cp) |
3947 | 185 | { |
3948 | 185 | return check_set_mpls(cp); |
3949 | 185 | } |
3950 | | |
3951 | | /* Decrement MPLS TTL actions. */ |
3952 | | |
3953 | | static enum ofperr |
3954 | | decode_OFPAT_RAW_DEC_MPLS_TTL(struct ofpbuf *out) |
3955 | 2.35k | { |
3956 | 2.35k | ofpact_put_DEC_MPLS_TTL(out); |
3957 | 2.35k | return 0; |
3958 | 2.35k | } |
3959 | | |
3960 | | static void |
3961 | | encode_DEC_MPLS_TTL(const struct ofpact_null *null OVS_UNUSED, |
3962 | | enum ofp_version ofp_version, struct ofpbuf *out) |
3963 | 0 | { |
3964 | 0 | put_OFPAT_DEC_MPLS_TTL(out, ofp_version); |
3965 | 0 | } |
3966 | | |
3967 | | static char * OVS_WARN_UNUSED_RESULT |
3968 | | parse_DEC_MPLS_TTL(char *arg OVS_UNUSED, const struct ofpact_parse_params *pp) |
3969 | 0 | { |
3970 | 0 | ofpact_put_DEC_MPLS_TTL(pp->ofpacts); |
3971 | 0 | return NULL; |
3972 | 0 | } |
3973 | | |
3974 | | static void |
3975 | | format_DEC_MPLS_TTL(const struct ofpact_null *a OVS_UNUSED, |
3976 | | const struct ofpact_format_params *fp) |
3977 | 2.31k | { |
3978 | 2.31k | ds_put_format(fp->s, "%sdec_mpls_ttl%s", colors.value, colors.end); |
3979 | 2.31k | } |
3980 | | |
3981 | | static enum ofperr |
3982 | | check_DEC_MPLS_TTL(const struct ofpact_null *a OVS_UNUSED, |
3983 | | struct ofpact_check_params *cp) |
3984 | 2.30k | { |
3985 | 2.30k | return check_set_mpls(cp); |
3986 | 2.30k | } |
3987 | | |
3988 | | /* Push MPLS label action. */ |
3989 | | |
3990 | | static enum ofperr |
3991 | | decode_OFPAT_RAW_PUSH_MPLS(ovs_be16 ethertype, |
3992 | | enum ofp_version ofp_version OVS_UNUSED, |
3993 | | struct ofpbuf *out) |
3994 | 1.34k | { |
3995 | 1.34k | struct ofpact_push_mpls *oam; |
3996 | | |
3997 | 1.34k | if (!eth_type_mpls(ethertype)) { |
3998 | 115 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
3999 | 115 | } |
4000 | 1.23k | oam = ofpact_put_PUSH_MPLS(out); |
4001 | 1.23k | oam->ethertype = ethertype; |
4002 | | |
4003 | 1.23k | return 0; |
4004 | 1.34k | } |
4005 | | |
4006 | | static void |
4007 | | encode_PUSH_MPLS(const struct ofpact_push_mpls *push_mpls, |
4008 | | enum ofp_version ofp_version, struct ofpbuf *out) |
4009 | 0 | { |
4010 | 0 | put_OFPAT_PUSH_MPLS(out, ofp_version, push_mpls->ethertype); |
4011 | 0 | } |
4012 | | |
4013 | | static char * OVS_WARN_UNUSED_RESULT |
4014 | | parse_PUSH_MPLS(char *arg, const struct ofpact_parse_params *pp) |
4015 | 0 | { |
4016 | 0 | uint16_t ethertype; |
4017 | 0 | char *error; |
4018 | |
|
4019 | 0 | error = str_to_u16(arg, "push_mpls", ðertype); |
4020 | 0 | if (!error) { |
4021 | 0 | ofpact_put_PUSH_MPLS(pp->ofpacts)->ethertype = htons(ethertype); |
4022 | 0 | } |
4023 | 0 | return error; |
4024 | 0 | } |
4025 | | |
4026 | | static void |
4027 | | format_PUSH_MPLS(const struct ofpact_push_mpls *a, |
4028 | | const struct ofpact_format_params *fp) |
4029 | 1.05k | { |
4030 | 1.05k | ds_put_format(fp->s, "%spush_mpls:%s0x%04"PRIx16, |
4031 | 1.05k | colors.param, colors.end, ntohs(a->ethertype)); |
4032 | 1.05k | } |
4033 | | |
4034 | | static enum ofperr |
4035 | | check_PUSH_MPLS(const struct ofpact_push_mpls *a, |
4036 | | struct ofpact_check_params *cp) |
4037 | 1.05k | { |
4038 | 1.05k | struct flow *flow = &cp->match->flow; |
4039 | | |
4040 | 1.05k | if (flow->packet_type != htonl(PT_ETH)) { |
4041 | 1 | inconsistent_match(&cp->usable_protocols); |
4042 | 1 | } |
4043 | 1.05k | flow->dl_type = a->ethertype; |
4044 | | |
4045 | | /* The packet is now MPLS and the MPLS payload is opaque. |
4046 | | * Thus nothing can be assumed about the network protocol. |
4047 | | * Temporarily mark that we have no nw_proto. */ |
4048 | 1.05k | flow->nw_proto = 0; |
4049 | | |
4050 | 1.05k | return 0; |
4051 | 1.05k | } |
4052 | | |
4053 | | /* Pop MPLS label action. */ |
4054 | | |
4055 | | static enum ofperr |
4056 | | decode_OFPAT_RAW_POP_MPLS(ovs_be16 ethertype, |
4057 | | enum ofp_version ofp_version OVS_UNUSED, |
4058 | | struct ofpbuf *out) |
4059 | 13.1k | { |
4060 | 13.1k | ofpact_put_POP_MPLS(out)->ethertype = ethertype; |
4061 | 13.1k | return 0; |
4062 | 13.1k | } |
4063 | | |
4064 | | static void |
4065 | | encode_POP_MPLS(const struct ofpact_pop_mpls *pop_mpls, |
4066 | | enum ofp_version ofp_version, struct ofpbuf *out) |
4067 | 0 | { |
4068 | 0 | put_OFPAT_POP_MPLS(out, ofp_version, pop_mpls->ethertype); |
4069 | 0 | } |
4070 | | |
4071 | | static char * OVS_WARN_UNUSED_RESULT |
4072 | | parse_POP_MPLS(char *arg, const struct ofpact_parse_params *pp) |
4073 | 0 | { |
4074 | 0 | uint16_t ethertype; |
4075 | 0 | char *error; |
4076 | |
|
4077 | 0 | error = str_to_u16(arg, "pop_mpls", ðertype); |
4078 | 0 | if (!error) { |
4079 | 0 | ofpact_put_POP_MPLS(pp->ofpacts)->ethertype = htons(ethertype); |
4080 | 0 | } |
4081 | 0 | return error; |
4082 | 0 | } |
4083 | | |
4084 | | static void |
4085 | | format_POP_MPLS(const struct ofpact_pop_mpls *a, |
4086 | | const struct ofpact_format_params *fp) |
4087 | 10.6k | { |
4088 | 10.6k | ds_put_format(fp->s, "%spop_mpls:%s0x%04"PRIx16, |
4089 | 10.6k | colors.param, colors.end, ntohs(a->ethertype)); |
4090 | 10.6k | } |
4091 | | |
4092 | | static enum ofperr |
4093 | | check_POP_MPLS(const struct ofpact_pop_mpls *a, struct ofpact_check_params *cp) |
4094 | 10.6k | { |
4095 | 10.6k | struct flow *flow = &cp->match->flow; |
4096 | 10.6k | ovs_be16 dl_type = get_dl_type(flow); |
4097 | | |
4098 | 10.6k | if (flow->packet_type != htonl(PT_ETH) || !eth_type_mpls(dl_type)) { |
4099 | 8.59k | inconsistent_match(&cp->usable_protocols); |
4100 | 8.59k | } |
4101 | 10.6k | flow->dl_type = a->ethertype; |
4102 | 10.6k | return 0; |
4103 | 10.6k | } |
4104 | | |
4105 | | /* Set tunnel ID actions. */ |
4106 | | |
4107 | | static enum ofperr |
4108 | | decode_NXAST_RAW_SET_TUNNEL(uint32_t tun_id, |
4109 | | enum ofp_version ofp_version OVS_UNUSED, |
4110 | | struct ofpbuf *out) |
4111 | 1.72k | { |
4112 | 1.72k | struct ofpact_tunnel *tunnel = ofpact_put_SET_TUNNEL(out); |
4113 | 1.72k | tunnel->ofpact.raw = NXAST_RAW_SET_TUNNEL; |
4114 | 1.72k | tunnel->tun_id = tun_id; |
4115 | 1.72k | return 0; |
4116 | 1.72k | } |
4117 | | |
4118 | | static enum ofperr |
4119 | | decode_NXAST_RAW_SET_TUNNEL64(uint64_t tun_id, |
4120 | | enum ofp_version ofp_version OVS_UNUSED, |
4121 | | struct ofpbuf *out) |
4122 | 169 | { |
4123 | 169 | struct ofpact_tunnel *tunnel = ofpact_put_SET_TUNNEL(out); |
4124 | 169 | tunnel->ofpact.raw = NXAST_RAW_SET_TUNNEL64; |
4125 | 169 | tunnel->tun_id = tun_id; |
4126 | 169 | return 0; |
4127 | 169 | } |
4128 | | |
4129 | | static void |
4130 | | encode_SET_TUNNEL(const struct ofpact_tunnel *tunnel, |
4131 | | enum ofp_version ofp_version, struct ofpbuf *out) |
4132 | 0 | { |
4133 | 0 | uint64_t tun_id = tunnel->tun_id; |
4134 | |
|
4135 | 0 | if (ofp_version < OFP12_VERSION) { |
4136 | 0 | if (tun_id <= UINT32_MAX |
4137 | 0 | && tunnel->ofpact.raw != NXAST_RAW_SET_TUNNEL64) { |
4138 | 0 | put_NXAST_SET_TUNNEL(out, tun_id); |
4139 | 0 | } else { |
4140 | 0 | put_NXAST_SET_TUNNEL64(out, tun_id); |
4141 | 0 | } |
4142 | 0 | } else { |
4143 | 0 | put_set_field(out, ofp_version, MFF_TUN_ID, tun_id); |
4144 | 0 | } |
4145 | 0 | } |
4146 | | |
4147 | | static char * OVS_WARN_UNUSED_RESULT |
4148 | | parse_set_tunnel(char *arg, enum ofp_raw_action_type raw, |
4149 | | const struct ofpact_parse_params *pp) |
4150 | 0 | { |
4151 | 0 | struct ofpact_tunnel *tunnel; |
4152 | |
|
4153 | 0 | tunnel = ofpact_put_SET_TUNNEL(pp->ofpacts); |
4154 | 0 | tunnel->ofpact.raw = raw; |
4155 | 0 | return str_to_u64(arg, &tunnel->tun_id); |
4156 | 0 | } |
4157 | | |
4158 | | static char * OVS_WARN_UNUSED_RESULT |
4159 | | parse_SET_TUNNEL(char *arg, const struct ofpact_parse_params *pp) |
4160 | 0 | { |
4161 | 0 | return parse_set_tunnel(arg, NXAST_RAW_SET_TUNNEL, pp); |
4162 | 0 | } |
4163 | | |
4164 | | static void |
4165 | | format_SET_TUNNEL(const struct ofpact_tunnel *a, |
4166 | | const struct ofpact_format_params *fp) |
4167 | 358 | { |
4168 | 358 | ds_put_format(fp->s, "%sset_tunnel%s:%s%#"PRIx64, colors.param, |
4169 | 358 | (a->tun_id > UINT32_MAX |
4170 | 358 | || a->ofpact.raw == NXAST_RAW_SET_TUNNEL64 ? "64" : ""), |
4171 | 358 | colors.end, a->tun_id); |
4172 | 358 | } |
4173 | | |
4174 | | static enum ofperr |
4175 | | check_SET_TUNNEL(const struct ofpact_tunnel *a OVS_UNUSED, |
4176 | | const struct ofpact_check_params *cp OVS_UNUSED) |
4177 | 139 | { |
4178 | 139 | return 0; |
4179 | 139 | } |
4180 | | |
4181 | | /* Delete field action. */ |
4182 | | |
4183 | | /* Action structure for DELETE_FIELD */ |
4184 | | struct nx_action_delete_field { |
4185 | | ovs_be16 type; /* OFPAT_VENDOR */ |
4186 | | ovs_be16 len; /* Length is 24. */ |
4187 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
4188 | | ovs_be16 subtype; /* NXAST_DELETE_FIELD. */ |
4189 | | /* Followed by: |
4190 | | * - OXM/NXM header for field to delete (4 or 8 bytes). |
4191 | | * - Enough 0-bytes to pad out the action to 24 bytes. */ |
4192 | | uint8_t pad[14]; |
4193 | | }; |
4194 | | OFP_ASSERT(sizeof(struct nx_action_delete_field ) == 24); |
4195 | | |
4196 | | static enum ofperr |
4197 | | decode_NXAST_RAW_DELETE_FIELD(const struct nx_action_delete_field *nadf, |
4198 | | enum ofp_version ofp_version OVS_UNUSED, |
4199 | | const struct vl_mff_map *vl_mff_map, |
4200 | | uint64_t *tlv_bitmap, struct ofpbuf *out) |
4201 | 54 | { |
4202 | 54 | struct ofpact_delete_field *delete_field; |
4203 | 54 | enum ofperr err; |
4204 | | |
4205 | 54 | delete_field = ofpact_put_DELETE_FIELD(out); |
4206 | 54 | delete_field->ofpact.raw = NXAST_RAW_DELETE_FIELD; |
4207 | | |
4208 | 54 | struct ofpbuf b = ofpbuf_const_initializer(nadf, ntohs(nadf->len)); |
4209 | 54 | ofpbuf_pull(&b, OBJECT_OFFSETOF(nadf, pad)); |
4210 | | |
4211 | 54 | err = mf_vl_mff_nx_pull_header(&b, vl_mff_map, &delete_field->field, |
4212 | 54 | NULL, tlv_bitmap); |
4213 | 54 | if (err) { |
4214 | 13 | return err; |
4215 | 13 | } |
4216 | | |
4217 | 41 | return 0; |
4218 | 54 | } |
4219 | | |
4220 | | static void |
4221 | | encode_DELETE_FIELD(const struct ofpact_delete_field *delete_field, |
4222 | | enum ofp_version ofp_version OVS_UNUSED, |
4223 | | struct ofpbuf *out) |
4224 | 0 | { |
4225 | 0 | size_t size; |
4226 | |
|
4227 | 0 | put_NXAST_DELETE_FIELD(out); |
4228 | 0 | size = out->size; |
4229 | |
|
4230 | 0 | out->size = size - MEMBER_SIZEOF(struct nx_action_delete_field, pad); |
4231 | 0 | nx_put_mff_header(out, delete_field->field, 0, false); |
4232 | 0 | out->size = size; |
4233 | 0 | } |
4234 | | |
4235 | | static char * OVS_WARN_UNUSED_RESULT |
4236 | | parse_DELETE_FIELD(char *arg, const struct ofpact_parse_params *pp) |
4237 | 0 | { |
4238 | 0 | struct ofpact_delete_field *delete_field; |
4239 | |
|
4240 | 0 | delete_field = ofpact_put_DELETE_FIELD(pp->ofpacts); |
4241 | 0 | return mf_parse_field(&delete_field->field, arg); |
4242 | 0 | } |
4243 | | |
4244 | | static void |
4245 | | format_DELETE_FIELD(const struct ofpact_delete_field *odf, |
4246 | | const struct ofpact_format_params *fp) |
4247 | 20 | { |
4248 | 20 | ds_put_format(fp->s, "%sdelete_field:%s", colors.param, |
4249 | 20 | colors.end); |
4250 | 20 | ds_put_format(fp->s, "%s", odf->field->name); |
4251 | 20 | } |
4252 | | |
4253 | | static enum ofperr |
4254 | | check_DELETE_FIELD(const struct ofpact_delete_field *odf, |
4255 | | struct ofpact_check_params *cp OVS_UNUSED) |
4256 | 24 | { |
4257 | 24 | if (odf->field->id < MFF_TUN_METADATA0 || |
4258 | 24 | odf->field->id > MFF_TUN_METADATA63) { |
4259 | 21 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
4260 | 21 | } |
4261 | 3 | return 0; |
4262 | 24 | } |
4263 | | |
4264 | | /* Set queue action. */ |
4265 | | |
4266 | | static enum ofperr |
4267 | | decode_OFPAT_RAW_SET_QUEUE(uint32_t queue_id, |
4268 | | enum ofp_version ofp_version OVS_UNUSED, |
4269 | | struct ofpbuf *out) |
4270 | 425 | { |
4271 | 425 | ofpact_put_SET_QUEUE(out)->queue_id = queue_id; |
4272 | 425 | return 0; |
4273 | 425 | } |
4274 | | |
4275 | | static void |
4276 | | encode_SET_QUEUE(const struct ofpact_queue *queue, |
4277 | | enum ofp_version ofp_version, struct ofpbuf *out) |
4278 | 0 | { |
4279 | 0 | put_OFPAT_SET_QUEUE(out, ofp_version, queue->queue_id); |
4280 | 0 | } |
4281 | | |
4282 | | static char * OVS_WARN_UNUSED_RESULT |
4283 | | parse_SET_QUEUE(char *arg, const struct ofpact_parse_params *pp) |
4284 | 0 | { |
4285 | 0 | return str_to_u32(arg, &ofpact_put_SET_QUEUE(pp->ofpacts)->queue_id); |
4286 | 0 | } |
4287 | | |
4288 | | static void |
4289 | | format_SET_QUEUE(const struct ofpact_queue *a, |
4290 | | const struct ofpact_format_params *fp) |
4291 | 406 | { |
4292 | 406 | ds_put_format(fp->s, "%sset_queue:%s%"PRIu32, |
4293 | 406 | colors.param, colors.end, a->queue_id); |
4294 | 406 | } |
4295 | | |
4296 | | static enum ofperr |
4297 | | check_SET_QUEUE(const struct ofpact_queue *a OVS_UNUSED, |
4298 | | const struct ofpact_check_params *cp OVS_UNUSED) |
4299 | 14 | { |
4300 | 14 | return 0; |
4301 | 14 | } |
4302 | | |
4303 | | /* Pop queue action. */ |
4304 | | |
4305 | | static enum ofperr |
4306 | | decode_NXAST_RAW_POP_QUEUE(struct ofpbuf *out) |
4307 | 2.43k | { |
4308 | 2.43k | ofpact_put_POP_QUEUE(out); |
4309 | 2.43k | return 0; |
4310 | 2.43k | } |
4311 | | |
4312 | | static void |
4313 | | encode_POP_QUEUE(const struct ofpact_null *null OVS_UNUSED, |
4314 | | enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out) |
4315 | 0 | { |
4316 | 0 | put_NXAST_POP_QUEUE(out); |
4317 | 0 | } |
4318 | | |
4319 | | static char * OVS_WARN_UNUSED_RESULT |
4320 | | parse_POP_QUEUE(const char *arg OVS_UNUSED, |
4321 | | const struct ofpact_parse_params *pp) |
4322 | 0 | { |
4323 | 0 | ofpact_put_POP_QUEUE(pp->ofpacts); |
4324 | 0 | return NULL; |
4325 | 0 | } |
4326 | | |
4327 | | static void |
4328 | | format_POP_QUEUE(const struct ofpact_null *a OVS_UNUSED, |
4329 | | const struct ofpact_format_params *fp) |
4330 | 682 | { |
4331 | 682 | ds_put_format(fp->s, "%spop_queue%s", colors.value, colors.end); |
4332 | 682 | } |
4333 | | |
4334 | | static enum ofperr |
4335 | | check_POP_QUEUE(const struct ofpact_null *a OVS_UNUSED, |
4336 | | const struct ofpact_check_params *cp OVS_UNUSED) |
4337 | 19 | { |
4338 | 19 | return 0; |
4339 | 19 | } |
4340 | | |
4341 | | /* Action structure for NXAST_FIN_TIMEOUT. |
4342 | | * |
4343 | | * This action changes the idle timeout or hard timeout, or both, of this |
4344 | | * OpenFlow rule when the rule matches a TCP packet with the FIN or RST flag. |
4345 | | * When such a packet is observed, the action reduces the rule's idle timeout |
4346 | | * to 'fin_idle_timeout' and its hard timeout to 'fin_hard_timeout'. This |
4347 | | * action has no effect on an existing timeout that is already shorter than the |
4348 | | * one that the action specifies. A 'fin_idle_timeout' or 'fin_hard_timeout' |
4349 | | * of zero has no effect on the respective timeout. |
4350 | | * |
4351 | | * 'fin_idle_timeout' and 'fin_hard_timeout' are measured in seconds. |
4352 | | * 'fin_hard_timeout' specifies time since the flow's creation, not since the |
4353 | | * receipt of the FIN or RST. |
4354 | | * |
4355 | | * This is useful for quickly discarding learned TCP flows that otherwise will |
4356 | | * take a long time to expire. |
4357 | | * |
4358 | | * This action is intended for use with an OpenFlow rule that matches only a |
4359 | | * single TCP flow. If the rule matches multiple TCP flows (e.g. it wildcards |
4360 | | * all TCP traffic, or all TCP traffic to a particular port), then any FIN or |
4361 | | * RST in any of those flows will cause the entire OpenFlow rule to expire |
4362 | | * early, which is not normally desirable. |
4363 | | */ |
4364 | | struct nx_action_fin_timeout { |
4365 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
4366 | | ovs_be16 len; /* 16. */ |
4367 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
4368 | | ovs_be16 subtype; /* NXAST_FIN_TIMEOUT. */ |
4369 | | ovs_be16 fin_idle_timeout; /* New idle timeout, if nonzero. */ |
4370 | | ovs_be16 fin_hard_timeout; /* New hard timeout, if nonzero. */ |
4371 | | ovs_be16 pad; /* Must be zero. */ |
4372 | | }; |
4373 | | OFP_ASSERT(sizeof(struct nx_action_fin_timeout) == 16); |
4374 | | |
4375 | | static enum ofperr |
4376 | | decode_NXAST_RAW_FIN_TIMEOUT(const struct nx_action_fin_timeout *naft, |
4377 | | enum ofp_version ofp_version OVS_UNUSED, |
4378 | | struct ofpbuf *out) |
4379 | 2.67k | { |
4380 | 2.67k | struct ofpact_fin_timeout *oft; |
4381 | | |
4382 | 2.67k | oft = ofpact_put_FIN_TIMEOUT(out); |
4383 | 2.67k | oft->fin_idle_timeout = ntohs(naft->fin_idle_timeout); |
4384 | 2.67k | oft->fin_hard_timeout = ntohs(naft->fin_hard_timeout); |
4385 | 2.67k | return 0; |
4386 | 2.67k | } |
4387 | | |
4388 | | static void |
4389 | | encode_FIN_TIMEOUT(const struct ofpact_fin_timeout *fin_timeout, |
4390 | | enum ofp_version ofp_version OVS_UNUSED, |
4391 | | struct ofpbuf *out) |
4392 | 0 | { |
4393 | 0 | struct nx_action_fin_timeout *naft = put_NXAST_FIN_TIMEOUT(out); |
4394 | 0 | naft->fin_idle_timeout = htons(fin_timeout->fin_idle_timeout); |
4395 | 0 | naft->fin_hard_timeout = htons(fin_timeout->fin_hard_timeout); |
4396 | 0 | } |
4397 | | |
4398 | | static char * OVS_WARN_UNUSED_RESULT |
4399 | | parse_FIN_TIMEOUT(char *arg, const struct ofpact_parse_params *pp) |
4400 | 0 | { |
4401 | 0 | struct ofpact_fin_timeout *oft = ofpact_put_FIN_TIMEOUT(pp->ofpacts); |
4402 | 0 | char *key, *value; |
4403 | |
|
4404 | 0 | while (ofputil_parse_key_value(&arg, &key, &value)) { |
4405 | 0 | char *error; |
4406 | |
|
4407 | 0 | if (!strcmp(key, "idle_timeout")) { |
4408 | 0 | error = str_to_u16(value, key, &oft->fin_idle_timeout); |
4409 | 0 | } else if (!strcmp(key, "hard_timeout")) { |
4410 | 0 | error = str_to_u16(value, key, &oft->fin_hard_timeout); |
4411 | 0 | } else { |
4412 | 0 | error = xasprintf("invalid key '%s' in 'fin_timeout' argument", |
4413 | 0 | key); |
4414 | 0 | } |
4415 | |
|
4416 | 0 | if (error) { |
4417 | 0 | return error; |
4418 | 0 | } |
4419 | 0 | } |
4420 | 0 | return NULL; |
4421 | 0 | } |
4422 | | |
4423 | | static void |
4424 | | format_FIN_TIMEOUT(const struct ofpact_fin_timeout *a, |
4425 | | const struct ofpact_format_params *fp) |
4426 | 2.29k | { |
4427 | 2.29k | ds_put_format(fp->s, "%sfin_timeout(%s", colors.paren, colors.end); |
4428 | 2.29k | if (a->fin_idle_timeout) { |
4429 | 1.96k | ds_put_format(fp->s, "%sidle_timeout=%s%"PRIu16",", |
4430 | 1.96k | colors.param, colors.end, a->fin_idle_timeout); |
4431 | 1.96k | } |
4432 | 2.29k | if (a->fin_hard_timeout) { |
4433 | 1.78k | ds_put_format(fp->s, "%shard_timeout=%s%"PRIu16",", |
4434 | 1.78k | colors.param, colors.end, a->fin_hard_timeout); |
4435 | 1.78k | } |
4436 | 2.29k | ds_chomp(fp->s, ','); |
4437 | 2.29k | ds_put_format(fp->s, "%s)%s", colors.paren, colors.end); |
4438 | 2.29k | } |
4439 | | |
4440 | | |
4441 | | static enum ofperr |
4442 | | check_FIN_TIMEOUT(const struct ofpact_fin_timeout *a OVS_UNUSED, |
4443 | | struct ofpact_check_params *cp) |
4444 | 1.40k | { |
4445 | 1.40k | if (cp->match->flow.nw_proto != IPPROTO_TCP) { |
4446 | 1.21k | inconsistent_match(&cp->usable_protocols); |
4447 | 1.21k | } |
4448 | 1.40k | return 0; |
4449 | 1.40k | } |
4450 | | |
4451 | | /* Action structure for NXAST_ENCAP */ |
4452 | | struct nx_action_encap { |
4453 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
4454 | | ovs_be16 len; /* Total size including any property TLVs. */ |
4455 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
4456 | | ovs_be16 subtype; /* NXAST_ENCAP. */ |
4457 | | ovs_be16 hdr_size; /* Header size in bytes, 0 = 'not specified'.*/ |
4458 | | ovs_be32 new_pkt_type; /* Header type to add and PACKET_TYPE of result. */ |
4459 | | struct ofp_ed_prop_header props[]; /* Encap TLV properties. */ |
4460 | | }; |
4461 | | OFP_ASSERT(sizeof(struct nx_action_encap) == 16); |
4462 | | |
4463 | | static enum ofperr |
4464 | | decode_NXAST_RAW_ENCAP(const struct nx_action_encap *nae, |
4465 | | enum ofp_version ofp_version OVS_UNUSED, |
4466 | | struct ofpbuf *out) |
4467 | 4.76k | { |
4468 | 4.76k | struct ofpact_encap *encap; |
4469 | 4.76k | const struct ofp_ed_prop_header *ofp_prop; |
4470 | 4.76k | const size_t encap_ofs = out->size; |
4471 | 4.76k | size_t props_len; |
4472 | 4.76k | uint16_t n_props = 0; |
4473 | 4.76k | int err; |
4474 | | |
4475 | 4.76k | encap = ofpact_put_ENCAP(out); |
4476 | 4.76k | encap->ofpact.raw = NXAST_RAW_ENCAP; |
4477 | 4.76k | switch (ntohl(nae->new_pkt_type)) { |
4478 | 3.11k | case PT_ETH: |
4479 | 3.68k | case PT_NSH: |
4480 | 4.29k | case PT_MPLS: |
4481 | 4.40k | case PT_MPLS_MC: |
4482 | | /* Add supported encap header types here. */ |
4483 | 4.40k | break; |
4484 | 351 | default: |
4485 | 351 | return OFPERR_NXBAC_BAD_HEADER_TYPE; |
4486 | 4.76k | } |
4487 | 4.40k | encap->new_pkt_type = nae->new_pkt_type; |
4488 | 4.40k | encap->hdr_size = ntohs(nae->hdr_size); |
4489 | | |
4490 | 4.40k | ofp_prop = nae->props; |
4491 | 4.40k | props_len = ntohs(nae->len) - offsetof(struct nx_action_encap, props); |
4492 | 4.40k | n_props = 0; |
4493 | 9.96k | while (props_len > 0) { |
4494 | 8.18k | err = decode_ed_prop(&ofp_prop, out, &props_len); |
4495 | 8.18k | if (err) { |
4496 | 2.62k | return err; |
4497 | 2.62k | } |
4498 | 5.55k | n_props++; |
4499 | 5.55k | } |
4500 | 1.78k | encap = ofpbuf_at_assert(out, encap_ofs, sizeof *encap); |
4501 | 1.78k | encap->n_props = n_props; |
4502 | 1.78k | out->header = &encap->ofpact; |
4503 | 1.78k | ofpact_finish_ENCAP(out, &encap); |
4504 | | |
4505 | 1.78k | return 0; |
4506 | 4.40k | } |
4507 | | |
4508 | | static void |
4509 | | encode_ENCAP(const struct ofpact_encap *encap, |
4510 | | enum ofp_version ofp_version OVS_UNUSED, |
4511 | | struct ofpbuf *out) |
4512 | 0 | { |
4513 | 0 | size_t start_ofs = out->size; |
4514 | 0 | struct nx_action_encap *nae = put_NXAST_ENCAP(out); |
4515 | 0 | int i; |
4516 | |
|
4517 | 0 | nae->new_pkt_type = encap->new_pkt_type; |
4518 | 0 | nae->hdr_size = htons(encap->hdr_size); |
4519 | 0 | const struct ofpact_ed_prop *prop = encap->props; |
4520 | 0 | for (i = 0; i < encap->n_props; i++) { |
4521 | 0 | encode_ed_prop(&prop, out); |
4522 | 0 | } |
4523 | 0 | pad_ofpat(out, start_ofs); |
4524 | 0 | } |
4525 | | |
4526 | | static bool |
4527 | | parse_encap_header(const char *hdr, ovs_be32 *packet_type) |
4528 | 0 | { |
4529 | 0 | if (strcmp(hdr, "ethernet") == 0) { |
4530 | 0 | *packet_type = htonl(PT_ETH); |
4531 | 0 | } else if (strcmp(hdr, "nsh") == 0) { |
4532 | 0 | *packet_type = htonl(PT_NSH); |
4533 | 0 | } else if (strcmp(hdr, "mpls") == 0) { |
4534 | 0 | *packet_type = htonl(PT_MPLS); |
4535 | 0 | } else if (strcmp(hdr, "mpls_mc") == 0) { |
4536 | 0 | *packet_type = htonl(PT_MPLS_MC); |
4537 | 0 | } else { |
4538 | 0 | return false; |
4539 | 0 | } |
4540 | 0 | return true; |
4541 | 0 | } |
4542 | | |
4543 | | static char * |
4544 | | parse_ed_props(const uint16_t prop_class, char **arg, int *n_props, struct ofpbuf *out) |
4545 | 0 | { |
4546 | 0 | char *key, *value, *err; |
4547 | 0 | uint8_t prop_type; |
4548 | |
|
4549 | 0 | while (ofputil_parse_key_value(arg, &key, &value)) { |
4550 | 0 | if (!parse_ed_prop_type(prop_class, key, &prop_type)) { |
4551 | 0 | return xasprintf("Invalid property: %s", key); |
4552 | 0 | } |
4553 | 0 | if (value == NULL) { |
4554 | 0 | return xasprintf("Missing the value for property: %s", key); |
4555 | 0 | } |
4556 | 0 | err = parse_ed_prop_value(prop_class, prop_type, value, out); |
4557 | 0 | if (err != NULL) { |
4558 | 0 | return err; |
4559 | 0 | } |
4560 | 0 | (*n_props)++; |
4561 | 0 | } |
4562 | 0 | return NULL; |
4563 | 0 | } |
4564 | | |
4565 | | /* The string representation of the encap action is |
4566 | | * encap(header_type(prop=<value>,tlv(<class>,<type>,<value>),...)) |
4567 | | */ |
4568 | | |
4569 | | static char * OVS_WARN_UNUSED_RESULT |
4570 | | parse_ENCAP(char *arg, const struct ofpact_parse_params *pp) |
4571 | 0 | { |
4572 | 0 | *pp->usable_protocols &= OFPUTIL_P_OF13_UP; |
4573 | |
|
4574 | 0 | struct ofpact_encap *encap; |
4575 | 0 | char *key, *value, *str; |
4576 | 0 | char *error = NULL; |
4577 | 0 | uint16_t prop_class; |
4578 | 0 | int n_props = 0; |
4579 | |
|
4580 | 0 | encap = ofpact_put_ENCAP(pp->ofpacts); |
4581 | 0 | encap->hdr_size = 0; |
4582 | | /* Parse encap header type. */ |
4583 | 0 | str = arg; |
4584 | 0 | if (!ofputil_parse_key_value(&arg, &key, &value)) { |
4585 | 0 | return xasprintf("Missing encap hdr: %s", str); |
4586 | 0 | } |
4587 | 0 | if (!parse_encap_header(key, &encap->new_pkt_type)) { |
4588 | 0 | return xasprintf("Encap hdr not supported: %s", value); |
4589 | 0 | } |
4590 | 0 | if (!parse_ed_prop_class(key, &prop_class)) { |
4591 | 0 | return xasprintf("Invalid encap prop class: %s", key); |
4592 | 0 | } |
4593 | | /* Parse encap properties. */ |
4594 | 0 | error = parse_ed_props(prop_class, &value, &n_props, pp->ofpacts); |
4595 | 0 | if (error != NULL) { |
4596 | 0 | return error; |
4597 | 0 | } |
4598 | | /* ofpbuf may have been re-allocated. */ |
4599 | 0 | encap = pp->ofpacts->header; |
4600 | 0 | encap->n_props = n_props; |
4601 | |
|
4602 | 0 | if (ofpbuf_oversized(pp->ofpacts)) { |
4603 | 0 | return xasprintf("input too big"); |
4604 | 0 | } |
4605 | | |
4606 | 0 | ofpact_finish_ENCAP(pp->ofpacts, &encap); |
4607 | 0 | return NULL; |
4608 | 0 | } |
4609 | | |
4610 | | static char * |
4611 | | format_encap_pkt_type(const ovs_be32 pkt_type) |
4612 | 1.55k | { |
4613 | 1.55k | switch (ntohl(pkt_type)) { |
4614 | 456 | case PT_ETH: |
4615 | 456 | return "ethernet"; |
4616 | 563 | case PT_NSH: |
4617 | 563 | return "nsh"; |
4618 | 452 | case PT_MPLS: |
4619 | 452 | return "mpls"; |
4620 | 86 | case PT_MPLS_MC: |
4621 | 86 | return "mpls_mc"; |
4622 | 0 | default: |
4623 | 0 | return "UNKNOWN"; |
4624 | 1.55k | } |
4625 | 1.55k | } |
4626 | | |
4627 | | static void |
4628 | | format_ed_props(struct ds *s, uint16_t n_props, |
4629 | | const struct ofpact_ed_prop *prop) |
4630 | 339 | { |
4631 | 339 | const uint8_t *p = (uint8_t *) prop; |
4632 | 339 | int i; |
4633 | | |
4634 | 339 | if (n_props == 0) { |
4635 | 0 | return; |
4636 | 0 | } |
4637 | 1.25k | for (i = 0; i < n_props; i++) { |
4638 | 914 | format_ed_prop(s, prop); |
4639 | 914 | ds_put_char(s, ','); |
4640 | 914 | p += ROUND_UP(prop->len, 8); |
4641 | 914 | prop = ALIGNED_CAST(const struct ofpact_ed_prop *, p); |
4642 | 914 | } |
4643 | 339 | if (n_props > 0) { |
4644 | 339 | ds_chomp(s, ','); |
4645 | 339 | } |
4646 | 339 | } |
4647 | | |
4648 | | static void |
4649 | | format_ENCAP(const struct ofpact_encap *a, |
4650 | | const struct ofpact_format_params *fp) |
4651 | 1.55k | { |
4652 | 1.55k | ds_put_format(fp->s, "%sencap(%s", colors.paren, colors.end); |
4653 | 1.55k | ds_put_format(fp->s, "%s", format_encap_pkt_type(a->new_pkt_type)); |
4654 | 1.55k | if (a->n_props > 0) { |
4655 | 339 | ds_put_format(fp->s, "%s(%s", colors.paren, colors.end); |
4656 | 339 | format_ed_props(fp->s, a->n_props, a->props); |
4657 | 339 | ds_put_format(fp->s, "%s)%s", colors.paren, colors.end); |
4658 | 339 | } |
4659 | 1.55k | ds_put_format(fp->s, "%s)%s", colors.paren, colors.end); |
4660 | 1.55k | } |
4661 | | |
4662 | | static enum ofperr |
4663 | | check_ENCAP(const struct ofpact_encap *a, struct ofpact_check_params *cp) |
4664 | 1.21k | { |
4665 | 1.21k | struct flow *flow = &cp->match->flow; |
4666 | 1.21k | flow->packet_type = a->new_pkt_type; |
4667 | 1.21k | if (pt_ns(flow->packet_type) == OFPHTN_ETHERTYPE) { |
4668 | 1.10k | flow->dl_type = htons(pt_ns_type(flow->packet_type)); |
4669 | 1.10k | } |
4670 | 1.21k | if (!is_ip_any(flow)) { |
4671 | 1.21k | flow->nw_proto = 0; |
4672 | 1.21k | } |
4673 | 1.21k | return 0; |
4674 | 1.21k | } |
4675 | | |
4676 | | /* Action structure for NXAST_DECAP */ |
4677 | | struct nx_action_decap { |
4678 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
4679 | | ovs_be16 len; /* Total size including any property TLVs. */ |
4680 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
4681 | | ovs_be16 subtype; /* NXAST_DECAP. */ |
4682 | | uint8_t pad[2]; /* 2 bytes padding */ |
4683 | | |
4684 | | /* Packet type or result. |
4685 | | * |
4686 | | * The special value (0,0xFFFE) "Use next proto" |
4687 | | * is used to request OVS to automatically set the new packet type based |
4688 | | * on the decap'ed header's next protocol. |
4689 | | */ |
4690 | | ovs_be32 new_pkt_type; |
4691 | | }; |
4692 | | OFP_ASSERT(sizeof(struct nx_action_decap) == 16); |
4693 | | |
4694 | | static enum ofperr |
4695 | | decode_NXAST_RAW_DECAP(const struct nx_action_decap *nad, |
4696 | | enum ofp_version ofp_version OVS_UNUSED, |
4697 | | struct ofpbuf *ofpacts) |
4698 | 22.9k | { |
4699 | 22.9k | struct ofpact_decap * decap; |
4700 | | |
4701 | 22.9k | if (ntohs(nad->len) > sizeof *nad) { |
4702 | | /* No properties supported yet. */ |
4703 | 10 | return OFPERR_NXBAC_UNKNOWN_ED_PROP; |
4704 | 10 | } |
4705 | | |
4706 | 22.9k | decap = ofpact_put_DECAP(ofpacts); |
4707 | 22.9k | decap->ofpact.raw = NXAST_RAW_DECAP; |
4708 | 22.9k | decap->new_pkt_type = nad->new_pkt_type; |
4709 | 22.9k | return 0; |
4710 | 22.9k | } |
4711 | | |
4712 | | static void |
4713 | | encode_DECAP(const struct ofpact_decap *decap, |
4714 | | enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out) |
4715 | 0 | { |
4716 | 0 | struct nx_action_decap *nad = put_NXAST_DECAP(out); |
4717 | |
|
4718 | 0 | nad->len = htons(sizeof(struct nx_action_decap)); |
4719 | 0 | nad->new_pkt_type = decap->new_pkt_type; |
4720 | 0 | } |
4721 | | |
4722 | | static char * OVS_WARN_UNUSED_RESULT |
4723 | | parse_DECAP(char *arg, const struct ofpact_parse_params *pp) |
4724 | 0 | { |
4725 | 0 | struct ofpact_decap *decap; |
4726 | 0 | char *key, *value, *pos; |
4727 | 0 | char *error = NULL; |
4728 | 0 | uint16_t ns, type; |
4729 | |
|
4730 | 0 | decap = ofpact_put_DECAP(pp->ofpacts); |
4731 | | /* Default next packet_type is PT_USE_NEXT_PROTO. */ |
4732 | 0 | decap->new_pkt_type = htonl(PT_USE_NEXT_PROTO); |
4733 | | |
4734 | | /* Parse decap packet_type if given. */ |
4735 | 0 | if (ofputil_parse_key_value(&arg, &key, &value)) { |
4736 | 0 | if (strcmp(key, "packet_type") == 0) { |
4737 | 0 | pos = value; |
4738 | 0 | if (!ofputil_parse_key_value(&pos, &key, &value) |
4739 | 0 | || strcmp(key, "ns") != 0) { |
4740 | 0 | return xstrdup("Missing packet_type attribute ns"); |
4741 | 0 | } |
4742 | 0 | error = str_to_u16(value, "ns", &ns); |
4743 | 0 | if (error) { |
4744 | 0 | return error; |
4745 | 0 | } |
4746 | 0 | if (ns >= OFPHTN_N_TYPES) { |
4747 | 0 | return xasprintf("Unsupported ns value: %"PRIu16, ns); |
4748 | 0 | } |
4749 | 0 | if (!ofputil_parse_key_value(&pos, &key, &value) |
4750 | 0 | || strcmp(key, "type") != 0) { |
4751 | 0 | return xstrdup("Missing packet_type attribute type"); |
4752 | 0 | } |
4753 | 0 | error = str_to_u16(value, "type", &type); |
4754 | 0 | if (error) { |
4755 | 0 | return error; |
4756 | 0 | } |
4757 | 0 | decap->new_pkt_type = htonl(PACKET_TYPE(ns, type)); |
4758 | 0 | } else { |
4759 | 0 | return xasprintf("Invalid decap argument: %s", key); |
4760 | 0 | } |
4761 | 0 | } |
4762 | 0 | return NULL; |
4763 | 0 | } |
4764 | | |
4765 | | static void |
4766 | | format_DECAP(const struct ofpact_decap *a, |
4767 | | const struct ofpact_format_params *fp) |
4768 | 13.8k | { |
4769 | 13.8k | ds_put_format(fp->s, "%sdecap(%s", colors.paren, colors.end); |
4770 | 13.8k | if (a->new_pkt_type != htonl(PT_USE_NEXT_PROTO)) { |
4771 | 13.8k | ds_put_format(fp->s, "packet_type(ns=%"PRIu16",type=%#"PRIx16")", |
4772 | 13.8k | pt_ns(a->new_pkt_type), |
4773 | 13.8k | pt_ns_type(a->new_pkt_type)); |
4774 | 13.8k | } |
4775 | 13.8k | ds_put_format(fp->s, "%s)%s", colors.paren, colors.end); |
4776 | 13.8k | } |
4777 | | |
4778 | | static enum ofperr |
4779 | | check_DECAP(const struct ofpact_decap *a OVS_UNUSED, |
4780 | | struct ofpact_check_params *cp) |
4781 | 16.4k | { |
4782 | 16.4k | struct flow *flow = &cp->match->flow; |
4783 | 16.4k | if (flow->packet_type == htonl(PT_ETH)) { |
4784 | | /* Adjust the packet_type to allow subsequent actions. */ |
4785 | 9.82k | flow->packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE, |
4786 | 9.82k | ntohs(flow->dl_type)); |
4787 | 9.82k | } else { |
4788 | | /* The actual packet_type is only known after decapsulation. |
4789 | | * Do not allow subsequent actions that depend on packet headers. */ |
4790 | 6.60k | flow->packet_type = htonl(PT_UNKNOWN); |
4791 | 6.60k | flow->dl_type = OVS_BE16_MAX; |
4792 | 6.60k | } |
4793 | 16.4k | return 0; |
4794 | 16.4k | } |
4795 | | |
4796 | | /* Action dec_nsh_ttl */ |
4797 | | |
4798 | | static enum ofperr |
4799 | | decode_NXAST_RAW_DEC_NSH_TTL(struct ofpbuf *out) |
4800 | 192 | { |
4801 | 192 | ofpact_put_DEC_NSH_TTL(out); |
4802 | 192 | return 0; |
4803 | 192 | } |
4804 | | |
4805 | | static void |
4806 | | encode_DEC_NSH_TTL(const struct ofpact_null *null OVS_UNUSED, |
4807 | | enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out) |
4808 | 0 | { |
4809 | 0 | put_NXAST_DEC_NSH_TTL(out); |
4810 | 0 | } |
4811 | | |
4812 | | static char * OVS_WARN_UNUSED_RESULT |
4813 | | parse_DEC_NSH_TTL(char *arg OVS_UNUSED, const struct ofpact_parse_params *pp) |
4814 | 0 | { |
4815 | 0 | ofpact_put_DEC_NSH_TTL(pp->ofpacts); |
4816 | 0 | return NULL; |
4817 | 0 | } |
4818 | | |
4819 | | static void |
4820 | | format_DEC_NSH_TTL(const struct ofpact_null *a OVS_UNUSED, |
4821 | | const struct ofpact_format_params *fp) |
4822 | 27 | { |
4823 | 27 | ds_put_format(fp->s, "%sdec_nsh_ttl%s", colors.special, colors.end); |
4824 | 27 | } |
4825 | | |
4826 | | static enum ofperr |
4827 | | check_DEC_NSH_TTL(const struct ofpact_null *a OVS_UNUSED, |
4828 | | struct ofpact_check_params *cp) |
4829 | 111 | { |
4830 | 111 | struct flow *flow = &cp->match->flow; |
4831 | 111 | if (flow->packet_type != htonl(PT_NSH) && |
4832 | 111 | flow->dl_type != htons(ETH_TYPE_NSH)) { |
4833 | 111 | inconsistent_match(&cp->usable_protocols); |
4834 | 111 | } |
4835 | 111 | return 0; |
4836 | 111 | } |
4837 | | |
4838 | | /* Action structures for NXAST_RESUBMIT, NXAST_RESUBMIT_TABLE, and |
4839 | | * NXAST_RESUBMIT_TABLE_CT. |
4840 | | * |
4841 | | * These actions search one of the switch's flow tables: |
4842 | | * |
4843 | | * - For NXAST_RESUBMIT_TABLE and NXAST_RESUBMIT_TABLE_CT, if the |
4844 | | * 'table' member is not 255, then it specifies the table to search. |
4845 | | * |
4846 | | * - Otherwise (for NXAST_RESUBMIT_TABLE or NXAST_RESUBMIT_TABLE_CT with a |
4847 | | * 'table' of 255, or for NXAST_RESUBMIT regardless of 'table'), it |
4848 | | * searches the current flow table, that is, the OpenFlow flow table that |
4849 | | * contains the flow from which this action was obtained. If this action |
4850 | | * did not come from a flow table (e.g. it came from an OFPT_PACKET_OUT |
4851 | | * message), then table 0 is the current table. |
4852 | | * |
4853 | | * The flow table lookup uses a flow that may be slightly modified from the |
4854 | | * original lookup: |
4855 | | * |
4856 | | * - For NXAST_RESUBMIT, the 'in_port' member of struct nx_action_resubmit |
4857 | | * is used as the flow's in_port. |
4858 | | * |
4859 | | * - For NXAST_RESUBMIT_TABLE and NXAST_RESUBMIT_TABLE_CT, if the 'in_port' |
4860 | | * member is not OFPP_IN_PORT, then its value is used as the flow's |
4861 | | * in_port. Otherwise, the original in_port is used. |
4862 | | * |
4863 | | * - For NXAST_RESUBMIT_TABLE_CT the Conntrack 5-tuple fields are used as |
4864 | | * the packets IP header fields during the lookup. |
4865 | | * |
4866 | | * - If actions that modify the flow (e.g. OFPAT_SET_VLAN_VID) precede the |
4867 | | * resubmit action, then the flow is updated with the new values. |
4868 | | * |
4869 | | * Following the lookup, the original in_port is restored. |
4870 | | * |
4871 | | * If the modified flow matched in the flow table, then the corresponding |
4872 | | * actions are executed. Afterward, actions following the resubmit in the |
4873 | | * original set of actions, if any, are executed; any changes made to the |
4874 | | * packet (e.g. changes to VLAN) by secondary actions persist when those |
4875 | | * actions are executed, although the original in_port is restored. |
4876 | | * |
4877 | | * Resubmit actions may be used any number of times within a set of actions. |
4878 | | * |
4879 | | * Resubmit actions may nest. To prevent infinite loops and excessive resource |
4880 | | * use, the implementation may limit nesting depth and the total number of |
4881 | | * resubmits: |
4882 | | * |
4883 | | * - Open vSwitch 1.0.1 and earlier did not support recursion. |
4884 | | * |
4885 | | * - Open vSwitch 1.0.2 and 1.0.3 limited recursion to 8 levels. |
4886 | | * |
4887 | | * - Open vSwitch 1.1 and 1.2 limited recursion to 16 levels. |
4888 | | * |
4889 | | * - Open vSwitch 1.2 through 1.8 limited recursion to 32 levels. |
4890 | | * |
4891 | | * - Open vSwitch 1.9 through 2.0 limited recursion to 64 levels. |
4892 | | * |
4893 | | * - Open vSwitch 2.1 through 2.5 limited recursion to 64 levels and impose |
4894 | | * a total limit of 4,096 resubmits per flow translation (earlier versions |
4895 | | * did not impose any total limit). |
4896 | | * |
4897 | | * NXAST_RESUBMIT ignores 'table' and 'pad'. NXAST_RESUBMIT_TABLE and |
4898 | | * NXAST_RESUBMIT_TABLE_CT require 'pad' to be all-bits-zero. |
4899 | | * |
4900 | | * Open vSwitch 1.0.1 and earlier did not support recursion. Open vSwitch |
4901 | | * before 1.2.90 did not support NXAST_RESUBMIT_TABLE. Open vSwitch before |
4902 | | * 2.8.0 did not support NXAST_RESUBMIT_TABLE_CT. |
4903 | | */ |
4904 | | struct nx_action_resubmit { |
4905 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
4906 | | ovs_be16 len; /* Length is 16. */ |
4907 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
4908 | | ovs_be16 subtype; /* NXAST_RESUBMIT. */ |
4909 | | ovs_be16 in_port; /* New in_port for checking flow table. */ |
4910 | | uint8_t table; /* NXAST_RESUBMIT_TABLE: table to use. */ |
4911 | | uint8_t pad[3]; |
4912 | | }; |
4913 | | OFP_ASSERT(sizeof(struct nx_action_resubmit) == 16); |
4914 | | |
4915 | | static enum ofperr |
4916 | | decode_NXAST_RAW_RESUBMIT(uint16_t port, |
4917 | | enum ofp_version ofp_version OVS_UNUSED, |
4918 | | struct ofpbuf *out) |
4919 | 811 | { |
4920 | 811 | struct ofpact_resubmit *resubmit; |
4921 | | |
4922 | 811 | resubmit = ofpact_put_RESUBMIT(out); |
4923 | 811 | resubmit->ofpact.raw = NXAST_RAW_RESUBMIT; |
4924 | 811 | resubmit->in_port = u16_to_ofp(port); |
4925 | 811 | resubmit->table_id = 0xff; |
4926 | 811 | return 0; |
4927 | 811 | } |
4928 | | |
4929 | | static enum ofperr |
4930 | | decode_NXAST_RAW_RESUBMIT_TABLE(const struct nx_action_resubmit *nar, |
4931 | | enum ofp_version ofp_version OVS_UNUSED, |
4932 | | struct ofpbuf *out) |
4933 | 2.84k | { |
4934 | 2.84k | struct ofpact_resubmit *resubmit; |
4935 | | |
4936 | 2.84k | if (nar->pad[0] || nar->pad[1] || nar->pad[2]) { |
4937 | 1.19k | return OFPERR_OFPBAC_BAD_ARGUMENT; |
4938 | 1.19k | } |
4939 | | |
4940 | 1.64k | resubmit = ofpact_put_RESUBMIT(out); |
4941 | 1.64k | resubmit->ofpact.raw = NXAST_RAW_RESUBMIT_TABLE; |
4942 | 1.64k | resubmit->in_port = u16_to_ofp(ntohs(nar->in_port)); |
4943 | 1.64k | resubmit->table_id = nar->table; |
4944 | 1.64k | return 0; |
4945 | 2.84k | } |
4946 | | |
4947 | | static enum ofperr |
4948 | | decode_NXAST_RAW_RESUBMIT_TABLE_CT(const struct nx_action_resubmit *nar, |
4949 | | enum ofp_version ofp_version OVS_UNUSED, |
4950 | | struct ofpbuf *out) |
4951 | 1.64k | { |
4952 | 1.64k | enum ofperr error = decode_NXAST_RAW_RESUBMIT_TABLE(nar, ofp_version, out); |
4953 | 1.64k | if (error) { |
4954 | 785 | return error; |
4955 | 785 | } |
4956 | 861 | struct ofpact_resubmit *resubmit = out->header; |
4957 | 861 | resubmit->ofpact.raw = NXAST_RAW_RESUBMIT_TABLE_CT; |
4958 | 861 | resubmit->with_ct_orig = true; |
4959 | 861 | return 0; |
4960 | 1.64k | } |
4961 | | |
4962 | | static void |
4963 | | encode_RESUBMIT(const struct ofpact_resubmit *resubmit, |
4964 | | enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out) |
4965 | 0 | { |
4966 | 0 | uint16_t in_port = ofp_to_u16(resubmit->in_port); |
4967 | |
|
4968 | 0 | if (resubmit->table_id == 0xff |
4969 | 0 | && resubmit->ofpact.raw == NXAST_RAW_RESUBMIT) { |
4970 | 0 | put_NXAST_RESUBMIT(out, in_port); |
4971 | 0 | } else { |
4972 | 0 | struct nx_action_resubmit *nar; |
4973 | 0 | nar = resubmit->with_ct_orig |
4974 | 0 | ? put_NXAST_RESUBMIT_TABLE_CT(out) : put_NXAST_RESUBMIT_TABLE(out); |
4975 | 0 | nar->table = resubmit->table_id; |
4976 | 0 | nar->in_port = htons(in_port); |
4977 | 0 | } |
4978 | 0 | } |
4979 | | |
4980 | | static char * OVS_WARN_UNUSED_RESULT |
4981 | | parse_RESUBMIT(char *arg, const struct ofpact_parse_params *pp) |
4982 | 0 | { |
4983 | 0 | struct ofpact_resubmit *resubmit; |
4984 | 0 | char *in_port_s, *table_s, *ct_s; |
4985 | |
|
4986 | 0 | resubmit = ofpact_put_RESUBMIT(pp->ofpacts); |
4987 | |
|
4988 | 0 | in_port_s = strsep(&arg, ","); |
4989 | 0 | if (in_port_s && in_port_s[0]) { |
4990 | 0 | if (!ofputil_port_from_string(in_port_s, pp->port_map, |
4991 | 0 | &resubmit->in_port)) { |
4992 | 0 | return xasprintf("%s: resubmit to unknown port", in_port_s); |
4993 | 0 | } |
4994 | 0 | } else { |
4995 | 0 | resubmit->in_port = OFPP_IN_PORT; |
4996 | 0 | } |
4997 | | |
4998 | 0 | table_s = strsep(&arg, ","); |
4999 | 0 | if (table_s && table_s[0]) { |
5000 | 0 | if (!ofputil_table_from_string(table_s, pp->table_map, |
5001 | 0 | &resubmit->table_id)) { |
5002 | 0 | return xasprintf("%s: resubmit to unknown table", table_s); |
5003 | 0 | } |
5004 | 0 | } else { |
5005 | 0 | resubmit->table_id = 255; |
5006 | 0 | } |
5007 | | |
5008 | 0 | ct_s = strsep(&arg, ","); |
5009 | 0 | if (ct_s && ct_s[0]) { |
5010 | 0 | if (strcmp(ct_s, "ct")) { |
5011 | 0 | return xasprintf("%s: unknown parameter", ct_s); |
5012 | 0 | } |
5013 | 0 | resubmit->with_ct_orig = true; |
5014 | 0 | } else { |
5015 | 0 | resubmit->with_ct_orig = false; |
5016 | 0 | } |
5017 | | |
5018 | 0 | if (resubmit->in_port == OFPP_IN_PORT && resubmit->table_id == 255) { |
5019 | 0 | return xstrdup("at least one \"in_port\" or \"table\" must be " |
5020 | 0 | "specified on resubmit"); |
5021 | 0 | } |
5022 | 0 | return NULL; |
5023 | 0 | } |
5024 | | |
5025 | | static void |
5026 | | format_RESUBMIT(const struct ofpact_resubmit *a, |
5027 | | const struct ofpact_format_params *fp) |
5028 | 1.65k | { |
5029 | 1.65k | if (a->in_port != OFPP_IN_PORT && a->table_id == 255) { |
5030 | 23 | ds_put_format(fp->s, "%sresubmit:%s", colors.special, colors.end); |
5031 | 23 | ofputil_format_port(a->in_port, fp->port_map, fp->s); |
5032 | 1.63k | } else { |
5033 | 1.63k | ds_put_format(fp->s, "%sresubmit(%s", colors.paren, colors.end); |
5034 | 1.63k | if (a->in_port != OFPP_IN_PORT) { |
5035 | 1.61k | ofputil_format_port(a->in_port, fp->port_map, fp->s); |
5036 | 1.61k | } |
5037 | 1.63k | ds_put_char(fp->s, ','); |
5038 | 1.63k | if (a->table_id != 255) { |
5039 | 1.61k | ofputil_format_table(a->table_id, fp->table_map, fp->s); |
5040 | 1.61k | } |
5041 | 1.63k | if (a->with_ct_orig) { |
5042 | 826 | ds_put_cstr(fp->s, ",ct"); |
5043 | 826 | } |
5044 | 1.63k | ds_put_format(fp->s, "%s)%s", colors.paren, colors.end); |
5045 | 1.63k | } |
5046 | 1.65k | } |
5047 | | |
5048 | | static enum ofperr |
5049 | | check_RESUBMIT(const struct ofpact_resubmit *a, |
5050 | | const struct ofpact_check_params *cp) |
5051 | 24 | { |
5052 | 24 | if (a->with_ct_orig && !is_ct_valid(&cp->match->flow, &cp->match->wc, |
5053 | 10 | NULL)) { |
5054 | 10 | return OFPERR_OFPBAC_MATCH_INCONSISTENT; |
5055 | 10 | } |
5056 | 14 | return 0; |
5057 | 24 | } |
5058 | | |
5059 | | /* Action structure for NXAST_LEARN and NXAST_LEARN2. |
5060 | | * |
5061 | | * This action adds or modifies a flow in an OpenFlow table, similar to |
5062 | | * OFPT_FLOW_MOD with OFPFC_MODIFY_STRICT as 'command'. The new flow has the |
5063 | | * specified idle timeout, hard timeout, priority, cookie, and flags. The new |
5064 | | * flow's match criteria and actions are built by applying each of the series |
5065 | | * of flow_mod_spec elements included as part of the action. |
5066 | | * |
5067 | | * A flow_mod_spec starts with a 16-bit header. A header that is all-bits-0 is |
5068 | | * a no-op used for padding the action as a whole to a multiple of 8 bytes in |
5069 | | * length. Otherwise, the flow_mod_spec can be thought of as copying 'n_bits' |
5070 | | * bits from a source to a destination. In this case, the header contains |
5071 | | * multiple fields: |
5072 | | * |
5073 | | * 15 14 13 12 11 10 0 |
5074 | | * +------+---+------+---------------------------------+ |
5075 | | * | 0 |src| dst | n_bits | |
5076 | | * +------+---+------+---------------------------------+ |
5077 | | * |
5078 | | * The meaning and format of a flow_mod_spec depends on 'src' and 'dst'. The |
5079 | | * following table summarizes the meaning of each possible combination. |
5080 | | * Details follow the table: |
5081 | | * |
5082 | | * src dst meaning |
5083 | | * --- --- ---------------------------------------------------------- |
5084 | | * 0 0 Add match criteria based on value in a field. |
5085 | | * 1 0 Add match criteria based on an immediate value. |
5086 | | * 0 1 Add NXAST_REG_LOAD action to copy field into a different field. |
5087 | | * 1 1 Add NXAST_REG_LOAD action to load immediate value into a field. |
5088 | | * 0 2 Add OFPAT_OUTPUT action to output to port from specified field. |
5089 | | * All other combinations are undefined and not allowed. |
5090 | | * |
5091 | | * The flow_mod_spec header is followed by a source specification and a |
5092 | | * destination specification. The format and meaning of the source |
5093 | | * specification depends on 'src': |
5094 | | * |
5095 | | * - If 'src' is 0, the source bits are taken from a field in the flow to |
5096 | | * which this action is attached. (This should be a wildcarded field. If |
5097 | | * its value is fully specified then the source bits being copied have |
5098 | | * constant values.) |
5099 | | * |
5100 | | * The source specification is an ovs_be32 'field' and an ovs_be16 'ofs'. |
5101 | | * 'field' is an nxm_header with nxm_hasmask=0, and 'ofs' the starting bit |
5102 | | * offset within that field. The source bits are field[ofs:ofs+n_bits-1]. |
5103 | | * 'field' and 'ofs' are subject to the same restrictions as the source |
5104 | | * field in NXAST_REG_MOVE. |
5105 | | * |
5106 | | * - If 'src' is 1, the source bits are a constant value. The source |
5107 | | * specification is (n_bits+15)/16*2 bytes long. Taking those bytes as a |
5108 | | * number in network order, the source bits are the 'n_bits' |
5109 | | * least-significant bits. The switch will report an error if other bits |
5110 | | * in the constant are nonzero. |
5111 | | * |
5112 | | * The flow_mod_spec destination specification, for 'dst' of 0 or 1, is an |
5113 | | * ovs_be32 'field' and an ovs_be16 'ofs'. 'field' is an nxm_header with |
5114 | | * nxm_hasmask=0 and 'ofs' is a starting bit offset within that field. The |
5115 | | * meaning of the flow_mod_spec depends on 'dst': |
5116 | | * |
5117 | | * - If 'dst' is 0, the flow_mod_spec specifies match criteria for the new |
5118 | | * flow. The new flow matches only if bits field[ofs:ofs+n_bits-1] in a |
5119 | | * packet equal the source bits. 'field' may be any nxm_header with |
5120 | | * nxm_hasmask=0 that is allowed in NXT_FLOW_MOD. |
5121 | | * |
5122 | | * Order is significant. Earlier flow_mod_specs must satisfy any |
5123 | | * prerequisites for matching fields specified later, by copying constant |
5124 | | * values into prerequisite fields. |
5125 | | * |
5126 | | * The switch will reject flow_mod_specs that do not satisfy NXM masking |
5127 | | * restrictions. |
5128 | | * |
5129 | | * - If 'dst' is 1, the flow_mod_spec specifies an NXAST_REG_LOAD action for |
5130 | | * the new flow. The new flow copies the source bits into |
5131 | | * field[ofs:ofs+n_bits-1]. Actions are executed in the same order as the |
5132 | | * flow_mod_specs. |
5133 | | * |
5134 | | * A single NXAST_REG_LOAD action writes no more than 64 bits, so n_bits |
5135 | | * greater than 64 yields multiple NXAST_REG_LOAD actions. |
5136 | | * |
5137 | | * The flow_mod_spec destination spec for 'dst' of 2 (when 'src' is 0) is |
5138 | | * empty. It has the following meaning: |
5139 | | * |
5140 | | * - The flow_mod_spec specifies an OFPAT_OUTPUT action for the new flow. |
5141 | | * The new flow outputs to the OpenFlow port specified by the source field. |
5142 | | * Of the special output ports with value OFPP_MAX or larger, OFPP_IN_PORT, |
5143 | | * OFPP_FLOOD, OFPP_LOCAL, and OFPP_ALL are supported. Other special ports |
5144 | | * may not be used. |
5145 | | * |
5146 | | * Resource Management |
5147 | | * ------------------- |
5148 | | * |
5149 | | * A switch has a finite amount of flow table space available for learning. |
5150 | | * When this space is exhausted, no new learning table entries will be learned |
5151 | | * until some existing flow table entries expire. The controller should be |
5152 | | * prepared to handle this by flooding (which can be implemented as a |
5153 | | * low-priority flow). |
5154 | | * |
5155 | | * If a learned flow matches a single TCP stream with a relatively long |
5156 | | * timeout, one may make the best of resource constraints by setting |
5157 | | * 'fin_idle_timeout' or 'fin_hard_timeout' (both measured in seconds), or |
5158 | | * both, to shorter timeouts. When either of these is specified as a nonzero |
5159 | | * value, OVS adds a NXAST_FIN_TIMEOUT action, with the specified timeouts, to |
5160 | | * the learned flow. |
5161 | | * |
5162 | | * Examples |
5163 | | * -------- |
5164 | | * |
5165 | | * The following examples give a prose description of the flow_mod_specs along |
5166 | | * with informal notation for how those would be represented and a hex dump of |
5167 | | * the bytes that would be required. |
5168 | | * |
5169 | | * These examples could work with various nx_action_learn parameters. Typical |
5170 | | * values would be idle_timeout=OFP_FLOW_PERMANENT, hard_timeout=60, |
5171 | | * priority=OFP_DEFAULT_PRIORITY, flags=0, table_id=10. |
5172 | | * |
5173 | | * 1. Learn input port based on the source MAC, with lookup into |
5174 | | * NXM_NX_REG1[16:31] by resubmit to in_port=99: |
5175 | | * |
5176 | | * Match on in_port=99: |
5177 | | * ovs_be16(src=1, dst=0, n_bits=16), 20 10 |
5178 | | * ovs_be16(99), 00 63 |
5179 | | * ovs_be32(NXM_OF_IN_PORT), ovs_be16(0) 00 00 00 02 00 00 |
5180 | | * |
5181 | | * Match Ethernet destination on Ethernet source from packet: |
5182 | | * ovs_be16(src=0, dst=0, n_bits=48), 00 30 |
5183 | | * ovs_be32(NXM_OF_ETH_SRC), ovs_be16(0) 00 00 04 06 00 00 |
5184 | | * ovs_be32(NXM_OF_ETH_DST), ovs_be16(0) 00 00 02 06 00 00 |
5185 | | * |
5186 | | * Set NXM_NX_REG1[16:31] to the packet's input port: |
5187 | | * ovs_be16(src=0, dst=1, n_bits=16), 08 10 |
5188 | | * ovs_be32(NXM_OF_IN_PORT), ovs_be16(0) 00 00 00 02 00 00 |
5189 | | * ovs_be32(NXM_NX_REG1), ovs_be16(16) 00 01 02 04 00 10 |
5190 | | * |
5191 | | * Given a packet that arrived on port A with Ethernet source address B, |
5192 | | * this would set up the flow "in_port=99, dl_dst=B, |
5193 | | * actions=load:A->NXM_NX_REG1[16..31]". |
5194 | | * |
5195 | | * In syntax accepted by ovs-ofctl, this action is: learn(in_port=99, |
5196 | | * NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[], |
5197 | | * load:NXM_OF_IN_PORT[]->NXM_NX_REG1[16..31]) |
5198 | | * |
5199 | | * 2. Output to input port based on the source MAC and VLAN VID, with lookup |
5200 | | * into NXM_NX_REG1[16:31]: |
5201 | | * |
5202 | | * Match on same VLAN ID as packet: |
5203 | | * ovs_be16(src=0, dst=0, n_bits=12), 00 0c |
5204 | | * ovs_be32(NXM_OF_VLAN_TCI), ovs_be16(0) 00 00 08 02 00 00 |
5205 | | * ovs_be32(NXM_OF_VLAN_TCI), ovs_be16(0) 00 00 08 02 00 00 |
5206 | | * |
5207 | | * Match Ethernet destination on Ethernet source from packet: |
5208 | | * ovs_be16(src=0, dst=0, n_bits=48), 00 30 |
5209 | | * ovs_be32(NXM_OF_ETH_SRC), ovs_be16(0) 00 00 04 06 00 00 |
5210 | | * ovs_be32(NXM_OF_ETH_DST), ovs_be16(0) 00 00 02 06 00 00 |
5211 | | * |
5212 | | * Output to the packet's input port: |
5213 | | * ovs_be16(src=0, dst=2, n_bits=16), 10 10 |
5214 | | * ovs_be32(NXM_OF_IN_PORT), ovs_be16(0) 00 00 00 02 00 00 |
5215 | | * |
5216 | | * Given a packet that arrived on port A with Ethernet source address B in |
5217 | | * VLAN C, this would set up the flow "dl_dst=B, vlan_vid=C, |
5218 | | * actions=output:A". |
5219 | | * |
5220 | | * In syntax accepted by ovs-ofctl, this action is: |
5221 | | * learn(NXM_OF_VLAN_TCI[0..11], NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[], |
5222 | | * output:NXM_OF_IN_PORT[]) |
5223 | | * |
5224 | | * 3. Here's a recipe for a very simple-minded MAC learning switch. It uses a |
5225 | | * 10-second MAC expiration time to make it easier to see what's going on |
5226 | | * |
5227 | | * ovs-vsctl del-controller br0 |
5228 | | * ovs-ofctl del-flows br0 |
5229 | | * ovs-ofctl add-flow br0 "table=0 actions=learn(table=1, \ |
5230 | | hard_timeout=10, NXM_OF_VLAN_TCI[0..11], \ |
5231 | | NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[], \ |
5232 | | output:NXM_OF_IN_PORT[]), resubmit(,1)" |
5233 | | * ovs-ofctl add-flow br0 "table=1 priority=0 actions=flood" |
5234 | | * |
5235 | | * You can then dump the MAC learning table with: |
5236 | | * |
5237 | | * ovs-ofctl dump-flows br0 table=1 |
5238 | | * |
5239 | | * Usage Advice |
5240 | | * ------------ |
5241 | | * |
5242 | | * For best performance, segregate learned flows into a table that is not used |
5243 | | * for any other flows except possibly for a lowest-priority "catch-all" flow |
5244 | | * (a flow with no match criteria). If different learning actions specify |
5245 | | * different match criteria, use different tables for the learned flows. |
5246 | | * |
5247 | | * The meaning of 'hard_timeout' and 'idle_timeout' can be counterintuitive. |
5248 | | * These timeouts apply to the flow that is added, which means that a flow with |
5249 | | * an idle timeout will expire when no traffic has been sent *to* the learned |
5250 | | * address. This is not usually the intent in MAC learning; instead, we want |
5251 | | * the MAC learn entry to expire when no traffic has been sent *from* the |
5252 | | * learned address. Use a hard timeout for that. |
5253 | | * |
5254 | | * |
5255 | | * Visibility of Changes |
5256 | | * --------------------- |
5257 | | * |
5258 | | * Prior to Open vSwitch 2.4, any changes made by a "learn" action in a given |
5259 | | * flow translation are visible to flow table lookups made later in the flow |
5260 | | * translation. This means that, in the example above, a MAC learned by the |
5261 | | * learn action in table 0 would be found in table 1 (if the packet being |
5262 | | * processed had the same source and destination MAC address). |
5263 | | * |
5264 | | * In Open vSwitch 2.4 and later, changes to a flow table (whether to add or |
5265 | | * modify a flow) by a "learn" action are visible only for later flow |
5266 | | * translations, not for later lookups within the same flow translation. In |
5267 | | * the MAC learning example, a MAC learned by the learn action in table 0 would |
5268 | | * not be found in table 1 if the flow translation would resubmit to table 1 |
5269 | | * after the processing of the learn action, meaning that if this MAC had not |
5270 | | * been learned before then the packet would be flooded. */ |
5271 | | struct nx_action_learn { |
5272 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
5273 | | ovs_be16 len; /* At least 24. */ |
5274 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
5275 | | ovs_be16 subtype; /* NXAST_LEARN. */ |
5276 | | ovs_be16 idle_timeout; /* Idle time before discarding (seconds). */ |
5277 | | ovs_be16 hard_timeout; /* Max time before discarding (seconds). */ |
5278 | | ovs_be16 priority; /* Priority level of flow entry. */ |
5279 | | ovs_be64 cookie; /* Cookie for new flow. */ |
5280 | | ovs_be16 flags; /* NX_LEARN_F_*. */ |
5281 | | uint8_t table_id; /* Table to insert flow entry. */ |
5282 | | uint8_t pad; /* Must be zero. */ |
5283 | | ovs_be16 fin_idle_timeout; /* Idle timeout after FIN, if nonzero. */ |
5284 | | ovs_be16 fin_hard_timeout; /* Hard timeout after FIN, if nonzero. */ |
5285 | | /* Followed by a sequence of flow_mod_spec elements, as described above, |
5286 | | * until the end of the action is reached. */ |
5287 | | }; |
5288 | | OFP_ASSERT(sizeof(struct nx_action_learn) == 32); |
5289 | | |
5290 | | struct nx_action_learn2 { |
5291 | | struct nx_action_learn up; /* The wire format includes nx_action_learn. */ |
5292 | | ovs_be32 limit; /* Maximum number of learned flows. |
5293 | | * 0 indicates unlimited. */ |
5294 | | |
5295 | | /* Where to store the result. */ |
5296 | | ovs_be16 result_dst_ofs; /* Starting bit offset in destination. */ |
5297 | | |
5298 | | ovs_be16 pad2; /* Must be zero. */ |
5299 | | /* Followed by: |
5300 | | * - OXM/NXM header for destination field (4 or 8 bytes), |
5301 | | * if NX_LEARN_F_WRITE_RESULT is set in 'flags' |
5302 | | * - a sequence of flow_mod_spec elements, as described above, |
5303 | | * until the end of the action is reached. */ |
5304 | | }; |
5305 | | OFP_ASSERT(sizeof(struct nx_action_learn2) == 40); |
5306 | | |
5307 | | static ovs_be16 |
5308 | | get_be16(const void **pp) |
5309 | 102k | { |
5310 | 102k | const ovs_be16 *p = *pp; |
5311 | 102k | ovs_be16 value = *p; |
5312 | 102k | *pp = p + 1; |
5313 | 102k | return value; |
5314 | 102k | } |
5315 | | |
5316 | | static ovs_be32 |
5317 | | get_be32(const void **pp) |
5318 | 45.0k | { |
5319 | 45.0k | const ovs_be32 *p = *pp; |
5320 | 45.0k | ovs_be32 value = get_unaligned_be32(p); |
5321 | 45.0k | *pp = p + 1; |
5322 | 45.0k | return value; |
5323 | 45.0k | } |
5324 | | |
5325 | | static enum ofperr |
5326 | | get_subfield(int n_bits, const void **p, struct mf_subfield *sf, |
5327 | | const struct vl_mff_map *vl_mff_map, uint64_t *tlv_bitmap) |
5328 | 45.0k | { |
5329 | 45.0k | enum ofperr error; |
5330 | | |
5331 | 45.0k | error = mf_vl_mff_mf_from_nxm_header(ntohl(get_be32(p)), vl_mff_map, |
5332 | 45.0k | &sf->field, tlv_bitmap); |
5333 | 45.0k | sf->ofs = ntohs(get_be16(p)); |
5334 | 45.0k | sf->n_bits = n_bits; |
5335 | 45.0k | return error; |
5336 | 45.0k | } |
5337 | | |
5338 | | static unsigned int |
5339 | | learn_min_len(uint16_t header) |
5340 | 45.5k | { |
5341 | 45.5k | int n_bits = header & NX_LEARN_N_BITS_MASK; |
5342 | 45.5k | int src_type = header & NX_LEARN_SRC_MASK; |
5343 | 45.5k | int dst_type = header & NX_LEARN_DST_MASK; |
5344 | 45.5k | unsigned int min_len; |
5345 | | |
5346 | 45.5k | min_len = 0; |
5347 | 45.5k | if (src_type == NX_LEARN_SRC_FIELD) { |
5348 | 4.15k | min_len += sizeof(ovs_be32); /* src_field */ |
5349 | 4.15k | min_len += sizeof(ovs_be16); /* src_ofs */ |
5350 | 41.4k | } else { |
5351 | 41.4k | min_len += 2 * DIV_ROUND_UP(n_bits, 16); |
5352 | 41.4k | } |
5353 | 45.5k | if (dst_type == NX_LEARN_DST_MATCH || |
5354 | 45.5k | dst_type == NX_LEARN_DST_LOAD) { |
5355 | 42.4k | min_len += sizeof(ovs_be32); /* dst_field */ |
5356 | 42.4k | min_len += sizeof(ovs_be16); /* dst_ofs */ |
5357 | 42.4k | } |
5358 | 45.5k | return min_len; |
5359 | 45.5k | } |
5360 | | |
5361 | | static enum ofperr |
5362 | | decode_LEARN_common(const struct nx_action_learn *nal, |
5363 | | enum ofp_raw_action_type raw, |
5364 | | struct ofpact_learn *learn) |
5365 | 26.5k | { |
5366 | 26.5k | if (nal->pad) { |
5367 | 2.09k | return OFPERR_OFPBAC_BAD_ARGUMENT; |
5368 | 2.09k | } |
5369 | | |
5370 | 24.4k | learn->ofpact.raw = raw; |
5371 | 24.4k | learn->idle_timeout = ntohs(nal->idle_timeout); |
5372 | 24.4k | learn->hard_timeout = ntohs(nal->hard_timeout); |
5373 | 24.4k | learn->priority = ntohs(nal->priority); |
5374 | 24.4k | learn->cookie = nal->cookie; |
5375 | 24.4k | learn->table_id = nal->table_id; |
5376 | 24.4k | learn->fin_idle_timeout = ntohs(nal->fin_idle_timeout); |
5377 | 24.4k | learn->fin_hard_timeout = ntohs(nal->fin_hard_timeout); |
5378 | 24.4k | learn->flags = ntohs(nal->flags); |
5379 | | |
5380 | 24.4k | if (learn->table_id == 0xff) { |
5381 | 175 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
5382 | 175 | } |
5383 | | |
5384 | 24.2k | return 0; |
5385 | 24.4k | } |
5386 | | |
5387 | | static enum ofperr |
5388 | | decode_LEARN_specs(const void *p, const void *end, |
5389 | | const struct vl_mff_map *vl_mff_map, uint64_t *tlv_bitmap, |
5390 | | struct ofpbuf *ofpacts) |
5391 | 23.8k | { |
5392 | 23.8k | struct ofpact_learn *learn = ofpacts->header; |
5393 | | |
5394 | 66.3k | while (p != end) { |
5395 | 57.7k | struct ofpact_learn_spec *spec; |
5396 | 57.7k | uint16_t header = ntohs(get_be16(&p)); |
5397 | | |
5398 | 57.7k | if (!header) { |
5399 | 11.6k | break; |
5400 | 11.6k | } |
5401 | | |
5402 | 46.0k | spec = ofpbuf_put_zeros(ofpacts, sizeof *spec); |
5403 | 46.0k | learn = ofpacts->header; |
5404 | | |
5405 | 46.0k | spec->src_type = header & NX_LEARN_SRC_MASK; |
5406 | 46.0k | spec->dst_type = header & NX_LEARN_DST_MASK; |
5407 | 46.0k | spec->n_bits = header & NX_LEARN_N_BITS_MASK; |
5408 | | |
5409 | | /* Check for valid src and dst type combination. */ |
5410 | 46.0k | if (spec->dst_type == NX_LEARN_DST_MATCH || |
5411 | 46.0k | spec->dst_type == NX_LEARN_DST_LOAD || |
5412 | 46.0k | (spec->dst_type == NX_LEARN_DST_OUTPUT && |
5413 | 45.5k | spec->src_type == NX_LEARN_SRC_FIELD)) { |
5414 | | /* OK. */ |
5415 | 45.5k | } else { |
5416 | 481 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
5417 | 481 | } |
5418 | | |
5419 | | /* Check that the arguments don't overrun the end of the action. */ |
5420 | 45.5k | if ((char *) end - (char *) p < learn_min_len(header)) { |
5421 | 628 | return OFPERR_OFPBAC_BAD_LEN; |
5422 | 628 | } |
5423 | | |
5424 | | /* Get the source. */ |
5425 | 44.9k | const uint8_t *imm = NULL; |
5426 | 44.9k | unsigned int imm_bytes = 0; |
5427 | 44.9k | enum ofperr error; |
5428 | 44.9k | if (spec->src_type == NX_LEARN_SRC_FIELD) { |
5429 | 3.74k | error = get_subfield(spec->n_bits, &p, &spec->src, vl_mff_map, |
5430 | 3.74k | tlv_bitmap); |
5431 | 3.74k | if (error) { |
5432 | 661 | return error; |
5433 | 661 | } |
5434 | 41.2k | } else { |
5435 | 41.2k | int p_bytes = 2 * DIV_ROUND_UP(spec->n_bits, 16); |
5436 | 41.2k | p = (const uint8_t *) p + p_bytes; |
5437 | | |
5438 | 41.2k | imm_bytes = DIV_ROUND_UP(spec->n_bits, 8); |
5439 | 41.2k | imm = (const uint8_t *) p - imm_bytes; |
5440 | 41.2k | } |
5441 | | |
5442 | | /* Get the destination. */ |
5443 | 44.3k | if (spec->dst_type == NX_LEARN_DST_MATCH || |
5444 | 44.3k | spec->dst_type == NX_LEARN_DST_LOAD) { |
5445 | 41.2k | error = get_subfield(spec->n_bits, &p, &spec->dst, vl_mff_map, |
5446 | 41.2k | tlv_bitmap); |
5447 | 41.2k | if (error) { |
5448 | 1.71k | return error; |
5449 | 1.71k | } |
5450 | 41.2k | } |
5451 | | |
5452 | 42.5k | if (imm) { |
5453 | 39.5k | uint8_t *src_imm = ofpbuf_put_zeros(ofpacts, |
5454 | 39.5k | OFPACT_ALIGN(imm_bytes)); |
5455 | 39.5k | memcpy(src_imm, imm, imm_bytes); |
5456 | | |
5457 | 39.5k | learn = ofpacts->header; |
5458 | 39.5k | } |
5459 | 42.5k | } |
5460 | 20.3k | ofpact_finish_LEARN(ofpacts, &learn); |
5461 | | |
5462 | 20.3k | if (!is_all_zeros(p, (char *) end - (char *) p)) { |
5463 | 947 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
5464 | 947 | } |
5465 | | |
5466 | 19.3k | return 0; |
5467 | 20.3k | } |
5468 | | |
5469 | | /* Converts 'nal' into a "struct ofpact_learn" and appends that struct to |
5470 | | * 'ofpacts'. Returns 0 if successful, otherwise an OFPERR_*. */ |
5471 | | static enum ofperr |
5472 | | decode_NXAST_RAW_LEARN(const struct nx_action_learn *nal, |
5473 | | enum ofp_version ofp_version OVS_UNUSED, |
5474 | | const struct vl_mff_map *vl_mff_map, |
5475 | | uint64_t *tlv_bitmap, struct ofpbuf *ofpacts) |
5476 | 24.8k | { |
5477 | 24.8k | struct ofpact_learn *learn; |
5478 | 24.8k | enum ofperr error; |
5479 | | |
5480 | 24.8k | learn = ofpact_put_LEARN(ofpacts); |
5481 | | |
5482 | 24.8k | error = decode_LEARN_common(nal, NXAST_RAW_LEARN, learn); |
5483 | 24.8k | if (error) { |
5484 | 817 | return error; |
5485 | 817 | } |
5486 | | |
5487 | 24.0k | if (learn->flags & ~(NX_LEARN_F_SEND_FLOW_REM | |
5488 | 24.0k | NX_LEARN_F_DELETE_LEARNED)) { |
5489 | 329 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
5490 | 329 | } |
5491 | | |
5492 | 23.6k | return decode_LEARN_specs(nal + 1, (char *) nal + ntohs(nal->len), |
5493 | 23.6k | vl_mff_map, tlv_bitmap, ofpacts); |
5494 | 24.0k | } |
5495 | | |
5496 | | /* Converts 'nal' into a "struct ofpact_learn" and appends that struct to |
5497 | | * 'ofpacts'. Returns 0 if successful, otherwise an OFPERR_*. */ |
5498 | | static enum ofperr |
5499 | | decode_NXAST_RAW_LEARN2(const struct nx_action_learn2 *nal, |
5500 | | enum ofp_version ofp_version OVS_UNUSED, |
5501 | | const struct vl_mff_map *vl_mff_map, |
5502 | | uint64_t *tlv_bitmap, struct ofpbuf *ofpacts) |
5503 | 2.34k | { |
5504 | 2.34k | struct ofpbuf b = ofpbuf_const_initializer(nal, ntohs(nal->up.len)); |
5505 | 2.34k | struct ofpact_learn *learn; |
5506 | 2.34k | enum ofperr error; |
5507 | | |
5508 | 2.34k | if (nal->pad2) { |
5509 | 603 | return OFPERR_NXBAC_MUST_BE_ZERO; |
5510 | 603 | } |
5511 | | |
5512 | 1.73k | learn = ofpact_put_LEARN(ofpacts); |
5513 | 1.73k | error = decode_LEARN_common(&nal->up, NXAST_RAW_LEARN2, learn); |
5514 | 1.73k | if (error) { |
5515 | 1.45k | return error; |
5516 | 1.45k | } |
5517 | | |
5518 | 287 | learn->limit = ntohl(nal->limit); |
5519 | | |
5520 | 287 | if (learn->flags & ~(NX_LEARN_F_SEND_FLOW_REM | |
5521 | 287 | NX_LEARN_F_DELETE_LEARNED | |
5522 | 287 | NX_LEARN_F_WRITE_RESULT)) { |
5523 | 40 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
5524 | 40 | } |
5525 | | |
5526 | 247 | ofpbuf_pull(&b, sizeof *nal); |
5527 | | |
5528 | 247 | if (learn->flags & NX_LEARN_F_WRITE_RESULT) { |
5529 | 111 | error = nx_pull_header(&b, vl_mff_map, &learn->result_dst.field, NULL); |
5530 | 111 | if (error) { |
5531 | 66 | return error; |
5532 | 66 | } |
5533 | 45 | if (!learn->result_dst.field->writable) { |
5534 | 37 | return OFPERR_OFPBAC_BAD_SET_ARGUMENT; |
5535 | 37 | } |
5536 | 8 | learn->result_dst.ofs = ntohs(nal->result_dst_ofs); |
5537 | 8 | learn->result_dst.n_bits = 1; |
5538 | 136 | } else if (nal->result_dst_ofs) { |
5539 | 11 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
5540 | 11 | } |
5541 | | |
5542 | 133 | return decode_LEARN_specs(b.data, (char *) nal + ntohs(nal->up.len), |
5543 | 133 | vl_mff_map, tlv_bitmap, ofpacts); |
5544 | 247 | } |
5545 | | |
5546 | | static void |
5547 | | put_be16(struct ofpbuf *b, ovs_be16 x) |
5548 | 0 | { |
5549 | 0 | ofpbuf_put(b, &x, sizeof x); |
5550 | 0 | } |
5551 | | |
5552 | | static void |
5553 | | put_be32(struct ofpbuf *b, ovs_be32 x) |
5554 | 0 | { |
5555 | 0 | ofpbuf_put(b, &x, sizeof x); |
5556 | 0 | } |
5557 | | |
5558 | | static void |
5559 | | put_u16(struct ofpbuf *b, uint16_t x) |
5560 | 0 | { |
5561 | 0 | put_be16(b, htons(x)); |
5562 | 0 | } |
5563 | | |
5564 | | static void |
5565 | | put_u32(struct ofpbuf *b, uint32_t x) |
5566 | 0 | { |
5567 | 0 | put_be32(b, htonl(x)); |
5568 | 0 | } |
5569 | | |
5570 | | static void |
5571 | | encode_LEARN(const struct ofpact_learn *learn, |
5572 | | enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out) |
5573 | 0 | { |
5574 | 0 | const struct ofpact_learn_spec *spec; |
5575 | 0 | struct nx_action_learn *nal; |
5576 | 0 | size_t start_ofs; |
5577 | |
|
5578 | 0 | start_ofs = out->size; |
5579 | |
|
5580 | 0 | if (learn->ofpact.raw == NXAST_RAW_LEARN2 |
5581 | 0 | || learn->limit != 0 |
5582 | 0 | || learn->flags & NX_LEARN_F_WRITE_RESULT) { |
5583 | 0 | struct nx_action_learn2 *nal2; |
5584 | |
|
5585 | 0 | nal2 = put_NXAST_LEARN2(out); |
5586 | 0 | nal2->limit = htonl(learn->limit); |
5587 | 0 | nal2->result_dst_ofs = htons(learn->result_dst.ofs); |
5588 | 0 | nal = &nal2->up; |
5589 | 0 | } else { |
5590 | 0 | nal = put_NXAST_LEARN(out); |
5591 | 0 | } |
5592 | 0 | nal->idle_timeout = htons(learn->idle_timeout); |
5593 | 0 | nal->hard_timeout = htons(learn->hard_timeout); |
5594 | 0 | nal->fin_idle_timeout = htons(learn->fin_idle_timeout); |
5595 | 0 | nal->fin_hard_timeout = htons(learn->fin_hard_timeout); |
5596 | 0 | nal->priority = htons(learn->priority); |
5597 | 0 | nal->cookie = learn->cookie; |
5598 | 0 | nal->flags = htons(learn->flags); |
5599 | 0 | nal->table_id = learn->table_id; |
5600 | |
|
5601 | 0 | if (learn->flags & NX_LEARN_F_WRITE_RESULT) { |
5602 | 0 | nx_put_header(out, learn->result_dst.field->id, 0, false); |
5603 | 0 | } |
5604 | |
|
5605 | 0 | OFPACT_LEARN_SPEC_FOR_EACH (spec, learn) { |
5606 | 0 | put_u16(out, spec->n_bits | spec->dst_type | spec->src_type); |
5607 | |
|
5608 | 0 | if (spec->src_type == NX_LEARN_SRC_FIELD) { |
5609 | 0 | put_u32(out, nxm_header_from_mff(spec->src.field)); |
5610 | 0 | put_u16(out, spec->src.ofs); |
5611 | 0 | } else { |
5612 | 0 | size_t n_dst_bytes = 2 * DIV_ROUND_UP(spec->n_bits, 16); |
5613 | 0 | uint8_t *bits = ofpbuf_put_zeros(out, n_dst_bytes); |
5614 | 0 | unsigned int n_bytes = DIV_ROUND_UP(spec->n_bits, 8); |
5615 | |
|
5616 | 0 | memcpy(bits + n_dst_bytes - n_bytes, ofpact_learn_spec_imm(spec), |
5617 | 0 | n_bytes); |
5618 | 0 | } |
5619 | |
|
5620 | 0 | if (spec->dst_type == NX_LEARN_DST_MATCH || |
5621 | 0 | spec->dst_type == NX_LEARN_DST_LOAD) { |
5622 | 0 | put_u32(out, nxm_header_from_mff(spec->dst.field)); |
5623 | 0 | put_u16(out, spec->dst.ofs); |
5624 | 0 | } |
5625 | 0 | } |
5626 | |
|
5627 | 0 | pad_ofpat(out, start_ofs); |
5628 | 0 | } |
5629 | | |
5630 | | static char * OVS_WARN_UNUSED_RESULT |
5631 | | parse_LEARN(char *arg, const struct ofpact_parse_params *pp) |
5632 | 0 | { |
5633 | 0 | return learn_parse(arg, pp->port_map, pp->table_map, pp->ofpacts); |
5634 | 0 | } |
5635 | | |
5636 | | static void |
5637 | | format_LEARN(const struct ofpact_learn *a, |
5638 | | const struct ofpact_format_params *fp) |
5639 | 18.4k | { |
5640 | 18.4k | learn_format(a, fp->port_map, fp->table_map, fp->s); |
5641 | 18.4k | } |
5642 | | |
5643 | | static enum ofperr |
5644 | | check_LEARN(const struct ofpact_learn *a, |
5645 | | const struct ofpact_check_params *cp) |
5646 | 18.8k | { |
5647 | 18.8k | return learn_check(a, cp->match); |
5648 | 18.8k | } |
5649 | | |
5650 | | /* Action structure for NXAST_CONJUNCTION. */ |
5651 | | struct nx_action_conjunction { |
5652 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
5653 | | ovs_be16 len; /* At least 16. */ |
5654 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
5655 | | ovs_be16 subtype; /* See enum ofp_raw_action_type. */ |
5656 | | uint8_t clause; |
5657 | | uint8_t n_clauses; |
5658 | | ovs_be32 id; |
5659 | | }; |
5660 | | OFP_ASSERT(sizeof(struct nx_action_conjunction) == 16); |
5661 | | |
5662 | | static void |
5663 | | add_conjunction(struct ofpbuf *out, |
5664 | | uint32_t id, uint8_t clause, uint8_t n_clauses) |
5665 | 5.00k | { |
5666 | 5.00k | struct ofpact_conjunction *oc; |
5667 | | |
5668 | 5.00k | oc = ofpact_put_CONJUNCTION(out); |
5669 | 5.00k | oc->id = id; |
5670 | 5.00k | oc->clause = clause; |
5671 | 5.00k | oc->n_clauses = n_clauses; |
5672 | 5.00k | } |
5673 | | |
5674 | | static enum ofperr |
5675 | | decode_NXAST_RAW_CONJUNCTION(const struct nx_action_conjunction *nac, |
5676 | | enum ofp_version ofp_version OVS_UNUSED, |
5677 | | struct ofpbuf *out) |
5678 | 7.17k | { |
5679 | 7.17k | if (nac->n_clauses < 2 || nac->n_clauses > 64 |
5680 | 7.17k | || nac->clause >= nac->n_clauses) { |
5681 | 2.16k | return OFPERR_NXBAC_BAD_CONJUNCTION; |
5682 | 5.00k | } else { |
5683 | 5.00k | add_conjunction(out, ntohl(nac->id), nac->clause, nac->n_clauses); |
5684 | 5.00k | return 0; |
5685 | 5.00k | } |
5686 | 7.17k | } |
5687 | | |
5688 | | static void |
5689 | | encode_CONJUNCTION(const struct ofpact_conjunction *oc, |
5690 | | enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out) |
5691 | 0 | { |
5692 | 0 | struct nx_action_conjunction *nac = put_NXAST_CONJUNCTION(out); |
5693 | 0 | nac->clause = oc->clause; |
5694 | 0 | nac->n_clauses = oc->n_clauses; |
5695 | 0 | nac->id = htonl(oc->id); |
5696 | 0 | } |
5697 | | |
5698 | | static void |
5699 | | format_CONJUNCTION(const struct ofpact_conjunction *oc, |
5700 | | const struct ofpact_format_params *fp) |
5701 | 2.05k | { |
5702 | 2.05k | ds_put_format(fp->s, "%sconjunction(%s%"PRIu32",%d/%"PRIu8"%s)%s", |
5703 | 2.05k | colors.paren, colors.end, |
5704 | 2.05k | oc->id, oc->clause + 1, oc->n_clauses, |
5705 | 2.05k | colors.paren, colors.end); |
5706 | 2.05k | } |
5707 | | |
5708 | | static char * OVS_WARN_UNUSED_RESULT |
5709 | | parse_CONJUNCTION(const char *arg, const struct ofpact_parse_params *pp) |
5710 | 0 | { |
5711 | 0 | uint8_t n_clauses; |
5712 | 0 | uint8_t clause; |
5713 | 0 | uint32_t id; |
5714 | 0 | int n; |
5715 | |
|
5716 | 0 | if (!ovs_scan(arg, "%"SCNi32" , %"SCNu8" / %"SCNu8" %n", |
5717 | 0 | &id, &clause, &n_clauses, &n) || n != strlen(arg)) { |
5718 | 0 | return xstrdup("\"conjunction\" syntax is \"conjunction(id,i/n)\""); |
5719 | 0 | } |
5720 | | |
5721 | 0 | if (n_clauses < 2) { |
5722 | 0 | return xstrdup("conjunction must have at least 2 clauses"); |
5723 | 0 | } else if (n_clauses > 64) { |
5724 | 0 | return xstrdup("conjunction must have at most 64 clauses"); |
5725 | 0 | } else if (clause < 1) { |
5726 | 0 | return xstrdup("clause index must be positive"); |
5727 | 0 | } else if (clause > n_clauses) { |
5728 | 0 | return xstrdup("clause index must be less than or equal to " |
5729 | 0 | "number of clauses"); |
5730 | 0 | } |
5731 | | |
5732 | 0 | add_conjunction(pp->ofpacts, id, clause - 1, n_clauses); |
5733 | 0 | return NULL; |
5734 | 0 | } |
5735 | | |
5736 | | static enum ofperr |
5737 | | check_CONJUNCTION(const struct ofpact_conjunction *a OVS_UNUSED, |
5738 | | const struct ofpact_check_params *cp OVS_UNUSED) |
5739 | 12 | { |
5740 | 12 | return 0; |
5741 | 12 | } |
5742 | | |
5743 | | /* Action structure for NXAST_MULTIPATH. |
5744 | | * |
5745 | | * This action performs the following steps in sequence: |
5746 | | * |
5747 | | * 1. Hashes the fields designated by 'fields', one of NX_HASH_FIELDS_*. |
5748 | | * Refer to the definition of "enum nx_mp_fields" for details. |
5749 | | * |
5750 | | * The 'basis' value is used as a universal hash parameter, that is, |
5751 | | * different values of 'basis' yield different hash functions. The |
5752 | | * particular universal hash function used is implementation-defined. |
5753 | | * |
5754 | | * The hashed fields' values are drawn from the current state of the |
5755 | | * flow, including all modifications that have been made by actions up to |
5756 | | * this point. |
5757 | | * |
5758 | | * 2. Applies the multipath link choice algorithm specified by 'algorithm', |
5759 | | * one of NX_MP_ALG_*. Refer to the definition of "enum nx_mp_algorithm" |
5760 | | * for details. |
5761 | | * |
5762 | | * The output of the algorithm is 'link', an unsigned integer less than |
5763 | | * or equal to 'max_link'. |
5764 | | * |
5765 | | * Some algorithms use 'arg' as an additional argument. |
5766 | | * |
5767 | | * 3. Stores 'link' in dst[ofs:ofs+n_bits]. The format and semantics of |
5768 | | * 'dst' and 'ofs_nbits' are similar to those for the NXAST_REG_LOAD |
5769 | | * action. |
5770 | | * |
5771 | | * The switch will reject actions that have an unknown 'fields', or an unknown |
5772 | | * 'algorithm', or in which ofs+n_bits is greater than the width of 'dst', or |
5773 | | * in which 'max_link' is greater than or equal to 2**n_bits, with error type |
5774 | | * OFPET_BAD_ACTION, code OFPBAC_BAD_ARGUMENT. |
5775 | | */ |
5776 | | struct nx_action_multipath { |
5777 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
5778 | | ovs_be16 len; /* Length is 32. */ |
5779 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
5780 | | ovs_be16 subtype; /* NXAST_MULTIPATH. */ |
5781 | | |
5782 | | /* What fields to hash and how. */ |
5783 | | ovs_be16 fields; /* One of NX_HASH_FIELDS_*. */ |
5784 | | ovs_be16 basis; /* Universal hash parameter. */ |
5785 | | ovs_be16 pad0; |
5786 | | |
5787 | | /* Multipath link choice algorithm to apply to hash value. */ |
5788 | | ovs_be16 algorithm; /* One of NX_MP_ALG_*. */ |
5789 | | ovs_be16 max_link; /* Number of output links, minus 1. */ |
5790 | | ovs_be32 arg; /* Algorithm-specific argument. */ |
5791 | | ovs_be16 pad1; |
5792 | | |
5793 | | /* Where to store the result. */ |
5794 | | ovs_be16 ofs_nbits; /* (ofs << 6) | (n_bits - 1). */ |
5795 | | ovs_be32 dst; /* Destination. */ |
5796 | | }; |
5797 | | OFP_ASSERT(sizeof(struct nx_action_multipath) == 32); |
5798 | | |
5799 | | static enum ofperr |
5800 | | decode_NXAST_RAW_MULTIPATH(const struct nx_action_multipath *nam, |
5801 | | enum ofp_version ofp_version OVS_UNUSED, |
5802 | | const struct vl_mff_map *vl_mff_map, |
5803 | | uint64_t *tlv_bitmap, struct ofpbuf *out) |
5804 | 13.5k | { |
5805 | 13.5k | uint32_t n_links = ntohs(nam->max_link) + 1; |
5806 | 13.5k | size_t min_n_bits = log_2_ceil(n_links); |
5807 | 13.5k | struct ofpact_multipath *mp; |
5808 | 13.5k | enum ofperr error; |
5809 | | |
5810 | 13.5k | mp = ofpact_put_MULTIPATH(out); |
5811 | 13.5k | mp->fields = ntohs(nam->fields); |
5812 | 13.5k | mp->basis = ntohs(nam->basis); |
5813 | 13.5k | mp->algorithm = ntohs(nam->algorithm); |
5814 | 13.5k | mp->max_link = ntohs(nam->max_link); |
5815 | 13.5k | mp->arg = ntohl(nam->arg); |
5816 | 13.5k | mp->dst.ofs = nxm_decode_ofs(nam->ofs_nbits); |
5817 | 13.5k | mp->dst.n_bits = nxm_decode_n_bits(nam->ofs_nbits); |
5818 | 13.5k | error = mf_vl_mff_mf_from_nxm_header(ntohl(nam->dst), vl_mff_map, |
5819 | 13.5k | &mp->dst.field, tlv_bitmap); |
5820 | 13.5k | if (error) { |
5821 | 1.00k | return error; |
5822 | 1.00k | } |
5823 | | |
5824 | 12.5k | if (!flow_hash_fields_valid(mp->fields)) { |
5825 | 1.14k | VLOG_WARN_RL(&rl, "unsupported fields %d", (int) mp->fields); |
5826 | 1.14k | return OFPERR_OFPBAC_BAD_ARGUMENT; |
5827 | 11.4k | } else if (mp->algorithm != NX_MP_ALG_MODULO_N |
5828 | 11.4k | && mp->algorithm != NX_MP_ALG_HASH_THRESHOLD |
5829 | 11.4k | && mp->algorithm != NX_MP_ALG_HRW |
5830 | 11.4k | && mp->algorithm != NX_MP_ALG_ITER_HASH) { |
5831 | 3.94k | VLOG_WARN_RL(&rl, "unsupported algorithm %d", (int) mp->algorithm); |
5832 | 3.94k | return OFPERR_OFPBAC_BAD_ARGUMENT; |
5833 | 7.49k | } else if (mp->dst.n_bits < min_n_bits) { |
5834 | 15 | VLOG_WARN_RL(&rl, "multipath action requires at least %"PRIuSIZE" bits for " |
5835 | 15 | "%"PRIu32" links", min_n_bits, n_links); |
5836 | 15 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
5837 | 15 | } |
5838 | | |
5839 | 7.47k | return multipath_check(mp, NULL); |
5840 | 12.5k | } |
5841 | | |
5842 | | static void |
5843 | | encode_MULTIPATH(const struct ofpact_multipath *mp, |
5844 | | enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out) |
5845 | 0 | { |
5846 | 0 | struct nx_action_multipath *nam = put_NXAST_MULTIPATH(out); |
5847 | |
|
5848 | 0 | nam->fields = htons(mp->fields); |
5849 | 0 | nam->basis = htons(mp->basis); |
5850 | 0 | nam->algorithm = htons(mp->algorithm); |
5851 | 0 | nam->max_link = htons(mp->max_link); |
5852 | 0 | nam->arg = htonl(mp->arg); |
5853 | 0 | nam->ofs_nbits = nxm_encode_ofs_nbits(mp->dst.ofs, mp->dst.n_bits); |
5854 | 0 | nam->dst = htonl(nxm_header_from_mff(mp->dst.field)); |
5855 | 0 | } |
5856 | | |
5857 | | static char * OVS_WARN_UNUSED_RESULT |
5858 | | parse_MULTIPATH(const char *arg, const struct ofpact_parse_params *pp) |
5859 | 0 | { |
5860 | 0 | return multipath_parse(ofpact_put_MULTIPATH(pp->ofpacts), arg); |
5861 | 0 | } |
5862 | | |
5863 | | static void |
5864 | | format_MULTIPATH(const struct ofpact_multipath *a, |
5865 | | const struct ofpact_format_params *fp) |
5866 | 5.00k | { |
5867 | 5.00k | multipath_format(a, fp->s); |
5868 | 5.00k | } |
5869 | | |
5870 | | static enum ofperr |
5871 | | check_MULTIPATH(const struct ofpact_multipath *a, |
5872 | | const struct ofpact_check_params *cp) |
5873 | 1 | { |
5874 | 1 | return multipath_check(a, cp->match); |
5875 | 1 | } |
5876 | | |
5877 | | /* Action structure for NXAST_NOTE. |
5878 | | * |
5879 | | * This action has no effect. It is variable length. The switch does not |
5880 | | * attempt to interpret the user-defined 'note' data in any way. A controller |
5881 | | * can use this action to attach arbitrary metadata to a flow. |
5882 | | * |
5883 | | * This action might go away in the future. |
5884 | | */ |
5885 | | struct nx_action_note { |
5886 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
5887 | | ovs_be16 len; /* A multiple of 8, but at least 16. */ |
5888 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
5889 | | ovs_be16 subtype; /* NXAST_NOTE. */ |
5890 | | uint8_t note[6]; /* Start of user-defined data. */ |
5891 | | /* Possibly followed by additional user-defined data. */ |
5892 | | }; |
5893 | | OFP_ASSERT(sizeof(struct nx_action_note) == 16); |
5894 | | |
5895 | | static enum ofperr |
5896 | | decode_NXAST_RAW_NOTE(const struct nx_action_note *nan, |
5897 | | enum ofp_version ofp_version OVS_UNUSED, |
5898 | | struct ofpbuf *out) |
5899 | 16.1k | { |
5900 | 16.1k | struct ofpact_note *note; |
5901 | 16.1k | unsigned int length; |
5902 | | |
5903 | 16.1k | length = ntohs(nan->len) - offsetof(struct nx_action_note, note); |
5904 | 16.1k | note = ofpact_put_NOTE(out); |
5905 | 16.1k | note->length = length; |
5906 | 16.1k | ofpbuf_put(out, nan->note, length); |
5907 | 16.1k | note = out->header; |
5908 | 16.1k | ofpact_finish_NOTE(out, ¬e); |
5909 | | |
5910 | 16.1k | return 0; |
5911 | 16.1k | } |
5912 | | |
5913 | | static void |
5914 | | encode_NOTE(const struct ofpact_note *note, |
5915 | | enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out) |
5916 | 0 | { |
5917 | 0 | size_t start_ofs = out->size; |
5918 | 0 | struct nx_action_note *nan; |
5919 | |
|
5920 | 0 | put_NXAST_NOTE(out); |
5921 | 0 | out->size = out->size - sizeof nan->note; |
5922 | |
|
5923 | 0 | ofpbuf_put(out, note->data, note->length); |
5924 | 0 | pad_ofpat(out, start_ofs); |
5925 | 0 | } |
5926 | | |
5927 | | static char * OVS_WARN_UNUSED_RESULT |
5928 | | parse_NOTE(const char *arg, const struct ofpact_parse_params *pp) |
5929 | 0 | { |
5930 | 0 | size_t start_ofs = pp->ofpacts->size; |
5931 | 0 | ofpact_put_NOTE(pp->ofpacts); |
5932 | 0 | arg = ofpbuf_put_hex(pp->ofpacts, arg, NULL); |
5933 | 0 | if (arg[0]) { |
5934 | 0 | return xstrdup("bad hex digit in `note' argument"); |
5935 | 0 | } |
5936 | 0 | struct ofpact_note *note = ofpbuf_at_assert(pp->ofpacts, start_ofs, |
5937 | 0 | sizeof *note); |
5938 | 0 | note->length = pp->ofpacts->size - (start_ofs + sizeof *note); |
5939 | |
|
5940 | 0 | if (ofpbuf_oversized(pp->ofpacts)) { |
5941 | 0 | return xasprintf("input too big"); |
5942 | 0 | } |
5943 | | |
5944 | 0 | ofpact_finish_NOTE(pp->ofpacts, ¬e); |
5945 | 0 | return NULL; |
5946 | 0 | } |
5947 | | |
5948 | | static void |
5949 | | format_NOTE(const struct ofpact_note *a, |
5950 | | const struct ofpact_format_params *fp) |
5951 | 5.13k | { |
5952 | 5.13k | ds_put_format(fp->s, "%snote:%s", colors.param, colors.end); |
5953 | 5.13k | ds_put_hex_with_delimiter(fp->s, a->data, a->length, "."); |
5954 | 5.13k | } |
5955 | | |
5956 | | static enum ofperr |
5957 | | check_NOTE(const struct ofpact_note *a OVS_UNUSED, |
5958 | | const struct ofpact_check_params *cp OVS_UNUSED) |
5959 | 355 | { |
5960 | 355 | return 0; |
5961 | 355 | } |
5962 | | |
5963 | | /* Exit action. */ |
5964 | | |
5965 | | static enum ofperr |
5966 | | decode_NXAST_RAW_EXIT(struct ofpbuf *out) |
5967 | 1.88k | { |
5968 | 1.88k | ofpact_put_EXIT(out); |
5969 | 1.88k | return 0; |
5970 | 1.88k | } |
5971 | | |
5972 | | static void |
5973 | | encode_EXIT(const struct ofpact_null *null OVS_UNUSED, |
5974 | | enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out) |
5975 | 0 | { |
5976 | 0 | put_NXAST_EXIT(out); |
5977 | 0 | } |
5978 | | |
5979 | | static char * OVS_WARN_UNUSED_RESULT |
5980 | | parse_EXIT(char *arg OVS_UNUSED, const struct ofpact_parse_params *pp) |
5981 | 0 | { |
5982 | 0 | ofpact_put_EXIT(pp->ofpacts); |
5983 | 0 | return NULL; |
5984 | 0 | } |
5985 | | |
5986 | | static void |
5987 | | format_EXIT(const struct ofpact_null *a OVS_UNUSED, |
5988 | | const struct ofpact_format_params *fp) |
5989 | 408 | { |
5990 | 408 | ds_put_format(fp->s, "%sexit%s", colors.special, colors.end); |
5991 | 408 | } |
5992 | | |
5993 | | static enum ofperr |
5994 | | check_EXIT(const struct ofpact_null *a OVS_UNUSED, |
5995 | | const struct ofpact_check_params *cp OVS_UNUSED) |
5996 | 18 | { |
5997 | 18 | return 0; |
5998 | 18 | } |
5999 | | |
6000 | | /* Unroll xlate action. */ |
6001 | | |
6002 | | static void |
6003 | | encode_UNROLL_XLATE(const struct ofpact_unroll_xlate *unroll OVS_UNUSED, |
6004 | | enum ofp_version ofp_version OVS_UNUSED, |
6005 | | struct ofpbuf *out OVS_UNUSED) |
6006 | 0 | { |
6007 | 0 | OVS_NOT_REACHED(); |
6008 | 0 | } |
6009 | | |
6010 | | static char * OVS_WARN_UNUSED_RESULT |
6011 | | parse_UNROLL_XLATE(char *arg OVS_UNUSED, |
6012 | | const struct ofpact_parse_params *pp OVS_UNUSED) |
6013 | 0 | { |
6014 | 0 | return xasprintf("UNROLL is an internal action " |
6015 | 0 | "that shouldn't be used via OpenFlow"); |
6016 | 0 | } |
6017 | | |
6018 | | static void |
6019 | | format_UNROLL_XLATE(const struct ofpact_unroll_xlate *a, |
6020 | | const struct ofpact_format_params *fp) |
6021 | 2.49k | { |
6022 | 2.49k | ds_put_format(fp->s, "%sunroll_xlate(%s%stable=%s", |
6023 | 2.49k | colors.paren, colors.end, |
6024 | 2.49k | colors.special, colors.end); |
6025 | 2.49k | ofputil_format_table(a->rule_table_id, fp->table_map, fp->s); |
6026 | 2.49k | ds_put_format(fp->s, ", %scookie=%s%"PRIu64"%s)%s", |
6027 | 2.49k | colors.param, colors.end, ntohll(a->rule_cookie), |
6028 | 2.49k | colors.paren, colors.end); |
6029 | 2.49k | } |
6030 | | |
6031 | | static enum ofperr |
6032 | | check_UNROLL_XLATE(const struct ofpact_unroll_xlate *a OVS_UNUSED, |
6033 | | const struct ofpact_check_params *cp OVS_UNUSED) |
6034 | 0 | { |
6035 | | /* UNROLL is an internal action that should never be seen via OpenFlow. */ |
6036 | 0 | return OFPERR_OFPBAC_BAD_TYPE; |
6037 | 0 | } |
6038 | | |
6039 | | /* The NXAST_CLONE action is "struct ext_action_header", followed by zero or |
6040 | | * more embedded OpenFlow actions. */ |
6041 | | |
6042 | | static enum ofperr |
6043 | | decode_NXAST_RAW_CLONE(const struct ext_action_header *eah, |
6044 | | enum ofp_version ofp_version, |
6045 | | const struct vl_mff_map *vl_mff_map, |
6046 | | uint64_t *tlv_bitmap, struct ofpbuf *out) |
6047 | 1.70k | { |
6048 | 1.70k | int error; |
6049 | 1.70k | struct ofpbuf openflow; |
6050 | 1.70k | const size_t clone_offset = ofpacts_pull(out); |
6051 | 1.70k | struct ofpact_nest *clone = ofpact_put_CLONE(out); |
6052 | | |
6053 | | /* decode action list */ |
6054 | 1.70k | ofpbuf_pull(out, sizeof(*clone)); |
6055 | 1.70k | openflow = ofpbuf_const_initializer( |
6056 | 1.70k | eah + 1, ntohs(eah->len) - sizeof *eah); |
6057 | 1.70k | error = ofpacts_pull_openflow_actions__(&openflow, openflow.size, |
6058 | 1.70k | ofp_version, |
6059 | 1.70k | 1u << OVSINST_OFPIT11_APPLY_ACTIONS, |
6060 | 1.70k | out, 0, vl_mff_map, tlv_bitmap); |
6061 | 1.70k | if (error) { |
6062 | 659 | return error; |
6063 | 659 | } |
6064 | 1.04k | clone = ofpbuf_push_uninit(out, sizeof *clone); |
6065 | 1.04k | out->header = &clone->ofpact; |
6066 | 1.04k | ofpact_finish_CLONE(out, &clone); |
6067 | 1.04k | ofpbuf_push_uninit(out, clone_offset); |
6068 | 1.04k | return error; |
6069 | 1.70k | } |
6070 | | |
6071 | | static void |
6072 | | encode_CLONE(const struct ofpact_nest *clone, |
6073 | | enum ofp_version ofp_version, struct ofpbuf *out) |
6074 | 0 | { |
6075 | 0 | size_t len; |
6076 | 0 | const size_t ofs = out->size; |
6077 | 0 | struct ext_action_header *eah; |
6078 | |
|
6079 | 0 | put_NXAST_CLONE(out); |
6080 | 0 | len = ofpacts_put_openflow_actions(clone->actions, |
6081 | 0 | ofpact_nest_get_action_len(clone), |
6082 | 0 | out, ofp_version); |
6083 | 0 | len += sizeof *eah; |
6084 | 0 | eah = ofpbuf_at(out, ofs, sizeof *eah); |
6085 | 0 | eah->len = htons(len); |
6086 | 0 | } |
6087 | | |
6088 | | static char * OVS_WARN_UNUSED_RESULT |
6089 | | parse_CLONE(char *arg, const struct ofpact_parse_params *pp) |
6090 | 0 | { |
6091 | 0 | const size_t clone_offset = ofpacts_pull(pp->ofpacts); |
6092 | 0 | struct ofpact_nest *clone = ofpact_put_CLONE(pp->ofpacts); |
6093 | 0 | char *error; |
6094 | |
|
6095 | 0 | ofpbuf_pull(pp->ofpacts, sizeof *clone); |
6096 | 0 | error = ofpacts_parse_copy(arg, pp, false, OFPACT_CLONE); |
6097 | | /* header points to the action list */ |
6098 | 0 | pp->ofpacts->header = ofpbuf_push_uninit(pp->ofpacts, sizeof *clone); |
6099 | 0 | clone = pp->ofpacts->header; |
6100 | |
|
6101 | 0 | if (ofpbuf_oversized(pp->ofpacts)) { |
6102 | 0 | free(error); |
6103 | 0 | return xasprintf("input too big"); |
6104 | 0 | } |
6105 | | |
6106 | 0 | ofpact_finish_CLONE(pp->ofpacts, &clone); |
6107 | 0 | ofpbuf_push_uninit(pp->ofpacts, clone_offset); |
6108 | 0 | return error; |
6109 | 0 | } |
6110 | | |
6111 | | static void |
6112 | | format_CLONE(const struct ofpact_nest *a, |
6113 | | const struct ofpact_format_params *fp) |
6114 | 73 | { |
6115 | 73 | ds_put_format(fp->s, "%sclone(%s", colors.paren, colors.end); |
6116 | 73 | ofpacts_format(a->actions, ofpact_nest_get_action_len(a), fp); |
6117 | 73 | ds_put_format(fp->s, "%s)%s", colors.paren, colors.end); |
6118 | 73 | } |
6119 | | |
6120 | | static enum ofperr |
6121 | | check_subactions(struct ofpact *ofpacts, size_t ofpacts_len, |
6122 | | struct ofpact_check_params *cp) |
6123 | 565 | { |
6124 | 565 | struct ofpact_check_params sub = *cp; |
6125 | 565 | enum ofperr error = ofpacts_check(ofpacts, ofpacts_len, &sub); |
6126 | 565 | cp->usable_protocols &= sub.usable_protocols; |
6127 | 565 | return error; |
6128 | 565 | } |
6129 | | |
6130 | | static enum ofperr |
6131 | | check_CLONE(struct ofpact_nest *a, struct ofpact_check_params *cp) |
6132 | 535 | { |
6133 | 535 | return check_subactions(a->actions, ofpact_nest_get_action_len(a), cp); |
6134 | 535 | } |
6135 | | |
6136 | | /* Action structure for NXAST_SAMPLE. |
6137 | | * |
6138 | | * Samples matching packets with the given probability and sends them |
6139 | | * each to the set of collectors identified with the given ID. The |
6140 | | * probability is expressed as a number of packets to be sampled out |
6141 | | * of USHRT_MAX packets, and must be >0. |
6142 | | * |
6143 | | * When sending packet samples to IPFIX collectors, the IPFIX flow |
6144 | | * record sent for each sampled packet is associated with the given |
6145 | | * observation domain ID and observation point ID. Each IPFIX flow |
6146 | | * record contain the sampled packet's headers when executing this |
6147 | | * rule. If a sampled packet's headers are modified by previous |
6148 | | * actions in the flow, those modified headers are sent. */ |
6149 | | struct nx_action_sample { |
6150 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
6151 | | ovs_be16 len; /* Length is 24. */ |
6152 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
6153 | | ovs_be16 subtype; /* NXAST_SAMPLE. */ |
6154 | | ovs_be16 probability; /* Fraction of packets to sample. */ |
6155 | | ovs_be32 collector_set_id; /* ID of collector set in OVSDB. */ |
6156 | | ovs_be32 obs_domain_id; /* ID of sampling observation domain. */ |
6157 | | ovs_be32 obs_point_id; /* ID of sampling observation point. */ |
6158 | | }; |
6159 | | OFP_ASSERT(sizeof(struct nx_action_sample) == 24); |
6160 | | |
6161 | | /* Action structure for NXAST_SAMPLE2 and NXAST_SAMPLE3. |
6162 | | * |
6163 | | * NXAST_SAMPLE2 was added in Open vSwitch 2.5.90. Compared to NXAST_SAMPLE, |
6164 | | * it adds support for exporting egress tunnel information. |
6165 | | * |
6166 | | * NXAST_SAMPLE3 was added in Open vSwitch 2.6.90. Compared to NXAST_SAMPLE2, |
6167 | | * it adds support for the 'direction' field. */ |
6168 | | struct nx_action_sample2 { |
6169 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
6170 | | ovs_be16 len; /* Length is 32. */ |
6171 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
6172 | | ovs_be16 subtype; /* NXAST_SAMPLE. */ |
6173 | | ovs_be16 probability; /* Fraction of packets to sample. */ |
6174 | | ovs_be32 collector_set_id; /* ID of collector set in OVSDB. */ |
6175 | | ovs_be32 obs_domain_id; /* ID of sampling observation domain. */ |
6176 | | ovs_be32 obs_point_id; /* ID of sampling observation point. */ |
6177 | | ovs_be16 sampling_port; /* Sampling port. */ |
6178 | | uint8_t direction; /* NXAST_SAMPLE3 only. */ |
6179 | | uint8_t zeros[5]; /* Pad to a multiple of 8 bytes */ |
6180 | | }; |
6181 | | OFP_ASSERT(sizeof(struct nx_action_sample2) == 32); |
6182 | | |
6183 | | /* Action structure for NXAST_SAMPLE4 |
6184 | | * |
6185 | | * NXAST_SAMPLE4 was added in Open vSwitch 3.4.0. Compared to NXAST_SAMPLE3, |
6186 | | * it adds support for using field specifiers for observation_domain_id and |
6187 | | * observation_point_id. */ |
6188 | | struct nx_action_sample4 { |
6189 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
6190 | | ovs_be16 len; /* Length is 40. */ |
6191 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
6192 | | ovs_be16 subtype; /* NXAST_SAMPLE4. */ |
6193 | | ovs_be16 probability; /* Fraction of packets to sample. */ |
6194 | | ovs_be32 collector_set_id; /* ID of collector set in OVSDB. */ |
6195 | | ovs_be32 obs_domain_src; /* The observation_domain_id source. */ |
6196 | | union { |
6197 | | ovs_be16 obs_domain_ofs_nbits; /* Range to use from source field. */ |
6198 | | ovs_be32 obs_domain_imm; /* Immediate value for domain id. */ |
6199 | | }; |
6200 | | ovs_be32 obs_point_src; /* The observation_point_id source. */ |
6201 | | union { |
6202 | | ovs_be16 obs_point_ofs_nbits; /* Range to use from source field. */ |
6203 | | ovs_be32 obs_point_imm; /* Immediate value for point id. */ |
6204 | | }; |
6205 | | ovs_be16 sampling_port; /* Sampling port. */ |
6206 | | uint8_t direction; /* Sampling direction. */ |
6207 | | uint8_t zeros[5]; /* Pad to a multiple of 8 bytes */ |
6208 | | }; |
6209 | | OFP_ASSERT(sizeof(struct nx_action_sample4) == 40); |
6210 | | |
6211 | | static enum ofperr |
6212 | | decode_NXAST_RAW_SAMPLE(const struct nx_action_sample *nas, |
6213 | | enum ofp_version ofp_version OVS_UNUSED, |
6214 | | struct ofpbuf *out) |
6215 | 34 | { |
6216 | 34 | struct ofpact_sample *sample; |
6217 | | |
6218 | 34 | sample = ofpact_put_SAMPLE(out); |
6219 | 34 | sample->ofpact.raw = NXAST_RAW_SAMPLE; |
6220 | 34 | sample->probability = ntohs(nas->probability); |
6221 | 34 | sample->collector_set_id = ntohl(nas->collector_set_id); |
6222 | 34 | sample->obs_domain_imm = ntohl(nas->obs_domain_id); |
6223 | 34 | sample->obs_domain_src.field = NULL; |
6224 | 34 | sample->obs_point_imm = ntohl(nas->obs_point_id); |
6225 | 34 | sample->obs_point_src.field = NULL; |
6226 | 34 | sample->sampling_port = OFPP_NONE; |
6227 | 34 | sample->direction = NX_ACTION_SAMPLE_DEFAULT; |
6228 | 34 | sample->obs_domain_src.field = NULL; |
6229 | 34 | sample->obs_point_src.field = NULL; |
6230 | 34 | if (sample->probability == 0) { |
6231 | 10 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
6232 | 10 | } |
6233 | | |
6234 | 24 | return 0; |
6235 | 34 | } |
6236 | | |
6237 | | static enum ofperr |
6238 | | decode_SAMPLE2(const struct nx_action_sample2 *nas, |
6239 | | enum ofp_raw_action_type raw, |
6240 | | enum nx_action_sample_direction direction, |
6241 | | struct ofpact_sample *sample) |
6242 | 2.32k | { |
6243 | 2.32k | sample->ofpact.raw = raw; |
6244 | 2.32k | sample->probability = ntohs(nas->probability); |
6245 | 2.32k | sample->collector_set_id = ntohl(nas->collector_set_id); |
6246 | 2.32k | sample->obs_domain_imm = ntohl(nas->obs_domain_id); |
6247 | 2.32k | sample->obs_domain_src.field = NULL; |
6248 | 2.32k | sample->obs_point_imm = ntohl(nas->obs_point_id); |
6249 | 2.32k | sample->obs_point_src.field = NULL; |
6250 | 2.32k | sample->sampling_port = u16_to_ofp(ntohs(nas->sampling_port)); |
6251 | 2.32k | sample->direction = direction; |
6252 | | |
6253 | 2.32k | if (sample->probability == 0) { |
6254 | 636 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
6255 | 636 | } |
6256 | | |
6257 | 1.68k | return 0; |
6258 | 2.32k | } |
6259 | | |
6260 | | static enum ofperr |
6261 | | decode_NXAST_RAW_SAMPLE2(const struct nx_action_sample2 *nas, |
6262 | | enum ofp_version ofp_version OVS_UNUSED, |
6263 | | struct ofpbuf *out) |
6264 | 21 | { |
6265 | 21 | return decode_SAMPLE2(nas, NXAST_RAW_SAMPLE2, NX_ACTION_SAMPLE_DEFAULT, |
6266 | 21 | ofpact_put_SAMPLE(out)); |
6267 | 21 | } |
6268 | | |
6269 | | static int |
6270 | | check_sample_direction(enum nx_action_sample_direction direction) |
6271 | 4.68k | { |
6272 | 4.68k | if (direction != NX_ACTION_SAMPLE_DEFAULT && |
6273 | 4.68k | direction != NX_ACTION_SAMPLE_INGRESS && |
6274 | 4.68k | direction != NX_ACTION_SAMPLE_EGRESS) { |
6275 | 265 | VLOG_WARN_RL(&rl, "invalid sample direction %"PRIu8, direction); |
6276 | 265 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
6277 | 265 | } |
6278 | 4.41k | return 0; |
6279 | 4.68k | } |
6280 | | |
6281 | | static enum ofperr |
6282 | | decode_NXAST_RAW_SAMPLE3(const struct nx_action_sample2 *nas, |
6283 | | enum ofp_version ofp_version OVS_UNUSED, |
6284 | | struct ofpbuf *out) |
6285 | 2.93k | { |
6286 | 2.93k | struct ofpact_sample *sample = ofpact_put_SAMPLE(out); |
6287 | 2.93k | int err; |
6288 | | |
6289 | 2.93k | if (!is_all_zeros(nas->zeros, sizeof nas->zeros)) { |
6290 | 617 | return OFPERR_NXBRC_MUST_BE_ZERO; |
6291 | 617 | } |
6292 | 2.31k | err = check_sample_direction(nas->direction); |
6293 | 2.31k | if (err) { |
6294 | 18 | return err; |
6295 | 18 | } |
6296 | 2.30k | return decode_SAMPLE2(nas, NXAST_RAW_SAMPLE3, nas->direction, sample); |
6297 | 2.31k | } |
6298 | | |
6299 | | static int |
6300 | | decode_sample_obs_id(ovs_be32 src, ovs_be16 ofs_nbits, ovs_be32 imm, |
6301 | | const struct vl_mff_map *vl_mff_map, uint64_t *tlv_bitmap, |
6302 | | struct mf_subfield *src_out, uint32_t *imm_out) |
6303 | 3.76k | { |
6304 | 3.76k | if (src) { |
6305 | 2.56k | enum ofperr error; |
6306 | | |
6307 | 2.56k | src_out->ofs = nxm_decode_ofs(ofs_nbits); |
6308 | 2.56k | src_out->n_bits = nxm_decode_n_bits(ofs_nbits); |
6309 | 2.56k | error = mf_vl_mff_mf_from_nxm_header(ntohl(src), |
6310 | 2.56k | vl_mff_map, &src_out->field, |
6311 | 2.56k | tlv_bitmap); |
6312 | 2.56k | if (error) { |
6313 | 1.40k | return error; |
6314 | 1.40k | } |
6315 | | |
6316 | 1.16k | error = mf_check_src(src_out, NULL); |
6317 | 1.16k | if (error) { |
6318 | 168 | return error; |
6319 | 168 | } |
6320 | | |
6321 | 996 | if (src_out->n_bits > 32) { |
6322 | 213 | VLOG_WARN_RL(&rl, "size of field used in observation_id (%d) " |
6323 | 213 | "exceeds maximum (32)", src_out->n_bits); |
6324 | 213 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
6325 | 213 | } |
6326 | 1.19k | } else { |
6327 | 1.19k | src_out->field = NULL; |
6328 | 1.19k | *imm_out = ntohl(imm); |
6329 | 1.19k | } |
6330 | | |
6331 | 1.97k | return 0; |
6332 | 3.76k | } |
6333 | | |
6334 | | static enum ofperr |
6335 | | decode_NXAST_RAW_SAMPLE4(const struct nx_action_sample4 *nas, |
6336 | | enum ofp_version ofp_version OVS_UNUSED, |
6337 | | const struct vl_mff_map *vl_mff_map, |
6338 | | uint64_t *tlv_bitmap, |
6339 | | struct ofpbuf *out) |
6340 | 2.56k | { |
6341 | 2.56k | struct ofpact_sample *sample = ofpact_put_SAMPLE(out); |
6342 | 2.56k | int err; |
6343 | | |
6344 | 2.56k | if (!is_all_zeros(nas->zeros, sizeof nas->zeros)) { |
6345 | 197 | return OFPERR_NXBRC_MUST_BE_ZERO; |
6346 | 197 | } |
6347 | | |
6348 | 2.36k | err = check_sample_direction(nas->direction); |
6349 | 2.36k | if (err) { |
6350 | 247 | return err; |
6351 | 247 | } |
6352 | | |
6353 | 2.11k | sample->ofpact.raw = NXAST_RAW_SAMPLE4; |
6354 | 2.11k | sample->probability = ntohs(nas->probability); |
6355 | 2.11k | sample->collector_set_id = ntohl(nas->collector_set_id); |
6356 | 2.11k | sample->sampling_port = u16_to_ofp(ntohs(nas->sampling_port)); |
6357 | 2.11k | sample->direction = nas->direction; |
6358 | | |
6359 | 2.11k | if (sample->probability == 0) { |
6360 | 6 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
6361 | 6 | } |
6362 | | |
6363 | 2.11k | err = decode_sample_obs_id(nas->obs_domain_src, |
6364 | 2.11k | nas->obs_domain_ofs_nbits, |
6365 | 2.11k | nas->obs_domain_imm, |
6366 | 2.11k | vl_mff_map, tlv_bitmap, |
6367 | 2.11k | &sample->obs_domain_src, |
6368 | 2.11k | &sample->obs_domain_imm); |
6369 | 2.11k | if (err) { |
6370 | 463 | return err; |
6371 | 463 | } |
6372 | | |
6373 | 1.65k | return decode_sample_obs_id(nas->obs_point_src, |
6374 | 1.65k | nas->obs_point_ofs_nbits, |
6375 | 1.65k | nas->obs_point_imm, |
6376 | 1.65k | vl_mff_map, tlv_bitmap, |
6377 | 1.65k | &sample->obs_point_src, |
6378 | 1.65k | &sample->obs_point_imm); |
6379 | 2.11k | } |
6380 | | |
6381 | | static void |
6382 | | encode_SAMPLE2(const struct ofpact_sample *sample, |
6383 | | struct nx_action_sample2 *nas) |
6384 | 0 | { |
6385 | 0 | nas->probability = htons(sample->probability); |
6386 | 0 | nas->collector_set_id = htonl(sample->collector_set_id); |
6387 | 0 | nas->obs_domain_id = htonl(sample->obs_domain_imm); |
6388 | 0 | nas->obs_point_id = htonl(sample->obs_point_imm); |
6389 | 0 | nas->sampling_port = htons(ofp_to_u16(sample->sampling_port)); |
6390 | 0 | nas->direction = sample->direction; |
6391 | 0 | } |
6392 | | |
6393 | | static void |
6394 | | encode_SAMPLE4(const struct ofpact_sample *sample, |
6395 | | struct nx_action_sample4 *nas) |
6396 | 0 | { |
6397 | 0 | nas->probability = htons(sample->probability); |
6398 | 0 | nas->collector_set_id = htonl(sample->collector_set_id); |
6399 | 0 | nas->sampling_port = htons(ofp_to_u16(sample->sampling_port)); |
6400 | 0 | nas->direction = sample->direction; |
6401 | |
|
6402 | 0 | if (sample->obs_domain_src.field) { |
6403 | 0 | nas->obs_domain_src = |
6404 | 0 | htonl(nxm_header_from_mff(sample->obs_domain_src.field)); |
6405 | 0 | nas->obs_domain_ofs_nbits = |
6406 | 0 | nxm_encode_ofs_nbits(sample->obs_domain_src.ofs, |
6407 | 0 | sample->obs_domain_src.n_bits); |
6408 | 0 | } else { |
6409 | 0 | nas->obs_domain_src = htonl(0); |
6410 | 0 | nas->obs_domain_imm = htonl(sample->obs_domain_imm); |
6411 | 0 | } |
6412 | 0 | if (sample->obs_point_src.field) { |
6413 | 0 | nas->obs_point_src = |
6414 | 0 | htonl(nxm_header_from_mff(sample->obs_point_src.field)); |
6415 | 0 | nas->obs_point_ofs_nbits = |
6416 | 0 | nxm_encode_ofs_nbits(sample->obs_point_src.ofs, |
6417 | 0 | sample->obs_point_src.n_bits); |
6418 | 0 | } else { |
6419 | 0 | nas->obs_point_src = htonl(0); |
6420 | 0 | nas->obs_point_imm = htonl(sample->obs_point_imm); |
6421 | 0 | } |
6422 | 0 | } |
6423 | | |
6424 | | static void |
6425 | | encode_SAMPLE(const struct ofpact_sample *sample, |
6426 | | enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out) |
6427 | 0 | { |
6428 | 0 | if (sample->ofpact.raw == NXAST_RAW_SAMPLE4 || |
6429 | 0 | sample->obs_domain_src.field || |
6430 | 0 | sample->obs_point_src.field) { |
6431 | 0 | encode_SAMPLE4(sample, put_NXAST_SAMPLE4(out)); |
6432 | 0 | } else if (sample->ofpact.raw == NXAST_RAW_SAMPLE3 |
6433 | 0 | || sample->direction != NX_ACTION_SAMPLE_DEFAULT) { |
6434 | 0 | encode_SAMPLE2(sample, put_NXAST_SAMPLE3(out)); |
6435 | 0 | } else if (sample->ofpact.raw == NXAST_RAW_SAMPLE2 |
6436 | 0 | || sample->sampling_port != OFPP_NONE) { |
6437 | 0 | encode_SAMPLE2(sample, put_NXAST_SAMPLE2(out)); |
6438 | 0 | } else { |
6439 | 0 | struct nx_action_sample *nas = put_NXAST_SAMPLE(out); |
6440 | 0 | nas->probability = htons(sample->probability); |
6441 | 0 | nas->collector_set_id = htonl(sample->collector_set_id); |
6442 | 0 | nas->obs_domain_id = htonl(sample->obs_domain_imm); |
6443 | 0 | nas->obs_point_id = htonl(sample->obs_point_imm); |
6444 | 0 | } |
6445 | 0 | } |
6446 | | |
6447 | | /* Parses 'arg' as the argument to a "sample" action, and appends such an |
6448 | | * action to 'pp->ofpacts'. |
6449 | | * |
6450 | | * Returns NULL if successful, otherwise a malloc()'d string describing the |
6451 | | * error. The caller is responsible for freeing the returned string. */ |
6452 | | static char * OVS_WARN_UNUSED_RESULT |
6453 | | parse_SAMPLE(char *arg, const struct ofpact_parse_params *pp) |
6454 | 0 | { |
6455 | 0 | struct ofpact_sample *os = ofpact_put_SAMPLE(pp->ofpacts); |
6456 | 0 | os->sampling_port = OFPP_NONE; |
6457 | 0 | os->direction = NX_ACTION_SAMPLE_DEFAULT; |
6458 | |
|
6459 | 0 | char *key, *value; |
6460 | 0 | while (ofputil_parse_key_value(&arg, &key, &value)) { |
6461 | 0 | char *error = NULL; |
6462 | |
|
6463 | 0 | if (!strcmp(key, "probability")) { |
6464 | 0 | error = str_to_u16(value, "probability", &os->probability); |
6465 | 0 | if (!error && os->probability == 0) { |
6466 | 0 | error = xasprintf("invalid probability value \"%s\"", value); |
6467 | 0 | } |
6468 | 0 | } else if (!strcmp(key, "collector_set_id")) { |
6469 | 0 | error = str_to_u32(value, &os->collector_set_id); |
6470 | 0 | } else if (!strcmp(key, "obs_domain_id")) { |
6471 | 0 | error = str_to_u32(value, &os->obs_domain_imm); |
6472 | |
|
6473 | 0 | if (error) { |
6474 | 0 | free(error); |
6475 | 0 | error = mf_parse_subfield(&os->obs_domain_src, value); |
6476 | 0 | if (error) { |
6477 | 0 | return error; |
6478 | 0 | } |
6479 | 0 | if (os->obs_domain_src.n_bits > 32) { |
6480 | 0 | return xasprintf("size of obs_domain_id field (%d) " |
6481 | 0 | "exceeds maximum (32)", |
6482 | 0 | os->obs_domain_src.n_bits); |
6483 | 0 | } |
6484 | 0 | } |
6485 | 0 | } else if (!strcmp(key, "obs_point_id")) { |
6486 | 0 | error = str_to_u32(value, &os->obs_point_imm); |
6487 | |
|
6488 | 0 | if (error) { |
6489 | 0 | free(error); |
6490 | 0 | error = mf_parse_subfield(&os->obs_point_src, value); |
6491 | 0 | if (error) { |
6492 | 0 | return error; |
6493 | 0 | } |
6494 | 0 | if (os->obs_point_src.n_bits > 32) { |
6495 | 0 | return xasprintf("size of obs_point_id field (%d) " |
6496 | 0 | "exceeds maximum (32)", |
6497 | 0 | os->obs_point_src.n_bits); |
6498 | 0 | } |
6499 | 0 | } |
6500 | 0 | } else if (!strcmp(key, "sampling_port")) { |
6501 | 0 | if (!ofputil_port_from_string(value, pp->port_map, |
6502 | 0 | &os->sampling_port)) { |
6503 | 0 | error = xasprintf("%s: unknown port", value); |
6504 | 0 | } |
6505 | 0 | } else if (!strcmp(key, "ingress")) { |
6506 | 0 | os->direction = NX_ACTION_SAMPLE_INGRESS; |
6507 | 0 | } else if (!strcmp(key, "egress")) { |
6508 | 0 | os->direction = NX_ACTION_SAMPLE_EGRESS; |
6509 | 0 | } else { |
6510 | 0 | error = xasprintf("invalid key \"%s\" in \"sample\" argument", |
6511 | 0 | key); |
6512 | 0 | } |
6513 | 0 | if (error) { |
6514 | 0 | return error; |
6515 | 0 | } |
6516 | 0 | } |
6517 | 0 | if (os->probability == 0) { |
6518 | 0 | return xstrdup("non-zero \"probability\" must be specified on sample"); |
6519 | 0 | } |
6520 | | |
6521 | 0 | return NULL; |
6522 | 0 | } |
6523 | | |
6524 | | static void |
6525 | | format_SAMPLE(const struct ofpact_sample *a, |
6526 | | const struct ofpact_format_params *fp) |
6527 | 2.02k | { |
6528 | 2.02k | ds_put_format(fp->s, "%ssample(%s%sprobability=%s%"PRIu16 |
6529 | 2.02k | ",%scollector_set_id=%s%"PRIu32, |
6530 | 2.02k | colors.paren, colors.end, |
6531 | 2.02k | colors.param, colors.end, a->probability, |
6532 | 2.02k | colors.param, colors.end, a->collector_set_id); |
6533 | | |
6534 | 2.02k | ds_put_format(fp->s, ",%sobs_domain_id=%s", colors.param, colors.end); |
6535 | 2.02k | if (a->obs_domain_src.field) { |
6536 | 33 | mf_format_subfield(&a->obs_domain_src, fp->s); |
6537 | 1.99k | } else { |
6538 | 1.99k | ds_put_format(fp->s, "%"PRIu32, a->obs_domain_imm); |
6539 | 1.99k | } |
6540 | 2.02k | ds_put_format(fp->s, ",%sobs_point_id=%s", colors.param, colors.end); |
6541 | 2.02k | if (a->obs_point_src.field) { |
6542 | 307 | mf_format_subfield(&a->obs_point_src, fp->s); |
6543 | 1.72k | } else { |
6544 | 1.72k | ds_put_format(fp->s, "%"PRIu32, a->obs_point_imm); |
6545 | 1.72k | } |
6546 | 2.02k | if (a->sampling_port != OFPP_NONE) { |
6547 | 2.00k | ds_put_format(fp->s, ",%ssampling_port=%s", colors.param, colors.end); |
6548 | 2.00k | ofputil_format_port(a->sampling_port, fp->port_map, fp->s); |
6549 | 2.00k | } |
6550 | 2.02k | if (a->direction == NX_ACTION_SAMPLE_INGRESS) { |
6551 | 284 | ds_put_format(fp->s, ",%singress%s", colors.param, colors.end); |
6552 | 1.74k | } else if (a->direction == NX_ACTION_SAMPLE_EGRESS) { |
6553 | 872 | ds_put_format(fp->s, ",%segress%s", colors.param, colors.end); |
6554 | 872 | } |
6555 | 2.02k | ds_put_format(fp->s, "%s)%s", colors.paren, colors.end); |
6556 | 2.02k | } |
6557 | | |
6558 | | static enum ofperr |
6559 | | check_SAMPLE(const struct ofpact_sample *a OVS_UNUSED, |
6560 | | const struct ofpact_check_params *cp OVS_UNUSED) |
6561 | 10 | { |
6562 | 10 | return 0; |
6563 | 10 | } |
6564 | | |
6565 | | /* debug instructions. */ |
6566 | | |
6567 | | static bool enable_debug; |
6568 | | |
6569 | | void |
6570 | | ofpact_dummy_enable(void) |
6571 | 0 | { |
6572 | 0 | enable_debug = true; |
6573 | 0 | } |
6574 | | |
6575 | | static enum ofperr |
6576 | | decode_NXAST_RAW_DEBUG_RECIRC(struct ofpbuf *out) |
6577 | 54 | { |
6578 | 54 | if (!enable_debug) { |
6579 | 54 | return OFPERR_OFPBAC_BAD_VENDOR_TYPE; |
6580 | 54 | } |
6581 | | |
6582 | 0 | ofpact_put_DEBUG_RECIRC(out); |
6583 | 0 | return 0; |
6584 | 54 | } |
6585 | | |
6586 | | static void |
6587 | | encode_DEBUG_RECIRC(const struct ofpact_null *n OVS_UNUSED, |
6588 | | enum ofp_version ofp_version OVS_UNUSED, |
6589 | | struct ofpbuf *out) |
6590 | 0 | { |
6591 | 0 | put_NXAST_DEBUG_RECIRC(out); |
6592 | 0 | } |
6593 | | |
6594 | | static char * OVS_WARN_UNUSED_RESULT |
6595 | | parse_DEBUG_RECIRC(char *arg OVS_UNUSED, const struct ofpact_parse_params *pp) |
6596 | 0 | { |
6597 | 0 | ofpact_put_DEBUG_RECIRC(pp->ofpacts); |
6598 | 0 | return NULL; |
6599 | 0 | } |
6600 | | |
6601 | | static void |
6602 | | format_DEBUG_RECIRC(const struct ofpact_null *a OVS_UNUSED, |
6603 | | const struct ofpact_format_params *fp) |
6604 | 0 | { |
6605 | 0 | ds_put_format(fp->s, "%sdebug_recirc%s", colors.value, colors.end); |
6606 | 0 | } |
6607 | | |
6608 | | static enum ofperr |
6609 | | check_DEBUG_RECIRC(const struct ofpact_null *a OVS_UNUSED, |
6610 | | const struct ofpact_check_params *cp OVS_UNUSED) |
6611 | 0 | { |
6612 | 0 | return 0; |
6613 | 0 | } |
6614 | | |
6615 | | static enum ofperr |
6616 | | decode_NXAST_RAW_DEBUG_SLOW(struct ofpbuf *out) |
6617 | 433 | { |
6618 | 433 | if (!enable_debug) { |
6619 | 433 | return OFPERR_OFPBAC_BAD_VENDOR_TYPE; |
6620 | 433 | } |
6621 | | |
6622 | 0 | ofpact_put_DEBUG_SLOW(out); |
6623 | 0 | return 0; |
6624 | 433 | } |
6625 | | |
6626 | | static void |
6627 | | encode_DEBUG_SLOW(const struct ofpact_null *n OVS_UNUSED, |
6628 | | enum ofp_version ofp_version OVS_UNUSED, |
6629 | | struct ofpbuf *out) |
6630 | 0 | { |
6631 | 0 | put_NXAST_DEBUG_SLOW(out); |
6632 | 0 | } |
6633 | | |
6634 | | static char * OVS_WARN_UNUSED_RESULT |
6635 | | parse_DEBUG_SLOW(char *arg OVS_UNUSED, const struct ofpact_parse_params *pp) |
6636 | 0 | { |
6637 | 0 | ofpact_put_DEBUG_SLOW(pp->ofpacts); |
6638 | 0 | return NULL; |
6639 | 0 | } |
6640 | | |
6641 | | static void |
6642 | | format_DEBUG_SLOW(const struct ofpact_null *a OVS_UNUSED, |
6643 | | const struct ofpact_format_params *fp) |
6644 | 0 | { |
6645 | 0 | ds_put_format(fp->s, "%sdebug_slow%s", colors.value, colors.end); |
6646 | 0 | } |
6647 | | |
6648 | | static enum ofperr |
6649 | | check_DEBUG_SLOW(const struct ofpact_null *a OVS_UNUSED, |
6650 | | const struct ofpact_check_params *cp OVS_UNUSED) |
6651 | 0 | { |
6652 | 0 | return 0; |
6653 | 0 | } |
6654 | | |
6655 | | /* Action structure for NXAST_CT. |
6656 | | * |
6657 | | * Pass traffic to the connection tracker. |
6658 | | * |
6659 | | * There are two important concepts to understanding the connection tracking |
6660 | | * interface: Packet state and Connection state. Packets may be "Untracked" or |
6661 | | * "Tracked". Connections may be "Uncommitted" or "Committed". |
6662 | | * |
6663 | | * - Packet State: |
6664 | | * |
6665 | | * Untracked packets have an unknown connection state. In most |
6666 | | * cases, packets entering the OpenFlow pipeline will initially be |
6667 | | * in the untracked state. Untracked packets may become tracked by |
6668 | | * executing NXAST_CT with a "recirc_table" specified. This makes |
6669 | | * various aspects about the connection available, in particular |
6670 | | * the connection state. |
6671 | | * |
6672 | | * An NXAST_CT action always puts the packet into an untracked |
6673 | | * state for the current processing path. If "recirc_table" is |
6674 | | * set, execution is forked and the packet passes through the |
6675 | | * connection tracker. The specified table's processing path is |
6676 | | * able to match on Connection state until the end of the OpenFlow |
6677 | | * pipeline or NXAST_CT is called again. |
6678 | | * |
6679 | | * - Connection State: |
6680 | | * |
6681 | | * Multiple packets may be associated with a single connection. Initially, |
6682 | | * all connections are uncommitted. The connection state corresponding to |
6683 | | * a packet is available in the NXM_NX_CT_STATE field for tracked packets. |
6684 | | * |
6685 | | * Uncommitted connections have no state stored about them. Uncommitted |
6686 | | * connections may transition into the committed state by executing |
6687 | | * NXAST_CT with the NX_CT_F_COMMIT flag. |
6688 | | * |
6689 | | * Once a connection becomes committed, information may be gathered about |
6690 | | * the connection by passing subsequent packets through the connection |
6691 | | * tracker, and the state of the connection will be stored beyond the |
6692 | | * lifetime of packet processing. |
6693 | | * |
6694 | | * A committed connection always has the directionality of the packet that |
6695 | | * caused the connection to be committed in the first place. This is the |
6696 | | * "original direction" of the connection, and the opposite direction is |
6697 | | * the "reply direction". If a connection is already committed, but it is |
6698 | | * then decided that the original direction should be the opposite of the |
6699 | | * existing connection, NX_CT_F_FORCE flag may be used in addition to |
6700 | | * NX_CT_F_COMMIT flag to in effect terminate the existing connection and |
6701 | | * start a new one in the current direction. |
6702 | | * |
6703 | | * Connections may transition back into the uncommitted state due to |
6704 | | * external timers, or due to the contents of packets that are sent to the |
6705 | | * connection tracker. This behaviour is outside of the scope of the |
6706 | | * OpenFlow interface. |
6707 | | * |
6708 | | * The "zone" specifies a context within which the tracking is done: |
6709 | | * |
6710 | | * The connection tracking zone is a 16-bit number. Each zone is an |
6711 | | * independent connection tracking context. The connection state for each |
6712 | | * connection is completely separate for each zone, so if a connection |
6713 | | * is committed to zone A, then it will remain uncommitted in zone B. |
6714 | | * If NXAST_CT is executed with the same zone multiple times, later |
6715 | | * executions have no effect. |
6716 | | * |
6717 | | * If 'zone_src' is nonzero, this specifies that the zone should be |
6718 | | * sourced from a field zone_src[ofs:ofs+nbits]. The format and semantics |
6719 | | * of 'zone_src' and 'zone_ofs_nbits' are similar to those for the |
6720 | | * NXAST_REG_LOAD action. The acceptable nxm_header values for 'zone_src' |
6721 | | * are the same as the acceptable nxm_header values for the 'src' field of |
6722 | | * NXAST_REG_MOVE. |
6723 | | * |
6724 | | * If 'zone_src' is zero, then the value of 'zone_imm' will be used as the |
6725 | | * connection tracking zone. |
6726 | | * |
6727 | | * The "recirc_table" allows NXM_NX_CT_* fields to become available: |
6728 | | * |
6729 | | * If "recirc_table" has a value other than NX_CT_RECIRC_NONE, then the |
6730 | | * packet will be logically cloned prior to executing this action. One |
6731 | | * copy will be sent to the connection tracker, then will be re-injected |
6732 | | * into the OpenFlow pipeline beginning at the OpenFlow table specified in |
6733 | | * this field. When the packet re-enters the pipeline, the NXM_NX_CT_* |
6734 | | * fields will be populated. The original instance of the packet will |
6735 | | * continue the current actions list. This can be thought of as similar to |
6736 | | * the effect of the "output" action: One copy is sent out (in this case, |
6737 | | * to the connection tracker), but the current copy continues processing. |
6738 | | * |
6739 | | * It is strongly recommended that this table is later than the current |
6740 | | * table, to prevent loops. |
6741 | | * |
6742 | | * The "alg" attaches protocol-specific behaviour to this action: |
6743 | | * |
6744 | | * The ALG is a 16-bit number which specifies that additional |
6745 | | * processing should be applied to this traffic. |
6746 | | * |
6747 | | * Protocol | Value | Meaning |
6748 | | * -------------------------------------------------------------------- |
6749 | | * None | 0 | No protocol-specific behaviour. |
6750 | | * FTP | 21 | Parse FTP control connections and observe the |
6751 | | * | | negotiation of related data connections. |
6752 | | * Other | Other | Unsupported protocols. |
6753 | | * |
6754 | | * By way of example, if FTP control connections have this action applied |
6755 | | * with the ALG set to FTP (21), then the connection tracker will observe |
6756 | | * the negotiation of data connections. This allows the connection |
6757 | | * tracker to identify subsequent data connections as "related" to this |
6758 | | * existing connection. The "related" flag will be populated in the |
6759 | | * NXM_NX_CT_STATE field for such connections if the 'recirc_table' is |
6760 | | * specified. |
6761 | | * |
6762 | | * Zero or more actions may immediately follow this action. These actions will |
6763 | | * be executed within the context of the connection tracker, and they require |
6764 | | * NX_CT_F_COMMIT flag be set. |
6765 | | */ |
6766 | | struct nx_action_conntrack { |
6767 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
6768 | | ovs_be16 len; /* At least 24. */ |
6769 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
6770 | | ovs_be16 subtype; /* NXAST_CT. */ |
6771 | | ovs_be16 flags; /* Zero or more NX_CT_F_* flags. |
6772 | | * Unspecified flag bits must be zero. */ |
6773 | | ovs_be32 zone_src; /* Connection tracking context. */ |
6774 | | union { |
6775 | | ovs_be16 zone_ofs_nbits;/* Range to use from source field. */ |
6776 | | ovs_be16 zone_imm; /* Immediate value for zone. */ |
6777 | | }; |
6778 | | uint8_t recirc_table; /* Recirculate to a specific table, or |
6779 | | NX_CT_RECIRC_NONE for no recirculation. */ |
6780 | | uint8_t pad[3]; /* Zeroes */ |
6781 | | ovs_be16 alg; /* Well-known port number for the protocol. |
6782 | | * 0 indicates no ALG is required. */ |
6783 | | /* Followed by a sequence of zero or more OpenFlow actions. The length of |
6784 | | * these is included in 'len'. */ |
6785 | | }; |
6786 | | OFP_ASSERT(sizeof(struct nx_action_conntrack) == 24); |
6787 | | |
6788 | | static enum ofperr |
6789 | | decode_ct_zone(const struct nx_action_conntrack *nac, |
6790 | | struct ofpact_conntrack *out, |
6791 | | const struct vl_mff_map *vl_mff_map, uint64_t *tlv_bitmap) |
6792 | 13.1k | { |
6793 | 13.1k | if (nac->zone_src) { |
6794 | 6.89k | enum ofperr error; |
6795 | | |
6796 | 6.89k | out->zone_src.ofs = nxm_decode_ofs(nac->zone_ofs_nbits); |
6797 | 6.89k | out->zone_src.n_bits = nxm_decode_n_bits(nac->zone_ofs_nbits); |
6798 | 6.89k | error = mf_vl_mff_mf_from_nxm_header(ntohl(nac->zone_src), |
6799 | 6.89k | vl_mff_map, &out->zone_src.field, |
6800 | 6.89k | tlv_bitmap); |
6801 | 6.89k | if (error) { |
6802 | 2.94k | return error; |
6803 | 2.94k | } |
6804 | | |
6805 | 3.95k | error = mf_check_src(&out->zone_src, NULL); |
6806 | 3.95k | if (error) { |
6807 | 770 | return error; |
6808 | 770 | } |
6809 | | |
6810 | 3.18k | if (out->zone_src.n_bits != 16) { |
6811 | 35 | VLOG_WARN_RL(&rl, "zone n_bits %d not within valid range [16..16]", |
6812 | 35 | out->zone_src.n_bits); |
6813 | 35 | return OFPERR_OFPBAC_BAD_SET_LEN; |
6814 | 35 | } |
6815 | 6.27k | } else { |
6816 | 6.27k | out->zone_src.field = NULL; |
6817 | 6.27k | out->zone_imm = ntohs(nac->zone_imm); |
6818 | 6.27k | } |
6819 | | |
6820 | 9.42k | return 0; |
6821 | 13.1k | } |
6822 | | |
6823 | | static enum ofperr |
6824 | | decode_NXAST_RAW_CT(const struct nx_action_conntrack *nac, |
6825 | | enum ofp_version ofp_version, |
6826 | | const struct vl_mff_map *vl_mff_map, uint64_t *tlv_bitmap, |
6827 | | struct ofpbuf *out) |
6828 | 13.2k | { |
6829 | 13.2k | const size_t ct_offset = ofpacts_pull(out); |
6830 | 13.2k | struct ofpact_conntrack *conntrack = ofpact_put_CT(out); |
6831 | 13.2k | int error; |
6832 | | |
6833 | 13.2k | conntrack->flags = ntohs(nac->flags); |
6834 | 13.2k | if (conntrack->flags & NX_CT_F_FORCE && |
6835 | 13.2k | !(conntrack->flags & NX_CT_F_COMMIT)) { |
6836 | 35 | error = OFPERR_OFPBAC_BAD_ARGUMENT; |
6837 | 35 | goto out; |
6838 | 35 | } |
6839 | | |
6840 | 13.1k | error = decode_ct_zone(nac, conntrack, vl_mff_map, tlv_bitmap); |
6841 | 13.1k | if (error) { |
6842 | 3.75k | goto out; |
6843 | 3.75k | } |
6844 | 9.42k | conntrack->recirc_table = nac->recirc_table; |
6845 | 9.42k | conntrack->alg = ntohs(nac->alg); |
6846 | | |
6847 | 9.42k | ofpbuf_pull(out, sizeof(*conntrack)); |
6848 | | |
6849 | 9.42k | struct ofpbuf openflow = ofpbuf_const_initializer( |
6850 | 9.42k | nac + 1, ntohs(nac->len) - sizeof(*nac)); |
6851 | 9.42k | error = ofpacts_pull_openflow_actions__(&openflow, openflow.size, |
6852 | 9.42k | ofp_version, |
6853 | 9.42k | 1u << OVSINST_OFPIT11_APPLY_ACTIONS, |
6854 | 9.42k | out, OFPACT_CT, vl_mff_map, |
6855 | 9.42k | tlv_bitmap); |
6856 | 9.42k | if (error) { |
6857 | 1.81k | return error; |
6858 | 1.81k | } |
6859 | | |
6860 | 7.61k | conntrack = ofpbuf_push_uninit(out, sizeof(*conntrack)); |
6861 | 7.61k | out->header = &conntrack->ofpact; |
6862 | 7.61k | ofpact_finish_CT(out, &conntrack); |
6863 | | |
6864 | 7.61k | if (conntrack->ofpact.len > sizeof(*conntrack) |
6865 | 7.61k | && !(conntrack->flags & NX_CT_F_COMMIT)) { |
6866 | 800 | const struct ofpact *a; |
6867 | 800 | size_t ofpacts_len = conntrack->ofpact.len - sizeof(*conntrack); |
6868 | | |
6869 | 800 | OFPACT_FOR_EACH (a, conntrack->actions, ofpacts_len) { |
6870 | 800 | if (a->type != OFPACT_NAT || ofpact_get_NAT(a)->flags |
6871 | 800 | || ofpact_get_NAT(a)->range_af != AF_UNSPEC) { |
6872 | 713 | VLOG_WARN_RL(&rl, "CT action requires commit flag if actions " |
6873 | 713 | "other than NAT without arguments are specified."); |
6874 | 713 | error = OFPERR_OFPBAC_BAD_ARGUMENT; |
6875 | 713 | goto out; |
6876 | 713 | } |
6877 | 800 | } |
6878 | 800 | } |
6879 | | |
6880 | 11.4k | out: |
6881 | 11.4k | ofpbuf_push_uninit(out, ct_offset); |
6882 | 11.4k | return error; |
6883 | 7.61k | } |
6884 | | |
6885 | | static void |
6886 | | encode_CT(const struct ofpact_conntrack *conntrack, |
6887 | | enum ofp_version ofp_version, struct ofpbuf *out) |
6888 | 0 | { |
6889 | 0 | struct nx_action_conntrack *nac; |
6890 | 0 | const size_t ofs = out->size; |
6891 | 0 | size_t len; |
6892 | |
|
6893 | 0 | nac = put_NXAST_CT(out); |
6894 | 0 | nac->flags = htons(conntrack->flags); |
6895 | 0 | if (conntrack->zone_src.field) { |
6896 | 0 | nac->zone_src = htonl(nxm_header_from_mff(conntrack->zone_src.field)); |
6897 | 0 | nac->zone_ofs_nbits = nxm_encode_ofs_nbits(conntrack->zone_src.ofs, |
6898 | 0 | conntrack->zone_src.n_bits); |
6899 | 0 | } else { |
6900 | 0 | nac->zone_src = htonl(0); |
6901 | 0 | nac->zone_imm = htons(conntrack->zone_imm); |
6902 | 0 | } |
6903 | 0 | nac->recirc_table = conntrack->recirc_table; |
6904 | 0 | nac->alg = htons(conntrack->alg); |
6905 | |
|
6906 | 0 | len = ofpacts_put_openflow_actions(conntrack->actions, |
6907 | 0 | ofpact_ct_get_action_len(conntrack), |
6908 | 0 | out, ofp_version); |
6909 | 0 | len += sizeof(*nac); |
6910 | 0 | nac = ofpbuf_at(out, ofs, sizeof(*nac)); |
6911 | 0 | nac->len = htons(len); |
6912 | 0 | } |
6913 | | |
6914 | | static char *OVS_WARN_UNUSED_RESULT |
6915 | | parse_NAT(char *arg, const struct ofpact_parse_params *pp); |
6916 | | |
6917 | | /* Parses 'arg' as the argument to a "ct" action, and appends such an |
6918 | | * action to 'pp->ofpacts'. |
6919 | | * |
6920 | | * Returns NULL if successful, otherwise a malloc()'d string describing the |
6921 | | * error. The caller is responsible for freeing the returned string. */ |
6922 | | static char * OVS_WARN_UNUSED_RESULT |
6923 | | parse_CT(char *arg, const struct ofpact_parse_params *pp) |
6924 | 0 | { |
6925 | 0 | const size_t ct_offset = ofpacts_pull(pp->ofpacts); |
6926 | 0 | struct ofpact_conntrack *oc; |
6927 | 0 | char *error = NULL; |
6928 | 0 | char *key, *value; |
6929 | |
|
6930 | 0 | oc = ofpact_put_CT(pp->ofpacts); |
6931 | 0 | oc->flags = 0; |
6932 | 0 | oc->recirc_table = NX_CT_RECIRC_NONE; |
6933 | 0 | while (ofputil_parse_key_value(&arg, &key, &value)) { |
6934 | 0 | if (!strcmp(key, "commit")) { |
6935 | 0 | oc->flags |= NX_CT_F_COMMIT; |
6936 | 0 | } else if (!strcmp(key, "force")) { |
6937 | 0 | oc->flags |= NX_CT_F_FORCE; |
6938 | 0 | } else if (!strcmp(key, "table")) { |
6939 | 0 | if (!ofputil_table_from_string(value, pp->table_map, |
6940 | 0 | &oc->recirc_table)) { |
6941 | 0 | error = xasprintf("unknown table %s", value); |
6942 | 0 | } else if (oc->recirc_table == NX_CT_RECIRC_NONE) { |
6943 | 0 | error = xasprintf("invalid table %#"PRIx8, oc->recirc_table); |
6944 | 0 | } |
6945 | 0 | } else if (!strcmp(key, "zone")) { |
6946 | 0 | error = str_to_u16(value, "zone", &oc->zone_imm); |
6947 | |
|
6948 | 0 | if (error) { |
6949 | 0 | free(error); |
6950 | 0 | error = mf_parse_subfield(&oc->zone_src, value); |
6951 | 0 | if (error) { |
6952 | 0 | return error; |
6953 | 0 | } |
6954 | 0 | } |
6955 | 0 | } else if (!strcmp(key, "alg")) { |
6956 | 0 | error = str_to_connhelper(value, &oc->alg); |
6957 | 0 | } else if (!strcmp(key, "nat")) { |
6958 | 0 | const size_t nat_offset = ofpacts_pull(pp->ofpacts); |
6959 | |
|
6960 | 0 | error = parse_NAT(value, pp); |
6961 | | /* Update CT action pointer and length. */ |
6962 | 0 | pp->ofpacts->header = ofpbuf_push_uninit(pp->ofpacts, nat_offset); |
6963 | 0 | oc = pp->ofpacts->header; |
6964 | 0 | } else if (!strcmp(key, "exec")) { |
6965 | | /* Hide existing actions from ofpacts_parse_copy(), so the |
6966 | | * nesting can be handled transparently. */ |
6967 | 0 | enum ofputil_protocol usable_protocols2; |
6968 | 0 | const size_t exec_offset = ofpacts_pull(pp->ofpacts); |
6969 | | |
6970 | | /* Initializes 'usable_protocol2', fold it back to |
6971 | | * '*usable_protocols' afterwards, so that we do not lose |
6972 | | * restrictions already in there. */ |
6973 | 0 | struct ofpact_parse_params pp2 = *pp; |
6974 | 0 | pp2.usable_protocols = &usable_protocols2; |
6975 | 0 | error = ofpacts_parse_copy(value, &pp2, false, OFPACT_CT); |
6976 | 0 | *pp->usable_protocols &= usable_protocols2; |
6977 | 0 | pp->ofpacts->header = ofpbuf_push_uninit(pp->ofpacts, exec_offset); |
6978 | 0 | oc = pp->ofpacts->header; |
6979 | 0 | } else { |
6980 | 0 | error = xasprintf("invalid argument to \"ct\" action: `%s'", key); |
6981 | 0 | } |
6982 | 0 | if (error) { |
6983 | 0 | break; |
6984 | 0 | } |
6985 | 0 | } |
6986 | 0 | if (!error && oc->flags & NX_CT_F_FORCE && !(oc->flags & NX_CT_F_COMMIT)) { |
6987 | 0 | error = xasprintf("\"force\" flag requires \"commit\" flag."); |
6988 | 0 | } |
6989 | |
|
6990 | 0 | if (ofpbuf_oversized(pp->ofpacts)) { |
6991 | 0 | free(error); |
6992 | 0 | return xasprintf("input too big"); |
6993 | 0 | } |
6994 | | |
6995 | 0 | ofpact_finish_CT(pp->ofpacts, &oc); |
6996 | 0 | ofpbuf_push_uninit(pp->ofpacts, ct_offset); |
6997 | 0 | return error; |
6998 | 0 | } |
6999 | | |
7000 | | static void |
7001 | | format_alg(int port, struct ds *s) |
7002 | 6.41k | { |
7003 | 6.41k | switch(port) { |
7004 | 255 | case IPPORT_FTP: |
7005 | 255 | ds_put_format(s, "%salg=%sftp,", colors.param, colors.end); |
7006 | 255 | break; |
7007 | 2.03k | case IPPORT_TFTP: |
7008 | 2.03k | ds_put_format(s, "%salg=%stftp,", colors.param, colors.end); |
7009 | 2.03k | break; |
7010 | 1.31k | case 0: |
7011 | | /* Don't print. */ |
7012 | 1.31k | break; |
7013 | 2.81k | default: |
7014 | 2.81k | ds_put_format(s, "%salg=%s%d,", colors.param, colors.end, port); |
7015 | 2.81k | break; |
7016 | 6.41k | } |
7017 | 6.41k | } |
7018 | | |
7019 | | static void format_NAT(const struct ofpact_nat *, |
7020 | | const struct ofpact_format_params *fp); |
7021 | | |
7022 | | static void |
7023 | | format_CT(const struct ofpact_conntrack *a, |
7024 | | const struct ofpact_format_params *fp) |
7025 | 6.41k | { |
7026 | 6.41k | ds_put_format(fp->s, "%sct(%s", colors.paren, colors.end); |
7027 | 6.41k | if (a->flags & NX_CT_F_COMMIT) { |
7028 | 2.92k | ds_put_format(fp->s, "%scommit%s,", colors.value, colors.end); |
7029 | 2.92k | } |
7030 | 6.41k | if (a->flags & NX_CT_F_FORCE) { |
7031 | 601 | ds_put_format(fp->s, "%sforce%s,", colors.value, colors.end); |
7032 | 601 | } |
7033 | 6.41k | if (a->recirc_table != NX_CT_RECIRC_NONE) { |
7034 | 4.95k | ds_put_format(fp->s, "%stable=%s", colors.special, colors.end); |
7035 | 4.95k | ofputil_format_table(a->recirc_table, fp->table_map, fp->s); |
7036 | 4.95k | ds_put_char(fp->s, ','); |
7037 | 4.95k | } |
7038 | 6.41k | if (a->zone_src.field) { |
7039 | 3.06k | ds_put_format(fp->s, "%szone=%s", colors.param, colors.end); |
7040 | 3.06k | mf_format_subfield(&a->zone_src, fp->s); |
7041 | 3.06k | ds_put_char(fp->s, ','); |
7042 | 3.35k | } else if (a->zone_imm) { |
7043 | 2.16k | ds_put_format(fp->s, "%szone=%s%"PRIu16",", |
7044 | 2.16k | colors.param, colors.end, a->zone_imm); |
7045 | 2.16k | } |
7046 | | /* If the first action is a NAT action, format it outside of the 'exec' |
7047 | | * envelope. */ |
7048 | 6.41k | const struct ofpact *action = a->actions; |
7049 | 6.41k | size_t actions_len = ofpact_ct_get_action_len(a); |
7050 | 6.41k | if (actions_len && action->type == OFPACT_NAT) { |
7051 | 1.79k | format_NAT(ofpact_get_NAT(action), fp); |
7052 | 1.79k | ds_put_char(fp->s, ','); |
7053 | 1.79k | actions_len -= OFPACT_ALIGN(action->len); |
7054 | 1.79k | action = ofpact_next(action); |
7055 | 1.79k | } |
7056 | 6.41k | if (actions_len) { |
7057 | 488 | ds_put_format(fp->s, "%sexec(%s", colors.paren, colors.end); |
7058 | 488 | ofpacts_format(action, actions_len, fp); |
7059 | 488 | ds_put_format(fp->s, "%s),%s", colors.paren, colors.end); |
7060 | 488 | } |
7061 | 6.41k | format_alg(a->alg, fp->s); |
7062 | 6.41k | ds_chomp(fp->s, ','); |
7063 | 6.41k | ds_put_format(fp->s, "%s)%s", colors.paren, colors.end); |
7064 | 6.41k | } |
7065 | | |
7066 | | static enum ofperr |
7067 | | check_CT(struct ofpact_conntrack *a, struct ofpact_check_params *cp) |
7068 | 1.22k | { |
7069 | 1.22k | struct flow *flow = &cp->match->flow; |
7070 | | |
7071 | 1.22k | if (!dl_type_is_ip_any(get_dl_type(flow)) |
7072 | 1.22k | || (flow->ct_state & CS_INVALID && a->flags & NX_CT_F_COMMIT) |
7073 | 1.22k | || (a->alg == IPPORT_FTP && flow->nw_proto != IPPROTO_TCP) |
7074 | 1.22k | || (a->alg == IPPORT_TFTP && flow->nw_proto != IPPROTO_UDP)) { |
7075 | | /* We can't downgrade to OF1.0 and expect inconsistent CT actions |
7076 | | * be silently discarded. Instead, datapath flow install fails, so |
7077 | | * it is better to flag inconsistent CT actions as hard errors. */ |
7078 | 199 | return OFPERR_OFPBAC_MATCH_INCONSISTENT; |
7079 | 199 | } |
7080 | | |
7081 | 1.02k | if (a->zone_src.field) { |
7082 | 995 | return mf_check_src(&a->zone_src, cp->match); |
7083 | 995 | } |
7084 | | |
7085 | 30 | return check_subactions(a->actions, ofpact_ct_get_action_len(a), cp); |
7086 | 1.02k | } |
7087 | | |
7088 | | /* ct_clear action. */ |
7089 | | |
7090 | | static enum ofperr |
7091 | | decode_NXAST_RAW_CT_CLEAR(struct ofpbuf *out) |
7092 | 359 | { |
7093 | 359 | ofpact_put_CT_CLEAR(out); |
7094 | 359 | return 0; |
7095 | 359 | } |
7096 | | |
7097 | | static void |
7098 | | encode_CT_CLEAR(const struct ofpact_null *null OVS_UNUSED, |
7099 | | enum ofp_version ofp_version OVS_UNUSED, |
7100 | | struct ofpbuf *out) |
7101 | 0 | { |
7102 | 0 | put_NXAST_CT_CLEAR(out); |
7103 | 0 | } |
7104 | | |
7105 | | static char * OVS_WARN_UNUSED_RESULT |
7106 | | parse_CT_CLEAR(char *arg OVS_UNUSED, const struct ofpact_parse_params *pp) |
7107 | 0 | { |
7108 | 0 | ofpact_put_CT_CLEAR(pp->ofpacts); |
7109 | 0 | return NULL; |
7110 | 0 | } |
7111 | | |
7112 | | static void |
7113 | | format_CT_CLEAR(const struct ofpact_null *a OVS_UNUSED, |
7114 | | const struct ofpact_format_params *fp) |
7115 | 84 | { |
7116 | 84 | ds_put_format(fp->s, "%sct_clear%s", colors.value, colors.end); |
7117 | 84 | } |
7118 | | |
7119 | | static enum ofperr |
7120 | | check_CT_CLEAR(const struct ofpact_null *a OVS_UNUSED, |
7121 | | const struct ofpact_check_params *cp OVS_UNUSED) |
7122 | 347 | { |
7123 | 347 | return 0; |
7124 | 347 | } |
7125 | | |
7126 | | /* NAT action. */ |
7127 | | |
7128 | | /* Which optional fields are present? */ |
7129 | | enum nx_nat_range { |
7130 | | NX_NAT_RANGE_IPV4_MIN = 1 << 0, /* ovs_be32 */ |
7131 | | NX_NAT_RANGE_IPV4_MAX = 1 << 1, /* ovs_be32 */ |
7132 | | NX_NAT_RANGE_IPV6_MIN = 1 << 2, /* struct in6_addr */ |
7133 | | NX_NAT_RANGE_IPV6_MAX = 1 << 3, /* struct in6_addr */ |
7134 | | NX_NAT_RANGE_PROTO_MIN = 1 << 4, /* ovs_be16 */ |
7135 | | NX_NAT_RANGE_PROTO_MAX = 1 << 5, /* ovs_be16 */ |
7136 | | }; |
7137 | | |
7138 | | /* Action structure for NXAST_NAT. */ |
7139 | | struct nx_action_nat { |
7140 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
7141 | | ovs_be16 len; /* At least 16. */ |
7142 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
7143 | | ovs_be16 subtype; /* NXAST_NAT. */ |
7144 | | uint8_t pad[2]; /* Must be zero. */ |
7145 | | ovs_be16 flags; /* Zero or more NX_NAT_F_* flags. |
7146 | | * Unspecified flag bits must be zero. */ |
7147 | | ovs_be16 range_present; /* NX_NAT_RANGE_* */ |
7148 | | /* Followed by optional parameters as specified by 'range_present' */ |
7149 | | }; |
7150 | | OFP_ASSERT(sizeof(struct nx_action_nat) == 16); |
7151 | | |
7152 | | static void |
7153 | | encode_NAT(const struct ofpact_nat *nat, |
7154 | | enum ofp_version ofp_version OVS_UNUSED, |
7155 | | struct ofpbuf *out) |
7156 | 0 | { |
7157 | 0 | struct nx_action_nat *nan; |
7158 | 0 | const size_t ofs = out->size; |
7159 | 0 | uint16_t range_present = 0; |
7160 | |
|
7161 | 0 | nan = put_NXAST_NAT(out); |
7162 | 0 | nan->flags = htons(nat->flags); |
7163 | 0 | if (nat->range_af == AF_INET) { |
7164 | 0 | if (nat->range.addr.ipv4.min) { |
7165 | 0 | ovs_be32 *min = ofpbuf_put_uninit(out, sizeof *min); |
7166 | 0 | *min = nat->range.addr.ipv4.min; |
7167 | 0 | range_present |= NX_NAT_RANGE_IPV4_MIN; |
7168 | 0 | } |
7169 | 0 | if (nat->range.addr.ipv4.max) { |
7170 | 0 | ovs_be32 *max = ofpbuf_put_uninit(out, sizeof *max); |
7171 | 0 | *max = nat->range.addr.ipv4.max; |
7172 | 0 | range_present |= NX_NAT_RANGE_IPV4_MAX; |
7173 | 0 | } |
7174 | 0 | } else if (nat->range_af == AF_INET6) { |
7175 | 0 | if (!ipv6_mask_is_any(&nat->range.addr.ipv6.min)) { |
7176 | 0 | struct in6_addr *min = ofpbuf_put_uninit(out, sizeof *min); |
7177 | 0 | *min = nat->range.addr.ipv6.min; |
7178 | 0 | range_present |= NX_NAT_RANGE_IPV6_MIN; |
7179 | 0 | } |
7180 | 0 | if (!ipv6_mask_is_any(&nat->range.addr.ipv6.max)) { |
7181 | 0 | struct in6_addr *max = ofpbuf_put_uninit(out, sizeof *max); |
7182 | 0 | *max = nat->range.addr.ipv6.max; |
7183 | 0 | range_present |= NX_NAT_RANGE_IPV6_MAX; |
7184 | 0 | } |
7185 | 0 | } |
7186 | 0 | if (nat->range_af != AF_UNSPEC) { |
7187 | 0 | if (nat->range.proto.min) { |
7188 | 0 | ovs_be16 *min = ofpbuf_put_uninit(out, sizeof *min); |
7189 | 0 | *min = htons(nat->range.proto.min); |
7190 | 0 | range_present |= NX_NAT_RANGE_PROTO_MIN; |
7191 | 0 | } |
7192 | 0 | if (nat->range.proto.max) { |
7193 | 0 | ovs_be16 *max = ofpbuf_put_uninit(out, sizeof *max); |
7194 | 0 | *max = htons(nat->range.proto.max); |
7195 | 0 | range_present |= NX_NAT_RANGE_PROTO_MAX; |
7196 | 0 | } |
7197 | 0 | } |
7198 | 0 | pad_ofpat(out, ofs); |
7199 | 0 | nan = ofpbuf_at(out, ofs, sizeof *nan); |
7200 | 0 | nan->range_present = htons(range_present); |
7201 | 0 | } |
7202 | | |
7203 | | static enum ofperr |
7204 | | decode_NXAST_RAW_NAT(const struct nx_action_nat *nan, |
7205 | | enum ofp_version ofp_version OVS_UNUSED, |
7206 | | struct ofpbuf *out) |
7207 | 17.9k | { |
7208 | 17.9k | struct ofpact_nat *nat; |
7209 | 17.9k | uint16_t range_present = ntohs(nan->range_present); |
7210 | 17.9k | const char *opts = (char *)(nan + 1); |
7211 | 17.9k | uint16_t len = ntohs(nan->len) - sizeof *nan; |
7212 | | |
7213 | 17.9k | nat = ofpact_put_NAT(out); |
7214 | 17.9k | nat->flags = ntohs(nan->flags); |
7215 | | |
7216 | | /* Check for unknown or mutually exclusive flags. */ |
7217 | 17.9k | if ((nat->flags & ~NX_NAT_F_MASK) |
7218 | 17.9k | || (nat->flags & NX_NAT_F_SRC && nat->flags & NX_NAT_F_DST) |
7219 | 17.9k | || (nat->flags & NX_NAT_F_PROTO_HASH |
7220 | 16.2k | && nat->flags & NX_NAT_F_PROTO_RANDOM)) { |
7221 | 1.63k | return OFPERR_OFPBAC_BAD_ARGUMENT; |
7222 | 1.63k | } |
7223 | | |
7224 | 16.2k | #define NX_NAT_GET_OPT(DST, SRC, LEN, TYPE) \ |
7225 | 39.3k | (LEN >= sizeof(TYPE) \ |
7226 | 39.3k | ? (memcpy(DST, SRC, sizeof(TYPE)), LEN -= sizeof(TYPE), \ |
7227 | 20.9k | SRC += sizeof(TYPE)) \ |
7228 | 39.3k | : NULL) |
7229 | | |
7230 | 16.2k | nat->range_af = AF_UNSPEC; |
7231 | 16.2k | if (range_present & NX_NAT_RANGE_IPV4_MIN) { |
7232 | 10.6k | if (range_present & (NX_NAT_RANGE_IPV6_MIN | NX_NAT_RANGE_IPV6_MAX)) { |
7233 | 2.01k | return OFPERR_OFPBAC_BAD_ARGUMENT; |
7234 | 2.01k | } |
7235 | | |
7236 | 8.62k | if (!NX_NAT_GET_OPT(&nat->range.addr.ipv4.min, opts, len, ovs_be32) |
7237 | 8.62k | || !nat->range.addr.ipv4.min) { |
7238 | 49 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
7239 | 49 | } |
7240 | | |
7241 | 8.57k | nat->range_af = AF_INET; |
7242 | | |
7243 | 8.57k | if (range_present & NX_NAT_RANGE_IPV4_MAX) { |
7244 | 1.55k | if (!NX_NAT_GET_OPT(&nat->range.addr.ipv4.max, opts, len, |
7245 | 1.55k | ovs_be32)) { |
7246 | 0 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
7247 | 0 | } |
7248 | 1.55k | if (ntohl(nat->range.addr.ipv4.max) |
7249 | 1.55k | < ntohl(nat->range.addr.ipv4.min)) { |
7250 | 448 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
7251 | 448 | } |
7252 | 1.55k | } |
7253 | 8.57k | } else if (range_present & NX_NAT_RANGE_IPV4_MAX) { |
7254 | 699 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
7255 | 4.94k | } else if (range_present & NX_NAT_RANGE_IPV6_MIN) { |
7256 | 4.01k | if (!NX_NAT_GET_OPT(&nat->range.addr.ipv6.min, opts, len, |
7257 | 4.01k | struct in6_addr) |
7258 | 4.01k | || ipv6_mask_is_any(&nat->range.addr.ipv6.min)) { |
7259 | 1.08k | return OFPERR_OFPBAC_BAD_ARGUMENT; |
7260 | 1.08k | } |
7261 | | |
7262 | 2.93k | nat->range_af = AF_INET6; |
7263 | | |
7264 | 2.93k | if (range_present & NX_NAT_RANGE_IPV6_MAX) { |
7265 | 2.85k | if (!NX_NAT_GET_OPT(&nat->range.addr.ipv6.max, opts, len, |
7266 | 2.85k | struct in6_addr)) { |
7267 | 57 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
7268 | 57 | } |
7269 | 2.79k | if (memcmp(&nat->range.addr.ipv6.max, &nat->range.addr.ipv6.min, |
7270 | 2.79k | sizeof(struct in6_addr)) < 0) { |
7271 | 329 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
7272 | 329 | } |
7273 | 2.79k | } |
7274 | 2.93k | } else if (range_present & NX_NAT_RANGE_IPV6_MAX) { |
7275 | 123 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
7276 | 123 | } |
7277 | | |
7278 | 11.4k | if (range_present & NX_NAT_RANGE_PROTO_MIN) { |
7279 | 4.20k | ovs_be16 proto; |
7280 | | |
7281 | 4.20k | if (nat->range_af == AF_UNSPEC) { |
7282 | 614 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
7283 | 614 | } |
7284 | 3.58k | if (!NX_NAT_GET_OPT(&proto, opts, len, ovs_be16) || proto == 0) { |
7285 | 1.06k | return OFPERR_OFPBAC_BAD_ARGUMENT; |
7286 | 1.06k | } |
7287 | 2.52k | nat->range.proto.min = ntohs(proto); |
7288 | 2.52k | if (range_present & NX_NAT_RANGE_PROTO_MAX) { |
7289 | 2.49k | if (!NX_NAT_GET_OPT(&proto, opts, len, ovs_be16)) { |
7290 | 0 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
7291 | 0 | } |
7292 | 2.49k | nat->range.proto.max = ntohs(proto); |
7293 | 2.49k | if (nat->range.proto.max < nat->range.proto.min) { |
7294 | 695 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
7295 | 695 | } |
7296 | 2.49k | } |
7297 | 7.27k | } else if (range_present & NX_NAT_RANGE_PROTO_MAX) { |
7298 | 440 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
7299 | 440 | } |
7300 | | |
7301 | 8.66k | return 0; |
7302 | 11.4k | } |
7303 | | |
7304 | | static void |
7305 | | format_NAT(const struct ofpact_nat *a, const struct ofpact_format_params *fp) |
7306 | 1.79k | { |
7307 | 1.79k | ds_put_format(fp->s, "%snat%s", colors.paren, colors.end); |
7308 | | |
7309 | 1.79k | if (a->flags & (NX_NAT_F_SRC | NX_NAT_F_DST)) { |
7310 | 1.69k | ds_put_format(fp->s, "%s(%s", colors.paren, colors.end); |
7311 | 1.69k | ds_put_format(fp->s, a->flags & NX_NAT_F_SRC ? "%ssrc%s" : "%sdst%s", |
7312 | 1.69k | colors.param, colors.end); |
7313 | | |
7314 | 1.69k | if (a->range_af != AF_UNSPEC) { |
7315 | 1.67k | ds_put_format(fp->s, "%s=%s", colors.param, colors.end); |
7316 | | |
7317 | 1.67k | if (a->range_af == AF_INET) { |
7318 | 1.67k | ds_put_format(fp->s, IP_FMT, IP_ARGS(a->range.addr.ipv4.min)); |
7319 | | |
7320 | 1.67k | if (a->range.addr.ipv4.max |
7321 | 1.67k | && a->range.addr.ipv4.max != a->range.addr.ipv4.min) { |
7322 | 35 | ds_put_format(fp->s, "-"IP_FMT, |
7323 | 35 | IP_ARGS(a->range.addr.ipv4.max)); |
7324 | 35 | } |
7325 | 1.67k | } else if (a->range_af == AF_INET6) { |
7326 | 0 | ipv6_format_addr_bracket(&a->range.addr.ipv6.min, fp->s, |
7327 | 0 | a->range.proto.min); |
7328 | |
|
7329 | 0 | if (!ipv6_mask_is_any(&a->range.addr.ipv6.max) |
7330 | 0 | && memcmp(&a->range.addr.ipv6.max, &a->range.addr.ipv6.min, |
7331 | 0 | sizeof(struct in6_addr)) != 0) { |
7332 | 0 | ds_put_char(fp->s, '-'); |
7333 | 0 | ipv6_format_addr_bracket(&a->range.addr.ipv6.max, fp->s, |
7334 | 0 | a->range.proto.min); |
7335 | 0 | } |
7336 | 0 | } |
7337 | 1.67k | if (a->range.proto.min) { |
7338 | 1.54k | ds_put_char(fp->s, ':'); |
7339 | 1.54k | ds_put_format(fp->s, "%"PRIu16, a->range.proto.min); |
7340 | | |
7341 | 1.54k | if (a->range.proto.max |
7342 | 1.54k | && a->range.proto.max != a->range.proto.min) { |
7343 | 1.04k | ds_put_format(fp->s, "-%"PRIu16, a->range.proto.max); |
7344 | 1.04k | } |
7345 | 1.54k | } |
7346 | 1.67k | ds_put_char(fp->s, ','); |
7347 | | |
7348 | 1.67k | if (a->flags & NX_NAT_F_PERSISTENT) { |
7349 | 145 | ds_put_format(fp->s, "%spersistent%s,", |
7350 | 145 | colors.value, colors.end); |
7351 | 145 | } |
7352 | 1.67k | if (a->flags & NX_NAT_F_PROTO_HASH) { |
7353 | 696 | ds_put_format(fp->s, "%shash%s,", colors.value, colors.end); |
7354 | 696 | } |
7355 | 1.67k | if (a->flags & NX_NAT_F_PROTO_RANDOM) { |
7356 | 30 | ds_put_format(fp->s, "%srandom%s,", colors.value, colors.end); |
7357 | 30 | } |
7358 | 1.67k | } |
7359 | 1.69k | ds_chomp(fp->s, ','); |
7360 | 1.69k | ds_put_format(fp->s, "%s)%s", colors.paren, colors.end); |
7361 | 1.69k | } |
7362 | 1.79k | } |
7363 | | |
7364 | | static char * OVS_WARN_UNUSED_RESULT |
7365 | | str_to_nat_range(const char *s, struct ofpact_nat *on) |
7366 | 0 | { |
7367 | 0 | char ipv6_s[IPV6_SCAN_LEN + 1]; |
7368 | 0 | int n = 0; |
7369 | |
|
7370 | 0 | on->range_af = AF_UNSPEC; |
7371 | 0 | if (ovs_scan_len(s, &n, IP_SCAN_FMT, |
7372 | 0 | IP_SCAN_ARGS(&on->range.addr.ipv4.min))) { |
7373 | 0 | on->range_af = AF_INET; |
7374 | |
|
7375 | 0 | if (s[n] == '-') { |
7376 | 0 | n++; |
7377 | 0 | if (!ovs_scan_len(s, &n, IP_SCAN_FMT, |
7378 | 0 | IP_SCAN_ARGS(&on->range.addr.ipv4.max)) |
7379 | 0 | || (ntohl(on->range.addr.ipv4.max) |
7380 | 0 | < ntohl(on->range.addr.ipv4.min))) { |
7381 | 0 | goto error; |
7382 | 0 | } |
7383 | 0 | } |
7384 | 0 | } else if ((ovs_scan_len(s, &n, IPV6_SCAN_FMT, ipv6_s) |
7385 | 0 | || ovs_scan_len(s, &n, "["IPV6_SCAN_FMT"]", ipv6_s)) |
7386 | 0 | && inet_pton(AF_INET6, ipv6_s, &on->range.addr.ipv6.min) == 1) { |
7387 | 0 | on->range_af = AF_INET6; |
7388 | |
|
7389 | 0 | if (s[n] == '-') { |
7390 | 0 | n++; |
7391 | 0 | if (!(ovs_scan_len(s, &n, IPV6_SCAN_FMT, ipv6_s) |
7392 | 0 | || ovs_scan_len(s, &n, "["IPV6_SCAN_FMT"]", ipv6_s)) |
7393 | 0 | || inet_pton(AF_INET6, ipv6_s, &on->range.addr.ipv6.max) != 1 |
7394 | 0 | || memcmp(&on->range.addr.ipv6.max, &on->range.addr.ipv6.min, |
7395 | 0 | sizeof on->range.addr.ipv6.max) < 0) { |
7396 | 0 | goto error; |
7397 | 0 | } |
7398 | 0 | } |
7399 | 0 | } |
7400 | 0 | if (on->range_af != AF_UNSPEC && s[n] == ':') { |
7401 | 0 | n++; |
7402 | 0 | if (!ovs_scan_len(s, &n, "%"SCNu16, &on->range.proto.min)) { |
7403 | 0 | goto error; |
7404 | 0 | } |
7405 | 0 | if (s[n] == '-') { |
7406 | 0 | n++; |
7407 | 0 | if (!ovs_scan_len(s, &n, "%"SCNu16, &on->range.proto.max) |
7408 | 0 | || on->range.proto.max < on->range.proto.min) { |
7409 | 0 | goto error; |
7410 | 0 | } |
7411 | 0 | } |
7412 | 0 | } |
7413 | 0 | if (strlen(s) != n) { |
7414 | 0 | return xasprintf("garbage (%s) after nat range \"%s\" (pos: %d)", |
7415 | 0 | &s[n], s, n); |
7416 | 0 | } |
7417 | 0 | return NULL; |
7418 | 0 | error: |
7419 | 0 | return xasprintf("invalid nat range \"%s\"", s); |
7420 | 0 | } |
7421 | | |
7422 | | |
7423 | | /* Parses 'arg' as the argument to a "nat" action, and appends such an |
7424 | | * action to 'pp->ofpacts'. |
7425 | | * |
7426 | | * Returns NULL if successful, otherwise a malloc()'d string describing the |
7427 | | * error. The caller is responsible for freeing the returned string. */ |
7428 | | static char * OVS_WARN_UNUSED_RESULT |
7429 | | parse_NAT(char *arg, const struct ofpact_parse_params *pp) |
7430 | 0 | { |
7431 | 0 | struct ofpact_nat *on = ofpact_put_NAT(pp->ofpacts); |
7432 | 0 | char *key, *value; |
7433 | |
|
7434 | 0 | on->flags = 0; |
7435 | 0 | on->range_af = AF_UNSPEC; |
7436 | |
|
7437 | 0 | while (ofputil_parse_key_value(&arg, &key, &value)) { |
7438 | 0 | char *error = NULL; |
7439 | |
|
7440 | 0 | if (!strcmp(key, "src")) { |
7441 | 0 | on->flags |= NX_NAT_F_SRC; |
7442 | 0 | error = str_to_nat_range(value, on); |
7443 | 0 | } else if (!strcmp(key, "dst")) { |
7444 | 0 | on->flags |= NX_NAT_F_DST; |
7445 | 0 | error = str_to_nat_range(value, on); |
7446 | 0 | } else if (!strcmp(key, "persistent")) { |
7447 | 0 | on->flags |= NX_NAT_F_PERSISTENT; |
7448 | 0 | } else if (!strcmp(key, "hash")) { |
7449 | 0 | on->flags |= NX_NAT_F_PROTO_HASH; |
7450 | 0 | } else if (!strcmp(key, "random")) { |
7451 | 0 | on->flags |= NX_NAT_F_PROTO_RANDOM; |
7452 | 0 | } else { |
7453 | 0 | error = xasprintf("invalid key \"%s\" in \"nat\" argument", |
7454 | 0 | key); |
7455 | 0 | } |
7456 | 0 | if (error) { |
7457 | 0 | return error; |
7458 | 0 | } |
7459 | 0 | } |
7460 | 0 | if (on->flags & NX_NAT_F_SRC && on->flags & NX_NAT_F_DST) { |
7461 | 0 | return xasprintf("May only specify one of \"src\" or \"dst\"."); |
7462 | 0 | } |
7463 | 0 | if (!(on->flags & NX_NAT_F_SRC || on->flags & NX_NAT_F_DST)) { |
7464 | 0 | if (on->flags) { |
7465 | 0 | return xasprintf("Flags allowed only with \"src\" or \"dst\"."); |
7466 | 0 | } |
7467 | 0 | if (on->range_af != AF_UNSPEC) { |
7468 | 0 | return xasprintf("Range allowed only with \"src\" or \"dst\"."); |
7469 | 0 | } |
7470 | 0 | } |
7471 | 0 | if (on->flags & NX_NAT_F_PROTO_HASH && on->flags & NX_NAT_F_PROTO_RANDOM) { |
7472 | 0 | return xasprintf("Both \"hash\" and \"random\" are not allowed."); |
7473 | 0 | } |
7474 | | |
7475 | 0 | return NULL; |
7476 | 0 | } |
7477 | | |
7478 | | static enum ofperr |
7479 | | check_NAT(const struct ofpact_nat *a, const struct ofpact_check_params *cp) |
7480 | 6 | { |
7481 | 6 | ovs_be16 dl_type = get_dl_type(&cp->match->flow); |
7482 | 6 | if (!dl_type_is_ip_any(dl_type) || |
7483 | 6 | (a->range_af == AF_INET && dl_type != htons(ETH_TYPE_IP)) || |
7484 | 6 | (a->range_af == AF_INET6 && dl_type != htons(ETH_TYPE_IPV6))) { |
7485 | 1 | return OFPERR_OFPBAC_MATCH_INCONSISTENT; |
7486 | 1 | } |
7487 | 5 | return 0; |
7488 | 6 | } |
7489 | | |
7490 | | /* Truncate output action. */ |
7491 | | struct nx_action_output_trunc { |
7492 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
7493 | | ovs_be16 len; /* At least 16. */ |
7494 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
7495 | | ovs_be16 subtype; /* NXAST_OUTPUT_TRUNC. */ |
7496 | | ovs_be16 port; /* Output port */ |
7497 | | ovs_be32 max_len; /* Truncate packet to size bytes */ |
7498 | | }; |
7499 | | OFP_ASSERT(sizeof(struct nx_action_output_trunc) == 16); |
7500 | | |
7501 | | static enum ofperr |
7502 | | decode_NXAST_RAW_OUTPUT_TRUNC(const struct nx_action_output_trunc *natrc, |
7503 | | enum ofp_version ofp_version OVS_UNUSED, |
7504 | | struct ofpbuf *out) |
7505 | 1.18k | { |
7506 | 1.18k | struct ofpact_output_trunc *output_trunc; |
7507 | | |
7508 | 1.18k | output_trunc = ofpact_put_OUTPUT_TRUNC(out); |
7509 | 1.18k | output_trunc->max_len = ntohl(natrc->max_len); |
7510 | 1.18k | output_trunc->port = u16_to_ofp(ntohs(natrc->port)); |
7511 | | |
7512 | 1.18k | if (output_trunc->max_len < ETH_HEADER_LEN) { |
7513 | 10 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
7514 | 10 | } |
7515 | 1.17k | return 0; |
7516 | 1.18k | } |
7517 | | |
7518 | | static void |
7519 | | encode_OUTPUT_TRUNC(const struct ofpact_output_trunc *output_trunc, |
7520 | | enum ofp_version ofp_version OVS_UNUSED, |
7521 | | struct ofpbuf *out) |
7522 | 0 | { |
7523 | 0 | struct nx_action_output_trunc *natrc = put_NXAST_OUTPUT_TRUNC(out); |
7524 | |
|
7525 | 0 | natrc->max_len = htonl(output_trunc->max_len); |
7526 | 0 | natrc->port = htons(ofp_to_u16(output_trunc->port)); |
7527 | 0 | } |
7528 | | |
7529 | | static char * OVS_WARN_UNUSED_RESULT |
7530 | | parse_OUTPUT_TRUNC(const char *arg, |
7531 | | const struct ofpact_parse_params *pp OVS_UNUSED) |
7532 | 0 | { |
7533 | | /* Disable output_trunc parsing. Expose as output(port=N,max_len=M) and |
7534 | | * reuse parse_OUTPUT to parse output_trunc action. */ |
7535 | 0 | return xasprintf("unknown action %s", arg); |
7536 | 0 | } |
7537 | | |
7538 | | static void |
7539 | | format_OUTPUT_TRUNC(const struct ofpact_output_trunc *a, |
7540 | | const struct ofpact_format_params *fp) |
7541 | 97 | { |
7542 | 97 | ds_put_format(fp->s, "%soutput%s(port=", colors.special, colors.end); |
7543 | 97 | ofputil_format_port(a->port, fp->port_map, fp->s); |
7544 | 97 | ds_put_format(fp->s, ",max_len=%"PRIu32")", a->max_len); |
7545 | 97 | } |
7546 | | |
7547 | | static enum ofperr |
7548 | | check_OUTPUT_TRUNC(const struct ofpact_output_trunc *a, |
7549 | | const struct ofpact_check_params *cp) |
7550 | 95 | { |
7551 | 95 | return ofpact_check_output_port(a->port, cp->max_ports); |
7552 | 95 | } |
7553 | | |
7554 | | /* Meter. |
7555 | | * |
7556 | | * In OpenFlow 1.3 and 1.4, "meter" is an instruction. |
7557 | | * In OpenFlow 1.5 and later, "meter" is an action. |
7558 | | * |
7559 | | * OpenFlow 1.5 */ |
7560 | | |
7561 | | static enum ofperr |
7562 | | decode_OFPAT_RAW15_METER(uint32_t meter_id, |
7563 | | enum ofp_version ofp_version OVS_UNUSED, |
7564 | | struct ofpbuf *out) |
7565 | 2.14k | { |
7566 | 2.14k | struct ofpact_meter *om = ofpact_put_METER(out); |
7567 | 2.14k | om->meter_id = meter_id; |
7568 | 2.14k | om->provider_meter_id = UINT32_MAX; /* No provider meter ID. */ |
7569 | 2.14k | return 0; |
7570 | 2.14k | } |
7571 | | |
7572 | | static void |
7573 | | encode_METER(const struct ofpact_meter *meter, |
7574 | | enum ofp_version ofp_version, struct ofpbuf *out) |
7575 | 0 | { |
7576 | 0 | if (ofp_version == OFP13_VERSION || ofp_version == OFP14_VERSION) { |
7577 | 0 | instruction_put_OFPIT13_METER(out)->meter_id = htonl(meter->meter_id); |
7578 | 0 | } else if (ofp_version >= OFP15_VERSION) { |
7579 | 0 | put_OFPAT15_METER(out, meter->meter_id); |
7580 | 0 | } |
7581 | 0 | } |
7582 | | |
7583 | | static char * OVS_WARN_UNUSED_RESULT |
7584 | | parse_METER(char *arg, const struct ofpact_parse_params *pp) |
7585 | 0 | { |
7586 | 0 | *pp->usable_protocols &= OFPUTIL_P_OF13_UP; |
7587 | 0 | return str_to_u32(arg, &ofpact_put_METER(pp->ofpacts)->meter_id); |
7588 | 0 | } |
7589 | | |
7590 | | static void |
7591 | | format_METER(const struct ofpact_meter *a, |
7592 | | const struct ofpact_format_params *fp) |
7593 | 1.45k | { |
7594 | 1.45k | ds_put_format(fp->s, "%smeter:%s%"PRIu32, |
7595 | 1.45k | colors.param, colors.end, a->meter_id); |
7596 | 1.45k | } |
7597 | | |
7598 | | static enum ofperr |
7599 | | check_METER(const struct ofpact_meter *a, |
7600 | | const struct ofpact_check_params *cp OVS_UNUSED) |
7601 | 90 | { |
7602 | 90 | uint32_t mid = a->meter_id; |
7603 | 90 | return mid == 0 || mid > OFPM13_MAX ? OFPERR_OFPMMFC_INVALID_METER : 0; |
7604 | 90 | } |
7605 | | |
7606 | | /* Clear-Actions instruction. */ |
7607 | | |
7608 | | static void |
7609 | | encode_CLEAR_ACTIONS(const struct ofpact_null *null OVS_UNUSED, |
7610 | | enum ofp_version ofp_version OVS_UNUSED, |
7611 | | struct ofpbuf *out OVS_UNUSED) |
7612 | 0 | { |
7613 | 0 | if (ofp_version > OFP10_VERSION) { |
7614 | 0 | instruction_put_OFPIT11_CLEAR_ACTIONS(out); |
7615 | 0 | } |
7616 | 0 | } |
7617 | | |
7618 | | static char * OVS_WARN_UNUSED_RESULT |
7619 | | parse_CLEAR_ACTIONS(char *arg OVS_UNUSED, const struct ofpact_parse_params *pp) |
7620 | 0 | { |
7621 | 0 | ofpact_put_CLEAR_ACTIONS(pp->ofpacts); |
7622 | 0 | return NULL; |
7623 | 0 | } |
7624 | | |
7625 | | static void |
7626 | | format_CLEAR_ACTIONS(const struct ofpact_null *a OVS_UNUSED, |
7627 | | const struct ofpact_format_params *fp) |
7628 | 75 | { |
7629 | 75 | ds_put_format(fp->s, "%sclear_actions%s", colors.value, colors.end); |
7630 | 75 | } |
7631 | | |
7632 | | static enum ofperr |
7633 | | check_CLEAR_ACTIONS(const struct ofpact_null *a OVS_UNUSED, |
7634 | | const struct ofpact_check_params *cp OVS_UNUSED) |
7635 | 75 | { |
7636 | 75 | return 0; |
7637 | 75 | } |
7638 | | |
7639 | | /* Write-Actions instruction. */ |
7640 | | |
7641 | | static void |
7642 | | encode_WRITE_ACTIONS(const struct ofpact_nest *actions, |
7643 | | enum ofp_version ofp_version, struct ofpbuf *out) |
7644 | 0 | { |
7645 | 0 | if (ofp_version > OFP10_VERSION) { |
7646 | 0 | const size_t ofs = out->size; |
7647 | |
|
7648 | 0 | instruction_put_OFPIT11_WRITE_ACTIONS(out); |
7649 | 0 | ofpacts_put_openflow_actions(actions->actions, |
7650 | 0 | ofpact_nest_get_action_len(actions), |
7651 | 0 | out, ofp_version); |
7652 | 0 | ofpacts_update_instruction_actions(out, ofs); |
7653 | 0 | } |
7654 | 0 | } |
7655 | | |
7656 | | static char * OVS_WARN_UNUSED_RESULT |
7657 | | parse_WRITE_ACTIONS(char *arg, const struct ofpact_parse_params *pp) |
7658 | 0 | { |
7659 | 0 | size_t ofs = ofpacts_pull(pp->ofpacts); |
7660 | 0 | struct ofpact_nest *on; |
7661 | 0 | char *error; |
7662 | | |
7663 | | /* Add a Write-Actions instruction and then pull it off. */ |
7664 | 0 | ofpact_put(pp->ofpacts, OFPACT_WRITE_ACTIONS, sizeof *on); |
7665 | 0 | ofpbuf_pull(pp->ofpacts, sizeof *on); |
7666 | | |
7667 | | /* Parse nested actions. |
7668 | | * |
7669 | | * We pulled off "write-actions" and the previous actions because the |
7670 | | * OFPACT_WRITE_ACTIONS is only partially constructed: its length is such |
7671 | | * that it doesn't actually include the nested actions. That means that |
7672 | | * ofpacts_parse() would reject them as being part of an Apply-Actions that |
7673 | | * follows a Write-Actions, which is an invalid order. */ |
7674 | 0 | error = ofpacts_parse(arg, pp, false, OFPACT_WRITE_ACTIONS); |
7675 | | |
7676 | | /* Put the Write-Actions back on and update its length. */ |
7677 | 0 | on = ofpbuf_push_uninit(pp->ofpacts, sizeof *on); |
7678 | 0 | on->ofpact.len = pp->ofpacts->size; |
7679 | | |
7680 | | /* Put any previous actions or instructions back on. */ |
7681 | 0 | ofpbuf_push_uninit(pp->ofpacts, ofs); |
7682 | |
|
7683 | 0 | return error; |
7684 | 0 | } |
7685 | | |
7686 | | static void |
7687 | | format_WRITE_ACTIONS(const struct ofpact_nest *a, |
7688 | | const struct ofpact_format_params *fp) |
7689 | 12.2k | { |
7690 | 12.2k | ds_put_format(fp->s, "%swrite_actions(%s", colors.paren, colors.end); |
7691 | 12.2k | ofpacts_format(a->actions, ofpact_nest_get_action_len(a), fp); |
7692 | 12.2k | ds_put_format(fp->s, "%s)%s", colors.paren, colors.end); |
7693 | 12.2k | } |
7694 | | |
7695 | | static enum ofperr |
7696 | | check_WRITE_ACTIONS(struct ofpact_nest *a, |
7697 | | const struct ofpact_check_params *cp) |
7698 | 12.8k | { |
7699 | | /* Use a temporary copy of 'cp' to avoid updating 'cp->usable_protocols', |
7700 | | * since we can't check consistency of an action set. */ |
7701 | 12.8k | struct ofpact_check_params tmp = *cp; |
7702 | 12.8k | return ofpacts_check(a->actions, ofpact_nest_get_action_len(a), &tmp); |
7703 | 12.8k | } |
7704 | | |
7705 | | /* Action structure for NXAST_WRITE_METADATA. |
7706 | | * |
7707 | | * Modifies the 'mask' bits of the metadata value. */ |
7708 | | struct nx_action_write_metadata { |
7709 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
7710 | | ovs_be16 len; /* Length is 32. */ |
7711 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
7712 | | ovs_be16 subtype; /* NXAST_WRITE_METADATA. */ |
7713 | | uint8_t zeros[6]; /* Must be zero. */ |
7714 | | ovs_be64 metadata; /* Metadata register. */ |
7715 | | ovs_be64 mask; /* Metadata mask. */ |
7716 | | }; |
7717 | | OFP_ASSERT(sizeof(struct nx_action_write_metadata) == 32); |
7718 | | |
7719 | | static enum ofperr |
7720 | | decode_NXAST_RAW_WRITE_METADATA(const struct nx_action_write_metadata *nawm, |
7721 | | enum ofp_version ofp_version OVS_UNUSED, |
7722 | | struct ofpbuf *out) |
7723 | 2.94k | { |
7724 | 2.94k | struct ofpact_metadata *om; |
7725 | | |
7726 | 2.94k | if (!is_all_zeros(nawm->zeros, sizeof nawm->zeros)) { |
7727 | 36 | return OFPERR_NXBRC_MUST_BE_ZERO; |
7728 | 36 | } |
7729 | | |
7730 | 2.91k | om = ofpact_put_WRITE_METADATA(out); |
7731 | 2.91k | om->metadata = nawm->metadata; |
7732 | 2.91k | om->mask = nawm->mask; |
7733 | | |
7734 | 2.91k | return 0; |
7735 | 2.94k | } |
7736 | | |
7737 | | static void |
7738 | | encode_WRITE_METADATA(const struct ofpact_metadata *metadata, |
7739 | | enum ofp_version ofp_version, struct ofpbuf *out) |
7740 | 0 | { |
7741 | 0 | if (ofp_version == OFP10_VERSION) { |
7742 | 0 | struct nx_action_write_metadata *nawm; |
7743 | |
|
7744 | 0 | nawm = put_NXAST_WRITE_METADATA(out); |
7745 | 0 | nawm->metadata = metadata->metadata; |
7746 | 0 | nawm->mask = metadata->mask; |
7747 | 0 | } else { |
7748 | 0 | struct ofp11_instruction_write_metadata *oiwm; |
7749 | |
|
7750 | 0 | oiwm = instruction_put_OFPIT11_WRITE_METADATA(out); |
7751 | 0 | oiwm->metadata = metadata->metadata; |
7752 | 0 | oiwm->metadata_mask = metadata->mask; |
7753 | 0 | } |
7754 | 0 | } |
7755 | | |
7756 | | static char * OVS_WARN_UNUSED_RESULT |
7757 | | parse_WRITE_METADATA(char *arg, const struct ofpact_parse_params *pp) |
7758 | 0 | { |
7759 | 0 | struct ofpact_metadata *om; |
7760 | 0 | char *mask = strchr(arg, '/'); |
7761 | |
|
7762 | 0 | *pp->usable_protocols &= OFPUTIL_P_NXM_OF11_UP; |
7763 | |
|
7764 | 0 | om = ofpact_put_WRITE_METADATA(pp->ofpacts); |
7765 | 0 | if (mask) { |
7766 | 0 | char *error; |
7767 | |
|
7768 | 0 | *mask = '\0'; |
7769 | 0 | error = str_to_be64(mask + 1, &om->mask); |
7770 | 0 | if (error) { |
7771 | 0 | return error; |
7772 | 0 | } |
7773 | 0 | } else { |
7774 | 0 | om->mask = OVS_BE64_MAX; |
7775 | 0 | } |
7776 | | |
7777 | 0 | return str_to_be64(arg, &om->metadata); |
7778 | 0 | } |
7779 | | |
7780 | | static void |
7781 | | format_WRITE_METADATA(const struct ofpact_metadata *a, |
7782 | | const struct ofpact_format_params *fp) |
7783 | 132 | { |
7784 | 132 | ds_put_format(fp->s, "%swrite_metadata:%s%#"PRIx64, |
7785 | 132 | colors.param, colors.end, ntohll(a->metadata)); |
7786 | 132 | if (a->mask != OVS_BE64_MAX) { |
7787 | 114 | ds_put_format(fp->s, "/%#"PRIx64, ntohll(a->mask)); |
7788 | 114 | } |
7789 | 132 | } |
7790 | | |
7791 | | static enum ofperr |
7792 | | check_WRITE_METADATA(const struct ofpact_metadata *a OVS_UNUSED, |
7793 | | const struct ofpact_check_params *cp OVS_UNUSED) |
7794 | 97 | { |
7795 | 97 | return 0; |
7796 | 97 | } |
7797 | | |
7798 | | /* Check packet length action. */ |
7799 | | |
7800 | | struct nx_action_check_pkt_larger { |
7801 | | ovs_be16 type; /* OFPAT_VENDOR. */ |
7802 | | ovs_be16 len; /* 24. */ |
7803 | | ovs_be32 vendor; /* NX_VENDOR_ID. */ |
7804 | | ovs_be16 subtype; /* NXAST_OUTPUT_REG. */ |
7805 | | ovs_be16 pkt_len; /* Length of the packet to check. */ |
7806 | | ovs_be16 offset; /* Result bit offset in destination. */ |
7807 | | /* Followed by: |
7808 | | * - 'dst', as an OXM/NXM header (either 4 or 8 bytes). |
7809 | | * - Enough 0-bytes to pad the action out to 24 bytes. */ |
7810 | | uint8_t pad[10]; |
7811 | | }; |
7812 | | |
7813 | | OFP_ASSERT(sizeof(struct nx_action_check_pkt_larger) == 24); |
7814 | | |
7815 | | static enum ofperr |
7816 | | decode_NXAST_RAW_CHECK_PKT_LARGER( |
7817 | | const struct nx_action_check_pkt_larger *ncpl, |
7818 | | enum ofp_version ofp_version OVS_UNUSED, |
7819 | | const struct vl_mff_map *vl_mff_map, uint64_t *tlv_bitmap, |
7820 | | struct ofpbuf *out) |
7821 | 583 | { |
7822 | 583 | struct ofpact_check_pkt_larger *check_pkt_larger; |
7823 | 583 | enum ofperr error; |
7824 | | |
7825 | 583 | check_pkt_larger = ofpact_put_CHECK_PKT_LARGER(out); |
7826 | 583 | check_pkt_larger->pkt_len = ntohs(ncpl->pkt_len); |
7827 | 583 | check_pkt_larger->dst.ofs = ntohs(ncpl->offset); |
7828 | 583 | check_pkt_larger->dst.n_bits = 1; |
7829 | | |
7830 | 583 | struct ofpbuf b = ofpbuf_const_initializer(ncpl, ntohs(ncpl->len)); |
7831 | 583 | ofpbuf_pull(&b, OBJECT_OFFSETOF(ncpl, pad)); |
7832 | | |
7833 | 583 | error = mf_vl_mff_nx_pull_header(&b, vl_mff_map, |
7834 | 583 | &check_pkt_larger->dst.field, |
7835 | 583 | NULL, tlv_bitmap); |
7836 | 583 | if (error) { |
7837 | 550 | return error; |
7838 | 550 | } |
7839 | | |
7840 | 33 | if (!is_all_zeros(b.data, b.size)) { |
7841 | 10 | return OFPERR_NXBRC_MUST_BE_ZERO; |
7842 | 10 | } |
7843 | | |
7844 | 23 | return mf_check_dst(&check_pkt_larger->dst, NULL); |
7845 | 33 | } |
7846 | | |
7847 | | static void |
7848 | | encode_CHECK_PKT_LARGER(const struct ofpact_check_pkt_larger *check_pkt_larger, |
7849 | | enum ofp_version ofp_version OVS_UNUSED, |
7850 | | struct ofpbuf *out) |
7851 | 0 | { |
7852 | 0 | struct nx_action_check_pkt_larger *ncpl = put_NXAST_CHECK_PKT_LARGER(out); |
7853 | 0 | ncpl->pkt_len = htons(check_pkt_larger->pkt_len); |
7854 | 0 | ncpl->offset = htons(check_pkt_larger->dst.ofs); |
7855 | |
|
7856 | 0 | if (check_pkt_larger->dst.field) { |
7857 | 0 | size_t size = out->size; |
7858 | 0 | out->size = size - sizeof ncpl->pad; |
7859 | 0 | nx_put_mff_header(out, check_pkt_larger->dst.field, 0, false); |
7860 | 0 | out->size = size; |
7861 | 0 | } |
7862 | 0 | } |
7863 | | |
7864 | | static char * OVS_WARN_UNUSED_RESULT |
7865 | | parse_CHECK_PKT_LARGER(char *arg, const struct ofpact_parse_params *pp) |
7866 | 0 | { |
7867 | 0 | char *value; |
7868 | 0 | char *delim; |
7869 | 0 | char *key; |
7870 | 0 | char *error = set_field_split_str(arg, &key, &value, &delim); |
7871 | 0 | if (error) { |
7872 | 0 | return error; |
7873 | 0 | } |
7874 | | |
7875 | 0 | delim[0] = '\0'; |
7876 | 0 | if (value[strlen(value) - 1] == ')') { |
7877 | 0 | value[strlen(value) - 1] = '\0'; |
7878 | 0 | } |
7879 | 0 | struct mf_subfield dst; |
7880 | 0 | error = mf_parse_subfield(&dst, key); |
7881 | 0 | if (error) { |
7882 | 0 | return error; |
7883 | 0 | } |
7884 | | |
7885 | 0 | if (dst.n_bits != 1) { |
7886 | 0 | return xstrdup("Only 1-bit destination field is allowed"); |
7887 | 0 | } |
7888 | | |
7889 | 0 | struct ofpact_check_pkt_larger *check_pkt_larger = |
7890 | 0 | ofpact_put_CHECK_PKT_LARGER(pp->ofpacts); |
7891 | 0 | error = str_to_u16(value, NULL, &check_pkt_larger->pkt_len); |
7892 | 0 | if (error) { |
7893 | 0 | return error; |
7894 | 0 | } |
7895 | 0 | check_pkt_larger->dst = dst; |
7896 | 0 | return NULL; |
7897 | 0 | } |
7898 | | |
7899 | | static void |
7900 | | format_CHECK_PKT_LARGER(const struct ofpact_check_pkt_larger *a, |
7901 | | const struct ofpact_format_params *fp) |
7902 | 23 | { |
7903 | 23 | ds_put_format(fp->s, "%scheck_pkt_larger(%s%"PRIu32")->", |
7904 | 23 | colors.param, colors.end, a->pkt_len); |
7905 | 23 | mf_format_subfield(&a->dst, fp->s); |
7906 | 23 | } |
7907 | | |
7908 | | static enum ofperr |
7909 | | check_CHECK_PKT_LARGER(const struct ofpact_check_pkt_larger *a OVS_UNUSED, |
7910 | | const struct ofpact_check_params *cp OVS_UNUSED) |
7911 | 12 | { |
7912 | 12 | return 0; |
7913 | 12 | } |
7914 | | |
7915 | | |
7916 | | /* Goto-Table instruction. */ |
7917 | | |
7918 | | static void |
7919 | | encode_GOTO_TABLE(const struct ofpact_goto_table *goto_table, |
7920 | | enum ofp_version ofp_version, struct ofpbuf *out) |
7921 | 0 | { |
7922 | 0 | if (ofp_version == OFP10_VERSION) { |
7923 | 0 | struct nx_action_resubmit *nar; |
7924 | |
|
7925 | 0 | nar = put_NXAST_RESUBMIT_TABLE(out); |
7926 | 0 | nar->table = goto_table->table_id; |
7927 | 0 | nar->in_port = htons(ofp_to_u16(OFPP_IN_PORT)); |
7928 | 0 | } else { |
7929 | 0 | struct ofp11_instruction_goto_table *oigt; |
7930 | |
|
7931 | 0 | oigt = instruction_put_OFPIT11_GOTO_TABLE(out); |
7932 | 0 | oigt->table_id = goto_table->table_id; |
7933 | 0 | memset(oigt->pad, 0, sizeof oigt->pad); |
7934 | 0 | } |
7935 | 0 | } |
7936 | | |
7937 | | static char * OVS_WARN_UNUSED_RESULT |
7938 | | parse_GOTO_TABLE(char *arg, const struct ofpact_parse_params *pp) |
7939 | 0 | { |
7940 | 0 | struct ofpact_goto_table *ogt = ofpact_put_GOTO_TABLE(pp->ofpacts); |
7941 | 0 | if (!ofputil_table_from_string(arg, pp->table_map, &ogt->table_id)) { |
7942 | 0 | return xasprintf("unknown table \"%s\"", arg); |
7943 | 0 | } |
7944 | 0 | return NULL; |
7945 | 0 | } |
7946 | | |
7947 | | static void |
7948 | | format_GOTO_TABLE(const struct ofpact_goto_table *a, |
7949 | | const struct ofpact_format_params *fp) |
7950 | 31 | { |
7951 | 31 | ds_put_format(fp->s, "%sgoto_table:%s", colors.param, colors.end); |
7952 | 31 | ofputil_format_table(a->table_id, fp->table_map, fp->s); |
7953 | 31 | } |
7954 | | |
7955 | | static enum ofperr |
7956 | | check_GOTO_TABLE(const struct ofpact_goto_table *a, |
7957 | | const struct ofpact_check_params *cp) |
7958 | 68 | { |
7959 | 68 | if ((cp->table_id != 255 && a->table_id <= cp->table_id) |
7960 | 68 | || (cp->n_tables != 255 && a->table_id >= cp->n_tables)) { |
7961 | 37 | return OFPERR_OFPBIC_BAD_TABLE_ID; |
7962 | 37 | } |
7963 | 31 | return 0; |
7964 | 68 | } |
7965 | | |
7966 | | static void |
7967 | | log_bad_action(const struct ofp_action_header *actions, size_t actions_len, |
7968 | | size_t action_offset, enum ofperr error) |
7969 | 116k | { |
7970 | 116k | if (!VLOG_DROP_WARN(&rl)) { |
7971 | 0 | struct ds s; |
7972 | |
|
7973 | 0 | ds_init(&s); |
7974 | 0 | ds_put_hex_dump(&s, actions, actions_len, 0, false); |
7975 | 0 | VLOG_WARN("bad action at offset %"PRIuSIZE" (%s):\n%s", action_offset, |
7976 | 0 | ofperr_get_name(error), ds_cstr(&s)); |
7977 | 0 | ds_destroy(&s); |
7978 | 0 | } |
7979 | 116k | } |
7980 | | |
7981 | | static enum ofperr |
7982 | | ofpacts_decode_aligned(struct ofpbuf *openflow, enum ofp_version ofp_version, |
7983 | | const struct vl_mff_map *vl_mff_map, |
7984 | | uint64_t *ofpacts_tlv_bitmap, struct ofpbuf *ofpacts, |
7985 | | size_t *bad_action_offset) |
7986 | 248k | { |
7987 | 248k | size_t decoded_len = 0; |
7988 | 248k | enum ofperr error = 0; |
7989 | | |
7990 | 248k | ovs_assert(OFPACT_IS_ALIGNED(openflow->data)); |
7991 | 555k | while (openflow->size) { |
7992 | | /* Ensure the next action data is properly aligned before decoding it. |
7993 | | * Some times it's valid to have to decode actions that are not |
7994 | | * properly aligned (e.g., when processing OF 1.0 statistics reply |
7995 | | * messages which have a header of 12 bytes - struct ofp10_stats_msg). |
7996 | | * In other cases the encoder might be buggy. |
7997 | | */ |
7998 | 423k | if (!OFPACT_IS_ALIGNED(openflow->data)) { |
7999 | 0 | ofpbuf_align(openflow); |
8000 | 0 | } |
8001 | | |
8002 | 423k | const struct ofp_action_header *action = openflow->data; |
8003 | 423k | enum ofp_raw_action_type raw; |
8004 | 423k | size_t act_len = 0; |
8005 | 423k | uint64_t arg; |
8006 | | |
8007 | 423k | error = ofpact_pull_raw(openflow, ofp_version, &raw, &arg, &act_len); |
8008 | 423k | if (!error) { |
8009 | 366k | error = ofpact_decode(action, raw, ofp_version, arg, vl_mff_map, |
8010 | 366k | ofpacts_tlv_bitmap, ofpacts); |
8011 | 366k | } |
8012 | | |
8013 | 423k | if (error) { |
8014 | 116k | *bad_action_offset = decoded_len; |
8015 | 116k | goto done; |
8016 | 116k | } |
8017 | 307k | decoded_len += act_len; |
8018 | 307k | } |
8019 | | |
8020 | 248k | done: |
8021 | 248k | return error; |
8022 | 248k | } |
8023 | | |
8024 | | static enum ofperr |
8025 | | ofpacts_decode(const void *actions, size_t actions_len, |
8026 | | enum ofp_version ofp_version, |
8027 | | const struct vl_mff_map *vl_mff_map, |
8028 | | uint64_t *ofpacts_tlv_bitmap, struct ofpbuf *ofpacts) |
8029 | 248k | { |
8030 | 248k | size_t bad_action_offset = 0; |
8031 | 248k | struct ofpbuf aligned_buf; |
8032 | | |
8033 | 248k | if (!OFPACT_IS_ALIGNED(actions)) { |
8034 | 176k | ofpbuf_init(&aligned_buf, actions_len); |
8035 | 176k | ofpbuf_put(&aligned_buf, actions, actions_len); |
8036 | 176k | } else { |
8037 | 71.5k | ofpbuf_use_data(&aligned_buf, actions, actions_len); |
8038 | 71.5k | } |
8039 | | |
8040 | 248k | enum ofperr error |
8041 | 248k | = ofpacts_decode_aligned(&aligned_buf, ofp_version, vl_mff_map, |
8042 | 248k | ofpacts_tlv_bitmap, ofpacts, |
8043 | 248k | &bad_action_offset); |
8044 | 248k | if (error) { |
8045 | 116k | log_bad_action(actions, actions_len, bad_action_offset, error); |
8046 | 116k | } |
8047 | 248k | ofpbuf_uninit(&aligned_buf); |
8048 | 248k | return error; |
8049 | 248k | } |
8050 | | |
8051 | | static enum ofperr |
8052 | | ofpacts_pull_openflow_actions__(struct ofpbuf *openflow, |
8053 | | unsigned int actions_len, |
8054 | | enum ofp_version version, |
8055 | | uint32_t allowed_ovsinsts, |
8056 | | struct ofpbuf *ofpacts, |
8057 | | enum ofpact_type outer_action, |
8058 | | const struct vl_mff_map *vl_mff_map, |
8059 | | uint64_t *ofpacts_tlv_bitmap) |
8060 | 236k | { |
8061 | 236k | const struct ofp_action_header *actions; |
8062 | 236k | enum ofperr error; |
8063 | | |
8064 | 236k | if (actions_len % OFP_ACTION_ALIGN != 0) { |
8065 | 12.3k | VLOG_WARN_RL(&rl, "OpenFlow message actions length %u is not a " |
8066 | 12.3k | "multiple of %d", actions_len, OFP_ACTION_ALIGN); |
8067 | 12.3k | return OFPERR_OFPBRC_BAD_LEN; |
8068 | 12.3k | } |
8069 | | |
8070 | 223k | actions = ofpbuf_try_pull(openflow, actions_len); |
8071 | 223k | if (actions == NULL) { |
8072 | 2.24k | VLOG_WARN_RL(&rl, "OpenFlow message actions length %u exceeds " |
8073 | 2.24k | "remaining message length (%"PRIu32")", |
8074 | 2.24k | actions_len, openflow->size); |
8075 | 2.24k | return OFPERR_OFPBRC_BAD_LEN; |
8076 | 2.24k | } |
8077 | | |
8078 | 221k | error = ofpacts_decode(actions, actions_len, version, vl_mff_map, |
8079 | 221k | ofpacts_tlv_bitmap, ofpacts); |
8080 | 221k | if (!error) { |
8081 | 111k | error = ofpacts_verify(ofpacts->data, ofpacts->size, version, |
8082 | 111k | allowed_ovsinsts, outer_action, NULL); |
8083 | 111k | } |
8084 | 221k | if (error) { |
8085 | 120k | ofpbuf_clear(ofpacts); |
8086 | 120k | } |
8087 | 221k | return error; |
8088 | 223k | } |
8089 | | |
8090 | | /* Attempts to convert 'actions_len' bytes of OpenFlow actions from the front |
8091 | | * of 'openflow' into ofpacts. On success, appends the converted actions to |
8092 | | * 'ofpacts'; on failure, clears 'ofpacts'. Returns 0 if successful, otherwise |
8093 | | * an OpenFlow error. |
8094 | | * |
8095 | | * Actions are processed according to their OpenFlow version which |
8096 | | * is provided in the 'version' parameter. |
8097 | | * |
8098 | | * In most places in OpenFlow, actions appear encapsulated in instructions, so |
8099 | | * you should call ofpacts_pull_openflow_instructions() instead of this |
8100 | | * function. |
8101 | | * |
8102 | | * 'vl_mff_map' and 'ofpacts_tlv_bitmap' are optional. If 'vl_mff_map' is |
8103 | | * provided, it is used to get variable length mf_fields with configured |
8104 | | * length in the actions. If an action uses a variable length mf_field, |
8105 | | * 'ofpacts_tlv_bitmap' is updated accordingly for ref counting. If |
8106 | | * 'vl_mff_map' is not provided, the default mf_fields with maximum length |
8107 | | * will be used. |
8108 | | * |
8109 | | * The parsed actions are valid generically, but they may not be valid in a |
8110 | | * specific context. For example, port numbers up to OFPP_MAX are valid |
8111 | | * generically, but specific datapaths may only support port numbers in a |
8112 | | * smaller range. Use ofpacts_check() to additional check whether actions are |
8113 | | * valid in a specific context. */ |
8114 | | enum ofperr |
8115 | | ofpacts_pull_openflow_actions(struct ofpbuf *openflow, |
8116 | | unsigned int actions_len, |
8117 | | enum ofp_version version, |
8118 | | const struct vl_mff_map *vl_mff_map, |
8119 | | uint64_t *ofpacts_tlv_bitmap, |
8120 | | struct ofpbuf *ofpacts) |
8121 | 153k | { |
8122 | 153k | return ofpacts_pull_openflow_actions__( |
8123 | 153k | openflow, actions_len, version, |
8124 | 153k | (1u << OVSINST_OFPIT11_APPLY_ACTIONS) | (1u << OVSINST_OFPIT13_METER), |
8125 | 153k | ofpacts, 0, vl_mff_map, ofpacts_tlv_bitmap); |
8126 | 153k | } |
8127 | | |
8128 | | /* OpenFlow 1.1 action sets. */ |
8129 | | |
8130 | | /* Append ofpact 'a' onto the tail of 'out' */ |
8131 | | static void |
8132 | | ofpact_copy(struct ofpbuf *out, const struct ofpact *a) |
8133 | 0 | { |
8134 | 0 | ofpbuf_put(out, a, OFPACT_ALIGN(a->len)); |
8135 | 0 | } |
8136 | | |
8137 | | /* The order in which actions in an action set get executed. This is only for |
8138 | | * the actions where only the last instance added is used. */ |
8139 | | #define ACTION_SET_ORDER \ |
8140 | 1.81k | SLOT(OFPACT_STRIP_VLAN) \ |
8141 | 10.6k | SLOT(OFPACT_POP_MPLS) \ |
8142 | 13.7k | SLOT(OFPACT_DECAP) \ |
8143 | 13.7k | SLOT(OFPACT_ENCAP) \ |
8144 | 1.24k | SLOT(OFPACT_PUSH_MPLS) \ |
8145 | 3.00k | SLOT(OFPACT_PUSH_VLAN) \ |
8146 | 6.91k | SLOT(OFPACT_DEC_TTL) \ |
8147 | 6.91k | SLOT(OFPACT_DEC_MPLS_TTL) \ |
8148 | 2.28k | SLOT(OFPACT_DEC_NSH_TTL) |
8149 | | |
8150 | | /* Priority for "final actions" in an action set. An action set only gets |
8151 | | * executed at all if at least one of these actions is present. If more than |
8152 | | * one is present, then only the one later in this list is executed (and if |
8153 | | * more than one of a given type, the one later in the action set). */ |
8154 | | #define ACTION_SET_FINAL_PRIORITY \ |
8155 | 93 | FINAL(OFPACT_CT) \ |
8156 | 93 | FINAL(OFPACT_CT_CLEAR) \ |
8157 | 14 | FINAL(OFPACT_RESUBMIT) \ |
8158 | 2.20k | FINAL(OFPACT_OUTPUT) \ |
8159 | 2.20k | FINAL(OFPACT_GROUP) |
8160 | | |
8161 | | enum action_set_class { |
8162 | | /* Actions that individually can usefully appear only once in an action |
8163 | | * set. If they do appear more than once, then only the last instance is |
8164 | | * honored. */ |
8165 | | #define SLOT(OFPACT) ACTION_SLOT_##OFPACT, |
8166 | | ACTION_SET_ORDER |
8167 | | #undef SLOT |
8168 | | |
8169 | | /* Final actions. */ |
8170 | | #define FINAL(OFPACT) ACTION_SLOT_##OFPACT, |
8171 | | ACTION_SET_FINAL_PRIORITY |
8172 | | #undef FINAL |
8173 | | |
8174 | | /* Actions that can appear in an action set more than once and are executed |
8175 | | * in order. */ |
8176 | | ACTION_SLOT_SET_OR_MOVE, |
8177 | | |
8178 | | /* Actions that shouldn't appear in the action set at all. */ |
8179 | | ACTION_SLOT_INVALID |
8180 | | }; |
8181 | | |
8182 | | /* Count the action set slots. */ |
8183 | | #define SLOT(OFPACT) +1 |
8184 | | enum { N_ACTION_SLOTS = ACTION_SET_ORDER }; |
8185 | | #undef SLOT |
8186 | | |
8187 | | static enum action_set_class |
8188 | | action_set_classify(const struct ofpact *a) |
8189 | 52.1k | { |
8190 | 52.1k | switch (a->type) { |
8191 | 40.7k | #define SLOT(OFPACT) case OFPACT: return ACTION_SLOT_##OFPACT; |
8192 | 0 | ACTION_SET_ORDER |
8193 | 0 | #undef SLOT |
8194 | | |
8195 | 3.50k | #define FINAL(OFPACT) case OFPACT: return ACTION_SLOT_##OFPACT; |
8196 | 21 | ACTION_SET_FINAL_PRIORITY |
8197 | 0 | #undef FINAL |
8198 | | |
8199 | 11 | case OFPACT_SET_FIELD: |
8200 | 11 | case OFPACT_REG_MOVE: |
8201 | 186 | case OFPACT_SET_ETH_DST: |
8202 | 192 | case OFPACT_SET_ETH_SRC: |
8203 | 1.20k | case OFPACT_SET_IP_DSCP: |
8204 | 1.46k | case OFPACT_SET_IP_ECN: |
8205 | 1.91k | case OFPACT_SET_IP_TTL: |
8206 | 1.96k | case OFPACT_SET_IPV4_DST: |
8207 | 2.28k | case OFPACT_SET_IPV4_SRC: |
8208 | 2.71k | case OFPACT_SET_L4_DST_PORT: |
8209 | 2.74k | case OFPACT_SET_L4_SRC_PORT: |
8210 | 2.93k | case OFPACT_SET_MPLS_LABEL: |
8211 | 3.29k | case OFPACT_SET_MPLS_TC: |
8212 | 3.46k | case OFPACT_SET_MPLS_TTL: |
8213 | 3.48k | case OFPACT_SET_QUEUE: |
8214 | 3.65k | case OFPACT_SET_TUNNEL: |
8215 | 4.67k | case OFPACT_SET_VLAN_PCP: |
8216 | 5.18k | case OFPACT_SET_VLAN_VID: |
8217 | 5.18k | return ACTION_SLOT_SET_OR_MOVE; |
8218 | | |
8219 | 0 | case OFPACT_BUNDLE: |
8220 | 0 | case OFPACT_CLEAR_ACTIONS: |
8221 | 2 | case OFPACT_CLONE: |
8222 | 3 | case OFPACT_NAT: |
8223 | 3 | case OFPACT_CONTROLLER: |
8224 | 3 | case OFPACT_ENQUEUE: |
8225 | 923 | case OFPACT_EXIT: |
8226 | 923 | case OFPACT_UNROLL_XLATE: |
8227 | 1.29k | case OFPACT_FIN_TIMEOUT: |
8228 | 1.29k | case OFPACT_GOTO_TABLE: |
8229 | 1.31k | case OFPACT_LEARN: |
8230 | 1.31k | case OFPACT_CONJUNCTION: |
8231 | 1.68k | case OFPACT_METER: |
8232 | 1.68k | case OFPACT_MULTIPATH: |
8233 | 1.68k | case OFPACT_NOTE: |
8234 | 1.68k | case OFPACT_OUTPUT_REG: |
8235 | 2.73k | case OFPACT_OUTPUT_TRUNC: |
8236 | 2.76k | case OFPACT_POP_QUEUE: |
8237 | 2.76k | case OFPACT_SAMPLE: |
8238 | 2.76k | case OFPACT_STACK_POP: |
8239 | 2.76k | case OFPACT_STACK_PUSH: |
8240 | 2.76k | case OFPACT_WRITE_ACTIONS: |
8241 | 2.76k | case OFPACT_WRITE_METADATA: |
8242 | 2.76k | case OFPACT_DEBUG_RECIRC: |
8243 | 2.76k | case OFPACT_DEBUG_SLOW: |
8244 | 2.76k | case OFPACT_CHECK_PKT_LARGER: |
8245 | 2.76k | case OFPACT_DELETE_FIELD: |
8246 | 2.76k | return ACTION_SLOT_INVALID; |
8247 | | |
8248 | 0 | default: |
8249 | 0 | OVS_NOT_REACHED(); |
8250 | 52.1k | } |
8251 | 52.1k | } |
8252 | | |
8253 | | /* True if an action is allowed in the action set. |
8254 | | * False otherwise. */ |
8255 | | static bool |
8256 | | ofpact_is_allowed_in_actions_set(const struct ofpact *a) |
8257 | 52.1k | { |
8258 | 52.1k | return action_set_classify(a) != ACTION_SLOT_INVALID; |
8259 | 52.1k | } |
8260 | | |
8261 | | /* Reads 'action_set', which contains ofpacts accumulated by |
8262 | | * OFPACT_WRITE_ACTIONS instructions, and writes equivalent actions to be |
8263 | | * executed directly into 'action_list'. (These names correspond to the |
8264 | | * "Action Set" and "Action List" terms used in OpenFlow 1.1+.) |
8265 | | * |
8266 | | * In general this involves appending the last instance of each action that is |
8267 | | * admissible in the action set in the order described in the OpenFlow |
8268 | | * specification. |
8269 | | * |
8270 | | * Exceptions: |
8271 | | * + output action is only appended if no group action was present in 'in'. |
8272 | | * + As a simplification all set actions are copied in the order the are |
8273 | | * provided in 'in' as many set actions applied to a field has the same |
8274 | | * affect as only applying the last action that sets a field and |
8275 | | * duplicates are removed by do_xlate_actions(). |
8276 | | * This has an unwanted side-effect of compsoting multiple |
8277 | | * LOAD_REG actions that touch different regions of the same field. */ |
8278 | | void |
8279 | | ofpacts_execute_action_set(struct ofpbuf *action_list, |
8280 | | const struct ofpbuf *action_set) |
8281 | 0 | { |
8282 | 0 | const struct ofpact *slots[N_ACTION_SLOTS] = {NULL, }; |
8283 | |
|
8284 | 0 | struct ofpbuf set_or_move; |
8285 | 0 | ofpbuf_init(&set_or_move, 0); |
8286 | |
|
8287 | 0 | const struct ofpact *final_action = NULL; |
8288 | 0 | enum action_set_class final_class = 0; |
8289 | |
|
8290 | 0 | const struct ofpact *cursor; |
8291 | 0 | OFPACT_FOR_EACH (cursor, action_set->data, action_set->size) { |
8292 | 0 | int class = action_set_classify(cursor); |
8293 | 0 | if (class < N_ACTION_SLOTS) { |
8294 | 0 | slots[class] = cursor; |
8295 | 0 | } else if (class < ACTION_SLOT_SET_OR_MOVE) { |
8296 | 0 | if (class >= final_class) { |
8297 | 0 | final_action = cursor; |
8298 | 0 | final_class = class; |
8299 | 0 | } |
8300 | 0 | } else if (class == ACTION_SLOT_SET_OR_MOVE) { |
8301 | 0 | ofpact_copy(&set_or_move, cursor); |
8302 | 0 | } else { |
8303 | 0 | ovs_assert(class == ACTION_SLOT_INVALID); |
8304 | 0 | } |
8305 | 0 | } |
8306 | |
|
8307 | 0 | if (final_action) { |
8308 | 0 | for (int i = 0; i < N_ACTION_SLOTS; i++) { |
8309 | 0 | if (slots[i]) { |
8310 | 0 | ofpact_copy(action_list, slots[i]); |
8311 | 0 | } |
8312 | 0 | } |
8313 | 0 | ofpbuf_put(action_list, set_or_move.data, set_or_move.size); |
8314 | 0 | ofpact_copy(action_list, final_action); |
8315 | 0 | } |
8316 | 0 | ofpbuf_uninit(&set_or_move); |
8317 | 0 | } |
8318 | | |
8319 | | |
8320 | | static enum ofperr |
8321 | | ofpacts_decode_for_action_set(const struct ofp_action_header *in, |
8322 | | size_t n_in, enum ofp_version version, |
8323 | | const struct vl_mff_map *vl_mff_map, |
8324 | | uint64_t *ofpacts_tlv_bitmap, |
8325 | | struct ofpbuf *out) |
8326 | 19.9k | { |
8327 | 19.9k | enum ofperr error; |
8328 | 19.9k | struct ofpact *a; |
8329 | 19.9k | size_t start = out->size; |
8330 | | |
8331 | 19.9k | error = ofpacts_decode(in, n_in, version, vl_mff_map, ofpacts_tlv_bitmap, |
8332 | 19.9k | out); |
8333 | | |
8334 | 19.9k | if (error) { |
8335 | 4.29k | return error; |
8336 | 4.29k | } |
8337 | | |
8338 | 52.1k | OFPACT_FOR_EACH (a, ofpact_end(out->data, start), out->size - start) { |
8339 | 52.1k | if (!ofpact_is_allowed_in_actions_set(a)) { |
8340 | 2.76k | VLOG_WARN_RL(&rl, "disallowed action in action set"); |
8341 | 2.76k | return OFPERR_OFPBAC_BAD_TYPE; |
8342 | 2.76k | } |
8343 | 52.1k | } |
8344 | | |
8345 | 12.9k | return 0; |
8346 | 15.6k | } |
8347 | | |
8348 | | /* OpenFlow 1.1 instructions. */ |
8349 | | |
8350 | | struct instruction_type_info { |
8351 | | enum ovs_instruction_type type; |
8352 | | const char *name; |
8353 | | }; |
8354 | | |
8355 | | static const struct instruction_type_info inst_info[] = { |
8356 | | #define DEFINE_INST(ENUM, STRUCT, EXTENSIBLE, NAME) {OVSINST_##ENUM, NAME}, |
8357 | | OVS_INSTRUCTIONS |
8358 | | #undef DEFINE_INST |
8359 | | }; |
8360 | | |
8361 | | const char * |
8362 | | ovs_instruction_name_from_type(enum ovs_instruction_type type) |
8363 | 22.8k | { |
8364 | 22.8k | return type < ARRAY_SIZE(inst_info) ? inst_info[type].name : NULL; |
8365 | 22.8k | } |
8366 | | |
8367 | | int |
8368 | | ovs_instruction_type_from_name(const char *name) |
8369 | 0 | { |
8370 | 0 | const struct instruction_type_info *p; |
8371 | 0 | for (p = inst_info; p < &inst_info[ARRAY_SIZE(inst_info)]; p++) { |
8372 | 0 | if (!strcasecmp(name, p->name)) { |
8373 | 0 | return p->type; |
8374 | 0 | } |
8375 | 0 | } |
8376 | 0 | return -1; |
8377 | 0 | } |
8378 | | |
8379 | | enum ovs_instruction_type |
8380 | | ovs_instruction_type_from_ofpact_type(enum ofpact_type type, |
8381 | | enum ofp_version version) |
8382 | 186k | { |
8383 | 186k | switch (type) { |
8384 | 1.47k | case OFPACT_METER: |
8385 | 1.47k | return (version >= OFP15_VERSION |
8386 | 1.47k | ? OVSINST_OFPIT11_APPLY_ACTIONS |
8387 | 1.47k | : OVSINST_OFPIT13_METER); |
8388 | 77 | case OFPACT_CLEAR_ACTIONS: |
8389 | 77 | return OVSINST_OFPIT11_CLEAR_ACTIONS; |
8390 | 12.9k | case OFPACT_WRITE_ACTIONS: |
8391 | 12.9k | return OVSINST_OFPIT11_WRITE_ACTIONS; |
8392 | 1.79k | case OFPACT_WRITE_METADATA: |
8393 | 1.79k | return OVSINST_OFPIT11_WRITE_METADATA; |
8394 | 68 | case OFPACT_GOTO_TABLE: |
8395 | 68 | return OVSINST_OFPIT11_GOTO_TABLE; |
8396 | 17.5k | case OFPACT_OUTPUT: |
8397 | 18.1k | case OFPACT_GROUP: |
8398 | 19.0k | case OFPACT_CLONE: |
8399 | 21.7k | case OFPACT_CONTROLLER: |
8400 | 21.9k | case OFPACT_ENQUEUE: |
8401 | 22.5k | case OFPACT_OUTPUT_REG: |
8402 | 22.6k | case OFPACT_OUTPUT_TRUNC: |
8403 | 23.9k | case OFPACT_BUNDLE: |
8404 | 32.2k | case OFPACT_SET_VLAN_VID: |
8405 | 36.9k | case OFPACT_SET_VLAN_PCP: |
8406 | 46.8k | case OFPACT_STRIP_VLAN: |
8407 | 46.9k | case OFPACT_PUSH_VLAN: |
8408 | 46.9k | case OFPACT_SET_ETH_SRC: |
8409 | 46.9k | case OFPACT_SET_ETH_DST: |
8410 | 51.2k | case OFPACT_SET_IPV4_SRC: |
8411 | 58.4k | case OFPACT_SET_IPV4_DST: |
8412 | 66.1k | case OFPACT_SET_IP_DSCP: |
8413 | 66.6k | case OFPACT_SET_IP_ECN: |
8414 | 66.6k | case OFPACT_SET_IP_TTL: |
8415 | 73.8k | case OFPACT_SET_L4_SRC_PORT: |
8416 | 89.6k | case OFPACT_SET_L4_DST_PORT: |
8417 | 89.8k | case OFPACT_REG_MOVE: |
8418 | 102k | case OFPACT_SET_FIELD: |
8419 | 102k | case OFPACT_STACK_PUSH: |
8420 | 103k | case OFPACT_STACK_POP: |
8421 | 108k | case OFPACT_DEC_TTL: |
8422 | 109k | case OFPACT_SET_MPLS_LABEL: |
8423 | 110k | case OFPACT_SET_MPLS_TC: |
8424 | 110k | case OFPACT_SET_MPLS_TTL: |
8425 | 110k | case OFPACT_DEC_MPLS_TTL: |
8426 | 110k | case OFPACT_PUSH_MPLS: |
8427 | 110k | case OFPACT_POP_MPLS: |
8428 | 111k | case OFPACT_SET_TUNNEL: |
8429 | 112k | case OFPACT_SET_QUEUE: |
8430 | 114k | case OFPACT_POP_QUEUE: |
8431 | 116k | case OFPACT_FIN_TIMEOUT: |
8432 | 118k | case OFPACT_RESUBMIT: |
8433 | 138k | case OFPACT_LEARN: |
8434 | 138k | case OFPACT_CONJUNCTION: |
8435 | 143k | case OFPACT_MULTIPATH: |
8436 | 151k | case OFPACT_NOTE: |
8437 | 152k | case OFPACT_EXIT: |
8438 | 155k | case OFPACT_UNROLL_XLATE: |
8439 | 157k | case OFPACT_SAMPLE: |
8440 | 157k | case OFPACT_DEBUG_RECIRC: |
8441 | 157k | case OFPACT_DEBUG_SLOW: |
8442 | 164k | case OFPACT_CT: |
8443 | 164k | case OFPACT_CT_CLEAR: |
8444 | 167k | case OFPACT_NAT: |
8445 | 167k | case OFPACT_ENCAP: |
8446 | 170k | case OFPACT_DECAP: |
8447 | 170k | case OFPACT_DEC_NSH_TTL: |
8448 | 170k | case OFPACT_CHECK_PKT_LARGER: |
8449 | 170k | case OFPACT_DELETE_FIELD: |
8450 | 170k | default: |
8451 | 170k | return OVSINST_OFPIT11_APPLY_ACTIONS; |
8452 | 186k | } |
8453 | 186k | } |
8454 | | |
8455 | | enum ofperr |
8456 | | ovs_instruction_type_from_inst_type(enum ovs_instruction_type *instruction_type, |
8457 | | const uint16_t inst_type) |
8458 | 3.36k | { |
8459 | 3.36k | switch (inst_type) { |
8460 | | |
8461 | 0 | #define DEFINE_INST(ENUM, STRUCT, EXTENSIBLE, NAME) \ |
8462 | 1.17k | case ENUM: \ |
8463 | 1.17k | *instruction_type = OVSINST_##ENUM; \ |
8464 | 1.17k | return 0; |
8465 | 0 | OVS_INSTRUCTIONS |
8466 | 0 | #undef DEFINE_INST |
8467 | | |
8468 | 2.18k | default: |
8469 | 2.18k | return OFPERR_OFPBIC_UNKNOWN_INST; |
8470 | 3.36k | } |
8471 | 3.36k | } |
8472 | | |
8473 | | /* Two-way translation between OVS's internal "OVSINST_*" representation of |
8474 | | * instructions and the "OFPIT_*" representation used in OpenFlow. */ |
8475 | | struct ovsinst_map { |
8476 | | enum ovs_instruction_type ovsinst; /* Internal name for instruction. */ |
8477 | | int ofpit; /* OFPIT_* number from OpenFlow spec. */ |
8478 | | }; |
8479 | | |
8480 | | static const struct ovsinst_map * |
8481 | | get_ovsinst_map(enum ofp_version version) |
8482 | 19.7k | { |
8483 | | /* OpenFlow 1.1, 1.2, and 1.5 instructions. */ |
8484 | 19.7k | static const struct ovsinst_map of11[] = { |
8485 | 19.7k | { OVSINST_OFPIT11_GOTO_TABLE, 1 }, |
8486 | 19.7k | { OVSINST_OFPIT11_WRITE_METADATA, 2 }, |
8487 | 19.7k | { OVSINST_OFPIT11_WRITE_ACTIONS, 3 }, |
8488 | 19.7k | { OVSINST_OFPIT11_APPLY_ACTIONS, 4 }, |
8489 | 19.7k | { OVSINST_OFPIT11_CLEAR_ACTIONS, 5 }, |
8490 | 19.7k | { 0, -1 }, |
8491 | 19.7k | }; |
8492 | | |
8493 | | /* OpenFlow 1.3 and 1.4 instructions. */ |
8494 | 19.7k | static const struct ovsinst_map of13[] = { |
8495 | 19.7k | { OVSINST_OFPIT11_GOTO_TABLE, 1 }, |
8496 | 19.7k | { OVSINST_OFPIT11_WRITE_METADATA, 2 }, |
8497 | 19.7k | { OVSINST_OFPIT11_WRITE_ACTIONS, 3 }, |
8498 | 19.7k | { OVSINST_OFPIT11_APPLY_ACTIONS, 4 }, |
8499 | 19.7k | { OVSINST_OFPIT11_CLEAR_ACTIONS, 5 }, |
8500 | 19.7k | { OVSINST_OFPIT13_METER, 6 }, |
8501 | 19.7k | { 0, -1 }, |
8502 | 19.7k | }; |
8503 | | |
8504 | 19.7k | return version == OFP13_VERSION || version == OFP14_VERSION ? of13 : of11; |
8505 | 19.7k | } |
8506 | | |
8507 | | /* Converts 'ovsinst_bitmap', a bitmap whose bits correspond to OVSINST_* |
8508 | | * values, into a bitmap of instructions suitable for OpenFlow 'version' |
8509 | | * (OFP11_VERSION or later), and returns the result. */ |
8510 | | ovs_be32 |
8511 | | ovsinst_bitmap_to_openflow(uint32_t ovsinst_bitmap, enum ofp_version version) |
8512 | 0 | { |
8513 | 0 | uint32_t ofpit_bitmap = 0; |
8514 | 0 | const struct ovsinst_map *x; |
8515 | |
|
8516 | 0 | for (x = get_ovsinst_map(version); x->ofpit >= 0; x++) { |
8517 | 0 | if (ovsinst_bitmap & (1u << x->ovsinst)) { |
8518 | 0 | ofpit_bitmap |= 1u << x->ofpit; |
8519 | 0 | } |
8520 | 0 | } |
8521 | 0 | return htonl(ofpit_bitmap); |
8522 | 0 | } |
8523 | | |
8524 | | /* Converts 'ofpit_bitmap', a bitmap of instructions from an OpenFlow message |
8525 | | * with the given 'version' (OFP11_VERSION or later) into a bitmap whose bits |
8526 | | * correspond to OVSINST_* values, and returns the result. */ |
8527 | | uint32_t |
8528 | | ovsinst_bitmap_from_openflow(ovs_be32 ofpit_bitmap, enum ofp_version version) |
8529 | 19.7k | { |
8530 | 19.7k | uint32_t ovsinst_bitmap = 0; |
8531 | 19.7k | const struct ovsinst_map *x; |
8532 | | |
8533 | 118k | for (x = get_ovsinst_map(version); x->ofpit >= 0; x++) { |
8534 | 98.5k | if (ofpit_bitmap & htonl(1u << x->ofpit)) { |
8535 | 29.0k | ovsinst_bitmap |= 1u << x->ovsinst; |
8536 | 29.0k | } |
8537 | 98.5k | } |
8538 | 19.7k | return ovsinst_bitmap; |
8539 | 19.7k | } |
8540 | | |
8541 | | static inline struct ofp11_instruction * |
8542 | | instruction_next(const struct ofp11_instruction *inst) |
8543 | 28.1k | { |
8544 | 28.1k | return ((struct ofp11_instruction *) (void *) |
8545 | 28.1k | ((uint8_t *) inst + ntohs(inst->len))); |
8546 | 28.1k | } |
8547 | | |
8548 | | static inline bool |
8549 | | instruction_is_valid(const struct ofp11_instruction *inst, |
8550 | | size_t n_instructions) |
8551 | 35.0k | { |
8552 | 35.0k | uint16_t len = ntohs(inst->len); |
8553 | 35.0k | return (!(len % OFP11_INSTRUCTION_ALIGN) |
8554 | 35.0k | && len >= sizeof *inst |
8555 | 35.0k | && len / sizeof *inst <= n_instructions); |
8556 | 35.0k | } |
8557 | | |
8558 | | /* This macro is careful to check for instructions with bad lengths. */ |
8559 | | #define INSTRUCTION_FOR_EACH(ITER, LEFT, INSTRUCTIONS, N_INSTRUCTIONS) \ |
8560 | 42.4k | for ((ITER) = (INSTRUCTIONS), (LEFT) = (N_INSTRUCTIONS); \ |
8561 | 70.5k | (LEFT) > 0 && instruction_is_valid(ITER, LEFT); \ |
8562 | 42.4k | ((LEFT) -= (ntohs((ITER)->len) \ |
8563 | 28.1k | / sizeof(struct ofp11_instruction)), \ |
8564 | 28.1k | (ITER) = instruction_next(ITER))) |
8565 | | |
8566 | | static enum ofperr |
8567 | | decode_openflow11_instruction(const struct ofp11_instruction *inst, |
8568 | | enum ovs_instruction_type *type) |
8569 | 30.5k | { |
8570 | 30.5k | uint16_t len = ntohs(inst->len); |
8571 | | |
8572 | 30.5k | switch (inst->type) { |
8573 | 232 | case CONSTANT_HTONS(OFPIT11_EXPERIMENTER): |
8574 | 232 | return OFPERR_OFPBIC_BAD_EXPERIMENTER; |
8575 | | |
8576 | 0 | #define DEFINE_INST(ENUM, STRUCT, EXTENSIBLE, NAME) \ |
8577 | 28.5k | case CONSTANT_HTONS(ENUM): \ |
8578 | 28.5k | if (EXTENSIBLE \ |
8579 | 28.5k | ? len >= sizeof(struct STRUCT) \ |
8580 | 28.5k | : len == sizeof(struct STRUCT)) { \ |
8581 | 28.3k | *type = OVSINST_##ENUM; \ |
8582 | 28.3k | return 0; \ |
8583 | 28.3k | } else { \ |
8584 | 198 | return OFPERR_OFPBIC_BAD_LEN; \ |
8585 | 198 | } |
8586 | 232 | OVS_INSTRUCTIONS |
8587 | 0 | #undef DEFINE_INST |
8588 | | |
8589 | 1.82k | default: |
8590 | 1.82k | return OFPERR_OFPBIC_UNKNOWN_INST; |
8591 | 30.5k | } |
8592 | 30.5k | } |
8593 | | |
8594 | | static enum ofperr |
8595 | | decode_openflow11_instructions(const struct ofp11_instruction insts[], |
8596 | | size_t n_insts, enum ofp_version version, |
8597 | | const struct ofp11_instruction *out[]) |
8598 | 42.4k | { |
8599 | 42.4k | const struct ofp11_instruction *inst; |
8600 | 42.4k | size_t left; |
8601 | | |
8602 | 42.4k | memset(out, 0, N_OVS_INSTRUCTIONS * sizeof *out); |
8603 | 42.4k | INSTRUCTION_FOR_EACH (inst, left, insts, n_insts) { |
8604 | 30.5k | enum ovs_instruction_type type; |
8605 | 30.5k | enum ofperr error; |
8606 | | |
8607 | 30.5k | error = decode_openflow11_instruction(inst, &type); |
8608 | 30.5k | if (error) { |
8609 | 2.25k | return error; |
8610 | 2.25k | } |
8611 | | |
8612 | 28.3k | if (type == OVSINST_OFPIT13_METER && version >= OFP15_VERSION) { |
8613 | | /* "meter" is an action, not an instruction, in OpenFlow 1.5. */ |
8614 | 150 | return OFPERR_OFPBIC_UNKNOWN_INST; |
8615 | 150 | } |
8616 | | |
8617 | 28.1k | if (out[type]) { |
8618 | 54 | return OFPERR_OFPBIC_DUP_INST; |
8619 | 54 | } |
8620 | 28.1k | out[type] = inst; |
8621 | 28.1k | } |
8622 | | |
8623 | 40.0k | if (left) { |
8624 | 4.51k | VLOG_WARN_RL(&rl, "bad instruction format at offset %"PRIuSIZE, |
8625 | 4.51k | (n_insts - left) * sizeof *inst); |
8626 | 4.51k | return OFPERR_OFPBIC_BAD_LEN; |
8627 | 4.51k | } |
8628 | 35.4k | return 0; |
8629 | 40.0k | } |
8630 | | |
8631 | | static void |
8632 | | get_actions_from_instruction(const struct ofp11_instruction *inst, |
8633 | | const struct ofp_action_header **actions, |
8634 | | size_t *actions_len) |
8635 | 26.5k | { |
8636 | 26.5k | *actions = ALIGNED_CAST(const struct ofp_action_header *, inst + 1); |
8637 | 26.5k | *actions_len = ntohs(inst->len) - sizeof *inst; |
8638 | 26.5k | } |
8639 | | |
8640 | | enum ofperr |
8641 | | ofpacts_pull_openflow_instructions(struct ofpbuf *openflow, |
8642 | | unsigned int instructions_len, |
8643 | | enum ofp_version version, |
8644 | | const struct vl_mff_map *vl_mff_map, |
8645 | | uint64_t *ofpacts_tlv_bitmap, |
8646 | | struct ofpbuf *ofpacts) |
8647 | 115k | { |
8648 | 115k | const struct ofp11_instruction *instructions; |
8649 | 115k | const struct ofp11_instruction *insts[N_OVS_INSTRUCTIONS]; |
8650 | 115k | enum ofperr error; |
8651 | | |
8652 | 115k | ofpbuf_clear(ofpacts); |
8653 | 115k | if (version == OFP10_VERSION) { |
8654 | 71.6k | return ofpacts_pull_openflow_actions__(openflow, instructions_len, |
8655 | 71.6k | version, |
8656 | 71.6k | (1u << N_OVS_INSTRUCTIONS) - 1, |
8657 | 71.6k | ofpacts, 0, vl_mff_map, |
8658 | 71.6k | ofpacts_tlv_bitmap); |
8659 | 71.6k | } |
8660 | | |
8661 | 43.9k | if (instructions_len % OFP11_INSTRUCTION_ALIGN != 0) { |
8662 | 774 | VLOG_WARN_RL(&rl, "OpenFlow message instructions length %u is not a " |
8663 | 774 | "multiple of %d", |
8664 | 774 | instructions_len, OFP11_INSTRUCTION_ALIGN); |
8665 | 774 | error = OFPERR_OFPBIC_BAD_LEN; |
8666 | 774 | goto exit; |
8667 | 774 | } |
8668 | | |
8669 | 43.1k | instructions = ofpbuf_try_pull(openflow, instructions_len); |
8670 | 43.1k | if (instructions == NULL) { |
8671 | 719 | VLOG_WARN_RL(&rl, "OpenFlow message instructions length %u exceeds " |
8672 | 719 | "remaining message length (%"PRIu32")", |
8673 | 719 | instructions_len, openflow->size); |
8674 | 719 | error = OFPERR_OFPBIC_BAD_LEN; |
8675 | 719 | goto exit; |
8676 | 719 | } |
8677 | | |
8678 | 42.4k | error = decode_openflow11_instructions( |
8679 | 42.4k | instructions, instructions_len / OFP11_INSTRUCTION_ALIGN, version, |
8680 | 42.4k | insts); |
8681 | 42.4k | if (error) { |
8682 | 6.97k | goto exit; |
8683 | 6.97k | } |
8684 | | |
8685 | 35.4k | if (insts[OVSINST_OFPIT13_METER]) { |
8686 | 109 | const struct ofp13_instruction_meter *oim; |
8687 | 109 | struct ofpact_meter *om; |
8688 | | |
8689 | 109 | oim = ALIGNED_CAST(const struct ofp13_instruction_meter *, |
8690 | 109 | insts[OVSINST_OFPIT13_METER]); |
8691 | | |
8692 | 109 | om = ofpact_put_METER(ofpacts); |
8693 | 109 | om->meter_id = ntohl(oim->meter_id); |
8694 | 109 | om->provider_meter_id = UINT32_MAX; /* No provider meter ID. */ |
8695 | 109 | } |
8696 | 35.4k | if (insts[OVSINST_OFPIT11_APPLY_ACTIONS]) { |
8697 | 6.56k | const struct ofp_action_header *actions; |
8698 | 6.56k | size_t actions_len; |
8699 | | |
8700 | 6.56k | get_actions_from_instruction(insts[OVSINST_OFPIT11_APPLY_ACTIONS], |
8701 | 6.56k | &actions, &actions_len); |
8702 | 6.56k | error = ofpacts_decode(actions, actions_len, version, vl_mff_map, |
8703 | 6.56k | ofpacts_tlv_bitmap, ofpacts); |
8704 | 6.56k | if (error) { |
8705 | 2.40k | goto exit; |
8706 | 2.40k | } |
8707 | 6.56k | } |
8708 | 33.0k | if (insts[OVSINST_OFPIT11_CLEAR_ACTIONS]) { |
8709 | 77 | instruction_get_OFPIT11_CLEAR_ACTIONS( |
8710 | 77 | insts[OVSINST_OFPIT11_CLEAR_ACTIONS]); |
8711 | 77 | ofpact_put_CLEAR_ACTIONS(ofpacts); |
8712 | 77 | } |
8713 | 33.0k | if (insts[OVSINST_OFPIT11_WRITE_ACTIONS]) { |
8714 | 19.9k | struct ofpact_nest *on; |
8715 | 19.9k | const struct ofp_action_header *actions; |
8716 | 19.9k | size_t actions_len; |
8717 | 19.9k | size_t start = ofpacts->size; |
8718 | 19.9k | ofpact_put(ofpacts, OFPACT_WRITE_ACTIONS, |
8719 | 19.9k | offsetof(struct ofpact_nest, actions)); |
8720 | 19.9k | get_actions_from_instruction(insts[OVSINST_OFPIT11_WRITE_ACTIONS], |
8721 | 19.9k | &actions, &actions_len); |
8722 | 19.9k | error = ofpacts_decode_for_action_set(actions, actions_len, |
8723 | 19.9k | version, vl_mff_map, |
8724 | 19.9k | ofpacts_tlv_bitmap, ofpacts); |
8725 | 19.9k | if (error) { |
8726 | 7.06k | goto exit; |
8727 | 7.06k | } |
8728 | 12.9k | on = ofpbuf_at_assert(ofpacts, start, sizeof *on); |
8729 | 12.9k | on->ofpact.len = ofpacts->size - start; |
8730 | 12.9k | } |
8731 | 26.0k | if (insts[OVSINST_OFPIT11_WRITE_METADATA]) { |
8732 | 132 | const struct ofp11_instruction_write_metadata *oiwm; |
8733 | 132 | struct ofpact_metadata *om; |
8734 | | |
8735 | 132 | oiwm = ALIGNED_CAST(const struct ofp11_instruction_write_metadata *, |
8736 | 132 | insts[OVSINST_OFPIT11_WRITE_METADATA]); |
8737 | | |
8738 | 132 | om = ofpact_put_WRITE_METADATA(ofpacts); |
8739 | 132 | om->metadata = oiwm->metadata; |
8740 | 132 | om->mask = oiwm->metadata_mask; |
8741 | 132 | } |
8742 | 26.0k | if (insts[OVSINST_OFPIT11_GOTO_TABLE]) { |
8743 | 68 | const struct ofp11_instruction_goto_table *oigt; |
8744 | 68 | struct ofpact_goto_table *ogt; |
8745 | | |
8746 | 68 | oigt = instruction_get_OFPIT11_GOTO_TABLE( |
8747 | 68 | insts[OVSINST_OFPIT11_GOTO_TABLE]); |
8748 | 68 | ogt = ofpact_put_GOTO_TABLE(ofpacts); |
8749 | 68 | ogt->table_id = oigt->table_id; |
8750 | 68 | } |
8751 | | |
8752 | 26.0k | error = ofpacts_verify(ofpacts->data, ofpacts->size, version, |
8753 | 26.0k | (1u << N_OVS_INSTRUCTIONS) - 1, 0, NULL); |
8754 | 43.9k | exit: |
8755 | 43.9k | if (error) { |
8756 | 17.9k | ofpbuf_clear(ofpacts); |
8757 | 17.9k | } |
8758 | 43.9k | return error; |
8759 | 26.0k | } |
8760 | | |
8761 | | /* Update the length of the instruction that begins at offset 'ofs' within |
8762 | | * 'openflow' and contains nested actions that extend to the end of 'openflow'. |
8763 | | * If the instruction contains no nested actions, deletes it entirely. */ |
8764 | | static void |
8765 | | ofpacts_update_instruction_actions(struct ofpbuf *openflow, size_t ofs) |
8766 | 0 | { |
8767 | 0 | struct ofp11_instruction_actions *oia; |
8768 | |
|
8769 | 0 | oia = ofpbuf_at_assert(openflow, ofs, sizeof *oia); |
8770 | 0 | if (openflow->size > ofs + sizeof *oia) { |
8771 | 0 | oia->len = htons(openflow->size - ofs); |
8772 | 0 | } else { |
8773 | 0 | openflow->size = ofs; |
8774 | 0 | } |
8775 | 0 | } |
8776 | | |
8777 | | /* Checks that 'port' is a valid output port for OFPACT_OUTPUT, given that the |
8778 | | * switch will never have more than 'max_ports' ports. Returns 0 if 'port' is |
8779 | | * valid, otherwise an OpenFlow error code. */ |
8780 | | enum ofperr |
8781 | | ofpact_check_output_port(ofp_port_t port, ofp_port_t max_ports) |
8782 | 56.8k | { |
8783 | 56.8k | switch (port) { |
8784 | 1.73k | case OFPP_IN_PORT: |
8785 | 12.2k | case OFPP_TABLE: |
8786 | 12.5k | case OFPP_NORMAL: |
8787 | 17.6k | case OFPP_FLOOD: |
8788 | 19.1k | case OFPP_ALL: |
8789 | 21.0k | case OFPP_CONTROLLER: |
8790 | 23.6k | case OFPP_LOCAL: |
8791 | 23.6k | return 0; |
8792 | | |
8793 | 0 | case OFPP_NONE: |
8794 | 0 | return OFPERR_OFPBAC_BAD_OUT_PORT; |
8795 | | |
8796 | 33.1k | default: |
8797 | 33.1k | if (ofp_to_u16(port) < ofp_to_u16(max_ports)) { |
8798 | 32.6k | return 0; |
8799 | 32.6k | } |
8800 | 543 | return OFPERR_OFPBAC_BAD_OUT_PORT; |
8801 | 56.8k | } |
8802 | 56.8k | } |
8803 | | |
8804 | | /* Removes the protocols that require consistency between match and actions |
8805 | | * (that's everything but OpenFlow 1.0) from '*usable_protocols'. |
8806 | | * |
8807 | | * (An example of an inconsistency between match and actions is a flow that |
8808 | | * does not match on an MPLS Ethertype but has an action that pops an MPLS |
8809 | | * label.) */ |
8810 | | static void |
8811 | | inconsistent_match(enum ofputil_protocol *usable_protocols) |
8812 | 38.5k | { |
8813 | 38.5k | *usable_protocols &= OFPUTIL_P_OF10_ANY; |
8814 | 38.5k | } |
8815 | | |
8816 | | /* May modify flow->packet_type, flow->dl_type, flow->nw_proto and |
8817 | | * flow->vlan_tci, caller must restore them. |
8818 | | * |
8819 | | * Modifies some actions, filling in fields that could not be properly set |
8820 | | * without context. */ |
8821 | | static enum ofperr |
8822 | | ofpact_check__(struct ofpact *a, struct ofpact_check_params *cp) |
8823 | 167k | { |
8824 | 167k | switch (a->type) { |
8825 | 0 | #define OFPACT(ENUM, STRUCT, MEMBER, NAME) \ |
8826 | 167k | case OFPACT_##ENUM: \ |
8827 | 167k | return check_##ENUM(ofpact_get_##ENUM(a), cp); |
8828 | 0 | OFPACTS |
8829 | 0 | #undef OFPACT |
8830 | 0 | default: |
8831 | 0 | OVS_NOT_REACHED(); |
8832 | 167k | } |
8833 | 167k | } |
8834 | | |
8835 | | /* Checks that the 'ofpacts_len' bytes of actions in 'ofpacts' are |
8836 | | * appropriate for a packet with the prerequisites satisfied by 'flow' in a |
8837 | | * switch with no more than 'max_ports' ports. |
8838 | | * |
8839 | | * If 'ofpacts' and 'flow' are inconsistent with one another, un-sets in |
8840 | | * '*usable_protocols' the protocols that forbid the inconsistency. (An |
8841 | | * example of an inconsistency between match and actions is a flow that does |
8842 | | * not match on an MPLS Ethertype but has an action that pops an MPLS label.) |
8843 | | * |
8844 | | * May annotate ofpacts with information gathered from the 'match'. |
8845 | | * |
8846 | | * May temporarily modify 'match', but restores the changes before |
8847 | | * returning. */ |
8848 | | enum ofperr |
8849 | | ofpacts_check(struct ofpact ofpacts[], size_t ofpacts_len, |
8850 | | struct ofpact_check_params *cp) |
8851 | 69.8k | { |
8852 | | /* Save fields that might temporarily be modified. */ |
8853 | 69.8k | struct flow *flow = &cp->match->flow; |
8854 | 69.8k | ovs_be32 packet_type = flow->packet_type; |
8855 | 69.8k | ovs_be16 dl_type = flow->dl_type; |
8856 | 69.8k | uint8_t nw_proto = flow->nw_proto; |
8857 | 69.8k | union flow_vlan_hdr vlans[FLOW_MAX_VLAN_HEADERS]; |
8858 | 69.8k | memcpy(vlans, flow->vlans, sizeof vlans); |
8859 | | |
8860 | | /* Check all the actions. */ |
8861 | 69.8k | cp->usable_protocols = OFPUTIL_P_ANY; |
8862 | 69.8k | enum ofperr error = 0; |
8863 | 69.8k | struct ofpact *a; |
8864 | 167k | OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { |
8865 | 167k | error = ofpact_check__(a, cp); |
8866 | 167k | if (error) { |
8867 | 3.30k | break; |
8868 | 3.30k | } |
8869 | 167k | } |
8870 | | |
8871 | | /* Restore fields that may have been modified. */ |
8872 | 69.8k | flow->packet_type = packet_type; |
8873 | 69.8k | flow->dl_type = dl_type; |
8874 | 69.8k | memcpy(flow->vlans, vlans, sizeof vlans); |
8875 | 69.8k | flow->nw_proto = nw_proto; |
8876 | | |
8877 | 69.8k | return error; |
8878 | 69.8k | } |
8879 | | |
8880 | | /* Like ofpacts_check(), but reports inconsistencies as |
8881 | | * OFPERR_OFPBAC_MATCH_INCONSISTENT rather than clearing bits. */ |
8882 | | enum ofperr |
8883 | | ofpacts_check_consistency(struct ofpact ofpacts[], size_t ofpacts_len, |
8884 | | enum ofputil_protocol needed_protocols, |
8885 | | struct ofpact_check_params *cp) |
8886 | 56.3k | { |
8887 | 56.3k | enum ofperr error = ofpacts_check(ofpacts, ofpacts_len, cp); |
8888 | 56.3k | if (!error && needed_protocols & ~cp->usable_protocols) { |
8889 | 1.90k | return OFPERR_OFPBAC_MATCH_INCONSISTENT; |
8890 | 1.90k | } |
8891 | 54.4k | return error; |
8892 | 56.3k | } |
8893 | | |
8894 | | /* Returns the destination field that 'ofpact' would write to, or NULL |
8895 | | * if the action would not write to an mf_field. */ |
8896 | | const struct mf_field * |
8897 | | ofpact_get_mf_dst(const struct ofpact *ofpact) |
8898 | 193k | { |
8899 | 193k | if (ofpact->type == OFPACT_SET_FIELD) { |
8900 | 13.1k | const struct ofpact_set_field *orl; |
8901 | | |
8902 | 13.1k | orl = CONTAINER_OF(ofpact, struct ofpact_set_field, ofpact); |
8903 | 13.1k | return orl->field; |
8904 | 180k | } else if (ofpact->type == OFPACT_REG_MOVE) { |
8905 | 275 | const struct ofpact_reg_move *orm; |
8906 | | |
8907 | 275 | orm = CONTAINER_OF(ofpact, struct ofpact_reg_move, ofpact); |
8908 | 275 | return orm->dst.field; |
8909 | 275 | } |
8910 | | |
8911 | 180k | return NULL; |
8912 | 193k | } |
8913 | | |
8914 | | static void OVS_PRINTF_FORMAT(2, 3) |
8915 | | verify_error(char **errorp, const char *format, ...) |
8916 | 10.6k | { |
8917 | 10.6k | va_list args; |
8918 | 10.6k | va_start(args, format); |
8919 | 10.6k | char *error = xvasprintf(format, args); |
8920 | 10.6k | va_end(args); |
8921 | | |
8922 | 10.6k | if (errorp) { |
8923 | 0 | *errorp = error; |
8924 | 10.6k | } else { |
8925 | 10.6k | VLOG_WARN("%s", error); |
8926 | 10.6k | free(error); |
8927 | 10.6k | } |
8928 | 10.6k | } |
8929 | | |
8930 | | static enum ofperr |
8931 | | unsupported_nesting(enum ofpact_type action, enum ofpact_type outer_action, |
8932 | | char **errorp) |
8933 | 272 | { |
8934 | 272 | verify_error(errorp, "%s action doesn't support nested action %s", |
8935 | 272 | ofpact_name(outer_action), ofpact_name(action)); |
8936 | 272 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
8937 | 272 | } |
8938 | | |
8939 | | static bool |
8940 | | field_requires_ct(enum mf_field_id field) |
8941 | 14.2k | { |
8942 | 14.2k | return field == MFF_CT_MARK || field == MFF_CT_LABEL; |
8943 | 14.2k | } |
8944 | | |
8945 | | /* Apply nesting constraints for actions */ |
8946 | | static enum ofperr |
8947 | | ofpacts_verify_nested(const struct ofpact *a, enum ofpact_type outer_action, |
8948 | | char **errorp) |
8949 | 193k | { |
8950 | 193k | const struct mf_field *field = ofpact_get_mf_dst(a); |
8951 | | |
8952 | 193k | if (field && field_requires_ct(field->id) && outer_action != OFPACT_CT) { |
8953 | 11 | verify_error(errorp, "cannot set CT fields outside of ct action"); |
8954 | 11 | return OFPERR_OFPBAC_BAD_SET_ARGUMENT; |
8955 | 11 | } |
8956 | 193k | if (a->type == OFPACT_NAT) { |
8957 | 8.62k | if (outer_action != OFPACT_CT) { |
8958 | 6.18k | verify_error(errorp, |
8959 | 6.18k | "Cannot have NAT action outside of \"ct\" action"); |
8960 | 6.18k | return OFPERR_OFPBAC_BAD_SET_ARGUMENT; |
8961 | 6.18k | } |
8962 | 2.43k | return 0; |
8963 | 8.62k | } |
8964 | | |
8965 | 184k | if (outer_action) { |
8966 | 1.12k | ovs_assert(outer_action == OFPACT_WRITE_ACTIONS |
8967 | 1.12k | || outer_action == OFPACT_CT |
8968 | 1.12k | || outer_action == OFPACT_CLONE); |
8969 | | |
8970 | 1.12k | if (outer_action == OFPACT_CT) { |
8971 | 1.12k | if (!field) { |
8972 | 272 | return unsupported_nesting(a->type, outer_action, errorp); |
8973 | 851 | } else if (!field_requires_ct(field->id)) { |
8974 | 293 | verify_error(errorp, |
8975 | 293 | "%s action doesn't support nested modification " |
8976 | 293 | "of %s", ofpact_name(outer_action), field->name); |
8977 | 293 | return OFPERR_OFPBAC_BAD_ARGUMENT; |
8978 | 293 | } |
8979 | 1.12k | } |
8980 | | |
8981 | 558 | if (a->type == OFPACT_METER) { |
8982 | 0 | return unsupported_nesting(a->type, outer_action, errorp); |
8983 | 0 | } |
8984 | 558 | } |
8985 | | |
8986 | 184k | return 0; |
8987 | 184k | } |
8988 | | |
8989 | | /* Verifies that the 'ofpacts_len' bytes of actions in 'ofpacts' are in the |
8990 | | * appropriate order as defined by the OpenFlow spec and as required by Open |
8991 | | * vSwitch. |
8992 | | * |
8993 | | * The 'version' is relevant only for error reporting: Open vSwitch enforces |
8994 | | * the same rules for every version of OpenFlow, but different versions require |
8995 | | * different error codes. |
8996 | | * |
8997 | | * 'allowed_ovsinsts' is a bitmap of OVSINST_* values, in which 1-bits indicate |
8998 | | * instructions that are allowed within 'ofpacts[]'. |
8999 | | * |
9000 | | * If 'outer_action' is not zero, it specifies that the actions are nested |
9001 | | * within another action of type 'outer_action'. */ |
9002 | | static enum ofperr |
9003 | | ofpacts_verify(const struct ofpact ofpacts[], size_t ofpacts_len, |
9004 | | enum ofp_version version, uint32_t allowed_ovsinsts, |
9005 | | enum ofpact_type outer_action, char **errorp) |
9006 | 137k | { |
9007 | 137k | const struct ofpact *a; |
9008 | 137k | enum ovs_instruction_type inst; |
9009 | | |
9010 | 137k | inst = OVSINST_OFPIT13_METER; |
9011 | 198k | OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { |
9012 | 198k | enum ovs_instruction_type next; |
9013 | 198k | enum ofperr error; |
9014 | | |
9015 | 198k | if (a->type == OFPACT_CONJUNCTION) { |
9016 | 10.2k | OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { |
9017 | 10.2k | if (a->type != OFPACT_CONJUNCTION && a->type != OFPACT_NOTE) { |
9018 | 2.94k | verify_error(errorp, "\"conjunction\" actions may be used " |
9019 | 2.94k | "along with \"note\" but not any other kind " |
9020 | 2.94k | "of action (such as the \"%s\" action used " |
9021 | 2.94k | "here)", ofpact_name(a->type)); |
9022 | 2.94k | return OFPERR_NXBAC_BAD_CONJUNCTION; |
9023 | 2.94k | } |
9024 | 10.2k | } |
9025 | 2.05k | return 0; |
9026 | 4.99k | } |
9027 | | |
9028 | 193k | error = ofpacts_verify_nested(a, outer_action, errorp); |
9029 | 193k | if (error) { |
9030 | 6.76k | return error; |
9031 | 6.76k | } |
9032 | | |
9033 | 186k | next = ovs_instruction_type_from_ofpact_type(a->type, version); |
9034 | 186k | if (a > ofpacts |
9035 | 186k | && (inst == OVSINST_OFPIT11_APPLY_ACTIONS |
9036 | 95.2k | ? next < inst |
9037 | 95.2k | : next <= inst)) { |
9038 | 954 | const char *name = ovs_instruction_name_from_type(inst); |
9039 | 954 | const char *next_name = ovs_instruction_name_from_type(next); |
9040 | | |
9041 | 954 | if (next == inst) { |
9042 | 678 | verify_error(errorp, "duplicate %s instruction not allowed, " |
9043 | 678 | "for OpenFlow 1.1+ compatibility", name); |
9044 | 678 | } else { |
9045 | 276 | verify_error(errorp, "invalid instruction ordering: " |
9046 | 276 | "%s must appear before %s, " |
9047 | 276 | "for OpenFlow 1.1+ compatibility", |
9048 | 276 | next_name, name); |
9049 | 276 | } |
9050 | 954 | return OFPERR_OFPBAC_UNSUPPORTED_ORDER; |
9051 | 954 | } |
9052 | 185k | if (!((1u << next) & allowed_ovsinsts)) { |
9053 | 35 | const char *name = ovs_instruction_name_from_type(next); |
9054 | | |
9055 | 35 | if (next == OVSINST_OFPIT13_METER && version >= OFP15_VERSION) { |
9056 | 0 | verify_error(errorp, "%s action not allowed here", name); |
9057 | 0 | return OFPERR_OFPBAC_BAD_TYPE; |
9058 | 35 | } else { |
9059 | 35 | verify_error(errorp, "%s instruction not allowed here", name); |
9060 | 35 | return OFPERR_OFPBIC_UNSUP_INST; |
9061 | 35 | } |
9062 | 35 | } |
9063 | | |
9064 | 185k | inst = next; |
9065 | 185k | } |
9066 | | |
9067 | 125k | return 0; |
9068 | 137k | } |
9069 | | |
9070 | | /* Converting ofpacts to OpenFlow. */ |
9071 | | |
9072 | | static void |
9073 | | encode_ofpact(const struct ofpact *a, enum ofp_version ofp_version, |
9074 | | struct ofpbuf *out) |
9075 | 0 | { |
9076 | 0 | switch (a->type) { |
9077 | 0 | #define OFPACT(ENUM, STRUCT, MEMBER, NAME) \ |
9078 | 0 | case OFPACT_##ENUM: \ |
9079 | 0 | encode_##ENUM(ofpact_get_##ENUM(a), ofp_version, out); \ |
9080 | 0 | return; |
9081 | 0 | OFPACTS |
9082 | 0 | #undef OFPACT |
9083 | 0 | default: |
9084 | 0 | OVS_NOT_REACHED(); |
9085 | 0 | } |
9086 | 0 | } |
9087 | | |
9088 | | /* Converts the 'ofpacts_len' bytes of ofpacts in 'ofpacts' into OpenFlow |
9089 | | * actions in 'openflow', appending the actions to any existing data in |
9090 | | * 'openflow'. */ |
9091 | | size_t |
9092 | | ofpacts_put_openflow_actions(const struct ofpact ofpacts[], size_t ofpacts_len, |
9093 | | struct ofpbuf *openflow, |
9094 | | enum ofp_version ofp_version) |
9095 | 0 | { |
9096 | 0 | const struct ofpact *a; |
9097 | 0 | size_t start_size = openflow->size; |
9098 | |
|
9099 | 0 | OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { |
9100 | 0 | encode_ofpact(a, ofp_version, openflow); |
9101 | 0 | } |
9102 | 0 | return openflow->size - start_size; |
9103 | 0 | } |
9104 | | |
9105 | | static enum ovs_instruction_type |
9106 | | ofpact_is_apply_actions(const struct ofpact *a, enum ofp_version version) |
9107 | 0 | { |
9108 | 0 | return (ovs_instruction_type_from_ofpact_type(a->type, version) |
9109 | 0 | == OVSINST_OFPIT11_APPLY_ACTIONS); |
9110 | 0 | } |
9111 | | |
9112 | | void |
9113 | | ofpacts_put_openflow_instructions(const struct ofpact ofpacts[], |
9114 | | size_t ofpacts_len, |
9115 | | struct ofpbuf *openflow, |
9116 | | enum ofp_version ofp_version) |
9117 | 0 | { |
9118 | 0 | const struct ofpact *end = ofpact_end(ofpacts, ofpacts_len); |
9119 | 0 | const struct ofpact *a; |
9120 | |
|
9121 | 0 | if (ofp_version == OFP10_VERSION) { |
9122 | 0 | ofpacts_put_openflow_actions(ofpacts, ofpacts_len, openflow, |
9123 | 0 | ofp_version); |
9124 | 0 | return; |
9125 | 0 | } |
9126 | | |
9127 | 0 | a = ofpacts; |
9128 | 0 | while (a < end) { |
9129 | 0 | if (ofpact_is_apply_actions(a, ofp_version)) { |
9130 | 0 | size_t ofs = openflow->size; |
9131 | |
|
9132 | 0 | instruction_put_OFPIT11_APPLY_ACTIONS(openflow); |
9133 | 0 | do { |
9134 | 0 | encode_ofpact(a, ofp_version, openflow); |
9135 | 0 | a = ofpact_next(a); |
9136 | 0 | } while (a < end && ofpact_is_apply_actions(a, ofp_version)); |
9137 | 0 | ofpacts_update_instruction_actions(openflow, ofs); |
9138 | 0 | } else { |
9139 | 0 | encode_ofpact(a, ofp_version, openflow); |
9140 | 0 | a = ofpact_next(a); |
9141 | 0 | } |
9142 | 0 | } |
9143 | 0 | } |
9144 | | |
9145 | | /* Sets of supported actions. */ |
9146 | | |
9147 | | /* Two-way translation between OVS's internal "OFPACT_*" representation of |
9148 | | * actions and the "OFPAT_*" representation used in some OpenFlow version. |
9149 | | * (OFPAT_* numbering varies from one OpenFlow version to another, so a given |
9150 | | * instance is specific to one OpenFlow version.) */ |
9151 | | struct ofpact_map { |
9152 | | enum ofpact_type ofpact; /* Internal name for action type. */ |
9153 | | int ofpat; /* OFPAT_* number from OpenFlow spec. */ |
9154 | | }; |
9155 | | |
9156 | | static const struct ofpact_map * |
9157 | | get_ofpact_map(enum ofp_version version) |
9158 | 43.4k | { |
9159 | | /* OpenFlow 1.0 actions. */ |
9160 | 43.4k | static const struct ofpact_map of10[] = { |
9161 | 43.4k | { OFPACT_OUTPUT, 0 }, |
9162 | 43.4k | { OFPACT_SET_VLAN_VID, 1 }, |
9163 | 43.4k | { OFPACT_SET_VLAN_PCP, 2 }, |
9164 | 43.4k | { OFPACT_STRIP_VLAN, 3 }, |
9165 | 43.4k | { OFPACT_SET_ETH_SRC, 4 }, |
9166 | 43.4k | { OFPACT_SET_ETH_DST, 5 }, |
9167 | 43.4k | { OFPACT_SET_IPV4_SRC, 6 }, |
9168 | 43.4k | { OFPACT_SET_IPV4_DST, 7 }, |
9169 | 43.4k | { OFPACT_SET_IP_DSCP, 8 }, |
9170 | 43.4k | { OFPACT_SET_L4_SRC_PORT, 9 }, |
9171 | 43.4k | { OFPACT_SET_L4_DST_PORT, 10 }, |
9172 | 43.4k | { OFPACT_ENQUEUE, 11 }, |
9173 | 43.4k | { 0, -1 }, |
9174 | 43.4k | }; |
9175 | | |
9176 | | /* OpenFlow 1.1 actions. */ |
9177 | 43.4k | static const struct ofpact_map of11[] = { |
9178 | 43.4k | { OFPACT_OUTPUT, 0 }, |
9179 | 43.4k | { OFPACT_SET_VLAN_VID, 1 }, |
9180 | 43.4k | { OFPACT_SET_VLAN_PCP, 2 }, |
9181 | 43.4k | { OFPACT_SET_ETH_SRC, 3 }, |
9182 | 43.4k | { OFPACT_SET_ETH_DST, 4 }, |
9183 | 43.4k | { OFPACT_SET_IPV4_SRC, 5 }, |
9184 | 43.4k | { OFPACT_SET_IPV4_DST, 6 }, |
9185 | 43.4k | { OFPACT_SET_IP_DSCP, 7 }, |
9186 | 43.4k | { OFPACT_SET_IP_ECN, 8 }, |
9187 | 43.4k | { OFPACT_SET_L4_SRC_PORT, 9 }, |
9188 | 43.4k | { OFPACT_SET_L4_DST_PORT, 10 }, |
9189 | | /* OFPAT_COPY_TTL_OUT (11) not supported. */ |
9190 | | /* OFPAT_COPY_TTL_IN (12) not supported. */ |
9191 | 43.4k | { OFPACT_SET_MPLS_LABEL, 13 }, |
9192 | 43.4k | { OFPACT_SET_MPLS_TC, 14 }, |
9193 | 43.4k | { OFPACT_SET_MPLS_TTL, 15 }, |
9194 | 43.4k | { OFPACT_DEC_MPLS_TTL, 16 }, |
9195 | 43.4k | { OFPACT_PUSH_VLAN, 17 }, |
9196 | 43.4k | { OFPACT_STRIP_VLAN, 18 }, |
9197 | 43.4k | { OFPACT_PUSH_MPLS, 19 }, |
9198 | 43.4k | { OFPACT_POP_MPLS, 20 }, |
9199 | 43.4k | { OFPACT_SET_QUEUE, 21 }, |
9200 | 43.4k | { OFPACT_GROUP, 22 }, |
9201 | 43.4k | { OFPACT_SET_IP_TTL, 23 }, |
9202 | 43.4k | { OFPACT_DEC_TTL, 24 }, |
9203 | 43.4k | { 0, -1 }, |
9204 | 43.4k | }; |
9205 | | |
9206 | | /* OpenFlow 1.2, 1.3, and 1.4 actions. */ |
9207 | 43.4k | static const struct ofpact_map of12[] = { |
9208 | 43.4k | { OFPACT_OUTPUT, 0 }, |
9209 | | /* OFPAT_COPY_TTL_OUT (11) not supported. */ |
9210 | | /* OFPAT_COPY_TTL_IN (12) not supported. */ |
9211 | 43.4k | { OFPACT_SET_MPLS_TTL, 15 }, |
9212 | 43.4k | { OFPACT_DEC_MPLS_TTL, 16 }, |
9213 | 43.4k | { OFPACT_PUSH_VLAN, 17 }, |
9214 | 43.4k | { OFPACT_STRIP_VLAN, 18 }, |
9215 | 43.4k | { OFPACT_PUSH_MPLS, 19 }, |
9216 | 43.4k | { OFPACT_POP_MPLS, 20 }, |
9217 | 43.4k | { OFPACT_SET_QUEUE, 21 }, |
9218 | 43.4k | { OFPACT_GROUP, 22 }, |
9219 | 43.4k | { OFPACT_SET_IP_TTL, 23 }, |
9220 | 43.4k | { OFPACT_DEC_TTL, 24 }, |
9221 | 43.4k | { OFPACT_SET_FIELD, 25 }, |
9222 | | /* OF1.3+ OFPAT_PUSH_PBB (26) not supported. */ |
9223 | | /* OF1.3+ OFPAT_POP_PBB (27) not supported. */ |
9224 | 43.4k | { 0, -1 }, |
9225 | 43.4k | }; |
9226 | | |
9227 | 43.4k | switch (version) { |
9228 | 1.04k | case OFP10_VERSION: |
9229 | 1.04k | return of10; |
9230 | | |
9231 | 11.9k | case OFP11_VERSION: |
9232 | 11.9k | return of11; |
9233 | | |
9234 | 27.4k | case OFP12_VERSION: |
9235 | 27.4k | case OFP13_VERSION: |
9236 | 29.9k | case OFP14_VERSION: |
9237 | 30.3k | case OFP15_VERSION: |
9238 | 30.3k | default: |
9239 | 30.3k | return of12; |
9240 | 43.4k | } |
9241 | 43.4k | } |
9242 | | |
9243 | | /* Converts 'ofpacts_bitmap', a bitmap whose bits correspond to OFPACT_* |
9244 | | * values, into a bitmap of actions suitable for OpenFlow 'version', and |
9245 | | * returns the result. */ |
9246 | | ovs_be32 |
9247 | | ofpact_bitmap_to_openflow(uint64_t ofpacts_bitmap, enum ofp_version version) |
9248 | 0 | { |
9249 | 0 | uint32_t openflow_bitmap = 0; |
9250 | 0 | const struct ofpact_map *x; |
9251 | |
|
9252 | 0 | for (x = get_ofpact_map(version); x->ofpat >= 0; x++) { |
9253 | 0 | if (ofpacts_bitmap & (UINT64_C(1) << x->ofpact)) { |
9254 | 0 | openflow_bitmap |= 1u << x->ofpat; |
9255 | 0 | } |
9256 | 0 | } |
9257 | 0 | return htonl(openflow_bitmap); |
9258 | 0 | } |
9259 | | |
9260 | | /* Converts 'ofpat_bitmap', a bitmap of actions from an OpenFlow message with |
9261 | | * the given 'version' into a bitmap whose bits correspond to OFPACT_* values, |
9262 | | * and returns the result. */ |
9263 | | uint64_t |
9264 | | ofpact_bitmap_from_openflow(ovs_be32 ofpat_bitmap, enum ofp_version version) |
9265 | 43.4k | { |
9266 | 43.4k | uint64_t ofpact_bitmap = 0; |
9267 | 43.4k | const struct ofpact_map *x; |
9268 | | |
9269 | 696k | for (x = get_ofpact_map(version); x->ofpat >= 0; x++) { |
9270 | 652k | if (ofpat_bitmap & htonl(1u << x->ofpat)) { |
9271 | 183k | ofpact_bitmap |= UINT64_C(1) << x->ofpact; |
9272 | 183k | } |
9273 | 652k | } |
9274 | 43.4k | return ofpact_bitmap; |
9275 | 43.4k | } |
9276 | | |
9277 | | /* Appends to 's' a string representation of the set of OFPACT_* represented |
9278 | | * by 'ofpacts_bitmap'. */ |
9279 | | void |
9280 | | ofpact_bitmap_format(uint64_t ofpacts_bitmap, struct ds *s) |
9281 | 20.9k | { |
9282 | 20.9k | if (!ofpacts_bitmap) { |
9283 | 62 | ds_put_cstr(s, "<none>"); |
9284 | 20.9k | } else { |
9285 | 126k | while (ofpacts_bitmap) { |
9286 | 105k | ds_put_format(s, "%s ", |
9287 | 105k | ofpact_name(rightmost_1bit_idx(ofpacts_bitmap))); |
9288 | 105k | ofpacts_bitmap = zero_rightmost_1bit(ofpacts_bitmap); |
9289 | 105k | } |
9290 | 20.9k | ds_chomp(s, ' '); |
9291 | 20.9k | } |
9292 | 20.9k | } |
9293 | | |
9294 | | /* Returns true if 'action' outputs to 'port', false otherwise. */ |
9295 | | static bool |
9296 | | ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port) |
9297 | 0 | { |
9298 | 0 | switch (ofpact->type) { |
9299 | 0 | case OFPACT_OUTPUT: |
9300 | 0 | return ofpact_get_OUTPUT(ofpact)->port == port; |
9301 | 0 | case OFPACT_ENQUEUE: |
9302 | 0 | return ofpact_get_ENQUEUE(ofpact)->port == port; |
9303 | 0 | case OFPACT_CONTROLLER: |
9304 | 0 | return port == OFPP_CONTROLLER; |
9305 | | |
9306 | 0 | case OFPACT_OUTPUT_REG: |
9307 | 0 | case OFPACT_OUTPUT_TRUNC: |
9308 | 0 | case OFPACT_BUNDLE: |
9309 | 0 | case OFPACT_SET_VLAN_VID: |
9310 | 0 | case OFPACT_SET_VLAN_PCP: |
9311 | 0 | case OFPACT_STRIP_VLAN: |
9312 | 0 | case OFPACT_PUSH_VLAN: |
9313 | 0 | case OFPACT_SET_ETH_SRC: |
9314 | 0 | case OFPACT_SET_ETH_DST: |
9315 | 0 | case OFPACT_SET_IPV4_SRC: |
9316 | 0 | case OFPACT_SET_IPV4_DST: |
9317 | 0 | case OFPACT_SET_IP_DSCP: |
9318 | 0 | case OFPACT_SET_IP_ECN: |
9319 | 0 | case OFPACT_SET_IP_TTL: |
9320 | 0 | case OFPACT_SET_L4_SRC_PORT: |
9321 | 0 | case OFPACT_SET_L4_DST_PORT: |
9322 | 0 | case OFPACT_REG_MOVE: |
9323 | 0 | case OFPACT_SET_FIELD: |
9324 | 0 | case OFPACT_STACK_PUSH: |
9325 | 0 | case OFPACT_STACK_POP: |
9326 | 0 | case OFPACT_DEC_TTL: |
9327 | 0 | case OFPACT_SET_MPLS_LABEL: |
9328 | 0 | case OFPACT_SET_MPLS_TC: |
9329 | 0 | case OFPACT_SET_MPLS_TTL: |
9330 | 0 | case OFPACT_DEC_MPLS_TTL: |
9331 | 0 | case OFPACT_SET_TUNNEL: |
9332 | 0 | case OFPACT_WRITE_METADATA: |
9333 | 0 | case OFPACT_SET_QUEUE: |
9334 | 0 | case OFPACT_POP_QUEUE: |
9335 | 0 | case OFPACT_FIN_TIMEOUT: |
9336 | 0 | case OFPACT_RESUBMIT: |
9337 | 0 | case OFPACT_LEARN: |
9338 | 0 | case OFPACT_CONJUNCTION: |
9339 | 0 | case OFPACT_MULTIPATH: |
9340 | 0 | case OFPACT_NOTE: |
9341 | 0 | case OFPACT_EXIT: |
9342 | 0 | case OFPACT_UNROLL_XLATE: |
9343 | 0 | case OFPACT_PUSH_MPLS: |
9344 | 0 | case OFPACT_POP_MPLS: |
9345 | 0 | case OFPACT_SAMPLE: |
9346 | 0 | case OFPACT_CLEAR_ACTIONS: |
9347 | 0 | case OFPACT_CLONE: |
9348 | 0 | case OFPACT_WRITE_ACTIONS: |
9349 | 0 | case OFPACT_GOTO_TABLE: |
9350 | 0 | case OFPACT_METER: |
9351 | 0 | case OFPACT_GROUP: |
9352 | 0 | case OFPACT_DEBUG_RECIRC: |
9353 | 0 | case OFPACT_DEBUG_SLOW: |
9354 | 0 | case OFPACT_CT: |
9355 | 0 | case OFPACT_CT_CLEAR: |
9356 | 0 | case OFPACT_NAT: |
9357 | 0 | case OFPACT_ENCAP: |
9358 | 0 | case OFPACT_DECAP: |
9359 | 0 | case OFPACT_DEC_NSH_TTL: |
9360 | 0 | case OFPACT_CHECK_PKT_LARGER: |
9361 | 0 | case OFPACT_DELETE_FIELD: |
9362 | 0 | default: |
9363 | 0 | return false; |
9364 | 0 | } |
9365 | 0 | } |
9366 | | |
9367 | | /* Returns true if any action in the 'ofpacts_len' bytes of 'ofpacts' outputs |
9368 | | * to 'port', false otherwise. */ |
9369 | | bool |
9370 | | ofpacts_output_to_port(const struct ofpact *ofpacts, size_t ofpacts_len, |
9371 | | ofp_port_t port) |
9372 | 0 | { |
9373 | 0 | const struct ofpact *a; |
9374 | |
|
9375 | 0 | OFPACT_FOR_EACH_FLATTENED (a, ofpacts, ofpacts_len) { |
9376 | 0 | if (ofpact_outputs_to_port(a, port)) { |
9377 | 0 | return true; |
9378 | 0 | } |
9379 | 0 | } |
9380 | | |
9381 | 0 | return false; |
9382 | 0 | } |
9383 | | |
9384 | | /* Returns true if any action in the 'ofpacts_len' bytes of 'ofpacts' outputs |
9385 | | * to 'group', false otherwise. */ |
9386 | | bool |
9387 | | ofpacts_output_to_group(const struct ofpact *ofpacts, size_t ofpacts_len, |
9388 | | uint32_t group_id) |
9389 | 0 | { |
9390 | 0 | const struct ofpact *a; |
9391 | |
|
9392 | 0 | OFPACT_FOR_EACH_FLATTENED (a, ofpacts, ofpacts_len) { |
9393 | 0 | if (a->type == OFPACT_GROUP |
9394 | 0 | && ofpact_get_GROUP(a)->group_id == group_id) { |
9395 | 0 | return true; |
9396 | 0 | } |
9397 | 0 | } |
9398 | | |
9399 | 0 | return false; |
9400 | 0 | } |
9401 | | |
9402 | | /* Returns true if the 'a_len' bytes of actions in 'a' and the 'b_len' bytes of |
9403 | | * actions in 'b' are bytewise identical. */ |
9404 | | bool |
9405 | | ofpacts_equal(const struct ofpact *a, size_t a_len, |
9406 | | const struct ofpact *b, size_t b_len) |
9407 | 0 | { |
9408 | 0 | return a_len == b_len && (!a_len || !memcmp(a, b, a_len)); |
9409 | 0 | } |
9410 | | |
9411 | | /* Returns true if the 'a_len' bytes of actions in 'a' and the 'b_len' bytes of |
9412 | | * actions in 'b' are identical when formatted as strings. (Converting actions |
9413 | | * to string form suppresses some rarely meaningful differences, such as the |
9414 | | * 'compat' member of actions.) */ |
9415 | | bool |
9416 | | ofpacts_equal_stringwise(const struct ofpact *a, size_t a_len, |
9417 | | const struct ofpact *b, size_t b_len) |
9418 | 0 | { |
9419 | 0 | struct ds a_s = DS_EMPTY_INITIALIZER; |
9420 | 0 | struct ofpact_format_params a_fp = { .s = &a_s }; |
9421 | 0 | ofpacts_format(a, a_len, &a_fp); |
9422 | |
|
9423 | 0 | struct ds b_s = DS_EMPTY_INITIALIZER; |
9424 | 0 | struct ofpact_format_params b_fp = { .s = &b_s }; |
9425 | 0 | ofpacts_format(b, b_len, &b_fp); |
9426 | |
|
9427 | 0 | bool equal = !strcmp(ds_cstr(&a_s), ds_cstr(&b_s)); |
9428 | |
|
9429 | 0 | ds_destroy(&a_s); |
9430 | 0 | ds_destroy(&b_s); |
9431 | |
|
9432 | 0 | return equal; |
9433 | 0 | } |
9434 | | |
9435 | | /* Finds the OFPACT_METER action, if any, in the 'ofpacts_len' bytes of |
9436 | | * 'ofpacts'. If found, returns its meter ID; if not, returns 0. |
9437 | | * |
9438 | | * This function relies on the order of 'ofpacts' being correct (as checked by |
9439 | | * ofpacts_verify()). */ |
9440 | | uint32_t |
9441 | | ofpacts_get_meter(const struct ofpact ofpacts[], size_t ofpacts_len) |
9442 | 0 | { |
9443 | 0 | const struct ofpact *a; |
9444 | |
|
9445 | 0 | OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { |
9446 | 0 | if (a->type == OFPACT_METER) { |
9447 | 0 | return ofpact_get_METER(a)->meter_id; |
9448 | 0 | } |
9449 | | |
9450 | 0 | enum ovs_instruction_type inst |
9451 | 0 | = ovs_instruction_type_from_ofpact_type(a->type, 0); |
9452 | 0 | if (inst > OVSINST_OFPIT13_METER) { |
9453 | 0 | break; |
9454 | 0 | } |
9455 | 0 | } |
9456 | | |
9457 | 0 | return 0; |
9458 | 0 | } |
9459 | | |
9460 | | /* Formatting ofpacts. */ |
9461 | | |
9462 | | static void |
9463 | | ofpact_format(const struct ofpact *a, |
9464 | | const struct ofpact_format_params *fp) |
9465 | 199k | { |
9466 | 199k | switch (a->type) { |
9467 | 0 | #define OFPACT(ENUM, STRUCT, MEMBER, NAME) \ |
9468 | 199k | case OFPACT_##ENUM: \ |
9469 | 199k | format_##ENUM(ALIGNED_CAST(const struct STRUCT *, a), fp); \ |
9470 | 199k | break; |
9471 | 0 | OFPACTS |
9472 | 0 | #undef OFPACT |
9473 | 0 | default: |
9474 | 0 | OVS_NOT_REACHED(); |
9475 | 199k | } |
9476 | 199k | } |
9477 | | |
9478 | | /* Appends a string representing the 'ofpacts_len' bytes of ofpacts in |
9479 | | * 'ofpacts' to 'fp->s'. If 'port_map' is nonnull, uses it to translate port |
9480 | | * numbers to names in output. */ |
9481 | | void |
9482 | | ofpacts_format(const struct ofpact *ofpacts, size_t ofpacts_len, |
9483 | | const struct ofpact_format_params *fp) |
9484 | 110k | { |
9485 | 110k | if (!ofpacts_len) { |
9486 | 20.8k | ds_put_format(fp->s, "%sdrop%s", colors.drop, colors.end); |
9487 | 89.4k | } else { |
9488 | 89.4k | const struct ofpact *a; |
9489 | | |
9490 | 199k | OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { |
9491 | 199k | if (a != ofpacts) { |
9492 | 109k | ds_put_char(fp->s, ','); |
9493 | 109k | } |
9494 | | |
9495 | 199k | ofpact_format(a, fp); |
9496 | 199k | } |
9497 | 89.4k | } |
9498 | 110k | } |
9499 | | |
9500 | | /* Internal use by helpers. */ |
9501 | | |
9502 | | /* Implementation of ofpact_put_<ENUM>(). */ |
9503 | | void * |
9504 | | ofpact_put(struct ofpbuf *ofpacts, enum ofpact_type type, size_t len) |
9505 | 378k | { |
9506 | 378k | struct ofpact *ofpact; |
9507 | | |
9508 | 378k | ofpacts->header = ofpbuf_put_uninit(ofpacts, len); |
9509 | 378k | ofpact = ofpacts->header; |
9510 | 378k | ofpact_init(ofpact, type, len); |
9511 | 378k | return ofpact; |
9512 | 378k | } |
9513 | | |
9514 | | /* Implementation of ofpact_init_<ENUM>(). */ |
9515 | | void |
9516 | | ofpact_init(struct ofpact *ofpact, enum ofpact_type type, size_t len) |
9517 | 378k | { |
9518 | 378k | memset(ofpact, 0, len); |
9519 | 378k | ofpact->type = type; |
9520 | 378k | ofpact->raw = -1; |
9521 | 378k | ofpact->len = len; |
9522 | 378k | } |
9523 | | |
9524 | | /* Implementation of ofpact_finish_<ENUM>(). |
9525 | | * |
9526 | | * Finishes composing a variable-length action (begun using |
9527 | | * ofpact_put_<NAME>()), by padding the action to a multiple of OFPACT_ALIGNTO |
9528 | | * bytes and updating its embedded length field. See the large comment near |
9529 | | * the end of ofp-actions.h for more information. |
9530 | | * |
9531 | | * May reallocate 'ofpacts'. Callers should consider updating their 'ofpact' |
9532 | | * pointer to the return value of this function. */ |
9533 | | void * |
9534 | | ofpact_finish(struct ofpbuf *ofpacts, struct ofpact *ofpact) |
9535 | 93.8k | { |
9536 | 93.8k | ptrdiff_t len; |
9537 | | |
9538 | 93.8k | ovs_assert(ofpact == ofpacts->header); |
9539 | 93.8k | len = (char *) ofpbuf_tail(ofpacts) - (char *) ofpact; |
9540 | 93.8k | ovs_assert(len > 0 && len <= UINT16_MAX); |
9541 | 93.8k | ofpact->len = len; |
9542 | 93.8k | ofpbuf_padto(ofpacts, OFPACT_ALIGN(ofpacts->size)); |
9543 | | |
9544 | 93.8k | return ofpacts->header; |
9545 | 93.8k | } |
9546 | | |
9547 | | static char * OVS_WARN_UNUSED_RESULT |
9548 | | ofpact_parse(enum ofpact_type type, char *value, |
9549 | | const struct ofpact_parse_params *pp) |
9550 | 0 | { |
9551 | 0 | switch (type) { |
9552 | 0 | #define OFPACT(ENUM, STRUCT, MEMBER, NAME) \ |
9553 | 0 | case OFPACT_##ENUM: \ |
9554 | 0 | return parse_##ENUM(value, pp); |
9555 | 0 | OFPACTS |
9556 | 0 | #undef OFPACT |
9557 | 0 | default: |
9558 | 0 | OVS_NOT_REACHED(); |
9559 | 0 | } |
9560 | 0 | } |
9561 | | |
9562 | | static bool |
9563 | | ofpact_type_from_name(const char *name, enum ofpact_type *type) |
9564 | 0 | { |
9565 | 0 | #define OFPACT(ENUM, STRUCT, MEMBER, NAME) \ |
9566 | 0 | if (!strcasecmp(name, NAME)) { \ |
9567 | 0 | *type = OFPACT_##ENUM; \ |
9568 | 0 | return true; \ |
9569 | 0 | } |
9570 | 0 | OFPACTS |
9571 | 0 | #undef OFPACT |
9572 | | |
9573 | 0 | return false; |
9574 | 0 | } |
9575 | | |
9576 | | /* Parses 'str' as a series of instructions, and appends them to 'ofpacts'. |
9577 | | * |
9578 | | * Returns NULL if successful, otherwise a malloc()'d string describing the |
9579 | | * error. The caller is responsible for freeing the returned string. |
9580 | | * |
9581 | | * If 'outer_action' is specified, indicates that the actions being parsed |
9582 | | * are nested within another action of the type specified in 'outer_action'. */ |
9583 | | static char * OVS_WARN_UNUSED_RESULT |
9584 | | ofpacts_parse__(char *str, const struct ofpact_parse_params *pp, |
9585 | | bool allow_instructions, enum ofpact_type outer_action) |
9586 | 0 | { |
9587 | 0 | uint32_t orig_size = pp->ofpacts->size; |
9588 | 0 | char *key, *value; |
9589 | 0 | bool drop = false; |
9590 | 0 | char *pos; |
9591 | |
|
9592 | 0 | pos = str; |
9593 | 0 | while (ofputil_parse_key_value(&pos, &key, &value)) { |
9594 | 0 | enum ofpact_type type; |
9595 | 0 | char *error = NULL; |
9596 | 0 | ofp_port_t port; |
9597 | 0 | if (ofpact_type_from_name(key, &type)) { |
9598 | 0 | error = ofpact_parse(type, value, pp); |
9599 | |
|
9600 | 0 | if (type == OFPACT_METER && !allow_instructions) { |
9601 | | /* Meter is an action in OF1.5 and it's being used in a |
9602 | | * context where instructions aren't allowed. Therefore, |
9603 | | * this must be OF1.5+. */ |
9604 | 0 | *pp->usable_protocols &= OFPUTIL_P_OF15_UP; |
9605 | 0 | } |
9606 | 0 | } else if (!strcasecmp(key, "mod_vlan_vid")) { |
9607 | 0 | error = parse_set_vlan_vid(value, true, pp); |
9608 | 0 | } else if (!strcasecmp(key, "mod_vlan_pcp")) { |
9609 | 0 | error = parse_set_vlan_pcp(value, true, pp); |
9610 | 0 | } else if (!strcasecmp(key, "set_nw_ttl")) { |
9611 | 0 | error = parse_SET_IP_TTL(value, pp); |
9612 | 0 | } else if (!strcasecmp(key, "pop_vlan")) { |
9613 | 0 | error = parse_pop_vlan(pp); |
9614 | 0 | } else if (!strcasecmp(key, "set_tunnel64")) { |
9615 | 0 | error = parse_set_tunnel(value, NXAST_RAW_SET_TUNNEL64, pp); |
9616 | 0 | } else if (!strcasecmp(key, "load")) { |
9617 | 0 | error = parse_reg_load(value, pp); |
9618 | 0 | } else if (!strcasecmp(key, "bundle_load")) { |
9619 | 0 | error = parse_bundle_load(value, pp); |
9620 | 0 | } else if (!strcasecmp(key, "drop")) { |
9621 | 0 | drop = true; |
9622 | 0 | } else if (!strcasecmp(key, "apply_actions")) { |
9623 | 0 | return xstrdup("apply_actions is the default instruction"); |
9624 | 0 | } else if (ofputil_port_from_string(key, pp->port_map, &port)) { |
9625 | 0 | ofpact_put_OUTPUT(pp->ofpacts)->port = port; |
9626 | 0 | } else { |
9627 | 0 | return xasprintf("unknown action %s", key); |
9628 | 0 | } |
9629 | 0 | if (error) { |
9630 | 0 | return error; |
9631 | 0 | } |
9632 | 0 | if (pp->ofpacts->size - orig_size > UINT16_MAX) { |
9633 | 0 | return xasprintf("input too big"); |
9634 | 0 | } |
9635 | 0 | } |
9636 | | |
9637 | 0 | if (drop && pp->ofpacts->size) { |
9638 | 0 | return xstrdup("\"drop\" must not be accompanied by any other action " |
9639 | 0 | "or instruction"); |
9640 | 0 | } |
9641 | | |
9642 | 0 | char *error = NULL; |
9643 | 0 | ofpacts_verify(pp->ofpacts->data, pp->ofpacts->size, OFP11_VERSION, |
9644 | 0 | (allow_instructions |
9645 | 0 | ? (1u << N_OVS_INSTRUCTIONS) - 1 |
9646 | 0 | : ((1u << OVSINST_OFPIT11_APPLY_ACTIONS) |
9647 | 0 | | (1u << OVSINST_OFPIT13_METER))), |
9648 | 0 | outer_action, &error); |
9649 | 0 | if (error) { |
9650 | 0 | return error; |
9651 | 0 | } |
9652 | | |
9653 | 0 | return NULL; |
9654 | 0 | } |
9655 | | |
9656 | | static char * OVS_WARN_UNUSED_RESULT |
9657 | | ofpacts_parse(char *str, const struct ofpact_parse_params *pp, |
9658 | | bool allow_instructions, enum ofpact_type outer_action) |
9659 | 0 | { |
9660 | 0 | if (pp->depth >= MAX_OFPACT_PARSE_DEPTH) { |
9661 | 0 | return xstrdup("Action nested too deeply"); |
9662 | 0 | } |
9663 | 0 | CONST_CAST(struct ofpact_parse_params *, pp)->depth++; |
9664 | 0 | uint32_t orig_size = pp->ofpacts->size; |
9665 | 0 | char *error = ofpacts_parse__(str, pp, allow_instructions, outer_action); |
9666 | 0 | if (error) { |
9667 | 0 | ofpbuf_truncate(pp->ofpacts, orig_size); |
9668 | 0 | } |
9669 | 0 | CONST_CAST(struct ofpact_parse_params *, pp)->depth--; |
9670 | 0 | return error; |
9671 | 0 | } |
9672 | | |
9673 | | static char * OVS_WARN_UNUSED_RESULT |
9674 | | ofpacts_parse_copy(const char *s_, const struct ofpact_parse_params *pp, |
9675 | | bool allow_instructions, enum ofpact_type outer_action) |
9676 | 0 | { |
9677 | 0 | char *error, *s; |
9678 | |
|
9679 | 0 | *pp->usable_protocols = OFPUTIL_P_ANY; |
9680 | |
|
9681 | 0 | s = xstrdup(s_); |
9682 | 0 | error = ofpacts_parse(s, pp, allow_instructions, outer_action); |
9683 | 0 | free(s); |
9684 | |
|
9685 | 0 | return error; |
9686 | 0 | } |
9687 | | |
9688 | | /* Parses 's' as a set of OpenFlow actions and appends the actions to |
9689 | | * 'ofpacts'. 'outer_action', if nonzero, specifies that 's' contains actions |
9690 | | * that are nested within the action of type 'outer_action'. |
9691 | | * |
9692 | | * Returns NULL if successful, otherwise a malloc()'d string describing the |
9693 | | * error. The caller is responsible for freeing the returned string. */ |
9694 | | char * OVS_WARN_UNUSED_RESULT |
9695 | | ofpacts_parse_actions(const char *s, const struct ofpact_parse_params *pp) |
9696 | 0 | { |
9697 | 0 | return ofpacts_parse_copy(s, pp, false, 0); |
9698 | 0 | } |
9699 | | |
9700 | | /* Parses 's' as a set of OpenFlow instructions and appends the instructions to |
9701 | | * 'ofpacts'. |
9702 | | * |
9703 | | * Returns NULL if successful, otherwise a malloc()'d string describing the |
9704 | | * error. The caller is responsible for freeing the returned string. */ |
9705 | | char * OVS_WARN_UNUSED_RESULT |
9706 | | ofpacts_parse_instructions(const char *s, const struct ofpact_parse_params *pp) |
9707 | 0 | { |
9708 | 0 | return ofpacts_parse_copy(s, pp, true, 0); |
9709 | 0 | } |
9710 | | |
9711 | | const char * |
9712 | | ofpact_name(enum ofpact_type type) |
9713 | 108k | { |
9714 | 108k | switch (type) { |
9715 | 108k | #define OFPACT(ENUM, STRUCT, MEMBER, NAME) case OFPACT_##ENUM: return NAME; |
9716 | 108k | OFPACTS |
9717 | 108k | #undef OFPACT |
9718 | 108k | } |
9719 | 0 | return "<unknown>"; |
9720 | 108k | } |
9721 | | |
9722 | | /* Low-level action decoding and encoding functions. */ |
9723 | | |
9724 | | /* Everything needed to identify a particular OpenFlow action. */ |
9725 | | struct ofpact_hdrs { |
9726 | | uint32_t vendor; /* 0 if standard, otherwise a vendor code. */ |
9727 | | uint16_t type; /* Type if standard, otherwise subtype. */ |
9728 | | uint8_t ofp_version; /* From ofp_header. */ |
9729 | | }; |
9730 | | |
9731 | | /* Information about a particular OpenFlow action. */ |
9732 | | struct ofpact_raw_instance { |
9733 | | /* The action's identity. */ |
9734 | | struct ofpact_hdrs hdrs; |
9735 | | enum ofp_raw_action_type raw; |
9736 | | |
9737 | | /* Looking up the action. */ |
9738 | | struct hmap_node decode_node; /* Based on 'hdrs'. */ |
9739 | | struct hmap_node encode_node; /* Based on 'raw' + 'hdrs.ofp_version'. */ |
9740 | | |
9741 | | /* The action's encoded size. |
9742 | | * |
9743 | | * If this action is fixed-length, 'min_length' == 'max_length'. |
9744 | | * If it is variable length, then 'max_length' is ROUND_DOWN(UINT16_MAX, |
9745 | | * OFP_ACTION_ALIGN) == 65528. */ |
9746 | | unsigned short int min_length; |
9747 | | unsigned short int max_length; |
9748 | | |
9749 | | /* For actions with a simple integer numeric argument, 'arg_ofs' is the |
9750 | | * offset of that argument from the beginning of the action and 'arg_len' |
9751 | | * its length, both in bytes. |
9752 | | * |
9753 | | * For actions that take other forms, these are both zero. */ |
9754 | | unsigned short int arg_ofs; |
9755 | | unsigned short int arg_len; |
9756 | | |
9757 | | /* The name of the action, e.g. "OFPAT_OUTPUT" or "NXAST_RESUBMIT". */ |
9758 | | const char *name; |
9759 | | |
9760 | | /* If this action is deprecated, a human-readable string with a brief |
9761 | | * explanation. */ |
9762 | | const char *deprecation; |
9763 | | }; |
9764 | | |
9765 | | /* Action header. */ |
9766 | | struct ofp_action_header { |
9767 | | /* The meaning of other values of 'type' generally depends on the OpenFlow |
9768 | | * version (see enum ofp_raw_action_type). |
9769 | | * |
9770 | | * Across all OpenFlow versions, OFPAT_VENDOR indicates that 'vendor' |
9771 | | * designates an OpenFlow vendor ID and that the remainder of the action |
9772 | | * structure has a vendor-defined meaning. |
9773 | | */ |
9774 | | #define OFPAT_VENDOR 0xffff |
9775 | | ovs_be16 type; |
9776 | | |
9777 | | /* Always a multiple of 8. */ |
9778 | | ovs_be16 len; |
9779 | | |
9780 | | /* For type == OFPAT_VENDOR only, this is a vendor ID, e.g. NX_VENDOR_ID or |
9781 | | * ONF_VENDOR_ID. Other 'type's use this space for some other purpose. */ |
9782 | | ovs_be32 vendor; |
9783 | | }; |
9784 | | OFP_ASSERT(sizeof(struct ofp_action_header) == 8); |
9785 | | |
9786 | | static bool |
9787 | | ofpact_hdrs_equal(const struct ofpact_hdrs *a, |
9788 | | const struct ofpact_hdrs *b) |
9789 | 381k | { |
9790 | 381k | return (a->vendor == b->vendor |
9791 | 381k | && a->type == b->type |
9792 | 381k | && a->ofp_version == b->ofp_version); |
9793 | 381k | } |
9794 | | |
9795 | | static uint32_t |
9796 | | ofpact_hdrs_hash(const struct ofpact_hdrs *hdrs) |
9797 | 405k | { |
9798 | 405k | return hash_2words(hdrs->vendor, |
9799 | 405k | ((uint32_t) hdrs->type << 16) | hdrs->ofp_version); |
9800 | 405k | } |
9801 | | |
9802 | | #include "ofp-actions.inc2" |
9803 | | |
9804 | | static struct hmap * |
9805 | | ofpact_decode_hmap(void) |
9806 | 405k | { |
9807 | 405k | static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; |
9808 | 405k | static struct hmap hmap; |
9809 | | |
9810 | 405k | if (ovsthread_once_start(&once)) { |
9811 | 1 | struct ofpact_raw_instance *inst; |
9812 | | |
9813 | 1 | hmap_init(&hmap); |
9814 | 1 | for (inst = all_raw_instances; |
9815 | 385 | inst < &all_raw_instances[ARRAY_SIZE(all_raw_instances)]; |
9816 | 384 | inst++) { |
9817 | 384 | hmap_insert(&hmap, &inst->decode_node, |
9818 | 384 | ofpact_hdrs_hash(&inst->hdrs)); |
9819 | 384 | } |
9820 | 1 | ovsthread_once_done(&once); |
9821 | 1 | } |
9822 | 405k | return &hmap; |
9823 | 405k | } |
9824 | | |
9825 | | static struct hmap * |
9826 | | ofpact_encode_hmap(void) |
9827 | 0 | { |
9828 | 0 | static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; |
9829 | 0 | static struct hmap hmap; |
9830 | |
|
9831 | 0 | if (ovsthread_once_start(&once)) { |
9832 | 0 | struct ofpact_raw_instance *inst; |
9833 | |
|
9834 | 0 | hmap_init(&hmap); |
9835 | 0 | for (inst = all_raw_instances; |
9836 | 0 | inst < &all_raw_instances[ARRAY_SIZE(all_raw_instances)]; |
9837 | 0 | inst++) { |
9838 | 0 | hmap_insert(&hmap, &inst->encode_node, |
9839 | 0 | hash_2words(inst->raw, inst->hdrs.ofp_version)); |
9840 | 0 | } |
9841 | 0 | ovsthread_once_done(&once); |
9842 | 0 | } |
9843 | 0 | return &hmap; |
9844 | 0 | } |
9845 | | |
9846 | | static enum ofperr |
9847 | | ofpact_decode_raw(enum ofp_version ofp_version, |
9848 | | const struct ofp_action_header *oah, size_t length, |
9849 | | const struct ofpact_raw_instance **instp) |
9850 | 423k | { |
9851 | 423k | const struct ofpact_raw_instance *inst; |
9852 | 423k | struct ofpact_hdrs hdrs; |
9853 | | |
9854 | 423k | *instp = NULL; |
9855 | 423k | if (length < sizeof *oah) { |
9856 | 0 | return OFPERR_OFPBAC_BAD_LEN; |
9857 | 0 | } |
9858 | | |
9859 | | /* Get base action type. */ |
9860 | 423k | if (oah->type == htons(OFPAT_VENDOR)) { |
9861 | | /* Get vendor. */ |
9862 | 212k | hdrs.vendor = ntohl(oah->vendor); |
9863 | 212k | if (hdrs.vendor == NX_VENDOR_ID || hdrs.vendor == ONF_VENDOR_ID) { |
9864 | | /* Get extension subtype. */ |
9865 | 194k | const struct ext_action_header *nah; |
9866 | | |
9867 | 194k | nah = ALIGNED_CAST(const struct ext_action_header *, oah); |
9868 | 194k | if (length < sizeof *nah) { |
9869 | 195 | return OFPERR_OFPBAC_BAD_LEN; |
9870 | 195 | } |
9871 | 193k | hdrs.type = ntohs(nah->subtype); |
9872 | 193k | } else { |
9873 | 18.2k | VLOG_WARN_RL(&rl, "OpenFlow action has unknown vendor %#"PRIx32, |
9874 | 18.2k | hdrs.vendor); |
9875 | 18.2k | return OFPERR_OFPBAC_BAD_VENDOR; |
9876 | 18.2k | } |
9877 | 212k | } else { |
9878 | 211k | hdrs.vendor = 0; |
9879 | 211k | hdrs.type = ntohs(oah->type); |
9880 | 211k | } |
9881 | | |
9882 | 405k | hdrs.ofp_version = ofp_version; |
9883 | 405k | HMAP_FOR_EACH_WITH_HASH (inst, decode_node, ofpact_hdrs_hash(&hdrs), |
9884 | 405k | ofpact_decode_hmap()) { |
9885 | 381k | if (ofpact_hdrs_equal(&hdrs, &inst->hdrs)) { |
9886 | 381k | *instp = inst; |
9887 | 381k | return 0; |
9888 | 381k | } |
9889 | 381k | } |
9890 | | |
9891 | 23.6k | VLOG_WARN_RL(&rl, "unknown %s action for vendor %#"PRIx32" and " |
9892 | 23.6k | "type %"PRIu16, ofputil_version_to_string(ofp_version), |
9893 | 23.6k | hdrs.vendor, hdrs.type); |
9894 | 23.6k | return (hdrs.vendor |
9895 | 23.6k | ? OFPERR_OFPBAC_BAD_VENDOR_TYPE |
9896 | 23.6k | : OFPERR_OFPBAC_BAD_TYPE); |
9897 | 405k | } |
9898 | | |
9899 | | static enum ofperr |
9900 | | ofpact_pull_raw(struct ofpbuf *buf, enum ofp_version ofp_version, |
9901 | | enum ofp_raw_action_type *raw, uint64_t *arg, |
9902 | | size_t *raw_len) |
9903 | 423k | { |
9904 | 423k | const struct ofp_action_header *oah = buf->data; |
9905 | 423k | const struct ofpact_raw_instance *action; |
9906 | 423k | unsigned int length; |
9907 | 423k | enum ofperr error; |
9908 | | |
9909 | 423k | *raw = *arg = *raw_len = 0; |
9910 | 423k | error = ofpact_decode_raw(ofp_version, oah, buf->size, &action); |
9911 | 423k | if (error) { |
9912 | 42.0k | return error; |
9913 | 42.0k | } |
9914 | | |
9915 | 381k | if (action->deprecation) { |
9916 | 11.6k | VLOG_INFO_RL(&rl, "%s is deprecated in %s (%s)", |
9917 | 11.6k | action->name, ofputil_version_to_string(ofp_version), |
9918 | 11.6k | action->deprecation); |
9919 | 11.6k | } |
9920 | | |
9921 | 381k | length = ntohs(oah->len); |
9922 | 381k | if (length > buf->size) { |
9923 | 6.24k | VLOG_WARN_RL(&rl, "OpenFlow action %s length %u exceeds action buffer " |
9924 | 6.24k | "length %"PRIu32, action->name, length, buf->size); |
9925 | 6.24k | return OFPERR_OFPBAC_BAD_LEN; |
9926 | 6.24k | } |
9927 | 375k | if (length < action->min_length || length > action->max_length) { |
9928 | 6.12k | VLOG_WARN_RL(&rl, "OpenFlow action %s length %u not in valid range " |
9929 | 6.12k | "[%hu,%hu]", action->name, length, |
9930 | 6.12k | action->min_length, action->max_length); |
9931 | 6.12k | return OFPERR_OFPBAC_BAD_LEN; |
9932 | 6.12k | } |
9933 | 369k | if (length % 8) { |
9934 | 2.35k | VLOG_WARN_RL(&rl, "OpenFlow action %s length %u is not a multiple " |
9935 | 2.35k | "of 8", action->name, length); |
9936 | 2.35k | return OFPERR_OFPBAC_BAD_LEN; |
9937 | 2.35k | } |
9938 | | |
9939 | 366k | *raw = action->raw; |
9940 | 366k | *arg = 0; |
9941 | 366k | if (action->arg_len) { |
9942 | 113k | const uint8_t *p; |
9943 | 113k | int i; |
9944 | | |
9945 | 113k | p = ofpbuf_at_assert(buf, action->arg_ofs, action->arg_len); |
9946 | 365k | for (i = 0; i < action->arg_len; i++) { |
9947 | 252k | *arg = (*arg << 8) | p[i]; |
9948 | 252k | } |
9949 | 113k | } |
9950 | | |
9951 | 366k | ofpbuf_pull(buf, length); |
9952 | 366k | *raw_len = length; |
9953 | | |
9954 | 366k | return 0; |
9955 | 369k | } |
9956 | | |
9957 | | static const struct ofpact_raw_instance * |
9958 | | ofpact_raw_lookup(enum ofp_version ofp_version, enum ofp_raw_action_type raw) |
9959 | 0 | { |
9960 | 0 | const struct ofpact_raw_instance *inst; |
9961 | |
|
9962 | 0 | HMAP_FOR_EACH_WITH_HASH (inst, encode_node, hash_2words(raw, ofp_version), |
9963 | 0 | ofpact_encode_hmap()) { |
9964 | 0 | if (inst->raw == raw && inst->hdrs.ofp_version == ofp_version) { |
9965 | 0 | return inst; |
9966 | 0 | } |
9967 | 0 | } |
9968 | 0 | OVS_NOT_REACHED(); |
9969 | 0 | } |
9970 | | |
9971 | | static void * |
9972 | | ofpact_put_raw(struct ofpbuf *buf, enum ofp_version ofp_version, |
9973 | | enum ofp_raw_action_type raw, uint64_t arg) |
9974 | 0 | { |
9975 | 0 | const struct ofpact_raw_instance *inst; |
9976 | 0 | struct ofp_action_header *oah; |
9977 | 0 | const struct ofpact_hdrs *hdrs; |
9978 | |
|
9979 | 0 | inst = ofpact_raw_lookup(ofp_version, raw); |
9980 | 0 | hdrs = &inst->hdrs; |
9981 | |
|
9982 | 0 | oah = ofpbuf_put_zeros(buf, inst->min_length); |
9983 | 0 | oah->type = htons(hdrs->vendor ? OFPAT_VENDOR : hdrs->type); |
9984 | 0 | oah->len = htons(inst->min_length); |
9985 | 0 | oah->vendor = htonl(hdrs->vendor); |
9986 | |
|
9987 | 0 | switch (hdrs->vendor) { |
9988 | 0 | case 0: |
9989 | 0 | break; |
9990 | | |
9991 | 0 | case NX_VENDOR_ID: |
9992 | 0 | case ONF_VENDOR_ID: { |
9993 | 0 | struct ext_action_header *nah = (struct ext_action_header *) oah; |
9994 | 0 | nah->subtype = htons(hdrs->type); |
9995 | 0 | break; |
9996 | 0 | } |
9997 | | |
9998 | 0 | default: |
9999 | 0 | OVS_NOT_REACHED(); |
10000 | 0 | } |
10001 | | |
10002 | 0 | if (inst->arg_len) { |
10003 | 0 | uint8_t *p = (uint8_t *) oah + inst->arg_ofs + inst->arg_len; |
10004 | 0 | int i; |
10005 | |
|
10006 | 0 | for (i = 0; i < inst->arg_len; i++) { |
10007 | 0 | *--p = arg; |
10008 | 0 | arg >>= 8; |
10009 | 0 | } |
10010 | 0 | } else { |
10011 | 0 | ovs_assert(!arg); |
10012 | 0 | } |
10013 | |
|
10014 | 0 | return oah; |
10015 | 0 | } |
10016 | | |
10017 | | static void |
10018 | | pad_ofpat(struct ofpbuf *openflow, size_t start_ofs) |
10019 | 0 | { |
10020 | 0 | struct ofp_action_header *oah; |
10021 | |
|
10022 | 0 | ofpbuf_put_zeros(openflow, PAD_SIZE(openflow->size - start_ofs, |
10023 | 0 | OFP_ACTION_ALIGN)); |
10024 | |
|
10025 | 0 | oah = ofpbuf_at_assert(openflow, start_ofs, sizeof *oah); |
10026 | 0 | oah->len = htons(openflow->size - start_ofs); |
10027 | 0 | } |
10028 | | |