Coverage Report

Created: 2025-07-18 06:07

/src/openvswitch/lib/ofp-connection.c
Line
Count
Source (jump to first uncovered line)
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"
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"
30
#include "util.h"
31
32
VLOG_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. */
39
enum ofperr
40
ofputil_decode_role_message(const struct ofp_header *oh,
41
                            struct ofputil_role_request *rr)
42
0
{
43
0
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
44
0
    enum ofpraw raw = ofpraw_pull_assert(&b);
45
0
    if (raw == OFPRAW_OFPT12_ROLE_REQUEST ||
46
0
        raw == OFPRAW_OFPT12_ROLE_REPLY) {
47
0
        const struct ofp12_role_request *orr = b.msg;
48
49
0
        if (orr->role != htonl(OFPCR12_ROLE_NOCHANGE) &&
50
0
            orr->role != htonl(OFPCR12_ROLE_EQUAL) &&
51
0
            orr->role != htonl(OFPCR12_ROLE_PRIMARY) &&
52
0
            orr->role != htonl(OFPCR12_ROLE_SECONDARY)) {
53
0
            return OFPERR_OFPRRFC_BAD_ROLE;
54
0
        }
55
56
0
        rr->role = ntohl(orr->role);
57
0
        if (raw == OFPRAW_OFPT12_ROLE_REQUEST
58
0
            ? orr->role == htonl(OFPCR12_ROLE_NOCHANGE)
59
0
            : orr->generation_id == OVS_BE64_MAX) {
60
0
            rr->have_generation_id = false;
61
0
            rr->generation_id = 0;
62
0
        } else {
63
0
            rr->have_generation_id = true;
64
0
            rr->generation_id = ntohll(orr->generation_id);
65
0
        }
66
0
    } else if (raw == OFPRAW_NXT_ROLE_REQUEST ||
67
0
               raw == OFPRAW_NXT_ROLE_REPLY) {
68
0
        const struct nx_role_request *nrr = b.msg;
69
70
0
        BUILD_ASSERT(NX_ROLE_OTHER + 1 == OFPCR12_ROLE_EQUAL);
71
0
        BUILD_ASSERT(NX_ROLE_PRIMARY + 1 == OFPCR12_ROLE_PRIMARY);
72
0
        BUILD_ASSERT(NX_ROLE_SECONDARY + 1 == OFPCR12_ROLE_SECONDARY);
73
74
0
        if (nrr->role != htonl(NX_ROLE_OTHER) &&
75
0
            nrr->role != htonl(NX_ROLE_PRIMARY) &&
76
0
            nrr->role != htonl(NX_ROLE_SECONDARY)) {
77
0
            return OFPERR_OFPRRFC_BAD_ROLE;
78
0
        }
79
80
0
        rr->role = ntohl(nrr->role) + 1;
81
0
        rr->have_generation_id = false;
82
0
        rr->generation_id = 0;
83
0
    } else {
84
0
        OVS_NOT_REACHED();
85
0
    }
86
87
0
    return 0;
88
0
}
89
90
static void
91
format_role_generic(struct ds *string, enum ofp12_controller_role role,
92
                    uint64_t generation_id)
93
0
{
94
0
    ds_put_cstr(string, " role=");
95
96
0
    switch (role) {
97
0
    case OFPCR12_ROLE_NOCHANGE:
98
0
        ds_put_cstr(string, "nochange");
99
0
        break;
100
0
    case OFPCR12_ROLE_EQUAL:
101
0
        ds_put_cstr(string, "equal"); /* OF 1.2 wording */
102
0
        break;
103
0
    case OFPCR12_ROLE_PRIMARY:
104
0
        ds_put_cstr(string, "primary");
105
0
        break;
106
0
    case OFPCR12_ROLE_SECONDARY:
107
0
        ds_put_cstr(string, "secondary");
108
0
        break;
109
0
    default:
110
0
        OVS_NOT_REACHED();
111
0
    }
112
113
0
    if (generation_id != UINT64_MAX) {
114
0
        ds_put_format(string, " generation_id=%"PRIu64, generation_id);
115
0
    }
116
0
}
117
118
void
119
ofputil_format_role_message(struct ds *string,
120
                            const struct ofputil_role_request *rr)
121
0
{
122
0
    format_role_generic(string, rr->role, (rr->have_generation_id
123
0
                                           ? rr->generation_id
124
0
                                           : UINT64_MAX));
125
0
}
126
127
/* Returns an encoded form of a role reply suitable for the "request" in a
128
 * buffer owned by the caller. */
129
struct ofpbuf *
130
ofputil_encode_role_reply(const struct ofp_header *request,
131
                          const struct ofputil_role_request *rr)
132
0
{
133
0
    struct ofpbuf *buf;
134
0
    enum ofpraw raw;
135
136
0
    raw = ofpraw_decode_assert(request);
137
0
    if (raw == OFPRAW_OFPT12_ROLE_REQUEST) {
138
0
        struct ofp12_role_request *orr;
139
140
0
        buf = ofpraw_alloc_reply(OFPRAW_OFPT12_ROLE_REPLY, request, 0);
141
0
        orr = ofpbuf_put_zeros(buf, sizeof *orr);
142
143
0
        orr->role = htonl(rr->role);
144
0
        orr->generation_id = htonll(rr->have_generation_id
145
0
                                    ? rr->generation_id
146
0
                                    : UINT64_MAX);
147
0
    } else if (raw == OFPRAW_NXT_ROLE_REQUEST) {
148
0
        struct nx_role_request *nrr;
149
150
0
        BUILD_ASSERT(NX_ROLE_OTHER == OFPCR12_ROLE_EQUAL - 1);
151
0
        BUILD_ASSERT(NX_ROLE_PRIMARY == OFPCR12_ROLE_PRIMARY - 1);
152
0
        BUILD_ASSERT(NX_ROLE_SECONDARY == OFPCR12_ROLE_SECONDARY - 1);
153
154
0
        buf = ofpraw_alloc_reply(OFPRAW_NXT_ROLE_REPLY, request, 0);
155
0
        nrr = ofpbuf_put_zeros(buf, sizeof *nrr);
156
0
        nrr->role = htonl(rr->role - 1);
157
0
    } else {
158
0
        OVS_NOT_REACHED();
159
0
    }
160
161
0
    return buf;
162
0
}
163

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. */
167
struct ofpbuf *
168
ofputil_encode_role_status(const struct ofputil_role_status *status,
169
                           enum ofputil_protocol protocol)
170
0
{
171
0
    enum ofp_version version = ofputil_protocol_to_ofp_version(protocol);
172
0
    if (version < OFP13_VERSION) {
173
0
        return NULL;
174
0
    }
175
176
0
    enum ofpraw raw = (version >= OFP14_VERSION
177
0
                       ? OFPRAW_OFPT14_ROLE_STATUS
178
0
                       : OFPRAW_ONFT13_ROLE_STATUS);
179
0
    struct ofpbuf *buf = ofpraw_alloc_xid(raw, version, htonl(0), 0);
180
0
    struct ofp14_role_status *rstatus = ofpbuf_put_zeros(buf, sizeof *rstatus);
181
0
    rstatus->role = htonl(status->role);
182
0
    rstatus->reason = status->reason;
183
0
    rstatus->generation_id = htonll(status->generation_id);
184
185
0
    return buf;
186
0
}
187
188
enum ofperr
189
ofputil_decode_role_status(const struct ofp_header *oh,
190
                           struct ofputil_role_status *rs)
191
0
{
192
0
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
193
0
    enum ofpraw raw = ofpraw_pull_assert(&b);
194
0
    ovs_assert(raw == OFPRAW_OFPT14_ROLE_STATUS ||
195
0
               raw == OFPRAW_ONFT13_ROLE_STATUS);
196
197
0
    const struct ofp14_role_status *r = b.msg;
198
0
    if (r->role != htonl(OFPCR12_ROLE_NOCHANGE) &&
199
0
        r->role != htonl(OFPCR12_ROLE_EQUAL) &&
200
0
        r->role != htonl(OFPCR12_ROLE_PRIMARY) &&
201
0
        r->role != htonl(OFPCR12_ROLE_SECONDARY)) {
202
0
        return OFPERR_OFPRRFC_BAD_ROLE;
203
0
    }
204
205
0
    rs->role = ntohl(r->role);
206
0
    rs->generation_id = ntohll(r->generation_id);
207
0
    rs->reason = r->reason;
208
209
0
    return 0;
210
0
}
211
212
void
213
ofputil_format_role_status(struct ds *string,
214
                           const struct ofputil_role_status *rs)
215
0
{
216
0
    format_role_generic(string, rs->role, rs->generation_id);
217
218
0
    ds_put_cstr(string, " reason=");
219
220
0
    switch (rs->reason) {
221
0
    case OFPCRR_PRIMARY_REQUEST:
222
0
        ds_put_cstr(string, "primary_request");
223
0
        break;
224
0
    case OFPCRR_CONFIG:
225
0
        ds_put_cstr(string, "configuration_changed");
226
0
        break;
227
0
    case OFPCRR_EXPERIMENTER:
228
0
        ds_put_cstr(string, "experimenter_data_changed");
229
0
        break;
230
0
    case OFPCRR_N_REASONS:
231
0
    default:
232
0
        ds_put_cstr(string, "(unknown)");
233
0
        break;
234
0
    }
235
0
}
236

237
const char *
238
ofputil_async_msg_type_to_string(enum ofputil_async_msg_type type)
239
0
{
240
0
    switch (type) {
241
0
    case OAM_PACKET_IN:      return "PACKET_IN";
242
0
    case OAM_PORT_STATUS:    return "PORT_STATUS";
243
0
    case OAM_FLOW_REMOVED:   return "FLOW_REMOVED";
244
0
    case OAM_ROLE_STATUS:    return "ROLE_STATUS";
245
0
    case OAM_TABLE_STATUS:   return "TABLE_STATUS";
246
0
    case OAM_REQUESTFORWARD: return "REQUESTFORWARD";
247
248
0
    case OAM_N_TYPES:
249
0
    default:
250
0
        OVS_NOT_REACHED();
251
0
    }
252
0
}
253
254
struct ofp14_async_prop {
255
    uint64_t prop_type;
256
    enum ofputil_async_msg_type oam;
257
    bool primary;
258
    uint32_t allowed10, allowed14;
259
};
260
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) }
264
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),
272
};
273
274
#define FOR_EACH_ASYNC_PROP(VAR)                                \
275
0
    for (const struct ofp14_async_prop *VAR = async_props;      \
276
0
         VAR < &async_props[ARRAY_SIZE(async_props)]; VAR++)
277
278
static const struct ofp14_async_prop *
279
get_ofp14_async_config_prop_by_prop_type(uint64_t prop_type)
280
0
{
281
0
    FOR_EACH_ASYNC_PROP (ap) {
282
0
        if (prop_type == ap->prop_type) {
283
0
            return ap;
284
0
        }
285
0
    }
286
0
    return NULL;
287
0
}
288
289
static const struct ofp14_async_prop *
290
get_ofp14_async_config_prop_by_oam(enum ofputil_async_msg_type oam,
291
                                   bool primary)
292
0
{
293
0
    FOR_EACH_ASYNC_PROP (ap) {
294
0
        if (ap->oam == oam && ap->primary == primary) {
295
0
            return ap;
296
0
        }
297
0
    }
298
0
    return NULL;
299
0
}
300
301
static uint32_t
302
ofp14_async_prop_allowed(const struct ofp14_async_prop *prop,
303
                         enum ofp_version version)
304
0
{
305
0
    return version >= OFP14_VERSION ? prop->allowed14 : prop->allowed10;
306
0
}
307
308
static ovs_be32
309
encode_async_mask(const struct ofputil_async_cfg *src,
310
                  const struct ofp14_async_prop *ap,
311
                  enum ofp_version version)
312
0
{
313
0
    uint32_t mask = (ap->primary
314
0
                     ? src->primary[ap->oam]
315
0
                     : src->secondary[ap->oam]);
316
0
    return htonl(mask & ofp14_async_prop_allowed(ap, version));
317
0
}
318
319
static enum ofperr
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)
323
0
{
324
0
    uint32_t mask = ntohl(src);
325
0
    uint32_t allowed = ofp14_async_prop_allowed(ap, version);
326
0
    if (mask & ~allowed) {
327
0
        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
328
0
        OFPPROP_LOG(&rl, loose,
329
0
                    "bad value %#x for %s (allowed mask %#x)",
330
0
                    mask, ofputil_async_msg_type_to_string(ap->oam),
331
0
                    allowed);
332
0
        mask &= allowed;
333
0
        if (!loose) {
334
0
            return OFPERR_OFPACFC_INVALID;
335
0
        }
336
0
    }
337
338
0
    if (ap->oam == OAM_PACKET_IN) {
339
0
        if (mask & (1u << OFPR_NO_MATCH)) {
340
0
            mask |= 1u << OFPR_EXPLICIT_MISS;
341
0
            if (version < OFP13_VERSION) {
342
0
                mask |= 1u << OFPR_IMPLICIT_MISS;
343
0
            }
344
0
        }
345
0
    }
346
347
0
    uint32_t *array = ap->primary ? dst->primary : dst->secondary;
348
0
    array[ap->oam] = mask;
349
0
    return 0;
350
0
}
351
352
static enum ofperr
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)
357
0
{
358
0
    enum ofperr error;
359
0
    ovs_be32 mask;
360
361
0
    error  = ofpprop_parse_be32(property, &mask);
362
0
    if (error) {
363
0
        return error;
364
0
    }
365
366
0
    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
0
        const struct ofp_prop_experimenter *ope = property->data;
371
0
        bool should_be_primary = ope->type == htons(0xffff);
372
0
        if (should_be_primary != ap->primary) {
373
0
            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
374
0
            VLOG_WARN_RL(&rl, "async property type %#"PRIx16" "
375
0
                         "indicates %s role but exp_type %"PRIu32" indicates "
376
0
                         "%s role",
377
0
                         ntohs(ope->type),
378
0
                         should_be_primary ? "primary" : "secondary",
379
0
                         ntohl(ope->exp_type),
380
0
                         ap->primary ? "primary" : "secondary");
381
0
            return OFPERR_OFPBPC_BAD_EXP_TYPE;
382
0
        }
383
0
    }
384
385
0
    return decode_async_mask(mask, ap, version, loose, ac);
386
0
}
387
388
static void
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)
393
0
{
394
0
    for (int i = 0; i < 2; i++) {
395
0
        bool primary = i == 0;
396
0
        const struct ofp14_async_prop *ap
397
0
            = get_ofp14_async_config_prop_by_oam(oam, primary);
398
0
        decode_async_mask(masks[i], ap, version, true, dst);
399
0
    }
400
0
}
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.*/
423
enum ofperr
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)
427
0
{
428
0
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
429
0
    enum ofpraw raw = ofpraw_pull_assert(&b);
430
431
0
    if (raw == OFPRAW_OFPT13_SET_ASYNC ||
432
0
        raw == OFPRAW_NXT_SET_ASYNC_CONFIG ||
433
0
        raw == OFPRAW_OFPT13_GET_ASYNC_REPLY) {
434
0
        const struct nx_async_config *msg = ofpmsg_body(oh);
435
436
0
        *ac = OFPUTIL_ASYNC_CFG_INIT;
437
0
        decode_legacy_async_masks(msg->packet_in_mask, OAM_PACKET_IN,
438
0
                                  oh->version, ac);
439
0
        decode_legacy_async_masks(msg->port_status_mask, OAM_PORT_STATUS,
440
0
                                  oh->version, ac);
441
0
        decode_legacy_async_masks(msg->flow_removed_mask, OAM_FLOW_REMOVED,
442
0
                                  oh->version, ac);
443
0
    } else if (raw == OFPRAW_OFPT14_SET_ASYNC ||
444
0
               raw == OFPRAW_OFPT14_GET_ASYNC_REPLY ||
445
0
               raw == OFPRAW_NXT_SET_ASYNC_CONFIG2) {
446
0
        *ac = *basis;
447
0
        while (b.size > 0) {
448
0
            struct ofpbuf property;
449
0
            enum ofperr error;
450
0
            uint64_t type;
451
452
0
            error = ofpprop_pull__(&b, &property, 8, 0xfffe, &type);
453
0
            if (error) {
454
0
                return error;
455
0
            }
456
457
0
            const struct ofp14_async_prop *ap
458
0
                = get_ofp14_async_config_prop_by_prop_type(type);
459
0
            error = (ap
460
0
                     ? parse_async_tlv(&property, ap, ac, oh->version, loose)
461
0
                     : OFPPROP_UNKNOWN(loose, "async config", type));
462
0
            if (error) {
463
                /* Most messages use OFPBPC_BAD_TYPE but async has its own (who
464
                 * knows why, it's OpenFlow. */
465
0
                if (error == OFPERR_OFPBPC_BAD_TYPE) {
466
0
                    error = OFPERR_OFPACFC_UNSUPPORTED;
467
0
                }
468
0
                return error;
469
0
            }
470
0
        }
471
0
    } else {
472
0
        return OFPERR_OFPBRC_BAD_VERSION;
473
0
    }
474
0
    return 0;
475
0
}
476
477
static void
478
encode_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
0
{
483
0
    for (int i = 0; i < 2; i++) {
484
0
        bool primary = i == 0;
485
0
        const struct ofp14_async_prop *ap
486
0
            = get_ofp14_async_config_prop_by_oam(oam, primary);
487
0
        masks[i] = encode_async_mask(ac, ap, version);
488
0
    }
489
0
}
490
491
static void
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)
495
0
{
496
0
    if (!tlv) {
497
0
        struct nx_async_config *msg = ofpbuf_put_zeros(buf, sizeof *msg);
498
0
        encode_legacy_async_masks(ac, OAM_PACKET_IN, version,
499
0
                                  msg->packet_in_mask);
500
0
        encode_legacy_async_masks(ac, OAM_PORT_STATUS, version,
501
0
                                  msg->port_status_mask);
502
0
        encode_legacy_async_masks(ac, OAM_FLOW_REMOVED, version,
503
0
                                  msg->flow_removed_mask);
504
0
    } else {
505
0
        FOR_EACH_ASYNC_PROP (ap) {
506
0
            if (oams & (1u << ap->oam)) {
507
0
                size_t ofs = buf->size;
508
0
                ofpprop_put_be32(buf, ap->prop_type,
509
0
                                 encode_async_mask(ac, ap, version));
510
511
                /* For experimenter properties, we need to use type 0xfffe for
512
                 * primary and 0xffff for secondaries. */
513
0
                if (ofpprop_is_experimenter(ap->prop_type)) {
514
0
                    struct ofp_prop_experimenter *ope
515
0
                        = ofpbuf_at_assert(buf, ofs, sizeof *ope);
516
0
                    ope->type = ap->primary ? htons(0xffff) : htons(0xfffe);
517
0
                }
518
0
            }
519
0
        }
520
0
    }
521
0
}
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'. */
525
struct ofpbuf *
526
ofputil_encode_get_async_reply(const struct ofp_header *oh,
527
                               const struct ofputil_async_cfg *ac)
528
0
{
529
0
    enum ofpraw raw = (oh->version < OFP14_VERSION
530
0
                       ? OFPRAW_OFPT13_GET_ASYNC_REPLY
531
0
                       : OFPRAW_OFPT14_GET_ASYNC_REPLY);
532
0
    struct ofpbuf *reply = ofpraw_alloc_reply(raw, oh, 0);
533
0
    ofputil_put_async_config__(ac, reply,
534
0
                               raw == OFPRAW_OFPT14_GET_ASYNC_REPLY,
535
0
                               oh->version, UINT32_MAX);
536
0
    return reply;
537
0
}
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_*. */
548
struct ofpbuf *
549
ofputil_encode_set_async_config(const struct ofputil_async_cfg *ac,
550
                                uint32_t oams, enum ofp_version ofp_version)
551
0
{
552
0
    enum ofpraw raw = (ofp_version >= OFP14_VERSION ? OFPRAW_OFPT14_SET_ASYNC
553
0
                       : oams & OAM_EXTENSIONS ? OFPRAW_NXT_SET_ASYNC_CONFIG2
554
0
                       : ofp_version >= OFP13_VERSION ? OFPRAW_OFPT13_SET_ASYNC
555
0
                       : OFPRAW_NXT_SET_ASYNC_CONFIG);
556
0
    struct ofpbuf *request = ofpraw_alloc(raw, ofp_version, 0);
557
0
    ofputil_put_async_config__(ac, request,
558
0
                               (raw == OFPRAW_OFPT14_SET_ASYNC ||
559
0
                                raw == OFPRAW_NXT_SET_ASYNC_CONFIG2),
560
0
                               ofp_version, oams);
561
0
    return request;
562
0
}
563
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)
568
static const char *
569
ofp_port_reason_to_string(enum ofp_port_reason reason,
570
                          char *reasonbuf, size_t bufsize)
571
0
{
572
0
    switch (reason) {
573
0
    case OFPPR_ADD:
574
0
        return "add";
575
576
0
    case OFPPR_DELETE:
577
0
        return "delete";
578
579
0
    case OFPPR_MODIFY:
580
0
        return "modify";
581
582
0
    case OFPPR_N_REASONS:
583
0
    default:
584
0
        snprintf(reasonbuf, bufsize, "%d", (int) reason);
585
0
        return reasonbuf;
586
0
    }
587
0
}
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. */
592
static const char*
593
ofp_role_reason_to_string(enum ofp14_controller_role_reason reason,
594
                          char *reasonbuf, size_t bufsize)
595
0
{
596
0
    switch (reason) {
597
0
    case OFPCRR_PRIMARY_REQUEST:
598
0
        return "primary_request";
599
600
0
    case OFPCRR_CONFIG:
601
0
        return "configuration_changed";
602
603
0
    case OFPCRR_EXPERIMENTER:
604
0
        return "experimenter_data_changed";
605
606
0
    case OFPCRR_N_REASONS:
607
0
    default:
608
0
        snprintf(reasonbuf, bufsize, "%d", (int) reason);
609
0
        return reasonbuf;
610
0
    }
611
0
}
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. */
616
static const char*
617
ofp_requestforward_reason_to_string(enum ofp14_requestforward_reason reason,
618
                                    char *reasonbuf, size_t bufsize)
619
0
{
620
0
    switch (reason) {
621
0
    case OFPRFR_GROUP_MOD:
622
0
        return "group_mod_request";
623
624
0
    case OFPRFR_METER_MOD:
625
0
        return "meter_mod_request";
626
627
0
    case OFPRFR_N_REASONS:
628
0
    default:
629
0
        snprintf(reasonbuf, bufsize, "%d", (int) reason);
630
0
        return reasonbuf;
631
0
    }
632
0
}
633
634
static const char *
635
ofp_async_config_reason_to_string(uint32_t reason,
636
                                  enum ofputil_async_msg_type type,
637
                                  char *reasonbuf, size_t bufsize)
638
0
{
639
0
    switch (type) {
640
0
    case OAM_PACKET_IN:
641
0
        return ofputil_packet_in_reason_to_string(reason, reasonbuf, bufsize);
642
643
0
    case OAM_PORT_STATUS:
644
0
        return ofp_port_reason_to_string(reason, reasonbuf, bufsize);
645
646
0
    case OAM_FLOW_REMOVED:
647
0
        return ofp_flow_removed_reason_to_string(reason, reasonbuf, bufsize);
648
649
0
    case OAM_ROLE_STATUS:
650
0
        return ofp_role_reason_to_string(reason, reasonbuf, bufsize);
651
652
0
    case OAM_TABLE_STATUS:
653
0
        return ofp_table_reason_to_string(reason, reasonbuf, bufsize);
654
655
0
    case OAM_REQUESTFORWARD:
656
0
        return ofp_requestforward_reason_to_string(reason, reasonbuf, bufsize);
657
658
0
    case OAM_N_TYPES:
659
0
    default:
660
0
        return "Unknown asynchronous configuration message type";
661
0
    }
662
0
}
663
664
void
665
ofputil_format_set_async_config(struct ds *string,
666
                                const struct ofputil_async_cfg *ac)
667
0
{
668
0
    for (int i = 0; i < 2; i++) {
669
0
        ds_put_format(string, "\n %s:\n", i == 0 ? "primary" : "secondary");
670
0
        for (uint32_t type = 0; type < OAM_N_TYPES; type++) {
671
0
            ds_put_format(string, "%16s:",
672
0
                          ofputil_async_msg_type_to_string(type));
673
674
0
            uint32_t role = i == 0 ? ac->primary[type] : ac->secondary[type];
675
0
            for (int j = 0; j < 32; j++) {
676
0
                if (role & (1u << j)) {
677
0
                    char reasonbuf[INT_STRLEN(int) + 1];
678
0
                    const char *reason;
679
680
0
                    reason = ofp_async_config_reason_to_string(
681
0
                        j, type, reasonbuf, sizeof reasonbuf);
682
0
                    if (reason[0]) {
683
0
                        ds_put_format(string, " %s", reason);
684
0
                    }
685
0
                }
686
0
            }
687
0
            if (!role) {
688
0
                ds_put_cstr(string, " (off)");
689
0
            }
690
0
            ds_put_char(string, '\n');
691
0
        }
692
0
    }
693
0
}
694
695
struct ofputil_async_cfg
696
ofputil_async_cfg_default(enum ofp_version version)
697
0
{
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
0
    uint32_t pin = OFPR14_BITS & ~(1u << OFPR_INVALID_TTL);
704
0
    pin |= 1u << OFPR_EXPLICIT_MISS;
705
0
    if (version <= OFP12_VERSION) {
706
0
        pin |= 1u << OFPR_IMPLICIT_MISS;
707
0
    }
708
709
0
    struct ofputil_async_cfg oac = {
710
0
        .primary[OAM_PACKET_IN] = pin,
711
0
        .primary[OAM_PORT_STATUS] = OFPPR_BITS,
712
0
        .secondary[OAM_PORT_STATUS] = OFPPR_BITS
713
0
    };
714
715
0
    if (version >= OFP14_VERSION) {
716
0
        oac.primary[OAM_FLOW_REMOVED] = OFPRR14_BITS;
717
0
    } else if (version == OFP13_VERSION) {
718
0
        oac.primary[OAM_FLOW_REMOVED] = OFPRR13_BITS;
719
0
    } else {
720
0
        oac.primary[OAM_FLOW_REMOVED] = OFPRR10_BITS;
721
0
    }
722
723
0
    return oac;
724
0
}