2 * Copyright (c) 2008-2017 Nicira, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include "openvswitch/ofp-packet.h"
20 #include "dp-packet.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"
35 VLOG_DEFINE_THIS_MODULE(ofp_packet
);
37 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 5);
40 ofputil_packet_in_format_to_string(enum ofputil_packet_in_format format
)
43 case OFPUTIL_PACKET_IN_STD
:
45 case OFPUTIL_PACKET_IN_NXT
:
46 return "nxt_packet_in";
47 case OFPUTIL_PACKET_IN_NXT2
:
48 return "nxt_packet_in2";
55 ofputil_packet_in_format_from_string(const char *s
)
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
67 ofputil_encode_set_packet_in_format(enum ofp_version ofp_version
,
68 enum ofputil_packet_in_format format
)
70 struct ofpbuf
*msg
= ofpraw_alloc(OFPRAW_NXT_SET_PACKET_IN_FORMAT
,
72 ovs_be32
*spif
= ofpbuf_put_uninit(msg
, sizeof *spif
);
73 *spif
= htonl(format
);
79 ofputil_decode_set_packet_in_format(const struct ofp_header
*oh
,
80 enum ofputil_packet_in_format
*format
)
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
);
88 case OFPUTIL_PACKET_IN_STD
:
89 case OFPUTIL_PACKET_IN_NXT
:
90 case OFPUTIL_PACKET_IN_NXT2
:
95 VLOG_WARN_RL(&rl
, "NXT_SET_PACKET_IN_FORMAT message specified invalid "
96 "packet-in format %"PRIu32
, spif
);
97 return OFPERR_OFPBRC_EPERM
;
101 /* The caller has done basic initialization of '*pin'; the other output
102 * arguments needs to be initialized. */
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
)
112 *buffer_id
= UINT32_MAX
;
114 struct ofpbuf properties
;
115 ofpbuf_use_const(&properties
, oh
, ntohs(oh
->length
));
116 ofpraw_pull_assert(&properties
);
118 while (properties
.size
> 0) {
119 struct ofpbuf payload
;
122 enum ofperr error
= ofpprop_pull(&properties
, &payload
, &type
);
129 pin
->packet
= payload
.msg
;
130 pin
->packet_len
= ofpbuf_msgsize(&payload
);
133 case NXPINT_FULL_LEN
: {
135 error
= ofpprop_parse_u32(&payload
, &u32
);
140 case NXPINT_BUFFER_ID
:
141 error
= ofpprop_parse_u32(&payload
, buffer_id
);
144 case NXPINT_TABLE_ID
:
145 error
= ofpprop_parse_u8(&payload
, &pin
->table_id
);
149 error
= ofpprop_parse_be64(&payload
, &pin
->cookie
);
152 case NXPINT_REASON
: {
154 error
= ofpprop_parse_u8(&payload
, &reason
);
155 pin
->reason
= reason
;
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
;
166 case NXPINT_USERDATA
:
167 pin
->userdata
= payload
.msg
;
168 pin
->userdata_len
= ofpbuf_msgsize(&payload
);
171 case NXPINT_CONTINUATION
:
173 error
= ofpprop_parse_nested(&payload
, continuation
);
178 error
= OFPPROP_UNKNOWN(loose
, "NX_PACKET_IN2", type
);
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
;
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
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().
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).
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.
221 * Returns 0 if successful, otherwise an OpenFlow error code. */
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
)
233 memset(pin
, 0, sizeof *pin
);
234 pin
->cookie
= OVS_BE64_MAX
;
236 ofpbuf_use_const(continuation
, NULL
, 0);
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
)
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
;
253 if (!ofpbuf_try_pull(&b
, 2)) {
254 return OFPERR_OFPBRC_BAD_LEN
;
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
);
262 pin
->cookie
= *cookie
;
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
;
270 opi
= ofpbuf_pull(&b
, offsetof(struct ofp10_packet_in
, data
));
272 pin
->packet
= CONST_CAST(uint8_t *, opi
->data
);
273 pin
->packet_len
= b
.size
;
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
;
286 opi
= ofpbuf_pull(&b
, sizeof *opi
);
288 pin
->packet
= b
.data
;
289 pin
->packet_len
= b
.size
;
291 buffer_id
= ntohl(opi
->buffer_id
);
292 error
= ofputil_port_from_ofp11(opi
->in_port
, &in_port
);
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
;
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,
313 if (!ofpbuf_try_pull(&b
, 2)) {
314 return OFPERR_OFPBRC_BAD_LEN
;
317 pin
->reason
= npi
->reason
;
318 pin
->table_id
= npi
->table_id
;
319 pin
->cookie
= npi
->cookie
;
321 buffer_id
= ntohl(npi
->buffer_id
);
322 total_len
= ntohs(npi
->total_len
);
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
);
338 *total_lenp
= total_len
;
341 *buffer_idp
= buffer_id
;
348 encode_packet_in_reason(enum ofp_packet_in_reason reason
,
349 enum ofp_version version
)
354 case OFPR_INVALID_TTL
:
357 case OFPR_ACTION_SET
:
359 case OFPR_PACKET_OUT
:
360 return version
< OFP14_VERSION
? OFPR_ACTION
: reason
;
362 case OFPR_EXPLICIT_MISS
:
363 return version
< OFP13_VERSION
? OFPR_ACTION
: OFPR_NO_MATCH
;
365 case OFPR_IMPLICIT_MISS
:
366 return OFPR_NO_MATCH
;
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. */
377 ofputil_put_packet_in(const struct ofputil_packet_in
*pin
,
378 enum ofp_version version
, size_t include_bytes
,
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
);
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
);
393 /* Add other properties. */
394 ofpprop_put_u8(msg
, NXPINT_REASON
,
395 encode_packet_in_reason(pin
->reason
, version
));
397 size_t start
= ofpprop_start(msg
, NXPINT_METADATA
);
398 oxm_put_raw(msg
, &pin
->flow_metadata
, version
);
399 ofpprop_end(msg
, start
);
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
)
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
);
414 enum nx_continuation_prop_type
{
415 NXCPT_BRIDGE
= 0x8000,
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. */
428 ofputil_put_packet_in_private(const struct ofputil_packet_in_private
*pin
,
429 enum ofp_version version
, size_t include_bytes
,
432 ofputil_put_packet_in(&pin
->base
, version
, include_bytes
, msg
);
434 size_t continuation_ofs
= ofpprop_start_nested(msg
, NXPINT_CONTINUATION
);
435 size_t inner_ofs
= msg
->size
;
437 if (!uuid_is_zero(&pin
->bridge
)) {
438 ofpprop_put_uuid(msg
, NXCPT_BRIDGE
, &pin
->bridge
);
441 struct ofpbuf pin_stack
;
442 ofpbuf_use_const(&pin_stack
, pin
->stack
, pin
->stack_size
);
444 while (pin_stack
.size
) {
446 uint8_t *val
= nx_stack_pop(&pin_stack
, &len
);
447 ofpprop_put(msg
, NXCPT_STACK
, val
, len
);
451 ofpprop_put_u32(msg
, NXCPT_MIRRORS
, pin
->mirrors
);
454 if (pin
->conntracked
) {
455 ofpprop_put_flag(msg
, NXCPT_CONNTRACKED
);
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
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
,
469 const struct ofpact_unroll_xlate
*unroll
= NULL
;
470 uint8_t table_id
= 0;
473 const struct ofpact
*a
;
474 for (a
= pin
->actions
; ; a
= ofpact_next(a
)) {
475 if (a
== end
|| a
->type
== OFPACT_UNROLL_XLATE
) {
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
;
482 if (cookie
!= unroll
->rule_cookie
) {
483 ofpprop_put_be64(msg
, NXCPT_COOKIE
,
484 unroll
->rule_cookie
);
485 cookie
= unroll
->rule_cookie
;
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
);
497 unroll
= ofpact_get_UNROLL_XLATE(a
);
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
);
509 if (msg
->size
> inner_ofs
) {
510 ofpprop_end(msg
, continuation_ofs
);
512 msg
->size
= continuation_ofs
;
516 static struct ofpbuf
*
517 ofputil_encode_ofp10_packet_in(const struct ofputil_packet_in
*pin
)
519 struct ofp10_packet_in
*opi
;
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
);
533 static struct ofpbuf
*
534 ofputil_encode_nx_packet_in(const struct ofputil_packet_in
*pin
,
535 enum ofp_version version
)
537 struct nx_packet_in
*npi
;
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);
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
);
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
)
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
568 + pin
->action_set_len
569 + 256); /* fudge factor */
570 struct ofpbuf
*msg
= ofpraw_alloc_xid(OFPRAW_NXT_PACKET_IN2
, version
,
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
);
579 ofpmsg_update_length(msg
);
583 static struct ofpbuf
*
584 ofputil_encode_ofp11_packet_in(const struct ofputil_packet_in
*pin
)
586 struct ofp11_packet_in
*opi
;
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
;
603 static struct ofpbuf
*
604 ofputil_encode_ofp12_packet_in(const struct ofputil_packet_in
*pin
,
605 enum ofp_version version
)
607 enum ofpraw raw
= (version
>= OFP13_VERSION
608 ? OFPRAW_OFPT13_PACKET_IN
609 : OFPRAW_OFPT12_PACKET_IN
);
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
);
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
;
622 if (version
>= OFP13_VERSION
) {
623 ovs_be64 cookie
= pin
->cookie
;
624 ofpbuf_put(msg
, &cookie
, sizeof cookie
);
627 oxm_put_match(msg
, &pin
->flow_metadata
, version
);
628 ofpbuf_put_zeros(msg
, 2);
633 /* Converts abstract ofputil_packet_in_private 'pin' into a PACKET_IN message
634 * for 'protocol', using the packet-in format specified by 'format'.
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,
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
)
649 enum ofp_version version
= ofputil_protocol_to_ofp_version(protocol
);
653 case OFPUTIL_PACKET_IN_STD
:
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
);
662 case OFPUTIL_P_OF11_STD
:
663 msg
= ofputil_encode_ofp11_packet_in(&pin
->base
);
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
);
678 case OFPUTIL_PACKET_IN_NXT
:
679 msg
= ofputil_encode_nx_packet_in(&pin
->base
, version
);
682 case OFPUTIL_PACKET_IN_NXT2
:
683 return ofputil_encode_nx_packet_in2(pin
, version
,
684 pin
->base
.packet_len
);
690 ofpbuf_put(msg
, pin
->base
.packet
, pin
->base
.packet_len
);
691 ofpmsg_update_length(msg
);
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. */
699 ofputil_packet_in_reason_to_string(enum ofp_packet_in_reason reason
,
700 char *reasonbuf
, size_t bufsize
)
707 case OFPR_INVALID_TTL
:
708 return "invalid_ttl";
709 case OFPR_ACTION_SET
:
713 case OFPR_PACKET_OUT
:
715 case OFPR_EXPLICIT_MISS
:
716 case OFPR_IMPLICIT_MISS
:
721 snprintf(reasonbuf
, bufsize
, "%d", (int) reason
);
727 ofputil_packet_in_reason_from_string(const char *s
,
728 enum ofp_packet_in_reason
*reason
)
732 for (i
= 0; i
< OFPR_N_REASONS
; i
++) {
733 char reasonbuf
[OFPUTIL_PACKET_IN_REASON_BUFSIZE
];
734 const char *reason_s
;
736 reason_s
= ofputil_packet_in_reason_to_string(i
, reasonbuf
,
738 if (!strcasecmp(s
, reason_s
)) {
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. */
751 ofputil_encode_resume(const struct ofputil_packet_in
*pin
,
752 const struct ofpbuf
*continuation
,
753 enum ofputil_protocol protocol
)
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
,
759 ofputil_put_packet_in(pin
, version
, pin
->packet_len
, msg
);
760 ofpprop_put_nested(msg
, NXPINT_CONTINUATION
, continuation
);
761 ofpmsg_update_length(msg
);
766 parse_stack_prop(const struct ofpbuf
*property
, struct ofpbuf
*stack
)
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",
772 return OFPERR_OFPBPC_BAD_LEN
;
774 nx_stack_push_bottom(stack
, property
->msg
, len
);
779 parse_actions_property(struct ofpbuf
*property
, enum ofp_version version
,
780 struct ofpbuf
*ofpacts
)
782 if (!ofpbuf_try_pull(property
, ROUND_UP(ofpbuf_headersize(property
), 8))) {
783 VLOG_WARN_RL(&rl
, "actions property has bad length %"PRIu32
,
785 return OFPERR_OFPBPC_BAD_LEN
;
788 return ofpacts_pull_openflow_actions(property
, property
->size
,
789 version
, NULL
, NULL
, ofpacts
);
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.
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.
801 * When successful, 'pin' contains some dynamically allocated data. Call
802 * ofputil_packet_in_private_destroy() to free this data. */
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
)
810 memset(pin
, 0, sizeof *pin
);
812 struct ofpbuf continuation
;
814 error
= ofputil_decode_packet_in(oh
, loose
, tun_table
, vl_mff_map
,
815 &pin
->base
, total_len
, buffer_id
,
821 struct ofpbuf actions
, action_set
;
822 ofpbuf_init(&actions
, 0);
823 ofpbuf_init(&action_set
, 0);
825 uint8_t table_id
= 0;
829 ofpbuf_init(&stack
, 0);
831 while (continuation
.size
> 0) {
832 struct ofpbuf payload
;
835 error
= ofpprop_pull(&continuation
, &payload
, &type
);
842 error
= ofpprop_parse_uuid(&payload
, &pin
->bridge
);
846 error
= parse_stack_prop(&payload
, &stack
);
850 error
= ofpprop_parse_u32(&payload
, &pin
->mirrors
);
853 case NXCPT_CONNTRACKED
:
854 pin
->conntracked
= true;
858 error
= ofpprop_parse_u8(&payload
, &table_id
);
862 error
= ofpprop_parse_be64(&payload
, &cookie
);
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
);
874 case NXCPT_ACTION_SET
:
875 error
= parse_actions_property(&payload
, oh
->version
, &action_set
);
879 error
= OFPPROP_UNKNOWN(loose
, "continuation", type
);
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
);
895 ofputil_packet_in_private_destroy(pin
);
902 format_hex_arg(struct ds
*s
, const uint8_t *data
, size_t len
)
904 for (size_t i
= 0; i
< len
; i
++) {
908 ds_put_format(s
, "%02"PRIx8
, data
[i
]);
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
,
920 char reasonbuf
[OFPUTIL_PACKET_IN_REASON_BUFSIZE
];
921 const struct ofputil_packet_in
*public = &pin
->base
;
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
);
929 if (public->cookie
!= OVS_BE64_MAX
) {
930 ds_put_format(s
, " cookie=0x%"PRIx64
, ntohll(public->cookie
));
933 ds_put_format(s
, " total_len=%"PRIuSIZE
" ", total_len
);
935 match_format(&public->flow_metadata
, port_map
, s
, OFP_DEFAULT_PRIORITY
);
937 ds_put_format(s
, " (via %s)",
938 ofputil_packet_in_reason_to_string(public->reason
,
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***)");
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***)");
954 ds_put_char(s
, '\n');
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');
962 if (!uuid_is_zero(&pin
->bridge
)) {
963 ds_put_format(s
, " continuation.bridge="UUID_FMT
"\n",
964 UUID_ARGS(&pin
->bridge
));
967 if (pin
->stack_size
) {
968 ds_put_cstr(s
, " continuation.stack=(top)");
970 struct ofpbuf pin_stack
;
971 ofpbuf_use_const(&pin_stack
, pin
->stack
, pin
->stack_size
);
973 while (pin_stack
.size
) {
975 uint8_t *val
= nx_stack_pop(&pin_stack
, &len
);
976 union mf_subvalue value
;
979 memset(&value
, 0, sizeof value
- len
);
980 memcpy(&value
.u8
[sizeof value
- len
], val
, len
);
981 mf_subvalue_format(&value
, s
);
983 ds_put_cstr(s
, " (bottom)\n");
987 ds_put_format(s
, " continuation.mirrors=0x%"PRIx32
"\n",
991 if (pin
->conntracked
) {
992 ds_put_cstr(s
, " continuation.conntracked=true\n");
995 struct ofpact_format_params fp
= {
996 .port_map
= port_map
,
997 .table_map
= table_map
,
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');
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');
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
);
1020 if (verbosity
> 2) {
1021 ds_put_hex_dump(s
, public->packet
, public->packet_len
, 0, false);
1025 /* Frees data in 'pin' that is dynamically allocated by
1026 * ofputil_decode_packet_in_private().
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. */
1032 ofputil_packet_in_private_destroy(struct ofputil_packet_in_private
*pin
)
1037 free(pin
->action_set
);
1041 /* Converts an OFPT_PACKET_OUT in 'opo' into an abstract ofputil_packet_out in
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.
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.
1051 * Returns 0 if successful, otherwise an OFPERR_* value. */
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
)
1058 struct ofpbuf b
= ofpbuf_const_initializer(oh
, ntohs(oh
->length
));
1059 enum ofpraw raw
= ofpraw_pull_assert(&b
);
1061 ofpbuf_clear(ofpacts
);
1062 match_init_catchall(&po
->flow_metadata
);
1063 if (raw
== OFPRAW_OFPT15_PACKET_OUT
) {
1065 const struct ofp15_packet_out
*opo
= ofpbuf_pull(&b
, sizeof *opo
);
1067 po
->buffer_id
= ntohl(opo
->buffer_id
);
1068 error
= oxm_pull_match_loose(&b
, true, tun_table
, &po
->flow_metadata
);
1073 if (!po
->flow_metadata
.wc
.masks
.in_port
.ofp_port
) {
1074 return OFPERR_OFPBRC_BAD_PORT
;
1077 error
= ofpacts_pull_openflow_actions(&b
, ntohs(opo
->actions_len
),
1078 oh
->version
, NULL
, NULL
,
1083 } else if (raw
== OFPRAW_OFPT11_PACKET_OUT
) {
1086 const struct ofp11_packet_out
*opo
= ofpbuf_pull(&b
, sizeof *opo
);
1088 po
->buffer_id
= ntohl(opo
->buffer_id
);
1089 error
= ofputil_port_from_ofp11(opo
->in_port
, &in_port
);
1093 match_set_packet_type(&po
->flow_metadata
, htonl(PT_ETH
));
1094 match_set_in_port(&po
->flow_metadata
, in_port
);
1096 error
= ofpacts_pull_openflow_actions(&b
, ntohs(opo
->actions_len
),
1097 oh
->version
, NULL
, NULL
,
1102 } else if (raw
== OFPRAW_OFPT10_PACKET_OUT
) {
1104 const struct ofp10_packet_out
*opo
= ofpbuf_pull(&b
, sizeof *opo
);
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
)));
1110 error
= ofpacts_pull_openflow_actions(&b
, ntohs(opo
->actions_len
),
1111 oh
->version
, NULL
, NULL
,
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
;
1130 po
->ofpacts
= ofpacts
->data
;
1131 po
->ofpacts_len
= ofpacts
->size
;
1133 if (po
->buffer_id
== UINT32_MAX
) {
1134 po
->packet
= b
.data
;
1135 po
->packet_len
= b
.size
;
1145 ofputil_encode_packet_out(const struct ofputil_packet_out
*po
,
1146 enum ofputil_protocol protocol
)
1148 enum ofp_version ofp_version
= ofputil_protocol_to_ofp_version(protocol
);
1152 size
= po
->ofpacts_len
;
1153 if (po
->buffer_id
== UINT32_MAX
) {
1154 size
+= po
->packet_len
;
1157 switch (ofp_version
) {
1158 case OFP10_VERSION
: {
1159 struct ofp10_packet_out
*opo
;
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
,
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
);
1179 case OFP14_VERSION
: {
1180 struct ofp11_packet_out
*opo
;
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
,
1188 opo
->buffer_id
= htonl(po
->buffer_id
);
1190 ofputil_port_to_ofp11(po
->flow_metadata
.flow
.in_port
.ofp_port
);
1191 opo
->actions_len
= htons(len
);
1195 case OFP15_VERSION
: {
1196 struct ofp15_packet_out
*opo
;
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
,
1207 opo
->buffer_id
= htonl(po
->buffer_id
);
1208 opo
->actions_len
= htons(len
);
1216 if (po
->buffer_id
== UINT32_MAX
) {
1217 ofpbuf_put(msg
, po
->packet
, po
->packet_len
);
1220 ofpmsg_update_length(msg
);
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
,
1231 ds_put_char(s
, ' ');
1232 match_format(&po
->flow_metadata
, port_map
, s
, OFP_DEFAULT_PRIORITY
);
1234 ds_put_cstr(s
, " actions=");
1235 struct ofpact_format_params fp
= {
1236 .port_map
= port_map
,
1237 .table_map
= table_map
,
1240 ofpacts_format(po
->ofpacts
, po
->ofpacts_len
, &fp
);
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
,
1248 ds_put_char(s
, '\n');
1249 ds_put_cstr(s
, packet
);
1252 if (verbosity
> 2) {
1253 ds_put_hex_dump(s
, po
->packet
, po
->packet_len
, 0, false);
1256 ds_put_format(s
, " buffer=0x%08"PRIx32
, po
->buffer_id
);
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
)
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
;
1276 *usable_protocols
= OFPUTIL_P_ANY
;
1278 *po
= (struct ofputil_packet_out
) {
1279 .buffer_id
= UINT32_MAX
,
1281 match_init_catchall(&po
->flow_metadata
);
1282 match_set_in_port(&po
->flow_metadata
, OFPP_CONTROLLER
);
1284 act_str
= ofp_extract_actions(string
);
1286 while (ofputil_parse_key_value(&string
, &name
, &value
)) {
1288 error
= xasprintf("field %s missing value", name
);
1292 if (!strcmp(name
, "in_port")) {
1294 if (!ofputil_port_from_string(value
, port_map
, &in_port
)) {
1295 error
= xasprintf("%s is not a valid OpenFlow port", value
);
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
) {
1303 "%s is not a valid OpenFlow port for PACKET_OUT",
1307 match_set_in_port(&po
->flow_metadata
, in_port
);
1308 } else if (!strcmp(name
, "packet_type")) {
1310 char *ns_type
= strstr(value
, ",");
1312 ovs_be32 packet_type
;
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
);
1318 error
= xasprintf("%s(%s) can't be interpreted", name
, value
);
1321 } else if (!strcmp(name
, "packet")) {
1322 const char *error_msg
= eth_from_hex(value
, &packet
);
1324 error
= xasprintf("%s: %s", name
, error_msg
);
1328 const struct mf_field
*mf
= mf_from_name(name
);
1330 error
= xasprintf("unknown keyword %s", name
);
1334 error
= ofp_parse_field(mf
, value
, port_map
, &po
->flow_metadata
,
1339 if (!mf_is_pipeline_field(mf
)) {
1340 error
= xasprintf("%s is not a valid pipeline field "
1341 "for PACKET_OUT", name
);
1347 if (!packet
|| !dp_packet_size(packet
)) {
1348 error
= xstrdup("must specify packet");
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
,
1359 error
= ofpacts_parse_actions(act_str
, &pp
);
1360 *usable_protocols
&= action_usable_protocols
;
1365 po
->ofpacts_len
= ofpacts
.size
;
1366 po
->ofpacts
= ofpbuf_steal_data(&ofpacts
);
1368 po
->packet_len
= dp_packet_size(packet
);
1369 po
->packet
= dp_packet_steal_data(packet
);
1371 ofpbuf_uninit(&ofpacts
);
1372 dp_packet_delete(packet
);
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'.
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
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
)
1390 char *string
= xstrdup(str_
);
1393 error
= parse_ofp_packet_out_str__(po
, string
, port_map
, table_map
,
1397 po
->ofpacts_len
= 0;