Coverage Report

Created: 2025-07-11 06:12

/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
13.2k
{
43
13.2k
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
44
13.2k
    enum ofpraw raw = ofpraw_pull_assert(&b);
45
13.2k
    if (raw == OFPRAW_OFPT12_ROLE_REQUEST ||
46
13.2k
        raw == OFPRAW_OFPT12_ROLE_REPLY) {
47
11.6k
        const struct ofp12_role_request *orr = b.msg;
48
49
11.6k
        if (orr->role != htonl(OFPCR12_ROLE_NOCHANGE) &&
50
11.6k
            orr->role != htonl(OFPCR12_ROLE_EQUAL) &&
51
11.6k
            orr->role != htonl(OFPCR12_ROLE_PRIMARY) &&
52
11.6k
            orr->role != htonl(OFPCR12_ROLE_SECONDARY)) {
53
3.27k
            return OFPERR_OFPRRFC_BAD_ROLE;
54
3.27k
        }
55
56
8.38k
        rr->role = ntohl(orr->role);
57
8.38k
        if (raw == OFPRAW_OFPT12_ROLE_REQUEST
58
8.38k
            ? orr->role == htonl(OFPCR12_ROLE_NOCHANGE)
59
8.38k
            : orr->generation_id == OVS_BE64_MAX) {
60
124
            rr->have_generation_id = false;
61
124
            rr->generation_id = 0;
62
8.26k
        } else {
63
8.26k
            rr->have_generation_id = true;
64
8.26k
            rr->generation_id = ntohll(orr->generation_id);
65
8.26k
        }
66
8.38k
    } else if (raw == OFPRAW_NXT_ROLE_REQUEST ||
67
1.56k
               raw == OFPRAW_NXT_ROLE_REPLY) {
68
1.56k
        const struct nx_role_request *nrr = b.msg;
69
70
1.56k
        BUILD_ASSERT(NX_ROLE_OTHER + 1 == OFPCR12_ROLE_EQUAL);
71
1.56k
        BUILD_ASSERT(NX_ROLE_PRIMARY + 1 == OFPCR12_ROLE_PRIMARY);
72
1.56k
        BUILD_ASSERT(NX_ROLE_SECONDARY + 1 == OFPCR12_ROLE_SECONDARY);
73
74
1.56k
        if (nrr->role != htonl(NX_ROLE_OTHER) &&
75
1.56k
            nrr->role != htonl(NX_ROLE_PRIMARY) &&
76
1.56k
            nrr->role != htonl(NX_ROLE_SECONDARY)) {
77
854
            return OFPERR_OFPRRFC_BAD_ROLE;
78
854
        }
79
80
707
        rr->role = ntohl(nrr->role) + 1;
81
707
        rr->have_generation_id = false;
82
707
        rr->generation_id = 0;
83
707
    } else {
84
0
        OVS_NOT_REACHED();
85
0
    }
86
87
9.09k
    return 0;
88
13.2k
}
89
90
static void
91
format_role_generic(struct ds *string, enum ofp12_controller_role role,
92
                    uint64_t generation_id)
93
9.72k
{
94
9.72k
    ds_put_cstr(string, " role=");
95
96
9.72k
    switch (role) {
97
292
    case OFPCR12_ROLE_NOCHANGE:
98
292
        ds_put_cstr(string, "nochange");
99
292
        break;
100
8.92k
    case OFPCR12_ROLE_EQUAL:
101
8.92k
        ds_put_cstr(string, "equal"); /* OF 1.2 wording */
102
8.92k
        break;
103
226
    case OFPCR12_ROLE_PRIMARY:
104
226
        ds_put_cstr(string, "primary");
105
226
        break;
106
284
    case OFPCR12_ROLE_SECONDARY:
107
284
        ds_put_cstr(string, "secondary");
108
284
        break;
109
0
    default:
110
0
        OVS_NOT_REACHED();
111
9.72k
    }
112
113
9.72k
    if (generation_id != UINT64_MAX) {
114
8.89k
        ds_put_format(string, " generation_id=%"PRIu64, generation_id);
115
8.89k
    }
116
9.72k
}
117
118
void
119
ofputil_format_role_message(struct ds *string,
120
                            const struct ofputil_role_request *rr)
121
9.09k
{
122
9.09k
    format_role_generic(string, rr->role, (rr->have_generation_id
123
9.09k
                                           ? rr->generation_id
124
9.09k
                                           : UINT64_MAX));
125
9.09k
}
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
1.22k
{
192
1.22k
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
193
1.22k
    enum ofpraw raw = ofpraw_pull_assert(&b);
194
1.22k
    ovs_assert(raw == OFPRAW_OFPT14_ROLE_STATUS ||
195
1.22k
               raw == OFPRAW_ONFT13_ROLE_STATUS);
196
197
1.22k
    const struct ofp14_role_status *r = b.msg;
198
1.22k
    if (r->role != htonl(OFPCR12_ROLE_NOCHANGE) &&
199
1.22k
        r->role != htonl(OFPCR12_ROLE_EQUAL) &&
200
1.22k
        r->role != htonl(OFPCR12_ROLE_PRIMARY) &&
201
1.22k
        r->role != htonl(OFPCR12_ROLE_SECONDARY)) {
202
591
        return OFPERR_OFPRRFC_BAD_ROLE;
203
591
    }
204
205
636
    rs->role = ntohl(r->role);
206
636
    rs->generation_id = ntohll(r->generation_id);
207
636
    rs->reason = r->reason;
208
209
636
    return 0;
210
1.22k
}
211
212
void
213
ofputil_format_role_status(struct ds *string,
214
                           const struct ofputil_role_status *rs)
215
636
{
216
636
    format_role_generic(string, rs->role, rs->generation_id);
217
218
636
    ds_put_cstr(string, " reason=");
219
220
636
    switch (rs->reason) {
221
213
    case OFPCRR_PRIMARY_REQUEST:
222
213
        ds_put_cstr(string, "primary_request");
223
213
        break;
224
1
    case OFPCRR_CONFIG:
225
1
        ds_put_cstr(string, "configuration_changed");
226
1
        break;
227
2
    case OFPCRR_EXPERIMENTER:
228
2
        ds_put_cstr(string, "experimenter_data_changed");
229
2
        break;
230
1
    case OFPCRR_N_REASONS:
231
420
    default:
232
420
        ds_put_cstr(string, "(unknown)");
233
420
        break;
234
636
    }
235
636
}
236

237
const char *
238
ofputil_async_msg_type_to_string(enum ofputil_async_msg_type type)
239
269k
{
240
269k
    switch (type) {
241
44.9k
    case OAM_PACKET_IN:      return "PACKET_IN";
242
44.9k
    case OAM_PORT_STATUS:    return "PORT_STATUS";
243
44.9k
    case OAM_FLOW_REMOVED:   return "FLOW_REMOVED";
244
44.9k
    case OAM_ROLE_STATUS:    return "ROLE_STATUS";
245
44.9k
    case OAM_TABLE_STATUS:   return "TABLE_STATUS";
246
44.9k
    case OAM_REQUESTFORWARD: return "REQUESTFORWARD";
247
248
0
    case OAM_N_TYPES:
249
0
    default:
250
0
        OVS_NOT_REACHED();
251
269k
    }
252
269k
}
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
37.1k
    for (const struct ofp14_async_prop *VAR = async_props;      \
276
257k
         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
26.1k
{
281
211k
    FOR_EACH_ASYNC_PROP (ap) {
282
211k
        if (prop_type == ap->prop_type) {
283
18.7k
            return ap;
284
18.7k
        }
285
211k
    }
286
7.35k
    return NULL;
287
26.1k
}
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
10.9k
{
293
38.4k
    FOR_EACH_ASYNC_PROP (ap) {
294
38.4k
        if (ap->oam == oam && ap->primary == primary) {
295
10.9k
            return ap;
296
10.9k
        }
297
38.4k
    }
298
0
    return NULL;
299
10.9k
}
300
301
static uint32_t
302
ofp14_async_prop_allowed(const struct ofp14_async_prop *prop,
303
                         enum ofp_version version)
304
28.3k
{
305
28.3k
    return version >= OFP14_VERSION ? prop->allowed14 : prop->allowed10;
306
28.3k
}
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
28.3k
{
324
28.3k
    uint32_t mask = ntohl(src);
325
28.3k
    uint32_t allowed = ofp14_async_prop_allowed(ap, version);
326
28.3k
    if (mask & ~allowed) {
327
21.4k
        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
328
21.4k
        OFPPROP_LOG(&rl, loose,
329
21.4k
                    "bad value %#x for %s (allowed mask %#x)",
330
21.4k
                    mask, ofputil_async_msg_type_to_string(ap->oam),
331
21.4k
                    allowed);
332
21.4k
        mask &= allowed;
333
21.4k
        if (!loose) {
334
1.53k
            return OFPERR_OFPACFC_INVALID;
335
1.53k
        }
336
21.4k
    }
337
338
26.7k
    if (ap->oam == OAM_PACKET_IN) {
339
7.64k
        if (mask & (1u << OFPR_NO_MATCH)) {
340
5.30k
            mask |= 1u << OFPR_EXPLICIT_MISS;
341
5.30k
            if (version < OFP13_VERSION) {
342
379
                mask |= 1u << OFPR_IMPLICIT_MISS;
343
379
            }
344
5.30k
        }
345
7.64k
    }
346
347
26.7k
    uint32_t *array = ap->primary ? dst->primary : dst->secondary;
348
26.7k
    array[ap->oam] = mask;
349
26.7k
    return 0;
350
28.3k
}
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
18.7k
{
358
18.7k
    enum ofperr error;
359
18.7k
    ovs_be32 mask;
360
361
18.7k
    error  = ofpprop_parse_be32(property, &mask);
362
18.7k
    if (error) {
363
1.47k
        return error;
364
1.47k
    }
365
366
17.3k
    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
17.3k
    return decode_async_mask(mask, ap, version, loose, ac);
386
17.3k
}
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
5.49k
{
394
16.4k
    for (int i = 0; i < 2; i++) {
395
10.9k
        bool primary = i == 0;
396
10.9k
        const struct ofp14_async_prop *ap
397
10.9k
            = get_ofp14_async_config_prop_by_oam(oam, primary);
398
10.9k
        decode_async_mask(masks[i], ap, version, true, dst);
399
10.9k
    }
400
5.49k
}
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
34.4k
{
428
34.4k
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
429
34.4k
    enum ofpraw raw = ofpraw_pull_assert(&b);
430
431
34.4k
    if (raw == OFPRAW_OFPT13_SET_ASYNC ||
432
34.4k
        raw == OFPRAW_NXT_SET_ASYNC_CONFIG ||
433
34.4k
        raw == OFPRAW_OFPT13_GET_ASYNC_REPLY) {
434
1.83k
        const struct nx_async_config *msg = ofpmsg_body(oh);
435
436
1.83k
        *ac = OFPUTIL_ASYNC_CFG_INIT;
437
1.83k
        decode_legacy_async_masks(msg->packet_in_mask, OAM_PACKET_IN,
438
1.83k
                                  oh->version, ac);
439
1.83k
        decode_legacy_async_masks(msg->port_status_mask, OAM_PORT_STATUS,
440
1.83k
                                  oh->version, ac);
441
1.83k
        decode_legacy_async_masks(msg->flow_removed_mask, OAM_FLOW_REMOVED,
442
1.83k
                                  oh->version, ac);
443
32.6k
    } else if (raw == OFPRAW_OFPT14_SET_ASYNC ||
444
32.6k
               raw == OFPRAW_OFPT14_GET_ASYNC_REPLY ||
445
32.6k
               raw == OFPRAW_NXT_SET_ASYNC_CONFIG2) {
446
32.6k
        *ac = *basis;
447
54.1k
        while (b.size > 0) {
448
33.4k
            struct ofpbuf property;
449
33.4k
            enum ofperr error;
450
33.4k
            uint64_t type;
451
452
33.4k
            error = ofpprop_pull__(&b, &property, 8, 0xfffe, &type);
453
33.4k
            if (error) {
454
7.33k
                return error;
455
7.33k
            }
456
457
26.1k
            const struct ofp14_async_prop *ap
458
26.1k
                = get_ofp14_async_config_prop_by_prop_type(type);
459
26.1k
            error = (ap
460
26.1k
                     ? parse_async_tlv(&property, ap, ac, oh->version, loose)
461
26.1k
                     : OFPPROP_UNKNOWN(loose, "async config", type));
462
26.1k
            if (error) {
463
                /* Most messages use OFPBPC_BAD_TYPE but async has its own (who
464
                 * knows why, it's OpenFlow. */
465
4.61k
                if (error == OFPERR_OFPBPC_BAD_TYPE) {
466
1.58k
                    error = OFPERR_OFPACFC_UNSUPPORTED;
467
1.58k
                }
468
4.61k
                return error;
469
4.61k
            }
470
26.1k
        }
471
32.6k
    } else {
472
0
        return OFPERR_OFPBRC_BAD_VERSION;
473
0
    }
474
22.4k
    return 0;
475
34.4k
}
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
11.3k
{
572
11.3k
    switch (reason) {
573
3.99k
    case OFPPR_ADD:
574
3.99k
        return "add";
575
576
3.69k
    case OFPPR_DELETE:
577
3.69k
        return "delete";
578
579
3.69k
    case OFPPR_MODIFY:
580
3.69k
        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
11.3k
    }
587
11.3k
}
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
4.57k
{
596
4.57k
    switch (reason) {
597
1.54k
    case OFPCRR_PRIMARY_REQUEST:
598
1.54k
        return "primary_request";
599
600
1.49k
    case OFPCRR_CONFIG:
601
1.49k
        return "configuration_changed";
602
603
1.53k
    case OFPCRR_EXPERIMENTER:
604
1.53k
        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
4.57k
    }
611
4.57k
}
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
6.91k
{
620
6.91k
    switch (reason) {
621
3.44k
    case OFPRFR_GROUP_MOD:
622
3.44k
        return "group_mod_request";
623
624
3.46k
    case OFPRFR_METER_MOD:
625
3.46k
        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
6.91k
    }
632
6.91k
}
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
70.1k
{
639
70.1k
    switch (type) {
640
30.7k
    case OAM_PACKET_IN:
641
30.7k
        return ofputil_packet_in_reason_to_string(reason, reasonbuf, bufsize);
642
643
11.3k
    case OAM_PORT_STATUS:
644
11.3k
        return ofp_port_reason_to_string(reason, reasonbuf, bufsize);
645
646
10.7k
    case OAM_FLOW_REMOVED:
647
10.7k
        return ofp_flow_removed_reason_to_string(reason, reasonbuf, bufsize);
648
649
4.57k
    case OAM_ROLE_STATUS:
650
4.57k
        return ofp_role_reason_to_string(reason, reasonbuf, bufsize);
651
652
5.81k
    case OAM_TABLE_STATUS:
653
5.81k
        return ofp_table_reason_to_string(reason, reasonbuf, bufsize);
654
655
6.91k
    case OAM_REQUESTFORWARD:
656
6.91k
        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
70.1k
    }
662
70.1k
}
663
664
void
665
ofputil_format_set_async_config(struct ds *string,
666
                                const struct ofputil_async_cfg *ac)
667
22.4k
{
668
67.4k
    for (int i = 0; i < 2; i++) {
669
44.9k
        ds_put_format(string, "\n %s:\n", i == 0 ? "primary" : "secondary");
670
314k
        for (uint32_t type = 0; type < OAM_N_TYPES; type++) {
671
269k
            ds_put_format(string, "%16s:",
672
269k
                          ofputil_async_msg_type_to_string(type));
673
674
269k
            uint32_t role = i == 0 ? ac->primary[type] : ac->secondary[type];
675
8.90M
            for (int j = 0; j < 32; j++) {
676
8.63M
                if (role & (1u << j)) {
677
70.1k
                    char reasonbuf[INT_STRLEN(int) + 1];
678
70.1k
                    const char *reason;
679
680
70.1k
                    reason = ofp_async_config_reason_to_string(
681
70.1k
                        j, type, reasonbuf, sizeof reasonbuf);
682
70.1k
                    if (reason[0]) {
683
64.7k
                        ds_put_format(string, " %s", reason);
684
64.7k
                    }
685
70.1k
                }
686
8.63M
            }
687
269k
            if (!role) {
688
249k
                ds_put_cstr(string, " (off)");
689
249k
            }
690
269k
            ds_put_char(string, '\n');
691
269k
        }
692
44.9k
    }
693
22.4k
}
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
}