]> git.proxmox.com Git - mirror_ovs.git/blob - lib/ofp-packet.c
Remove support for OpenFlow 1.6 (draft).
[mirror_ovs.git] / lib / ofp-packet.c
1 /*
2 * Copyright (c) 2008-2017 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 #include "openvswitch/ofp-packet.h"
19 #include <string.h>
20 #include "dp-packet.h"
21 #include "nx-match.h"
22 #include "openvswitch/ofp-actions.h"
23 #include "openvswitch/ofp-errors.h"
24 #include "openvswitch/ofp-msgs.h"
25 #include "openvswitch/ofp-parse.h"
26 #include "openvswitch/ofp-print.h"
27 #include "openvswitch/ofp-port.h"
28 #include "openvswitch/ofp-prop.h"
29 #include "openvswitch/ofp-table.h"
30 #include "openvswitch/ofpbuf.h"
31 #include "openvswitch/vlog.h"
32 #include "util.h"
33 #include "uuid.h"
34
35 VLOG_DEFINE_THIS_MODULE(ofp_packet);
36
37 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
38
39 const char *
40 ofputil_packet_in_format_to_string(enum ofputil_packet_in_format format)
41 {
42 switch (format) {
43 case OFPUTIL_PACKET_IN_STD:
44 return "standard";
45 case OFPUTIL_PACKET_IN_NXT:
46 return "nxt_packet_in";
47 case OFPUTIL_PACKET_IN_NXT2:
48 return "nxt_packet_in2";
49 default:
50 OVS_NOT_REACHED();
51 }
52 }
53
54 int
55 ofputil_packet_in_format_from_string(const char *s)
56 {
57 return (!strcmp(s, "standard") || !strcmp(s, "openflow10")
58 ? OFPUTIL_PACKET_IN_STD
59 : !strcmp(s, "nxt_packet_in") || !strcmp(s, "nxm")
60 ? OFPUTIL_PACKET_IN_NXT
61 : !strcmp(s, "nxt_packet_in2")
62 ? OFPUTIL_PACKET_IN_NXT2
63 : -1);
64 }
65
66 struct ofpbuf *
67 ofputil_encode_set_packet_in_format(enum ofp_version ofp_version,
68 enum ofputil_packet_in_format format)
69 {
70 struct ofpbuf *msg = ofpraw_alloc(OFPRAW_NXT_SET_PACKET_IN_FORMAT,
71 ofp_version, 0);
72 ovs_be32 *spif = ofpbuf_put_uninit(msg, sizeof *spif);
73 *spif = htonl(format);
74
75 return msg;
76 }
77
78 enum ofperr
79 ofputil_decode_set_packet_in_format(const struct ofp_header *oh,
80 enum ofputil_packet_in_format *format)
81 {
82 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
83 ovs_assert(ofpraw_pull_assert(&b) == OFPRAW_NXT_SET_PACKET_IN_FORMAT);
84 ovs_be32 *spifp = ofpbuf_pull(&b, sizeof *spifp);
85 uint32_t spif = ntohl(*spifp);
86
87 switch (spif) {
88 case OFPUTIL_PACKET_IN_STD:
89 case OFPUTIL_PACKET_IN_NXT:
90 case OFPUTIL_PACKET_IN_NXT2:
91 *format = spif;
92 return 0;
93
94 default:
95 VLOG_WARN_RL(&rl, "NXT_SET_PACKET_IN_FORMAT message specified invalid "
96 "packet-in format %"PRIu32, spif);
97 return OFPERR_OFPBRC_EPERM;
98 }
99 }
100 \f
101 /* The caller has done basic initialization of '*pin'; the other output
102 * arguments needs to be initialized. */
103 static enum ofperr
104 decode_nx_packet_in2(const struct ofp_header *oh, bool loose,
105 const struct tun_table *tun_table,
106 const struct vl_mff_map *vl_mff_map,
107 struct ofputil_packet_in *pin,
108 size_t *total_len, uint32_t *buffer_id,
109 struct ofpbuf *continuation)
110 {
111 *total_len = 0;
112 *buffer_id = UINT32_MAX;
113
114 struct ofpbuf properties;
115 ofpbuf_use_const(&properties, oh, ntohs(oh->length));
116 ofpraw_pull_assert(&properties);
117
118 while (properties.size > 0) {
119 struct ofpbuf payload;
120 uint64_t type;
121
122 enum ofperr error = ofpprop_pull(&properties, &payload, &type);
123 if (error) {
124 return error;
125 }
126
127 switch (type) {
128 case NXPINT_PACKET:
129 pin->packet = payload.msg;
130 pin->packet_len = ofpbuf_msgsize(&payload);
131 break;
132
133 case NXPINT_FULL_LEN: {
134 uint32_t u32;
135 error = ofpprop_parse_u32(&payload, &u32);
136 *total_len = u32;
137 break;
138 }
139
140 case NXPINT_BUFFER_ID:
141 error = ofpprop_parse_u32(&payload, buffer_id);
142 break;
143
144 case NXPINT_TABLE_ID:
145 error = ofpprop_parse_u8(&payload, &pin->table_id);
146 break;
147
148 case NXPINT_COOKIE:
149 error = ofpprop_parse_be64(&payload, &pin->cookie);
150 break;
151
152 case NXPINT_REASON: {
153 uint8_t reason;
154 error = ofpprop_parse_u8(&payload, &reason);
155 pin->reason = reason;
156 break;
157 }
158
159 case NXPINT_METADATA:
160 error = oxm_decode_match(payload.msg, ofpbuf_msgsize(&payload),
161 loose, tun_table, vl_mff_map,
162 &pin->flow_metadata);
163 pin->flow_metadata.flow.tunnel.metadata.tab = tun_table;
164 break;
165
166 case NXPINT_USERDATA:
167 pin->userdata = payload.msg;
168 pin->userdata_len = ofpbuf_msgsize(&payload);
169 break;
170
171 case NXPINT_CONTINUATION:
172 if (continuation) {
173 error = ofpprop_parse_nested(&payload, continuation);
174 }
175 break;
176
177 default:
178 error = OFPPROP_UNKNOWN(loose, "NX_PACKET_IN2", type);
179 break;
180 }
181 if (error) {
182 return error;
183 }
184 }
185
186 if (!pin->packet_len) {
187 VLOG_WARN_RL(&rl, "NXT_PACKET_IN2 lacks packet");
188 return OFPERR_OFPBRC_BAD_LEN;
189 } else if (!*total_len) {
190 *total_len = pin->packet_len;
191 } else if (*total_len < pin->packet_len) {
192 VLOG_WARN_RL(&rl, "NXT_PACKET_IN2 claimed full_len < len");
193 return OFPERR_OFPBRC_BAD_LEN;
194 }
195
196 return 0;
197 }
198
199 /* Decodes the packet-in message starting at 'oh' into '*pin'. Populates
200 * 'pin->packet' and 'pin->packet_len' with the part of the packet actually
201 * included in the message. If 'total_lenp' is nonnull, populates
202 * '*total_lenp' with the original length of the packet (which is larger than
203 * 'packet->len' if only part of the packet was included). If 'buffer_idp' is
204 * nonnull, stores the packet's buffer ID in '*buffer_idp' (UINT32_MAX if it
205 * was not buffered).
206 *
207 * Populates 'continuation', if nonnull, with the continuation data from the
208 * packet-in (an empty buffer, if 'oh' did not contain continuation data). The
209 * format of this data is supposed to be opaque to anything other than
210 * ovs-vswitchd, so that in any other process the only reasonable use of this
211 * data is to be copied into an NXT_RESUME message via ofputil_encode_resume().
212 *
213 * This function points 'pin->packet' into 'oh', so the caller should not free
214 * it separately from the original OpenFlow message. This is also true for
215 * 'pin->userdata' (which could also end up NULL if there is no userdata).
216 *
217 * 'vl_mff_map' is an optional parameter that is used to validate the length
218 * of variable length mf_fields in 'match'. If it is not provided, the
219 * default mf_fields with maximum length will be used.
220 *
221 * Returns 0 if successful, otherwise an OpenFlow error code. */
222 enum ofperr
223 ofputil_decode_packet_in(const struct ofp_header *oh, bool loose,
224 const struct tun_table *tun_table,
225 const struct vl_mff_map *vl_mff_map,
226 struct ofputil_packet_in *pin,
227 size_t *total_lenp, uint32_t *buffer_idp,
228 struct ofpbuf *continuation)
229 {
230 uint32_t buffer_id;
231 size_t total_len;
232
233 memset(pin, 0, sizeof *pin);
234 pin->cookie = OVS_BE64_MAX;
235 if (continuation) {
236 ofpbuf_use_const(continuation, NULL, 0);
237 }
238
239 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
240 enum ofpraw raw = ofpraw_pull_assert(&b);
241 if (raw == OFPRAW_OFPT13_PACKET_IN || raw == OFPRAW_OFPT12_PACKET_IN) {
242 const struct ofp12_packet_in *opi = ofpbuf_pull(&b, sizeof *opi);
243 const ovs_be64 *cookie = (raw == OFPRAW_OFPT13_PACKET_IN
244 ? ofpbuf_pull(&b, sizeof *cookie)
245 : NULL);
246 enum ofperr error = oxm_pull_match_loose(&b, false, tun_table,
247 &pin->flow_metadata);
248 pin->flow_metadata.flow.tunnel.metadata.tab = tun_table;
249 if (error) {
250 return error;
251 }
252
253 if (!ofpbuf_try_pull(&b, 2)) {
254 return OFPERR_OFPBRC_BAD_LEN;
255 }
256
257 pin->reason = opi->reason;
258 pin->table_id = opi->table_id;
259 buffer_id = ntohl(opi->buffer_id);
260 total_len = ntohs(opi->total_len);
261 if (cookie) {
262 pin->cookie = *cookie;
263 }
264
265 pin->packet = b.data;
266 pin->packet_len = b.size;
267 } else if (raw == OFPRAW_OFPT10_PACKET_IN) {
268 const struct ofp10_packet_in *opi;
269
270 opi = ofpbuf_pull(&b, offsetof(struct ofp10_packet_in, data));
271
272 pin->packet = CONST_CAST(uint8_t *, opi->data);
273 pin->packet_len = b.size;
274
275 match_init_catchall(&pin->flow_metadata);
276 match_set_in_port(&pin->flow_metadata,
277 u16_to_ofp(ntohs(opi->in_port)));
278 pin->reason = opi->reason;
279 buffer_id = ntohl(opi->buffer_id);
280 total_len = ntohs(opi->total_len);
281 } else if (raw == OFPRAW_OFPT11_PACKET_IN) {
282 const struct ofp11_packet_in *opi;
283 ofp_port_t in_port;
284 enum ofperr error;
285
286 opi = ofpbuf_pull(&b, sizeof *opi);
287
288 pin->packet = b.data;
289 pin->packet_len = b.size;
290
291 buffer_id = ntohl(opi->buffer_id);
292 error = ofputil_port_from_ofp11(opi->in_port, &in_port);
293 if (error) {
294 return error;
295 }
296 match_init_catchall(&pin->flow_metadata);
297 match_set_in_port(&pin->flow_metadata, in_port);
298 total_len = ntohs(opi->total_len);
299 pin->reason = opi->reason;
300 pin->table_id = opi->table_id;
301 } else if (raw == OFPRAW_NXT_PACKET_IN) {
302 const struct nx_packet_in *npi;
303 int error;
304
305 npi = ofpbuf_pull(&b, sizeof *npi);
306 error = nx_pull_match_loose(&b, ntohs(npi->match_len),
307 &pin->flow_metadata, NULL, NULL, false,
308 NULL);
309 if (error) {
310 return error;
311 }
312
313 if (!ofpbuf_try_pull(&b, 2)) {
314 return OFPERR_OFPBRC_BAD_LEN;
315 }
316
317 pin->reason = npi->reason;
318 pin->table_id = npi->table_id;
319 pin->cookie = npi->cookie;
320
321 buffer_id = ntohl(npi->buffer_id);
322 total_len = ntohs(npi->total_len);
323
324 pin->packet = b.data;
325 pin->packet_len = b.size;
326 } else if (raw == OFPRAW_NXT_PACKET_IN2 || raw == OFPRAW_NXT_RESUME) {
327 enum ofperr error = decode_nx_packet_in2(oh, loose, tun_table,
328 vl_mff_map, pin, &total_len,
329 &buffer_id, continuation);
330 if (error) {
331 return error;
332 }
333 } else {
334 OVS_NOT_REACHED();
335 }
336
337 if (total_lenp) {
338 *total_lenp = total_len;
339 }
340 if (buffer_idp) {
341 *buffer_idp = buffer_id;
342 }
343
344 return 0;
345 }
346
347 static int
348 encode_packet_in_reason(enum ofp_packet_in_reason reason,
349 enum ofp_version version)
350 {
351 switch (reason) {
352 case OFPR_NO_MATCH:
353 case OFPR_ACTION:
354 case OFPR_INVALID_TTL:
355 return reason;
356
357 case OFPR_ACTION_SET:
358 case OFPR_GROUP:
359 case OFPR_PACKET_OUT:
360 return version < OFP14_VERSION ? OFPR_ACTION : reason;
361
362 case OFPR_EXPLICIT_MISS:
363 return version < OFP13_VERSION ? OFPR_ACTION : OFPR_NO_MATCH;
364
365 case OFPR_IMPLICIT_MISS:
366 return OFPR_NO_MATCH;
367
368 case OFPR_N_REASONS:
369 default:
370 OVS_NOT_REACHED();
371 }
372 }
373
374 /* Only NXT_PACKET_IN2 (not NXT_RESUME) should include NXCPT_USERDATA, so this
375 * function omits it. The caller can add it itself if desired. */
376 static void
377 ofputil_put_packet_in(const struct ofputil_packet_in *pin,
378 enum ofp_version version, size_t include_bytes,
379 struct ofpbuf *msg)
380 {
381 /* Add packet properties. */
382 ofpprop_put(msg, NXPINT_PACKET, pin->packet, include_bytes);
383 if (include_bytes != pin->packet_len) {
384 ofpprop_put_u32(msg, NXPINT_FULL_LEN, pin->packet_len);
385 }
386
387 /* Add flow properties. */
388 ofpprop_put_u8(msg, NXPINT_TABLE_ID, pin->table_id);
389 if (pin->cookie != OVS_BE64_MAX) {
390 ofpprop_put_be64(msg, NXPINT_COOKIE, pin->cookie);
391 }
392
393 /* Add other properties. */
394 ofpprop_put_u8(msg, NXPINT_REASON,
395 encode_packet_in_reason(pin->reason, version));
396
397 size_t start = ofpprop_start(msg, NXPINT_METADATA);
398 oxm_put_raw(msg, &pin->flow_metadata, version);
399 ofpprop_end(msg, start);
400 }
401
402 static void
403 put_actions_property(struct ofpbuf *msg, uint64_t prop_type,
404 enum ofp_version version,
405 const struct ofpact *actions, size_t actions_len)
406 {
407 if (actions_len) {
408 size_t start = ofpprop_start_nested(msg, prop_type);
409 ofpacts_put_openflow_actions(actions, actions_len, msg, version);
410 ofpprop_end(msg, start);
411 }
412 }
413
414 enum nx_continuation_prop_type {
415 NXCPT_BRIDGE = 0x8000,
416 NXCPT_STACK,
417 NXCPT_MIRRORS,
418 NXCPT_CONNTRACKED,
419 NXCPT_TABLE_ID,
420 NXCPT_COOKIE,
421 NXCPT_ACTIONS,
422 NXCPT_ACTION_SET,
423 };
424
425 /* Only NXT_PACKET_IN2 (not NXT_RESUME) should include NXCPT_USERDATA, so this
426 * function omits it. The caller can add it itself if desired. */
427 static void
428 ofputil_put_packet_in_private(const struct ofputil_packet_in_private *pin,
429 enum ofp_version version, size_t include_bytes,
430 struct ofpbuf *msg)
431 {
432 ofputil_put_packet_in(&pin->base, version, include_bytes, msg);
433
434 size_t continuation_ofs = ofpprop_start_nested(msg, NXPINT_CONTINUATION);
435 size_t inner_ofs = msg->size;
436
437 if (!uuid_is_zero(&pin->bridge)) {
438 ofpprop_put_uuid(msg, NXCPT_BRIDGE, &pin->bridge);
439 }
440
441 struct ofpbuf pin_stack;
442 ofpbuf_use_const(&pin_stack, pin->stack, pin->stack_size);
443
444 while (pin_stack.size) {
445 uint8_t len;
446 uint8_t *val = nx_stack_pop(&pin_stack, &len);
447 ofpprop_put(msg, NXCPT_STACK, val, len);
448 }
449
450 if (pin->mirrors) {
451 ofpprop_put_u32(msg, NXCPT_MIRRORS, pin->mirrors);
452 }
453
454 if (pin->conntracked) {
455 ofpprop_put_flag(msg, NXCPT_CONNTRACKED);
456 }
457
458 if (pin->actions_len) {
459 /* Divide 'pin->actions' into groups that begins with an
460 * unroll_xlate action. For each group, emit a NXCPT_TABLE_ID and
461 * NXCPT_COOKIE property (if either has changed; each is initially
462 * assumed 0), then a NXCPT_ACTIONS property with the grouped
463 * actions.
464 *
465 * The alternative is to make OFPACT_UNROLL_XLATE public. We can
466 * always do that later, since this is a private property. */
467 const struct ofpact *const end = ofpact_end(pin->actions,
468 pin->actions_len);
469 const struct ofpact_unroll_xlate *unroll = NULL;
470 uint8_t table_id = 0;
471 ovs_be64 cookie = 0;
472
473 const struct ofpact *a;
474 for (a = pin->actions; ; a = ofpact_next(a)) {
475 if (a == end || a->type == OFPACT_UNROLL_XLATE) {
476 if (unroll) {
477 if (table_id != unroll->rule_table_id) {
478 ofpprop_put_u8(msg, NXCPT_TABLE_ID,
479 unroll->rule_table_id);
480 table_id = unroll->rule_table_id;
481 }
482 if (cookie != unroll->rule_cookie) {
483 ofpprop_put_be64(msg, NXCPT_COOKIE,
484 unroll->rule_cookie);
485 cookie = unroll->rule_cookie;
486 }
487 }
488
489 const struct ofpact *start
490 = unroll ? ofpact_next(&unroll->ofpact) : pin->actions;
491 put_actions_property(msg, NXCPT_ACTIONS, version,
492 start, (a - start) * sizeof *a);
493
494 if (a == end) {
495 break;
496 }
497 unroll = ofpact_get_UNROLL_XLATE(a);
498 }
499 }
500 }
501
502 if (pin->action_set_len) {
503 size_t start = ofpprop_start_nested(msg, NXCPT_ACTION_SET);
504 ofpacts_put_openflow_actions(pin->action_set,
505 pin->action_set_len, msg, version);
506 ofpprop_end(msg, start);
507 }
508
509 if (msg->size > inner_ofs) {
510 ofpprop_end(msg, continuation_ofs);
511 } else {
512 msg->size = continuation_ofs;
513 }
514 }
515
516 static struct ofpbuf *
517 ofputil_encode_ofp10_packet_in(const struct ofputil_packet_in *pin)
518 {
519 struct ofp10_packet_in *opi;
520 struct ofpbuf *msg;
521
522 msg = ofpraw_alloc_xid(OFPRAW_OFPT10_PACKET_IN, OFP10_VERSION,
523 htonl(0), pin->packet_len);
524 opi = ofpbuf_put_zeros(msg, offsetof(struct ofp10_packet_in, data));
525 opi->total_len = htons(pin->packet_len);
526 opi->in_port = htons(ofp_to_u16(pin->flow_metadata.flow.in_port.ofp_port));
527 opi->reason = encode_packet_in_reason(pin->reason, OFP10_VERSION);
528 opi->buffer_id = htonl(UINT32_MAX);
529
530 return msg;
531 }
532
533 static struct ofpbuf *
534 ofputil_encode_nx_packet_in(const struct ofputil_packet_in *pin,
535 enum ofp_version version)
536 {
537 struct nx_packet_in *npi;
538 struct ofpbuf *msg;
539 size_t match_len;
540
541 /* The final argument is just an estimate of the space required. */
542 msg = ofpraw_alloc_xid(OFPRAW_NXT_PACKET_IN, version,
543 htonl(0), NXM_TYPICAL_LEN + 2 + pin->packet_len);
544 ofpbuf_put_zeros(msg, sizeof *npi);
545 match_len = nx_put_match(msg, &pin->flow_metadata, 0, 0);
546 ofpbuf_put_zeros(msg, 2);
547
548 npi = msg->msg;
549 npi->buffer_id = htonl(UINT32_MAX);
550 npi->total_len = htons(pin->packet_len);
551 npi->reason = encode_packet_in_reason(pin->reason, version);
552 npi->table_id = pin->table_id;
553 npi->cookie = pin->cookie;
554 npi->match_len = htons(match_len);
555
556 return msg;
557 }
558
559 static struct ofpbuf *
560 ofputil_encode_nx_packet_in2(const struct ofputil_packet_in_private *pin,
561 enum ofp_version version, size_t include_bytes)
562 {
563 /* 'extra' is just an estimate of the space required. */
564 size_t extra = (pin->base.packet_len
565 + NXM_TYPICAL_LEN /* flow_metadata */
566 + pin->stack_size * 4
567 + pin->actions_len
568 + pin->action_set_len
569 + 256); /* fudge factor */
570 struct ofpbuf *msg = ofpraw_alloc_xid(OFPRAW_NXT_PACKET_IN2, version,
571 htonl(0), extra);
572
573 ofputil_put_packet_in_private(pin, version, include_bytes, msg);
574 if (pin->base.userdata_len) {
575 ofpprop_put(msg, NXPINT_USERDATA, pin->base.userdata,
576 pin->base.userdata_len);
577 }
578
579 ofpmsg_update_length(msg);
580 return msg;
581 }
582
583 static struct ofpbuf *
584 ofputil_encode_ofp11_packet_in(const struct ofputil_packet_in *pin)
585 {
586 struct ofp11_packet_in *opi;
587 struct ofpbuf *msg;
588
589 msg = ofpraw_alloc_xid(OFPRAW_OFPT11_PACKET_IN, OFP11_VERSION,
590 htonl(0), pin->packet_len);
591 opi = ofpbuf_put_zeros(msg, sizeof *opi);
592 opi->buffer_id = htonl(UINT32_MAX);
593 opi->in_port = ofputil_port_to_ofp11(
594 pin->flow_metadata.flow.in_port.ofp_port);
595 opi->in_phy_port = opi->in_port;
596 opi->total_len = htons(pin->packet_len);
597 opi->reason = encode_packet_in_reason(pin->reason, OFP11_VERSION);
598 opi->table_id = pin->table_id;
599
600 return msg;
601 }
602
603 static struct ofpbuf *
604 ofputil_encode_ofp12_packet_in(const struct ofputil_packet_in *pin,
605 enum ofp_version version)
606 {
607 enum ofpraw raw = (version >= OFP13_VERSION
608 ? OFPRAW_OFPT13_PACKET_IN
609 : OFPRAW_OFPT12_PACKET_IN);
610 struct ofpbuf *msg;
611
612 /* The final argument is just an estimate of the space required. */
613 msg = ofpraw_alloc_xid(raw, version,
614 htonl(0), NXM_TYPICAL_LEN + 2 + pin->packet_len);
615
616 struct ofp12_packet_in *opi = ofpbuf_put_zeros(msg, sizeof *opi);
617 opi->buffer_id = htonl(UINT32_MAX);
618 opi->total_len = htons(pin->packet_len);
619 opi->reason = encode_packet_in_reason(pin->reason, version);
620 opi->table_id = pin->table_id;
621
622 if (version >= OFP13_VERSION) {
623 ovs_be64 cookie = pin->cookie;
624 ofpbuf_put(msg, &cookie, sizeof cookie);
625 }
626
627 oxm_put_match(msg, &pin->flow_metadata, version);
628 ofpbuf_put_zeros(msg, 2);
629
630 return msg;
631 }
632
633 /* Converts abstract ofputil_packet_in_private 'pin' into a PACKET_IN message
634 * for 'protocol', using the packet-in format specified by 'format'.
635 *
636 * This function is really meant only for use by ovs-vswitchd. To any other
637 * code, the "continuation" data, i.e. the data that is in struct
638 * ofputil_packet_in_private but not in struct ofputil_packet_in, is supposed
639 * to be opaque (and it might change from one OVS version to another). Thus,
640 * if any other code wants to encode a packet-in, it should use a non-"private"
641 * version of this function. (Such a version doesn't currently exist because
642 * only ovs-vswitchd currently wants to encode packet-ins. If you need one,
643 * write it...) */
644 struct ofpbuf *
645 ofputil_encode_packet_in_private(const struct ofputil_packet_in_private *pin,
646 enum ofputil_protocol protocol,
647 enum ofputil_packet_in_format format)
648 {
649 enum ofp_version version = ofputil_protocol_to_ofp_version(protocol);
650
651 struct ofpbuf *msg;
652 switch (format) {
653 case OFPUTIL_PACKET_IN_STD:
654 switch (protocol) {
655 case OFPUTIL_P_OF10_STD:
656 case OFPUTIL_P_OF10_STD_TID:
657 case OFPUTIL_P_OF10_NXM:
658 case OFPUTIL_P_OF10_NXM_TID:
659 msg = ofputil_encode_ofp10_packet_in(&pin->base);
660 break;
661
662 case OFPUTIL_P_OF11_STD:
663 msg = ofputil_encode_ofp11_packet_in(&pin->base);
664 break;
665
666 case OFPUTIL_P_OF12_OXM:
667 case OFPUTIL_P_OF13_OXM:
668 case OFPUTIL_P_OF14_OXM:
669 case OFPUTIL_P_OF15_OXM:
670 msg = ofputil_encode_ofp12_packet_in(&pin->base, version);
671 break;
672
673 default:
674 OVS_NOT_REACHED();
675 }
676 break;
677
678 case OFPUTIL_PACKET_IN_NXT:
679 msg = ofputil_encode_nx_packet_in(&pin->base, version);
680 break;
681
682 case OFPUTIL_PACKET_IN_NXT2:
683 return ofputil_encode_nx_packet_in2(pin, version,
684 pin->base.packet_len);
685
686 default:
687 OVS_NOT_REACHED();
688 }
689
690 ofpbuf_put(msg, pin->base.packet, pin->base.packet_len);
691 ofpmsg_update_length(msg);
692 return msg;
693 }
694
695 /* Returns a string form of 'reason'. The return value is either a statically
696 * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
697 * 'bufsize' should be at least OFPUTIL_PACKET_IN_REASON_BUFSIZE. */
698 const char *
699 ofputil_packet_in_reason_to_string(enum ofp_packet_in_reason reason,
700 char *reasonbuf, size_t bufsize)
701 {
702 switch (reason) {
703 case OFPR_NO_MATCH:
704 return "no_match";
705 case OFPR_ACTION:
706 return "action";
707 case OFPR_INVALID_TTL:
708 return "invalid_ttl";
709 case OFPR_ACTION_SET:
710 return "action_set";
711 case OFPR_GROUP:
712 return "group";
713 case OFPR_PACKET_OUT:
714 return "packet_out";
715 case OFPR_EXPLICIT_MISS:
716 case OFPR_IMPLICIT_MISS:
717 return "";
718
719 case OFPR_N_REASONS:
720 default:
721 snprintf(reasonbuf, bufsize, "%d", (int) reason);
722 return reasonbuf;
723 }
724 }
725
726 bool
727 ofputil_packet_in_reason_from_string(const char *s,
728 enum ofp_packet_in_reason *reason)
729 {
730 int i;
731
732 for (i = 0; i < OFPR_N_REASONS; i++) {
733 char reasonbuf[OFPUTIL_PACKET_IN_REASON_BUFSIZE];
734 const char *reason_s;
735
736 reason_s = ofputil_packet_in_reason_to_string(i, reasonbuf,
737 sizeof reasonbuf);
738 if (!strcasecmp(s, reason_s)) {
739 *reason = i;
740 return true;
741 }
742 }
743 return false;
744 }
745
746 /* Returns a newly allocated NXT_RESUME message for 'pin', with the given
747 * 'continuation', for 'protocol'. This message is suitable for resuming the
748 * pipeline traveral of the packet represented by 'pin', if sent to the switch
749 * from which 'pin' was received. */
750 struct ofpbuf *
751 ofputil_encode_resume(const struct ofputil_packet_in *pin,
752 const struct ofpbuf *continuation,
753 enum ofputil_protocol protocol)
754 {
755 enum ofp_version version = ofputil_protocol_to_ofp_version(protocol);
756 size_t extra = pin->packet_len + NXM_TYPICAL_LEN + continuation->size;
757 struct ofpbuf *msg = ofpraw_alloc_xid(OFPRAW_NXT_RESUME, version,
758 0, extra);
759 ofputil_put_packet_in(pin, version, pin->packet_len, msg);
760 ofpprop_put_nested(msg, NXPINT_CONTINUATION, continuation);
761 ofpmsg_update_length(msg);
762 return msg;
763 }
764
765 static enum ofperr
766 parse_stack_prop(const struct ofpbuf *property, struct ofpbuf *stack)
767 {
768 unsigned int len = ofpbuf_msgsize(property);
769 if (len > sizeof(union mf_subvalue)) {
770 VLOG_WARN_RL(&rl, "NXCPT_STACK property has bad length %u",
771 len);
772 return OFPERR_OFPBPC_BAD_LEN;
773 }
774 nx_stack_push_bottom(stack, property->msg, len);
775 return 0;
776 }
777
778 static enum ofperr
779 parse_actions_property(struct ofpbuf *property, enum ofp_version version,
780 struct ofpbuf *ofpacts)
781 {
782 if (!ofpbuf_try_pull(property, ROUND_UP(ofpbuf_headersize(property), 8))) {
783 VLOG_WARN_RL(&rl, "actions property has bad length %"PRIu32,
784 property->size);
785 return OFPERR_OFPBPC_BAD_LEN;
786 }
787
788 return ofpacts_pull_openflow_actions(property, property->size,
789 version, NULL, NULL, ofpacts);
790 }
791
792 /* This is like ofputil_decode_packet_in(), except that it decodes the
793 * continuation data into 'pin'. The format of this data is supposed to be
794 * opaque to any process other than ovs-vswitchd, so this function should not
795 * be used outside ovs-vswitchd.
796 *
797 * 'vl_mff_map' is an optional parameter that is used to validate the length
798 * of variable length mf_fields in 'match'. If it is not provided, the
799 * default mf_fields with maximum length will be used.
800 *
801 * When successful, 'pin' contains some dynamically allocated data. Call
802 * ofputil_packet_in_private_destroy() to free this data. */
803 enum ofperr
804 ofputil_decode_packet_in_private(const struct ofp_header *oh, bool loose,
805 const struct tun_table *tun_table,
806 const struct vl_mff_map *vl_mff_map,
807 struct ofputil_packet_in_private *pin,
808 size_t *total_len, uint32_t *buffer_id)
809 {
810 memset(pin, 0, sizeof *pin);
811
812 struct ofpbuf continuation;
813 enum ofperr error;
814 error = ofputil_decode_packet_in(oh, loose, tun_table, vl_mff_map,
815 &pin->base, total_len, buffer_id,
816 &continuation);
817 if (error) {
818 return error;
819 }
820
821 struct ofpbuf actions, action_set;
822 ofpbuf_init(&actions, 0);
823 ofpbuf_init(&action_set, 0);
824
825 uint8_t table_id = 0;
826 ovs_be64 cookie = 0;
827
828 struct ofpbuf stack;
829 ofpbuf_init(&stack, 0);
830
831 while (continuation.size > 0) {
832 struct ofpbuf payload;
833 uint64_t type;
834
835 error = ofpprop_pull(&continuation, &payload, &type);
836 if (error) {
837 break;
838 }
839
840 switch (type) {
841 case NXCPT_BRIDGE:
842 error = ofpprop_parse_uuid(&payload, &pin->bridge);
843 break;
844
845 case NXCPT_STACK:
846 error = parse_stack_prop(&payload, &stack);
847 break;
848
849 case NXCPT_MIRRORS:
850 error = ofpprop_parse_u32(&payload, &pin->mirrors);
851 break;
852
853 case NXCPT_CONNTRACKED:
854 pin->conntracked = true;
855 break;
856
857 case NXCPT_TABLE_ID:
858 error = ofpprop_parse_u8(&payload, &table_id);
859 break;
860
861 case NXCPT_COOKIE:
862 error = ofpprop_parse_be64(&payload, &cookie);
863 break;
864
865 case NXCPT_ACTIONS: {
866 struct ofpact_unroll_xlate *unroll
867 = ofpact_put_UNROLL_XLATE(&actions);
868 unroll->rule_table_id = table_id;
869 unroll->rule_cookie = cookie;
870 error = parse_actions_property(&payload, oh->version, &actions);
871 break;
872 }
873
874 case NXCPT_ACTION_SET:
875 error = parse_actions_property(&payload, oh->version, &action_set);
876 break;
877
878 default:
879 error = OFPPROP_UNKNOWN(loose, "continuation", type);
880 break;
881 }
882 if (error) {
883 break;
884 }
885 }
886
887 pin->actions_len = actions.size;
888 pin->actions = ofpbuf_steal_data(&actions);
889 pin->action_set_len = action_set.size;
890 pin->action_set = ofpbuf_steal_data(&action_set);
891 pin->stack_size = stack.size;
892 pin->stack = ofpbuf_steal_data(&stack);
893
894 if (error) {
895 ofputil_packet_in_private_destroy(pin);
896 }
897
898 return error;
899 }
900
901 static void
902 format_hex_arg(struct ds *s, const uint8_t *data, size_t len)
903 {
904 for (size_t i = 0; i < len; i++) {
905 if (i) {
906 ds_put_char(s, '.');
907 }
908 ds_put_format(s, "%02"PRIx8, data[i]);
909 }
910 }
911
912 void
913 ofputil_packet_in_private_format(struct ds *s,
914 const struct ofputil_packet_in_private *pin,
915 size_t total_len, uint32_t buffer_id,
916 const struct ofputil_port_map *port_map,
917 const struct ofputil_table_map *table_map,
918 int verbosity)
919 {
920 char reasonbuf[OFPUTIL_PACKET_IN_REASON_BUFSIZE];
921 const struct ofputil_packet_in *public = &pin->base;
922
923 if (public->table_id
924 || ofputil_table_map_get_name(table_map, public->table_id)) {
925 ds_put_format(s, " table_id=");
926 ofputil_format_table(public->table_id, table_map, s);
927 }
928
929 if (public->cookie != OVS_BE64_MAX) {
930 ds_put_format(s, " cookie=0x%"PRIx64, ntohll(public->cookie));
931 }
932
933 ds_put_format(s, " total_len=%"PRIuSIZE" ", total_len);
934
935 match_format(&public->flow_metadata, port_map, s, OFP_DEFAULT_PRIORITY);
936
937 ds_put_format(s, " (via %s)",
938 ofputil_packet_in_reason_to_string(public->reason,
939 reasonbuf,
940 sizeof reasonbuf));
941
942 ds_put_format(s, " data_len=%"PRIuSIZE, public->packet_len);
943 if (buffer_id == UINT32_MAX) {
944 ds_put_format(s, " (unbuffered)");
945 if (total_len != public->packet_len) {
946 ds_put_format(s, " (***total_len != data_len***)");
947 }
948 } else {
949 ds_put_format(s, " buffer=0x%08"PRIx32, buffer_id);
950 if (total_len < public->packet_len) {
951 ds_put_format(s, " (***total_len < data_len***)");
952 }
953 }
954 ds_put_char(s, '\n');
955
956 if (public->userdata_len) {
957 ds_put_cstr(s, " userdata=");
958 format_hex_arg(s, pin->base.userdata, pin->base.userdata_len);
959 ds_put_char(s, '\n');
960 }
961
962 if (!uuid_is_zero(&pin->bridge)) {
963 ds_put_format(s, " continuation.bridge="UUID_FMT"\n",
964 UUID_ARGS(&pin->bridge));
965 }
966
967 if (pin->stack_size) {
968 ds_put_cstr(s, " continuation.stack=(top)");
969
970 struct ofpbuf pin_stack;
971 ofpbuf_use_const(&pin_stack, pin->stack, pin->stack_size);
972
973 while (pin_stack.size) {
974 uint8_t len;
975 uint8_t *val = nx_stack_pop(&pin_stack, &len);
976 union mf_subvalue value;
977
978 ds_put_char(s, ' ');
979 memset(&value, 0, sizeof value - len);
980 memcpy(&value.u8[sizeof value - len], val, len);
981 mf_subvalue_format(&value, s);
982 }
983 ds_put_cstr(s, " (bottom)\n");
984 }
985
986 if (pin->mirrors) {
987 ds_put_format(s, " continuation.mirrors=0x%"PRIx32"\n",
988 pin->mirrors);
989 }
990
991 if (pin->conntracked) {
992 ds_put_cstr(s, " continuation.conntracked=true\n");
993 }
994
995 struct ofpact_format_params fp = {
996 .port_map = port_map,
997 .table_map = table_map,
998 .s = s,
999 };
1000
1001 if (pin->actions_len) {
1002 ds_put_cstr(s, " continuation.actions=");
1003 ofpacts_format(pin->actions, pin->actions_len, &fp);
1004 ds_put_char(s, '\n');
1005 }
1006
1007 if (pin->action_set_len) {
1008 ds_put_cstr(s, " continuation.action_set=");
1009 ofpacts_format(pin->action_set, pin->action_set_len, &fp);
1010 ds_put_char(s, '\n');
1011 }
1012
1013 if (verbosity > 0) {
1014 char *packet = ofp_packet_to_string(
1015 public->packet, public->packet_len,
1016 public->flow_metadata.flow.packet_type);
1017 ds_put_cstr(s, packet);
1018 free(packet);
1019 }
1020 if (verbosity > 2) {
1021 ds_put_hex_dump(s, public->packet, public->packet_len, 0, false);
1022 }
1023 }
1024
1025 /* Frees data in 'pin' that is dynamically allocated by
1026 * ofputil_decode_packet_in_private().
1027 *
1028 * 'pin->base' contains some pointer members that
1029 * ofputil_decode_packet_in_private() doesn't initialize to newly allocated
1030 * data, so this function doesn't free those. */
1031 void
1032 ofputil_packet_in_private_destroy(struct ofputil_packet_in_private *pin)
1033 {
1034 if (pin) {
1035 free(pin->stack);
1036 free(pin->actions);
1037 free(pin->action_set);
1038 }
1039 }
1040
1041 /* Converts an OFPT_PACKET_OUT in 'opo' into an abstract ofputil_packet_out in
1042 * 'po'.
1043 *
1044 * Uses 'ofpacts' to store the abstract OFPACT_* version of the packet out
1045 * message's actions. The caller must initialize 'ofpacts' and retains
1046 * ownership of it. 'po->ofpacts' will point into the 'ofpacts' buffer.
1047 *
1048 * 'po->packet' refers to the packet data in 'oh', so the buffer containing
1049 * 'oh' must not be destroyed while 'po' is being used.
1050 *
1051 * Returns 0 if successful, otherwise an OFPERR_* value. */
1052 enum ofperr
1053 ofputil_decode_packet_out(struct ofputil_packet_out *po,
1054 const struct ofp_header *oh,
1055 const struct tun_table *tun_table,
1056 struct ofpbuf *ofpacts)
1057 {
1058 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
1059 enum ofpraw raw = ofpraw_pull_assert(&b);
1060
1061 ofpbuf_clear(ofpacts);
1062 match_init_catchall(&po->flow_metadata);
1063 if (raw == OFPRAW_OFPT15_PACKET_OUT) {
1064 enum ofperr error;
1065 const struct ofp15_packet_out *opo = ofpbuf_pull(&b, sizeof *opo);
1066
1067 po->buffer_id = ntohl(opo->buffer_id);
1068 error = oxm_pull_match_loose(&b, true, tun_table, &po->flow_metadata);
1069 if (error) {
1070 return error;
1071 }
1072
1073 if (!po->flow_metadata.wc.masks.in_port.ofp_port) {
1074 return OFPERR_OFPBRC_BAD_PORT;
1075 }
1076
1077 error = ofpacts_pull_openflow_actions(&b, ntohs(opo->actions_len),
1078 oh->version, NULL, NULL,
1079 ofpacts);
1080 if (error) {
1081 return error;
1082 }
1083 } else if (raw == OFPRAW_OFPT11_PACKET_OUT) {
1084 enum ofperr error;
1085 ofp_port_t in_port;
1086 const struct ofp11_packet_out *opo = ofpbuf_pull(&b, sizeof *opo);
1087
1088 po->buffer_id = ntohl(opo->buffer_id);
1089 error = ofputil_port_from_ofp11(opo->in_port, &in_port);
1090 if (error) {
1091 return error;
1092 }
1093 match_set_packet_type(&po->flow_metadata, htonl(PT_ETH));
1094 match_set_in_port(&po->flow_metadata, in_port);
1095
1096 error = ofpacts_pull_openflow_actions(&b, ntohs(opo->actions_len),
1097 oh->version, NULL, NULL,
1098 ofpacts);
1099 if (error) {
1100 return error;
1101 }
1102 } else if (raw == OFPRAW_OFPT10_PACKET_OUT) {
1103 enum ofperr error;
1104 const struct ofp10_packet_out *opo = ofpbuf_pull(&b, sizeof *opo);
1105
1106 po->buffer_id = ntohl(opo->buffer_id);
1107 match_set_packet_type(&po->flow_metadata, htonl(PT_ETH));
1108 match_set_in_port(&po->flow_metadata, u16_to_ofp(ntohs(opo->in_port)));
1109
1110 error = ofpacts_pull_openflow_actions(&b, ntohs(opo->actions_len),
1111 oh->version, NULL, NULL,
1112 ofpacts);
1113 if (error) {
1114 return error;
1115 }
1116 } else {
1117 OVS_NOT_REACHED();
1118 }
1119
1120 ofp_port_t in_port = po->flow_metadata.flow.in_port.ofp_port;
1121 if (ofp_to_u16(in_port) >= ofp_to_u16(OFPP_MAX)
1122 && in_port != OFPP_LOCAL
1123 && in_port != OFPP_NONE
1124 && in_port != OFPP_CONTROLLER) {
1125 VLOG_WARN_RL(&rl, "packet-out has bad input port %#"PRIx32,
1126 po->flow_metadata.flow.in_port.ofp_port);
1127 return OFPERR_OFPBRC_BAD_PORT;
1128 }
1129
1130 po->ofpacts = ofpacts->data;
1131 po->ofpacts_len = ofpacts->size;
1132
1133 if (po->buffer_id == UINT32_MAX) {
1134 po->packet = b.data;
1135 po->packet_len = b.size;
1136 } else {
1137 po->packet = NULL;
1138 po->packet_len = 0;
1139 }
1140
1141 return 0;
1142 }
1143
1144 struct ofpbuf *
1145 ofputil_encode_packet_out(const struct ofputil_packet_out *po,
1146 enum ofputil_protocol protocol)
1147 {
1148 enum ofp_version ofp_version = ofputil_protocol_to_ofp_version(protocol);
1149 struct ofpbuf *msg;
1150 size_t size;
1151
1152 size = po->ofpacts_len;
1153 if (po->buffer_id == UINT32_MAX) {
1154 size += po->packet_len;
1155 }
1156
1157 switch (ofp_version) {
1158 case OFP10_VERSION: {
1159 struct ofp10_packet_out *opo;
1160 size_t actions_ofs;
1161
1162 msg = ofpraw_alloc(OFPRAW_OFPT10_PACKET_OUT, OFP10_VERSION, size);
1163 ofpbuf_put_zeros(msg, sizeof *opo);
1164 actions_ofs = msg->size;
1165 ofpacts_put_openflow_actions(po->ofpacts, po->ofpacts_len, msg,
1166 ofp_version);
1167
1168 opo = msg->msg;
1169 opo->buffer_id = htonl(po->buffer_id);
1170 opo->in_port =htons(ofp_to_u16(
1171 po->flow_metadata.flow.in_port.ofp_port));
1172 opo->actions_len = htons(msg->size - actions_ofs);
1173 break;
1174 }
1175
1176 case OFP11_VERSION:
1177 case OFP12_VERSION:
1178 case OFP13_VERSION:
1179 case OFP14_VERSION: {
1180 struct ofp11_packet_out *opo;
1181 size_t len;
1182
1183 msg = ofpraw_alloc(OFPRAW_OFPT11_PACKET_OUT, ofp_version, size);
1184 ofpbuf_put_zeros(msg, sizeof *opo);
1185 len = ofpacts_put_openflow_actions(po->ofpacts, po->ofpacts_len, msg,
1186 ofp_version);
1187 opo = msg->msg;
1188 opo->buffer_id = htonl(po->buffer_id);
1189 opo->in_port =
1190 ofputil_port_to_ofp11(po->flow_metadata.flow.in_port.ofp_port);
1191 opo->actions_len = htons(len);
1192 break;
1193 }
1194
1195 case OFP15_VERSION: {
1196 struct ofp15_packet_out *opo;
1197 size_t len;
1198
1199 /* The final argument is just an estimate of the space required. */
1200 msg = ofpraw_alloc(OFPRAW_OFPT15_PACKET_OUT, ofp_version,
1201 size + NXM_TYPICAL_LEN);
1202 ofpbuf_put_zeros(msg, sizeof *opo);
1203 oxm_put_match(msg, &po->flow_metadata, ofp_version);
1204 len = ofpacts_put_openflow_actions(po->ofpacts, po->ofpacts_len, msg,
1205 ofp_version);
1206 opo = msg->msg;
1207 opo->buffer_id = htonl(po->buffer_id);
1208 opo->actions_len = htons(len);
1209 break;
1210 }
1211
1212 default:
1213 OVS_NOT_REACHED();
1214 }
1215
1216 if (po->buffer_id == UINT32_MAX) {
1217 ofpbuf_put(msg, po->packet, po->packet_len);
1218 }
1219
1220 ofpmsg_update_length(msg);
1221
1222 return msg;
1223 }
1224
1225 void
1226 ofputil_packet_out_format(struct ds *s, const struct ofputil_packet_out *po,
1227 const struct ofputil_port_map *port_map,
1228 const struct ofputil_table_map *table_map,
1229 int verbosity)
1230 {
1231 ds_put_char(s, ' ');
1232 match_format(&po->flow_metadata, port_map, s, OFP_DEFAULT_PRIORITY);
1233
1234 ds_put_cstr(s, " actions=");
1235 struct ofpact_format_params fp = {
1236 .port_map = port_map,
1237 .table_map = table_map,
1238 .s = s,
1239 };
1240 ofpacts_format(po->ofpacts, po->ofpacts_len, &fp);
1241
1242 if (po->buffer_id == UINT32_MAX) {
1243 ds_put_format(s, " data_len=%"PRIuSIZE, po->packet_len);
1244 if (verbosity > 0 && po->packet_len > 0) {
1245 ovs_be32 po_packet_type = po->flow_metadata.flow.packet_type;
1246 char *packet = ofp_packet_to_string(po->packet, po->packet_len,
1247 po_packet_type);
1248 ds_put_char(s, '\n');
1249 ds_put_cstr(s, packet);
1250 free(packet);
1251 }
1252 if (verbosity > 2) {
1253 ds_put_hex_dump(s, po->packet, po->packet_len, 0, false);
1254 }
1255 } else {
1256 ds_put_format(s, " buffer=0x%08"PRIx32, po->buffer_id);
1257 }
1258 }
1259 \f
1260 /* Parse a string representation of a OFPT_PACKET_OUT to '*po'. If successful,
1261 * both 'po->ofpacts' and 'po->packet' must be free()d by the caller. */
1262 static char * OVS_WARN_UNUSED_RESULT
1263 parse_ofp_packet_out_str__(struct ofputil_packet_out *po, char *string,
1264 const struct ofputil_port_map *port_map,
1265 const struct ofputil_table_map *table_map,
1266 enum ofputil_protocol *usable_protocols)
1267 {
1268 enum ofputil_protocol action_usable_protocols;
1269 uint64_t stub[256 / 8];
1270 struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(stub);
1271 struct dp_packet *packet = NULL;
1272 char *act_str = NULL;
1273 char *name, *value;
1274 char *error = NULL;
1275
1276 *usable_protocols = OFPUTIL_P_ANY;
1277
1278 *po = (struct ofputil_packet_out) {
1279 .buffer_id = UINT32_MAX,
1280 };
1281 match_init_catchall(&po->flow_metadata);
1282 match_set_in_port(&po->flow_metadata, OFPP_CONTROLLER);
1283
1284 act_str = ofp_extract_actions(string);
1285
1286 while (ofputil_parse_key_value(&string, &name, &value)) {
1287 if (!*value) {
1288 error = xasprintf("field %s missing value", name);
1289 goto out;
1290 }
1291
1292 if (!strcmp(name, "in_port")) {
1293 ofp_port_t in_port;
1294 if (!ofputil_port_from_string(value, port_map, &in_port)) {
1295 error = xasprintf("%s is not a valid OpenFlow port", value);
1296 goto out;
1297 }
1298 if (ofp_to_u16(in_port) > ofp_to_u16(OFPP_MAX)
1299 && in_port != OFPP_LOCAL
1300 && in_port != OFPP_NONE
1301 && in_port != OFPP_CONTROLLER) {
1302 error = xasprintf(
1303 "%s is not a valid OpenFlow port for PACKET_OUT",
1304 value);
1305 goto out;
1306 }
1307 match_set_in_port(&po->flow_metadata, in_port);
1308 } else if (!strcmp(name, "packet_type")) {
1309 char *ns = value;
1310 char *ns_type = strstr(value, ",");
1311 if (ns_type) {
1312 ovs_be32 packet_type;
1313 *ns_type = '\0';
1314 packet_type = PACKET_TYPE_BE(strtoul(ns, NULL, 0),
1315 strtoul(++ns_type, NULL, 0));
1316 match_set_packet_type(&po->flow_metadata, packet_type);
1317 } else {
1318 error = xasprintf("%s(%s) can't be interpreted", name, value);
1319 goto out;
1320 }
1321 } else if (!strcmp(name, "packet")) {
1322 const char *error_msg = eth_from_hex(value, &packet);
1323 if (error_msg) {
1324 error = xasprintf("%s: %s", name, error_msg);
1325 goto out;
1326 }
1327 } else {
1328 const struct mf_field *mf = mf_from_name(name);
1329 if (!mf) {
1330 error = xasprintf("unknown keyword %s", name);
1331 goto out;
1332 }
1333
1334 error = ofp_parse_field(mf, value, port_map, &po->flow_metadata,
1335 usable_protocols);
1336 if (error) {
1337 goto out;
1338 }
1339 if (!mf_is_pipeline_field(mf)) {
1340 error = xasprintf("%s is not a valid pipeline field "
1341 "for PACKET_OUT", name);
1342 goto out;
1343 }
1344 }
1345 }
1346
1347 if (!packet || !dp_packet_size(packet)) {
1348 error = xstrdup("must specify packet");
1349 goto out;
1350 }
1351
1352 if (act_str) {
1353 struct ofpact_parse_params pp = {
1354 .port_map = port_map,
1355 .table_map = table_map,
1356 .ofpacts = &ofpacts,
1357 .usable_protocols = &action_usable_protocols,
1358 };
1359 error = ofpacts_parse_actions(act_str, &pp);
1360 *usable_protocols &= action_usable_protocols;
1361 if (error) {
1362 goto out;
1363 }
1364 }
1365 po->ofpacts_len = ofpacts.size;
1366 po->ofpacts = ofpbuf_steal_data(&ofpacts);
1367
1368 po->packet_len = dp_packet_size(packet);
1369 po->packet = dp_packet_steal_data(packet);
1370 out:
1371 ofpbuf_uninit(&ofpacts);
1372 dp_packet_delete(packet);
1373 return error;
1374 }
1375
1376 /* Convert 'str_' (as described in the Packet-Out Syntax section of the
1377 * ovs-ofctl man page) into 'po' for sending a OFPT_PACKET_OUT message to a
1378 * switch. Returns the set of usable protocols in '*usable_protocols'.
1379 *
1380 * Returns NULL if successful, otherwise a malloc()'d string describing the
1381 * error. The caller is responsible for freeing the returned string.
1382 * If successful, both 'po->ofpacts' and 'po->packet' must be free()d by
1383 * the caller. */
1384 char * OVS_WARN_UNUSED_RESULT
1385 parse_ofp_packet_out_str(struct ofputil_packet_out *po, const char *str_,
1386 const struct ofputil_port_map *port_map,
1387 const struct ofputil_table_map *table_map,
1388 enum ofputil_protocol *usable_protocols)
1389 {
1390 char *string = xstrdup(str_);
1391 char *error;
1392
1393 error = parse_ofp_packet_out_str__(po, string, port_map, table_map,
1394 usable_protocols);
1395 if (error) {
1396 po->ofpacts = NULL;
1397 po->ofpacts_len = 0;
1398 }
1399
1400 free(string);
1401 return error;
1402 }