]> git.proxmox.com Git - mirror_ovs.git/blame - lib/ofp-connection.c
netdev-offload-tc: Use single 'once' variable for probing tc features
[mirror_ovs.git] / lib / ofp-connection.c
CommitLineData
0d71302e
BP
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-connection.h"
19#include "byte-order.h"
20#include "openflow/nicira-ext.h"
21#include "openvswitch/ofp-errors.h"
fe2c69f4 22#include "openvswitch/ofp-monitor.h"
0d71302e 23#include "openvswitch/ofp-msgs.h"
fe2c69f4 24#include "openvswitch/ofp-packet.h"
0d71302e 25#include "openvswitch/ofp-prop.h"
fe2c69f4 26#include "openvswitch/ofp-table.h"
0d71302e 27#include "openvswitch/ofpbuf.h"
fe2c69f4 28#include "openvswitch/type-props.h"
0d71302e
BP
29#include "openvswitch/vlog.h"
30#include "util.h"
31
32VLOG_DEFINE_THIS_MODULE(ofp_connection);
33
34/* ofputil_role_request */
35
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
38 * OFPERR_* value. */
39enum ofperr
40ofputil_decode_role_message(const struct ofp_header *oh,
41 struct ofputil_role_request *rr)
42{
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;
48
49 if (orr->role != htonl(OFPCR12_ROLE_NOCHANGE) &&
50 orr->role != htonl(OFPCR12_ROLE_EQUAL) &&
807152a4
BP
51 orr->role != htonl(OFPCR12_ROLE_PRIMARY) &&
52 orr->role != htonl(OFPCR12_ROLE_SECONDARY)) {
0d71302e
BP
53 return OFPERR_OFPRRFC_BAD_ROLE;
54 }
55
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;
62 } else {
63 rr->have_generation_id = true;
64 rr->generation_id = ntohll(orr->generation_id);
65 }
66 } else if (raw == OFPRAW_NXT_ROLE_REQUEST ||
67 raw == OFPRAW_NXT_ROLE_REPLY) {
68 const struct nx_role_request *nrr = b.msg;
69
70 BUILD_ASSERT(NX_ROLE_OTHER + 1 == OFPCR12_ROLE_EQUAL);
807152a4
BP
71 BUILD_ASSERT(NX_ROLE_PRIMARY + 1 == OFPCR12_ROLE_PRIMARY);
72 BUILD_ASSERT(NX_ROLE_SECONDARY + 1 == OFPCR12_ROLE_SECONDARY);
0d71302e
BP
73
74 if (nrr->role != htonl(NX_ROLE_OTHER) &&
807152a4
BP
75 nrr->role != htonl(NX_ROLE_PRIMARY) &&
76 nrr->role != htonl(NX_ROLE_SECONDARY)) {
0d71302e
BP
77 return OFPERR_OFPRRFC_BAD_ROLE;
78 }
79
80 rr->role = ntohl(nrr->role) + 1;
81 rr->have_generation_id = false;
82 rr->generation_id = 0;
83 } else {
84 OVS_NOT_REACHED();
85 }
86
87 return 0;
88}
89
fe2c69f4
BP
90static void
91format_role_generic(struct ds *string, enum ofp12_controller_role role,
92 uint64_t generation_id)
93{
94 ds_put_cstr(string, " role=");
95
96 switch (role) {
97 case OFPCR12_ROLE_NOCHANGE:
98 ds_put_cstr(string, "nochange");
99 break;
100 case OFPCR12_ROLE_EQUAL:
101 ds_put_cstr(string, "equal"); /* OF 1.2 wording */
102 break;
807152a4
BP
103 case OFPCR12_ROLE_PRIMARY:
104 ds_put_cstr(string, "primary");
fe2c69f4 105 break;
807152a4
BP
106 case OFPCR12_ROLE_SECONDARY:
107 ds_put_cstr(string, "secondary");
fe2c69f4
BP
108 break;
109 default:
110 OVS_NOT_REACHED();
111 }
112
113 if (generation_id != UINT64_MAX) {
114 ds_put_format(string, " generation_id=%"PRIu64, generation_id);
115 }
116}
117
118void
119ofputil_format_role_message(struct ds *string,
120 const struct ofputil_role_request *rr)
121{
122 format_role_generic(string, rr->role, (rr->have_generation_id
123 ? rr->generation_id
124 : UINT64_MAX));
125}
126
0d71302e
BP
127/* Returns an encoded form of a role reply suitable for the "request" in a
128 * buffer owned by the caller. */
129struct ofpbuf *
130ofputil_encode_role_reply(const struct ofp_header *request,
131 const struct ofputil_role_request *rr)
132{
133 struct ofpbuf *buf;
134 enum ofpraw raw;
135
136 raw = ofpraw_decode_assert(request);
137 if (raw == OFPRAW_OFPT12_ROLE_REQUEST) {
138 struct ofp12_role_request *orr;
139
140 buf = ofpraw_alloc_reply(OFPRAW_OFPT12_ROLE_REPLY, request, 0);
141 orr = ofpbuf_put_zeros(buf, sizeof *orr);
142
143 orr->role = htonl(rr->role);
144 orr->generation_id = htonll(rr->have_generation_id
145 ? rr->generation_id
146 : UINT64_MAX);
147 } else if (raw == OFPRAW_NXT_ROLE_REQUEST) {
148 struct nx_role_request *nrr;
149
150 BUILD_ASSERT(NX_ROLE_OTHER == OFPCR12_ROLE_EQUAL - 1);
807152a4
BP
151 BUILD_ASSERT(NX_ROLE_PRIMARY == OFPCR12_ROLE_PRIMARY - 1);
152 BUILD_ASSERT(NX_ROLE_SECONDARY == OFPCR12_ROLE_SECONDARY - 1);
0d71302e
BP
153
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);
157 } else {
158 OVS_NOT_REACHED();
159 }
160
161 return buf;
162}
163\f
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. */
167struct ofpbuf *
168ofputil_encode_role_status(const struct ofputil_role_status *status,
169 enum ofputil_protocol protocol)
170{
b0e07d50
BP
171 enum ofp_version version = ofputil_protocol_to_ofp_version(protocol);
172 if (version < OFP13_VERSION) {
0d71302e
BP
173 return NULL;
174 }
b0e07d50
BP
175
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);
184
185 return buf;
0d71302e
BP
186}
187
188enum ofperr
189ofputil_decode_role_status(const struct ofp_header *oh,
190 struct ofputil_role_status *rs)
191{
192 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
b0e07d50
BP
193 enum ofpraw raw = ofpraw_pull_assert(&b);
194 ovs_assert(raw == OFPRAW_OFPT14_ROLE_STATUS ||
195 raw == OFPRAW_ONFT13_ROLE_STATUS);
0d71302e
BP
196
197 const struct ofp14_role_status *r = b.msg;
198 if (r->role != htonl(OFPCR12_ROLE_NOCHANGE) &&
199 r->role != htonl(OFPCR12_ROLE_EQUAL) &&
807152a4
BP
200 r->role != htonl(OFPCR12_ROLE_PRIMARY) &&
201 r->role != htonl(OFPCR12_ROLE_SECONDARY)) {
0d71302e
BP
202 return OFPERR_OFPRRFC_BAD_ROLE;
203 }
204
205 rs->role = ntohl(r->role);
206 rs->generation_id = ntohll(r->generation_id);
207 rs->reason = r->reason;
208
209 return 0;
210}
fe2c69f4
BP
211
212void
213ofputil_format_role_status(struct ds *string,
214 const struct ofputil_role_status *rs)
215{
216 format_role_generic(string, rs->role, rs->generation_id);
217
218 ds_put_cstr(string, " reason=");
219
220 switch (rs->reason) {
807152a4
BP
221 case OFPCRR_PRIMARY_REQUEST:
222 ds_put_cstr(string, "primary_request");
fe2c69f4
BP
223 break;
224 case OFPCRR_CONFIG:
225 ds_put_cstr(string, "configuration_changed");
226 break;
227 case OFPCRR_EXPERIMENTER:
228 ds_put_cstr(string, "experimenter_data_changed");
229 break;
230 case OFPCRR_N_REASONS:
231 default:
232 ds_put_cstr(string, "(unknown)");
233 break;
234 }
235}
0d71302e
BP
236\f
237const char *
238ofputil_async_msg_type_to_string(enum ofputil_async_msg_type type)
239{
240 switch (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";
247
248 case OAM_N_TYPES:
249 default:
250 OVS_NOT_REACHED();
251 }
252}
253
254struct ofp14_async_prop {
255 uint64_t prop_type;
256 enum ofputil_async_msg_type oam;
807152a4 257 bool primary;
0d71302e
BP
258 uint32_t allowed10, allowed14;
259};
260
807152a4
BP
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) }
0d71302e
BP
264
265static 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),
272};
273
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++)
277
278static const struct ofp14_async_prop *
279get_ofp14_async_config_prop_by_prop_type(uint64_t prop_type)
280{
281 FOR_EACH_ASYNC_PROP (ap) {
282 if (prop_type == ap->prop_type) {
283 return ap;
284 }
285 }
286 return NULL;
287}
288
289static const struct ofp14_async_prop *
290get_ofp14_async_config_prop_by_oam(enum ofputil_async_msg_type oam,
807152a4 291 bool primary)
0d71302e
BP
292{
293 FOR_EACH_ASYNC_PROP (ap) {
807152a4 294 if (ap->oam == oam && ap->primary == primary) {
0d71302e
BP
295 return ap;
296 }
297 }
298 return NULL;
299}
300
301static uint32_t
302ofp14_async_prop_allowed(const struct ofp14_async_prop *prop,
303 enum ofp_version version)
304{
305 return version >= OFP14_VERSION ? prop->allowed14 : prop->allowed10;
306}
307
308static ovs_be32
309encode_async_mask(const struct ofputil_async_cfg *src,
310 const struct ofp14_async_prop *ap,
311 enum ofp_version version)
312{
807152a4
BP
313 uint32_t mask = (ap->primary
314 ? src->primary[ap->oam]
315 : src->secondary[ap->oam]);
0d71302e
BP
316 return htonl(mask & ofp14_async_prop_allowed(ap, version));
317}
318
319static enum ofperr
320decode_async_mask(ovs_be32 src,
321 const struct ofp14_async_prop *ap, enum ofp_version version,
322 bool loose, struct ofputil_async_cfg *dst)
323{
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),
331 allowed);
332 mask &= allowed;
333 if (!loose) {
334 return OFPERR_OFPACFC_INVALID;
335 }
336 }
337
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;
343 }
344 }
345 }
346
807152a4 347 uint32_t *array = ap->primary ? dst->primary : dst->secondary;
0d71302e
BP
348 array[ap->oam] = mask;
349 return 0;
350}
351
352static enum ofperr
353parse_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)
357{
358 enum ofperr error;
359 ovs_be32 mask;
360
361 error = ofpprop_parse_be32(property, &mask);
362 if (error) {
363 return error;
364 }
365
366 if (ofpprop_is_experimenter(ap->prop_type)) {
807152a4
BP
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
0d71302e
BP
369 * ofp_prop_experimenter. Check that these are consistent. */
370 const struct ofp_prop_experimenter *ope = property->data;
807152a4
BP
371 bool should_be_primary = ope->type == htons(0xffff);
372 if (should_be_primary != ap->primary) {
0d71302e
BP
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 "
376 "%s role",
377 ntohs(ope->type),
807152a4 378 should_be_primary ? "primary" : "secondary",
0d71302e 379 ntohl(ope->exp_type),
807152a4 380 ap->primary ? "primary" : "secondary");
0d71302e
BP
381 return OFPERR_OFPBPC_BAD_EXP_TYPE;
382 }
383 }
384
385 return decode_async_mask(mask, ap, version, loose, ac);
386}
387
388static void
389decode_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)
393{
394 for (int i = 0; i < 2; i++) {
807152a4 395 bool primary = i == 0;
0d71302e 396 const struct ofp14_async_prop *ap
807152a4 397 = get_ofp14_async_config_prop_by_oam(oam, primary);
0d71302e
BP
398 decode_async_mask(masks[i], ap, version, true, dst);
399 }
400}
401
402/* Decodes the OpenFlow "set async config" request and "get async config
403 * reply" message in '*oh' into an abstract form in 'ac'.
404 *
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.
409 *
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.
415 *
416 * Returns 0 if successful, otherwise an OFPERR_* value.
417 *
418 * Returns error code OFPERR_OFPACFC_INVALID if the value of mask is not in
419 * the valid range of mask.
420 *
421 * Returns error code OFPERR_OFPACFC_UNSUPPORTED if the configuration is not
422 * supported.*/
423enum ofperr
424ofputil_decode_set_async_config(const struct ofp_header *oh, bool loose,
425 const struct ofputil_async_cfg *basis,
426 struct ofputil_async_cfg *ac)
427{
428 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
429 enum ofpraw raw = ofpraw_pull_assert(&b);
430
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);
435
436 *ac = OFPUTIL_ASYNC_CFG_INIT;
437 decode_legacy_async_masks(msg->packet_in_mask, OAM_PACKET_IN,
438 oh->version, ac);
439 decode_legacy_async_masks(msg->port_status_mask, OAM_PORT_STATUS,
440 oh->version, ac);
441 decode_legacy_async_masks(msg->flow_removed_mask, OAM_FLOW_REMOVED,
442 oh->version, ac);
443 } else if (raw == OFPRAW_OFPT14_SET_ASYNC ||
444 raw == OFPRAW_OFPT14_GET_ASYNC_REPLY ||
445 raw == OFPRAW_NXT_SET_ASYNC_CONFIG2) {
446 *ac = *basis;
447 while (b.size > 0) {
448 struct ofpbuf property;
449 enum ofperr error;
450 uint64_t type;
451
452 error = ofpprop_pull__(&b, &property, 8, 0xfffe, &type);
453 if (error) {
454 return error;
455 }
456
457 const struct ofp14_async_prop *ap
458 = get_ofp14_async_config_prop_by_prop_type(type);
459 error = (ap
460 ? parse_async_tlv(&property, ap, ac, oh->version, loose)
461 : OFPPROP_UNKNOWN(loose, "async config", type));
462 if (error) {
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;
467 }
468 return error;
469 }
470 }
471 } else {
472 return OFPERR_OFPBRC_BAD_VERSION;
473 }
474 return 0;
475}
476
477static void
478encode_legacy_async_masks(const struct ofputil_async_cfg *ac,
479 enum ofputil_async_msg_type oam,
480 enum ofp_version version,
481 ovs_be32 masks[2])
482{
483 for (int i = 0; i < 2; i++) {
807152a4 484 bool primary = i == 0;
0d71302e 485 const struct ofp14_async_prop *ap
807152a4 486 = get_ofp14_async_config_prop_by_oam(oam, primary);
0d71302e
BP
487 masks[i] = encode_async_mask(ac, ap, version);
488 }
489}
490
491static void
492ofputil_put_async_config__(const struct ofputil_async_cfg *ac,
493 struct ofpbuf *buf, bool tlv,
494 enum ofp_version version, uint32_t oams)
495{
496 if (!tlv) {
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);
504 } else {
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));
510
511 /* For experimenter properties, we need to use type 0xfffe for
807152a4 512 * primary and 0xffff for secondaries. */
0d71302e
BP
513 if (ofpprop_is_experimenter(ap->prop_type)) {
514 struct ofp_prop_experimenter *ope
515 = ofpbuf_at_assert(buf, ofs, sizeof *ope);
807152a4 516 ope->type = ap->primary ? htons(0xffff) : htons(0xfffe);
0d71302e
BP
517 }
518 }
519 }
520 }
521}
522
523/* Encodes and returns a reply to the OFPT_GET_ASYNC_REQUEST in 'oh' that
524 * states that the asynchronous message configuration is 'ac'. */
525struct ofpbuf *
526ofputil_encode_get_async_reply(const struct ofp_header *oh,
527 const struct ofputil_async_cfg *ac)
528{
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);
536 return reply;
537}
538
539/* Encodes and returns a message, in a format appropriate for OpenFlow version
540 * 'ofp_version', that sets the asynchronous message configuration to 'ac'.
541 *
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_*. */
548struct ofpbuf *
549ofputil_encode_set_async_config(const struct ofputil_async_cfg *ac,
550 uint32_t oams, enum ofp_version ofp_version)
551{
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),
560 ofp_version, oams);
561 return request;
562}
563
fe2c69f4
BP
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)
568static const char *
569ofp_port_reason_to_string(enum ofp_port_reason reason,
570 char *reasonbuf, size_t bufsize)
571{
572 switch (reason) {
573 case OFPPR_ADD:
574 return "add";
575
576 case OFPPR_DELETE:
577 return "delete";
578
579 case OFPPR_MODIFY:
580 return "modify";
581
582 case OFPPR_N_REASONS:
583 default:
584 snprintf(reasonbuf, bufsize, "%d", (int) reason);
585 return reasonbuf;
586 }
587}
588
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. */
592static const char*
593ofp_role_reason_to_string(enum ofp14_controller_role_reason reason,
594 char *reasonbuf, size_t bufsize)
595{
596 switch (reason) {
807152a4
BP
597 case OFPCRR_PRIMARY_REQUEST:
598 return "primary_request";
fe2c69f4
BP
599
600 case OFPCRR_CONFIG:
601 return "configuration_changed";
602
603 case OFPCRR_EXPERIMENTER:
604 return "experimenter_data_changed";
605
606 case OFPCRR_N_REASONS:
607 default:
608 snprintf(reasonbuf, bufsize, "%d", (int) reason);
609 return reasonbuf;
610 }
611}
612
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. */
616static const char*
617ofp_requestforward_reason_to_string(enum ofp14_requestforward_reason reason,
618 char *reasonbuf, size_t bufsize)
619{
620 switch (reason) {
621 case OFPRFR_GROUP_MOD:
622 return "group_mod_request";
623
624 case OFPRFR_METER_MOD:
625 return "meter_mod_request";
626
627 case OFPRFR_N_REASONS:
628 default:
629 snprintf(reasonbuf, bufsize, "%d", (int) reason);
630 return reasonbuf;
631 }
632}
633
634static const char *
635ofp_async_config_reason_to_string(uint32_t reason,
636 enum ofputil_async_msg_type type,
637 char *reasonbuf, size_t bufsize)
638{
639 switch (type) {
640 case OAM_PACKET_IN:
641 return ofputil_packet_in_reason_to_string(reason, reasonbuf, bufsize);
642
643 case OAM_PORT_STATUS:
644 return ofp_port_reason_to_string(reason, reasonbuf, bufsize);
645
646 case OAM_FLOW_REMOVED:
647 return ofp_flow_removed_reason_to_string(reason, reasonbuf, bufsize);
648
649 case OAM_ROLE_STATUS:
650 return ofp_role_reason_to_string(reason, reasonbuf, bufsize);
651
652 case OAM_TABLE_STATUS:
653 return ofp_table_reason_to_string(reason, reasonbuf, bufsize);
654
655 case OAM_REQUESTFORWARD:
656 return ofp_requestforward_reason_to_string(reason, reasonbuf, bufsize);
657
658 case OAM_N_TYPES:
659 default:
660 return "Unknown asynchronous configuration message type";
661 }
662}
663
664void
665ofputil_format_set_async_config(struct ds *string,
666 const struct ofputil_async_cfg *ac)
667{
668 for (int i = 0; i < 2; i++) {
807152a4 669 ds_put_format(string, "\n %s:\n", i == 0 ? "primary" : "secondary");
fe2c69f4
BP
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));
673
807152a4 674 uint32_t role = i == 0 ? ac->primary[type] : ac->secondary[type];
fe2c69f4
BP
675 for (int j = 0; j < 32; j++) {
676 if (role & (1u << j)) {
677 char reasonbuf[INT_STRLEN(int) + 1];
678 const char *reason;
679
680 reason = ofp_async_config_reason_to_string(
681 j, type, reasonbuf, sizeof reasonbuf);
682 if (reason[0]) {
683 ds_put_format(string, " %s", reason);
684 }
685 }
686 }
687 if (!role) {
688 ds_put_cstr(string, " (off)");
689 }
690 ds_put_char(string, '\n');
691 }
692 }
693}
694
0d71302e
BP
695struct ofputil_async_cfg
696ofputil_async_cfg_default(enum ofp_version version)
697{
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
702 * OFPR_ACTION. */
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;
707 }
708
709 struct ofputil_async_cfg oac = {
807152a4
BP
710 .primary[OAM_PACKET_IN] = pin,
711 .primary[OAM_PORT_STATUS] = OFPPR_BITS,
712 .secondary[OAM_PORT_STATUS] = OFPPR_BITS
0d71302e
BP
713 };
714
715 if (version >= OFP14_VERSION) {
807152a4 716 oac.primary[OAM_FLOW_REMOVED] = OFPRR14_BITS;
0d71302e 717 } else if (version == OFP13_VERSION) {
807152a4 718 oac.primary[OAM_FLOW_REMOVED] = OFPRR13_BITS;
0d71302e 719 } else {
807152a4 720 oac.primary[OAM_FLOW_REMOVED] = OFPRR10_BITS;
0d71302e
BP
721 }
722
723 return oac;
724}