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-connection.h"
19 #include "byte-order.h"
20 #include "openflow/nicira-ext.h"
21 #include "openvswitch/ofp-errors.h"
22 #include "openvswitch/ofp-monitor.h"
23 #include "openvswitch/ofp-msgs.h"
24 #include "openvswitch/ofp-packet.h"
25 #include "openvswitch/ofp-prop.h"
26 #include "openvswitch/ofp-table.h"
27 #include "openvswitch/ofpbuf.h"
28 #include "openvswitch/type-props.h"
29 #include "openvswitch/vlog.h"
32 VLOG_DEFINE_THIS_MODULE(ofp_connection
);
34 /* ofputil_role_request */
36 /* Decodes the OpenFlow "role request" or "role reply" message in '*oh' into
37 * an abstract form in '*rr'. Returns 0 if successful, otherwise an
40 ofputil_decode_role_message(const struct ofp_header
*oh
,
41 struct ofputil_role_request
*rr
)
43 struct ofpbuf b
= ofpbuf_const_initializer(oh
, ntohs(oh
->length
));
44 enum ofpraw raw
= ofpraw_pull_assert(&b
);
45 if (raw
== OFPRAW_OFPT12_ROLE_REQUEST
||
46 raw
== OFPRAW_OFPT12_ROLE_REPLY
) {
47 const struct ofp12_role_request
*orr
= b
.msg
;
49 if (orr
->role
!= htonl(OFPCR12_ROLE_NOCHANGE
) &&
50 orr
->role
!= htonl(OFPCR12_ROLE_EQUAL
) &&
51 orr
->role
!= htonl(OFPCR12_ROLE_PRIMARY
) &&
52 orr
->role
!= htonl(OFPCR12_ROLE_SECONDARY
)) {
53 return OFPERR_OFPRRFC_BAD_ROLE
;
56 rr
->role
= ntohl(orr
->role
);
57 if (raw
== OFPRAW_OFPT12_ROLE_REQUEST
58 ? orr
->role
== htonl(OFPCR12_ROLE_NOCHANGE
)
59 : orr
->generation_id
== OVS_BE64_MAX
) {
60 rr
->have_generation_id
= false;
61 rr
->generation_id
= 0;
63 rr
->have_generation_id
= true;
64 rr
->generation_id
= ntohll(orr
->generation_id
);
66 } else if (raw
== OFPRAW_NXT_ROLE_REQUEST
||
67 raw
== OFPRAW_NXT_ROLE_REPLY
) {
68 const struct nx_role_request
*nrr
= b
.msg
;
70 BUILD_ASSERT(NX_ROLE_OTHER
+ 1 == OFPCR12_ROLE_EQUAL
);
71 BUILD_ASSERT(NX_ROLE_PRIMARY
+ 1 == OFPCR12_ROLE_PRIMARY
);
72 BUILD_ASSERT(NX_ROLE_SECONDARY
+ 1 == OFPCR12_ROLE_SECONDARY
);
74 if (nrr
->role
!= htonl(NX_ROLE_OTHER
) &&
75 nrr
->role
!= htonl(NX_ROLE_PRIMARY
) &&
76 nrr
->role
!= htonl(NX_ROLE_SECONDARY
)) {
77 return OFPERR_OFPRRFC_BAD_ROLE
;
80 rr
->role
= ntohl(nrr
->role
) + 1;
81 rr
->have_generation_id
= false;
82 rr
->generation_id
= 0;
91 format_role_generic(struct ds
*string
, enum ofp12_controller_role role
,
92 uint64_t generation_id
)
94 ds_put_cstr(string
, " role=");
97 case OFPCR12_ROLE_NOCHANGE
:
98 ds_put_cstr(string
, "nochange");
100 case OFPCR12_ROLE_EQUAL
:
101 ds_put_cstr(string
, "equal"); /* OF 1.2 wording */
103 case OFPCR12_ROLE_PRIMARY
:
104 ds_put_cstr(string
, "primary");
106 case OFPCR12_ROLE_SECONDARY
:
107 ds_put_cstr(string
, "secondary");
113 if (generation_id
!= UINT64_MAX
) {
114 ds_put_format(string
, " generation_id=%"PRIu64
, generation_id
);
119 ofputil_format_role_message(struct ds
*string
,
120 const struct ofputil_role_request
*rr
)
122 format_role_generic(string
, rr
->role
, (rr
->have_generation_id
127 /* Returns an encoded form of a role reply suitable for the "request" in a
128 * buffer owned by the caller. */
130 ofputil_encode_role_reply(const struct ofp_header
*request
,
131 const struct ofputil_role_request
*rr
)
136 raw
= ofpraw_decode_assert(request
);
137 if (raw
== OFPRAW_OFPT12_ROLE_REQUEST
) {
138 struct ofp12_role_request
*orr
;
140 buf
= ofpraw_alloc_reply(OFPRAW_OFPT12_ROLE_REPLY
, request
, 0);
141 orr
= ofpbuf_put_zeros(buf
, sizeof *orr
);
143 orr
->role
= htonl(rr
->role
);
144 orr
->generation_id
= htonll(rr
->have_generation_id
147 } else if (raw
== OFPRAW_NXT_ROLE_REQUEST
) {
148 struct nx_role_request
*nrr
;
150 BUILD_ASSERT(NX_ROLE_OTHER
== OFPCR12_ROLE_EQUAL
- 1);
151 BUILD_ASSERT(NX_ROLE_PRIMARY
== OFPCR12_ROLE_PRIMARY
- 1);
152 BUILD_ASSERT(NX_ROLE_SECONDARY
== OFPCR12_ROLE_SECONDARY
- 1);
154 buf
= ofpraw_alloc_reply(OFPRAW_NXT_ROLE_REPLY
, request
, 0);
155 nrr
= ofpbuf_put_zeros(buf
, sizeof *nrr
);
156 nrr
->role
= htonl(rr
->role
- 1);
164 /* Encodes "role status" message 'status' for sending in the given
165 * 'protocol'. Returns the role status message, if 'protocol' supports them,
166 * otherwise a null pointer. */
168 ofputil_encode_role_status(const struct ofputil_role_status
*status
,
169 enum ofputil_protocol protocol
)
171 enum ofp_version version
= ofputil_protocol_to_ofp_version(protocol
);
172 if (version
< OFP13_VERSION
) {
176 enum ofpraw raw
= (version
>= OFP14_VERSION
177 ? OFPRAW_OFPT14_ROLE_STATUS
178 : OFPRAW_ONFT13_ROLE_STATUS
);
179 struct ofpbuf
*buf
= ofpraw_alloc_xid(raw
, version
, htonl(0), 0);
180 struct ofp14_role_status
*rstatus
= ofpbuf_put_zeros(buf
, sizeof *rstatus
);
181 rstatus
->role
= htonl(status
->role
);
182 rstatus
->reason
= status
->reason
;
183 rstatus
->generation_id
= htonll(status
->generation_id
);
189 ofputil_decode_role_status(const struct ofp_header
*oh
,
190 struct ofputil_role_status
*rs
)
192 struct ofpbuf b
= ofpbuf_const_initializer(oh
, ntohs(oh
->length
));
193 enum ofpraw raw
= ofpraw_pull_assert(&b
);
194 ovs_assert(raw
== OFPRAW_OFPT14_ROLE_STATUS
||
195 raw
== OFPRAW_ONFT13_ROLE_STATUS
);
197 const struct ofp14_role_status
*r
= b
.msg
;
198 if (r
->role
!= htonl(OFPCR12_ROLE_NOCHANGE
) &&
199 r
->role
!= htonl(OFPCR12_ROLE_EQUAL
) &&
200 r
->role
!= htonl(OFPCR12_ROLE_PRIMARY
) &&
201 r
->role
!= htonl(OFPCR12_ROLE_SECONDARY
)) {
202 return OFPERR_OFPRRFC_BAD_ROLE
;
205 rs
->role
= ntohl(r
->role
);
206 rs
->generation_id
= ntohll(r
->generation_id
);
207 rs
->reason
= r
->reason
;
213 ofputil_format_role_status(struct ds
*string
,
214 const struct ofputil_role_status
*rs
)
216 format_role_generic(string
, rs
->role
, rs
->generation_id
);
218 ds_put_cstr(string
, " reason=");
220 switch (rs
->reason
) {
221 case OFPCRR_PRIMARY_REQUEST
:
222 ds_put_cstr(string
, "primary_request");
225 ds_put_cstr(string
, "configuration_changed");
227 case OFPCRR_EXPERIMENTER
:
228 ds_put_cstr(string
, "experimenter_data_changed");
230 case OFPCRR_N_REASONS
:
232 ds_put_cstr(string
, "(unknown)");
238 ofputil_async_msg_type_to_string(enum ofputil_async_msg_type type
)
241 case OAM_PACKET_IN
: return "PACKET_IN";
242 case OAM_PORT_STATUS
: return "PORT_STATUS";
243 case OAM_FLOW_REMOVED
: return "FLOW_REMOVED";
244 case OAM_ROLE_STATUS
: return "ROLE_STATUS";
245 case OAM_TABLE_STATUS
: return "TABLE_STATUS";
246 case OAM_REQUESTFORWARD
: return "REQUESTFORWARD";
254 struct ofp14_async_prop
{
256 enum ofputil_async_msg_type oam
;
258 uint32_t allowed10
, allowed14
;
261 #define AP_PAIR(SECONDARY_PROP_TYPE, OAM, A10, A14) \
262 { SECONDARY_PROP_TYPE, OAM, false, A10, (A14) ? (A14) : (A10) }, \
263 { (SECONDARY_PROP_TYPE + 1), OAM, true, A10, (A14) ? (A14) : (A10) }
265 static const struct ofp14_async_prop async_props
[] = {
266 AP_PAIR( 0, OAM_PACKET_IN
, OFPR10_BITS
, OFPR14_BITS
),
267 AP_PAIR( 2, OAM_PORT_STATUS
, (1 << OFPPR_N_REASONS
) - 1, 0),
268 AP_PAIR( 4, OAM_FLOW_REMOVED
, (1 << OVS_OFPRR_NONE
) - 1, 0),
269 AP_PAIR( 6, OAM_ROLE_STATUS
, (1 << OFPCRR_N_REASONS
) - 1, 0),
270 AP_PAIR( 8, OAM_TABLE_STATUS
, OFPTR_BITS
, 0),
271 AP_PAIR(10, OAM_REQUESTFORWARD
, (1 << OFPRFR_N_REASONS
) - 1, 0),
274 #define FOR_EACH_ASYNC_PROP(VAR) \
275 for (const struct ofp14_async_prop *VAR = async_props; \
276 VAR < &async_props[ARRAY_SIZE(async_props)]; VAR++)
278 static const struct ofp14_async_prop
*
279 get_ofp14_async_config_prop_by_prop_type(uint64_t prop_type
)
281 FOR_EACH_ASYNC_PROP (ap
) {
282 if (prop_type
== ap
->prop_type
) {
289 static const struct ofp14_async_prop
*
290 get_ofp14_async_config_prop_by_oam(enum ofputil_async_msg_type oam
,
293 FOR_EACH_ASYNC_PROP (ap
) {
294 if (ap
->oam
== oam
&& ap
->primary
== primary
) {
302 ofp14_async_prop_allowed(const struct ofp14_async_prop
*prop
,
303 enum ofp_version version
)
305 return version
>= OFP14_VERSION
? prop
->allowed14
: prop
->allowed10
;
309 encode_async_mask(const struct ofputil_async_cfg
*src
,
310 const struct ofp14_async_prop
*ap
,
311 enum ofp_version version
)
313 uint32_t mask
= (ap
->primary
314 ? src
->primary
[ap
->oam
]
315 : src
->secondary
[ap
->oam
]);
316 return htonl(mask
& ofp14_async_prop_allowed(ap
, version
));
320 decode_async_mask(ovs_be32 src
,
321 const struct ofp14_async_prop
*ap
, enum ofp_version version
,
322 bool loose
, struct ofputil_async_cfg
*dst
)
324 uint32_t mask
= ntohl(src
);
325 uint32_t allowed
= ofp14_async_prop_allowed(ap
, version
);
326 if (mask
& ~allowed
) {
327 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 5);
328 OFPPROP_LOG(&rl
, loose
,
329 "bad value %#x for %s (allowed mask %#x)",
330 mask
, ofputil_async_msg_type_to_string(ap
->oam
),
334 return OFPERR_OFPACFC_INVALID
;
338 if (ap
->oam
== OAM_PACKET_IN
) {
339 if (mask
& (1u << OFPR_NO_MATCH
)) {
340 mask
|= 1u << OFPR_EXPLICIT_MISS
;
341 if (version
< OFP13_VERSION
) {
342 mask
|= 1u << OFPR_IMPLICIT_MISS
;
347 uint32_t *array
= ap
->primary
? dst
->primary
: dst
->secondary
;
348 array
[ap
->oam
] = mask
;
353 parse_async_tlv(const struct ofpbuf
*property
,
354 const struct ofp14_async_prop
*ap
,
355 struct ofputil_async_cfg
*ac
,
356 enum ofp_version version
, bool loose
)
361 error
= ofpprop_parse_be32(property
, &mask
);
366 if (ofpprop_is_experimenter(ap
->prop_type
)) {
367 /* For experimenter properties, whether a property is for the primary or
368 * secondary role is indicated by both 'type' and 'exp_type' in struct
369 * ofp_prop_experimenter. Check that these are consistent. */
370 const struct ofp_prop_experimenter
*ope
= property
->data
;
371 bool should_be_primary
= ope
->type
== htons(0xffff);
372 if (should_be_primary
!= ap
->primary
) {
373 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 5);
374 VLOG_WARN_RL(&rl
, "async property type %#"PRIx16
" "
375 "indicates %s role but exp_type %"PRIu32
" indicates "
378 should_be_primary
? "primary" : "secondary",
379 ntohl(ope
->exp_type
),
380 ap
->primary
? "primary" : "secondary");
381 return OFPERR_OFPBPC_BAD_EXP_TYPE
;
385 return decode_async_mask(mask
, ap
, version
, loose
, ac
);
389 decode_legacy_async_masks(const ovs_be32 masks
[2],
390 enum ofputil_async_msg_type oam
,
391 enum ofp_version version
,
392 struct ofputil_async_cfg
*dst
)
394 for (int i
= 0; i
< 2; i
++) {
395 bool primary
= i
== 0;
396 const struct ofp14_async_prop
*ap
397 = get_ofp14_async_config_prop_by_oam(oam
, primary
);
398 decode_async_mask(masks
[i
], ap
, version
, true, dst
);
402 /* Decodes the OpenFlow "set async config" request and "get async config
403 * reply" message in '*oh' into an abstract form in 'ac'.
405 * Some versions of the "set async config" request change only some of the
406 * settings and leave the others alone. This function uses 'basis' as the
407 * initial state for decoding these. Other versions of the request change all
408 * the settings; this function ignores 'basis' when decoding these.
410 * If 'loose' is true, this function ignores properties and values that it does
411 * not understand, as a controller would want to do when interpreting
412 * capabilities provided by a switch. If 'loose' is false, this function
413 * treats unknown properties and values as an error, as a switch would want to
414 * do when interpreting a configuration request made by a controller.
416 * Returns 0 if successful, otherwise an OFPERR_* value.
418 * Returns error code OFPERR_OFPACFC_INVALID if the value of mask is not in
419 * the valid range of mask.
421 * Returns error code OFPERR_OFPACFC_UNSUPPORTED if the configuration is not
424 ofputil_decode_set_async_config(const struct ofp_header
*oh
, bool loose
,
425 const struct ofputil_async_cfg
*basis
,
426 struct ofputil_async_cfg
*ac
)
428 struct ofpbuf b
= ofpbuf_const_initializer(oh
, ntohs(oh
->length
));
429 enum ofpraw raw
= ofpraw_pull_assert(&b
);
431 if (raw
== OFPRAW_OFPT13_SET_ASYNC
||
432 raw
== OFPRAW_NXT_SET_ASYNC_CONFIG
||
433 raw
== OFPRAW_OFPT13_GET_ASYNC_REPLY
) {
434 const struct nx_async_config
*msg
= ofpmsg_body(oh
);
436 *ac
= OFPUTIL_ASYNC_CFG_INIT
;
437 decode_legacy_async_masks(msg
->packet_in_mask
, OAM_PACKET_IN
,
439 decode_legacy_async_masks(msg
->port_status_mask
, OAM_PORT_STATUS
,
441 decode_legacy_async_masks(msg
->flow_removed_mask
, OAM_FLOW_REMOVED
,
443 } else if (raw
== OFPRAW_OFPT14_SET_ASYNC
||
444 raw
== OFPRAW_OFPT14_GET_ASYNC_REPLY
||
445 raw
== OFPRAW_NXT_SET_ASYNC_CONFIG2
) {
448 struct ofpbuf property
;
452 error
= ofpprop_pull__(&b
, &property
, 8, 0xfffe, &type
);
457 const struct ofp14_async_prop
*ap
458 = get_ofp14_async_config_prop_by_prop_type(type
);
460 ? parse_async_tlv(&property
, ap
, ac
, oh
->version
, loose
)
461 : OFPPROP_UNKNOWN(loose
, "async config", type
));
463 /* Most messages use OFPBPC_BAD_TYPE but async has its own (who
464 * knows why, it's OpenFlow. */
465 if (error
== OFPERR_OFPBPC_BAD_TYPE
) {
466 error
= OFPERR_OFPACFC_UNSUPPORTED
;
472 return OFPERR_OFPBRC_BAD_VERSION
;
478 encode_legacy_async_masks(const struct ofputil_async_cfg
*ac
,
479 enum ofputil_async_msg_type oam
,
480 enum ofp_version version
,
483 for (int i
= 0; i
< 2; i
++) {
484 bool primary
= i
== 0;
485 const struct ofp14_async_prop
*ap
486 = get_ofp14_async_config_prop_by_oam(oam
, primary
);
487 masks
[i
] = encode_async_mask(ac
, ap
, version
);
492 ofputil_put_async_config__(const struct ofputil_async_cfg
*ac
,
493 struct ofpbuf
*buf
, bool tlv
,
494 enum ofp_version version
, uint32_t oams
)
497 struct nx_async_config
*msg
= ofpbuf_put_zeros(buf
, sizeof *msg
);
498 encode_legacy_async_masks(ac
, OAM_PACKET_IN
, version
,
499 msg
->packet_in_mask
);
500 encode_legacy_async_masks(ac
, OAM_PORT_STATUS
, version
,
501 msg
->port_status_mask
);
502 encode_legacy_async_masks(ac
, OAM_FLOW_REMOVED
, version
,
503 msg
->flow_removed_mask
);
505 FOR_EACH_ASYNC_PROP (ap
) {
506 if (oams
& (1u << ap
->oam
)) {
507 size_t ofs
= buf
->size
;
508 ofpprop_put_be32(buf
, ap
->prop_type
,
509 encode_async_mask(ac
, ap
, version
));
511 /* For experimenter properties, we need to use type 0xfffe for
512 * primary and 0xffff for secondaries. */
513 if (ofpprop_is_experimenter(ap
->prop_type
)) {
514 struct ofp_prop_experimenter
*ope
515 = ofpbuf_at_assert(buf
, ofs
, sizeof *ope
);
516 ope
->type
= ap
->primary
? htons(0xffff) : htons(0xfffe);
523 /* Encodes and returns a reply to the OFPT_GET_ASYNC_REQUEST in 'oh' that
524 * states that the asynchronous message configuration is 'ac'. */
526 ofputil_encode_get_async_reply(const struct ofp_header
*oh
,
527 const struct ofputil_async_cfg
*ac
)
529 enum ofpraw raw
= (oh
->version
< OFP14_VERSION
530 ? OFPRAW_OFPT13_GET_ASYNC_REPLY
531 : OFPRAW_OFPT14_GET_ASYNC_REPLY
);
532 struct ofpbuf
*reply
= ofpraw_alloc_reply(raw
, oh
, 0);
533 ofputil_put_async_config__(ac
, reply
,
534 raw
== OFPRAW_OFPT14_GET_ASYNC_REPLY
,
535 oh
->version
, UINT32_MAX
);
539 /* Encodes and returns a message, in a format appropriate for OpenFlow version
540 * 'ofp_version', that sets the asynchronous message configuration to 'ac'.
542 * Specify 'oams' as a bitmap of OAM_* that indicate the asynchronous messages
543 * to configure. OF1.0 through OF1.3 can't natively configure a subset of
544 * messages, so more messages than requested may be configured. OF1.0 through
545 * OF1.3 also can't configure OVS extension OAM_* values, so if 'oam' includes
546 * any extensions then this function encodes an Open vSwitch extension message
547 * that does support configuring OVS extension OAM_*. */
549 ofputil_encode_set_async_config(const struct ofputil_async_cfg
*ac
,
550 uint32_t oams
, enum ofp_version ofp_version
)
552 enum ofpraw raw
= (ofp_version
>= OFP14_VERSION
? OFPRAW_OFPT14_SET_ASYNC
553 : oams
& OAM_EXTENSIONS
? OFPRAW_NXT_SET_ASYNC_CONFIG2
554 : ofp_version
>= OFP13_VERSION
? OFPRAW_OFPT13_SET_ASYNC
555 : OFPRAW_NXT_SET_ASYNC_CONFIG
);
556 struct ofpbuf
*request
= ofpraw_alloc(raw
, ofp_version
, 0);
557 ofputil_put_async_config__(ac
, request
,
558 (raw
== OFPRAW_OFPT14_SET_ASYNC
||
559 raw
== OFPRAW_NXT_SET_ASYNC_CONFIG2
),
564 /* Returns a string form of 'reason'. The return value is either a statically
565 * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
566 * 'bufsize' should be at least OFP_PORT_REASON_BUFSIZE. */
567 #define OFP_PORT_REASON_BUFSIZE (INT_STRLEN(int) + 1)
569 ofp_port_reason_to_string(enum ofp_port_reason reason
,
570 char *reasonbuf
, size_t bufsize
)
582 case OFPPR_N_REASONS
:
584 snprintf(reasonbuf
, bufsize
, "%d", (int) reason
);
589 /* Returns a string form of 'reason'. The return value is either a statically
590 * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
591 * 'bufsize' should be at least OFP_ASYNC_CONFIG_REASON_BUFSIZE. */
593 ofp_role_reason_to_string(enum ofp14_controller_role_reason reason
,
594 char *reasonbuf
, size_t bufsize
)
597 case OFPCRR_PRIMARY_REQUEST
:
598 return "primary_request";
601 return "configuration_changed";
603 case OFPCRR_EXPERIMENTER
:
604 return "experimenter_data_changed";
606 case OFPCRR_N_REASONS
:
608 snprintf(reasonbuf
, bufsize
, "%d", (int) reason
);
613 /* Returns a string form of 'reason'. The return value is either a statically
614 * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
615 * 'bufsize' should be at least OFP_ASYNC_CONFIG_REASON_BUFSIZE. */
617 ofp_requestforward_reason_to_string(enum ofp14_requestforward_reason reason
,
618 char *reasonbuf
, size_t bufsize
)
621 case OFPRFR_GROUP_MOD
:
622 return "group_mod_request";
624 case OFPRFR_METER_MOD
:
625 return "meter_mod_request";
627 case OFPRFR_N_REASONS
:
629 snprintf(reasonbuf
, bufsize
, "%d", (int) reason
);
635 ofp_async_config_reason_to_string(uint32_t reason
,
636 enum ofputil_async_msg_type type
,
637 char *reasonbuf
, size_t bufsize
)
641 return ofputil_packet_in_reason_to_string(reason
, reasonbuf
, bufsize
);
643 case OAM_PORT_STATUS
:
644 return ofp_port_reason_to_string(reason
, reasonbuf
, bufsize
);
646 case OAM_FLOW_REMOVED
:
647 return ofp_flow_removed_reason_to_string(reason
, reasonbuf
, bufsize
);
649 case OAM_ROLE_STATUS
:
650 return ofp_role_reason_to_string(reason
, reasonbuf
, bufsize
);
652 case OAM_TABLE_STATUS
:
653 return ofp_table_reason_to_string(reason
, reasonbuf
, bufsize
);
655 case OAM_REQUESTFORWARD
:
656 return ofp_requestforward_reason_to_string(reason
, reasonbuf
, bufsize
);
660 return "Unknown asynchronous configuration message type";
665 ofputil_format_set_async_config(struct ds
*string
,
666 const struct ofputil_async_cfg
*ac
)
668 for (int i
= 0; i
< 2; i
++) {
669 ds_put_format(string
, "\n %s:\n", i
== 0 ? "primary" : "secondary");
670 for (uint32_t type
= 0; type
< OAM_N_TYPES
; type
++) {
671 ds_put_format(string
, "%16s:",
672 ofputil_async_msg_type_to_string(type
));
674 uint32_t role
= i
== 0 ? ac
->primary
[type
] : ac
->secondary
[type
];
675 for (int j
= 0; j
< 32; j
++) {
676 if (role
& (1u << j
)) {
677 char reasonbuf
[INT_STRLEN(int) + 1];
680 reason
= ofp_async_config_reason_to_string(
681 j
, type
, reasonbuf
, sizeof reasonbuf
);
683 ds_put_format(string
, " %s", reason
);
688 ds_put_cstr(string
, " (off)");
690 ds_put_char(string
, '\n');
695 struct ofputil_async_cfg
696 ofputil_async_cfg_default(enum ofp_version version
)
698 /* We enable all of the OF1.4 reasons regardless of 'version' because the
699 * reasons added in OF1.4 just are just refinements of the OFPR_ACTION
700 * introduced in OF1.0, breaking it into more specific categories. When we
701 * encode these for earlier OpenFlow versions, we translate them into
703 uint32_t pin
= OFPR14_BITS
& ~(1u << OFPR_INVALID_TTL
);
704 pin
|= 1u << OFPR_EXPLICIT_MISS
;
705 if (version
<= OFP12_VERSION
) {
706 pin
|= 1u << OFPR_IMPLICIT_MISS
;
709 struct ofputil_async_cfg oac
= {
710 .primary
[OAM_PACKET_IN
] = pin
,
711 .primary
[OAM_PORT_STATUS
] = OFPPR_BITS
,
712 .secondary
[OAM_PORT_STATUS
] = OFPPR_BITS
715 if (version
>= OFP14_VERSION
) {
716 oac
.primary
[OAM_FLOW_REMOVED
] = OFPRR14_BITS
;
717 } else if (version
== OFP13_VERSION
) {
718 oac
.primary
[OAM_FLOW_REMOVED
] = OFPRR13_BITS
;
720 oac
.primary
[OAM_FLOW_REMOVED
] = OFPRR10_BITS
;