Coverage Report

Created: 2025-07-01 06:50

/src/openvswitch/lib/ofp-port.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-port.h"
19
#include <ctype.h>
20
#include "byte-order.h"
21
#include "flow.h"
22
#include "openflow/intel-ext.h"
23
#include "openvswitch/json.h"
24
#include "openvswitch/ofp-errors.h"
25
#include "openvswitch/ofp-msgs.h"
26
#include "openvswitch/ofp-print.h"
27
#include "openvswitch/ofp-prop.h"
28
#include "openvswitch/ofpbuf.h"
29
#include "openvswitch/vlog.h"
30
31
VLOG_DEFINE_THIS_MODULE(ofp_port);
32
33
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
34
35
/* ofputil_port_map.  */
36
37
void
38
ofputil_port_map_init(struct ofputil_port_map *map)
39
0
{
40
0
    namemap_init(&map->map);
41
0
}
42
43
void
44
ofputil_port_map_put(struct ofputil_port_map *map,
45
                     ofp_port_t ofp_port, const char *name)
46
0
{
47
0
    namemap_put(&map->map, ofp_to_u16(ofp_port), name);
48
0
}
49
50
const char *
51
ofputil_port_map_get_name(const struct ofputil_port_map *map,
52
                          ofp_port_t ofp_port)
53
0
{
54
0
    struct namemap_node *node
55
0
        = (map
56
0
           ? namemap_find_by_number(&map->map, ofp_to_u16(ofp_port))
57
0
           : NULL);
58
0
    return node && !node->duplicate ? node->name : NULL;
59
0
}
60
61
ofp_port_t
62
ofputil_port_map_get_number(const struct ofputil_port_map *map,
63
                            const char *name)
64
0
{
65
0
    struct namemap_node *node
66
0
        = map ? namemap_find_by_name(&map->map, name) : NULL;
67
0
    return node && !node->duplicate ? u16_to_ofp(node->number) : OFPP_NONE;
68
0
}
69
70
void
71
ofputil_port_map_destroy(struct ofputil_port_map *map)
72
0
{
73
0
    namemap_destroy(&map->map);
74
0
}
75

76
/* Converts the OpenFlow 1.1+ port number 'ofp11_port' into an OpenFlow 1.0
77
 * port number and stores the latter in '*ofp10_port', for the purpose of
78
 * decoding OpenFlow 1.1+ protocol messages.  Returns 0 if successful,
79
 * otherwise an OFPERR_* number.  On error, stores OFPP_NONE in '*ofp10_port'.
80
 *
81
 * See the definition of OFP11_MAX for an explanation of the mapping. */
82
enum ofperr
83
ofputil_port_from_ofp11(ovs_be32 ofp11_port, ofp_port_t *ofp10_port)
84
0
{
85
0
    uint32_t ofp11_port_h = ntohl(ofp11_port);
86
87
0
    if (ofp11_port_h < ofp_to_u16(OFPP_MAX)) {
88
0
        *ofp10_port = u16_to_ofp(ofp11_port_h);
89
0
        return 0;
90
0
    } else if (ofp11_port_h >= ofp11_to_u32(OFPP11_MAX)) {
91
0
        *ofp10_port = u16_to_ofp(ofp11_port_h - OFPP11_OFFSET);
92
0
        return 0;
93
0
    } else {
94
0
        *ofp10_port = OFPP_NONE;
95
96
0
        static struct vlog_rate_limit rll = VLOG_RATE_LIMIT_INIT(1, 5);
97
0
        VLOG_WARN_RL(&rll, "port %"PRIu32" is outside the supported "
98
0
                     "range 0 through %d or 0x%"PRIx32" through 0x%"PRIx32,
99
0
                     ofp11_port_h, ofp_to_u16(OFPP_MAX) - 1,
100
0
                     ofp11_to_u32(OFPP11_MAX), UINT32_MAX);
101
102
0
        return OFPERR_OFPBAC_BAD_OUT_PORT;
103
0
    }
104
0
}
105
106
/* Returns the OpenFlow 1.1+ port number equivalent to the OpenFlow 1.0 port
107
 * number 'ofp10_port', for encoding OpenFlow 1.1+ protocol messages.
108
 *
109
 * See the definition of OFP11_MAX for an explanation of the mapping. */
110
ovs_be32
111
ofputil_port_to_ofp11(ofp_port_t ofp10_port)
112
0
{
113
0
    return htonl(ofp_to_u16(ofp10_port) < ofp_to_u16(OFPP_MAX)
114
0
                 ? ofp_to_u16(ofp10_port)
115
0
                 : ofp_to_u16(ofp10_port) + OFPP11_OFFSET);
116
0
}
117
118
#define OFPUTIL_NAMED_PORTS                     \
119
0
        OFPUTIL_NAMED_PORT(IN_PORT)             \
120
0
        OFPUTIL_NAMED_PORT(TABLE)               \
121
0
        OFPUTIL_NAMED_PORT(NORMAL)              \
122
0
        OFPUTIL_NAMED_PORT(FLOOD)               \
123
0
        OFPUTIL_NAMED_PORT(ALL)                 \
124
0
        OFPUTIL_NAMED_PORT(CONTROLLER)          \
125
0
        OFPUTIL_NAMED_PORT(LOCAL)               \
126
0
        OFPUTIL_NAMED_PORT(ANY)                 \
127
0
        OFPUTIL_NAMED_PORT(UNSET)
128
129
/* For backwards compatibility, so that "none" is recognized as OFPP_ANY */
130
#define OFPUTIL_NAMED_PORTS_WITH_NONE           \
131
0
        OFPUTIL_NAMED_PORTS                     \
132
0
        OFPUTIL_NAMED_PORT(NONE)
133
134
/* Stores the port number represented by 's' into '*portp'.  's' may be an
135
 * integer or, for reserved ports, the standard OpenFlow name for the port
136
 * (e.g. "LOCAL").  If 'port_map' is nonnull, also accepts names in it (quoted
137
 * or unquoted).
138
 *
139
 * Returns true if successful, false if 's' is not a valid OpenFlow port number
140
 * or name.  The caller should issue an error message in this case, because
141
 * this function usually does not.  (This gives the caller an opportunity to
142
 * look up the port name another way, e.g. by contacting the switch and listing
143
 * the names of all its ports).
144
 *
145
 * This function accepts OpenFlow 1.0 port numbers.  It also accepts a subset
146
 * of OpenFlow 1.1+ port numbers, mapping those port numbers into the 16-bit
147
 * range as described in include/openflow/openflow-1.1.h. */
148
bool
149
ofputil_port_from_string(const char *s,
150
                         const struct ofputil_port_map *port_map,
151
                         ofp_port_t *portp)
152
0
{
153
0
    unsigned int port32; /* int is at least 32 bits wide. */
154
155
0
    if (*s == '-') {
156
0
        VLOG_WARN("Negative value %s is not a valid port number.", s);
157
0
        return false;
158
0
    }
159
0
    *portp = 0;
160
0
    if (str_to_uint(s, 10, &port32)) {
161
0
        if (port32 < ofp_to_u16(OFPP_MAX)) {
162
            /* Pass. */
163
0
        } else if (port32 < ofp_to_u16(OFPP_FIRST_RESV)) {
164
0
            VLOG_WARN("port %u is a reserved OF1.0 port number that will "
165
0
                      "be translated to %u when talking to an OF1.1 or "
166
0
                      "later controller", port32, port32 + OFPP11_OFFSET);
167
0
        } else if (port32 <= ofp_to_u16(OFPP_LAST_RESV)) {
168
0
            char name[OFP_MAX_PORT_NAME_LEN];
169
170
0
            ofputil_port_to_string(u16_to_ofp(port32), NULL,
171
0
                                   name, sizeof name);
172
0
            VLOG_WARN_ONCE("referring to port %s as %"PRIu32" is deprecated "
173
0
                           "for compatibility with OpenFlow 1.1 and later",
174
0
                           name, port32);
175
0
        } else if (port32 < ofp11_to_u32(OFPP11_MAX)) {
176
0
            VLOG_WARN("port %u is outside the supported range 0 through "
177
0
                      "%x or 0x%x through 0x%"PRIx32, port32,
178
0
                      UINT16_MAX, ofp11_to_u32(OFPP11_MAX), UINT32_MAX);
179
0
            return false;
180
0
        } else {
181
0
            port32 -= OFPP11_OFFSET;
182
0
        }
183
184
0
        *portp = u16_to_ofp(port32);
185
0
        return true;
186
0
    } else {
187
0
        struct pair {
188
0
            const char *name;
189
0
            ofp_port_t value;
190
0
        };
191
0
        static const struct pair pairs[] = {
192
0
#define OFPUTIL_NAMED_PORT(NAME) {#NAME, OFPP_##NAME},
193
0
            OFPUTIL_NAMED_PORTS_WITH_NONE
194
0
#undef OFPUTIL_NAMED_PORT
195
0
        };
196
0
        const struct pair *p;
197
198
0
        for (p = pairs; p < &pairs[ARRAY_SIZE(pairs)]; p++) {
199
0
            if (!strcasecmp(s, p->name)) {
200
0
                *portp = p->value;
201
0
                return true;
202
0
            }
203
0
        }
204
205
0
        ofp_port_t ofp_port = OFPP_NONE;
206
0
        if (s[0] != '"') {
207
0
            ofp_port = ofputil_port_map_get_number(port_map, s);
208
0
        } else {
209
0
            size_t length = strlen(s);
210
0
            char *name = NULL;
211
0
            if (length > 1
212
0
                && s[length - 1] == '"'
213
0
                && json_string_unescape(s + 1, length - 2, &name)) {
214
0
                ofp_port = ofputil_port_map_get_number(port_map, name);
215
0
            }
216
0
            free(name);
217
0
        }
218
0
        if (ofp_port != OFPP_NONE) {
219
0
            *portp = ofp_port;
220
0
            return true;
221
0
        }
222
223
0
        return false;
224
0
    }
225
0
}
226
227
const char *
228
ofputil_port_get_reserved_name(ofp_port_t port)
229
0
{
230
0
    switch (port) {
231
0
#define OFPUTIL_NAMED_PORT(NAME) case OFPP_##NAME: return #NAME;
232
0
        OFPUTIL_NAMED_PORTS
233
0
#undef OFPUTIL_NAMED_PORT
234
235
0
    default:
236
0
        return NULL;
237
0
    }
238
0
}
239
240
/* Appends to 's' a string representation of the OpenFlow port number 'port'.
241
 * Most ports' string representation is just the port number, but for special
242
 * ports, e.g. OFPP_LOCAL, it is the name, e.g. "LOCAL". */
243
void
244
ofputil_format_port(ofp_port_t port, const struct ofputil_port_map *port_map,
245
                    struct ds *s)
246
0
{
247
0
    const char *reserved_name = ofputil_port_get_reserved_name(port);
248
0
    if (reserved_name) {
249
0
        ds_put_cstr(s, reserved_name);
250
0
        return;
251
0
    }
252
253
0
    const char *port_name = ofputil_port_map_get_name(port_map, port);
254
0
    if (port_name) {
255
0
        namemap_put_name(port_name, s);
256
0
        return;
257
0
    }
258
259
0
    ds_put_format(s, "%"PRIu32, port);
260
0
}
261
262
/* Puts in the 'bufsize' byte in 'namebuf' a null-terminated string
263
 * representation of OpenFlow port number 'port'.  Most ports are represented
264
 * as just the port number, but special ports, e.g. OFPP_LOCAL, are represented
265
 * by name, e.g. "LOCAL". */
266
void
267
ofputil_port_to_string(ofp_port_t port,
268
                       const struct ofputil_port_map *port_map,
269
                       char *namebuf, size_t bufsize)
270
0
{
271
0
    const char *reserved_name = ofputil_port_get_reserved_name(port);
272
0
    if (reserved_name) {
273
0
        ovs_strlcpy(namebuf, reserved_name, bufsize);
274
0
        return;
275
0
    }
276
277
0
    const char *port_name = ofputil_port_map_get_name(port_map, port);
278
0
    if (port_name) {
279
0
        struct ds s = DS_EMPTY_INITIALIZER;
280
0
        namemap_put_name(port_name, &s);
281
0
        ovs_strlcpy(namebuf, ds_cstr(&s), bufsize);
282
0
        ds_destroy(&s);
283
0
        return;
284
0
    }
285
286
0
    snprintf(namebuf, bufsize, "%"PRIu32, port);
287
0
}
288

289
/* ofputil_port_config */
290
291
static const char *
292
ofputil_port_config_to_name(uint32_t bit)
293
0
{
294
0
    enum ofputil_port_config pc = bit;
295
296
0
    switch (pc) {
297
0
    case OFPUTIL_PC_PORT_DOWN:    return "PORT_DOWN";
298
0
    case OFPUTIL_PC_NO_STP:       return "NO_STP";
299
0
    case OFPUTIL_PC_NO_RECV:      return "NO_RECV";
300
0
    case OFPUTIL_PC_NO_RECV_STP:  return "NO_RECV_STP";
301
0
    case OFPUTIL_PC_NO_FLOOD:     return "NO_FLOOD";
302
0
    case OFPUTIL_PC_NO_FWD:       return "NO_FWD";
303
0
    case OFPUTIL_PC_NO_PACKET_IN: return "NO_PACKET_IN";
304
0
    }
305
306
0
    return NULL;
307
0
}
308
309
void
310
ofputil_port_config_format(struct ds *s, enum ofputil_port_config config)
311
0
{
312
0
    ofp_print_bit_names(s, config, ofputil_port_config_to_name, ' ');
313
0
    ds_put_char(s, '\n');
314
0
}
315

316
/* ofputil_port_state */
317
318
static const char *
319
ofputil_port_state_to_name(uint32_t bit)
320
0
{
321
0
    enum ofputil_port_state ps = bit;
322
323
0
    switch (ps) {
324
0
    case OFPUTIL_PS_LINK_DOWN: return "LINK_DOWN";
325
0
    case OFPUTIL_PS_BLOCKED:   return "BLOCKED";
326
0
    case OFPUTIL_PS_LIVE:      return "LIVE";
327
328
0
    case OFPUTIL_PS_STP_LISTEN:
329
0
    case OFPUTIL_PS_STP_LEARN:
330
0
    case OFPUTIL_PS_STP_FORWARD:
331
0
    case OFPUTIL_PS_STP_BLOCK:
332
        /* Handled elsewhere. */
333
0
        return NULL;
334
0
    }
335
336
0
    return NULL;
337
0
}
338
339
void
340
ofputil_port_state_format(struct ds *s, enum ofputil_port_state state)
341
0
{
342
0
    enum ofputil_port_state stp_state;
343
344
    /* The STP state is a 2-bit field so it doesn't fit in with the bitmask
345
     * pattern.  We have to special case it.
346
     *
347
     * OVS doesn't support STP, so this field will always be 0 if we are
348
     * talking to OVS, so we'd always print STP_LISTEN in that case.
349
     * Therefore, we don't print anything at all if the value is STP_LISTEN, to
350
     * avoid confusing users. */
351
0
    stp_state = state & OFPUTIL_PS_STP_MASK;
352
0
    if (stp_state) {
353
0
        ds_put_cstr(s, (stp_state == OFPUTIL_PS_STP_LEARN ? "STP_LEARN"
354
0
                        : stp_state == OFPUTIL_PS_STP_FORWARD ? "STP_FORWARD"
355
0
                        : "STP_BLOCK"));
356
0
        state &= ~OFPUTIL_PS_STP_MASK;
357
0
        if (state) {
358
0
            ofp_print_bit_names(s, state, ofputil_port_state_to_name, ' ');
359
0
        }
360
0
    } else {
361
0
        ofp_print_bit_names(s, state, ofputil_port_state_to_name, ' ');
362
0
    }
363
0
    ds_put_char(s, '\n');
364
0
}
365

366
/* ofputil_phy_port */
367
368
/* NETDEV_F_* to and from OFPPF_* and OFPPF10_*. */
369
BUILD_ASSERT_DECL((int) NETDEV_F_10MB_HD    == OFPPF_10MB_HD);  /* bit 0 */
370
BUILD_ASSERT_DECL((int) NETDEV_F_10MB_FD    == OFPPF_10MB_FD);  /* bit 1 */
371
BUILD_ASSERT_DECL((int) NETDEV_F_100MB_HD   == OFPPF_100MB_HD); /* bit 2 */
372
BUILD_ASSERT_DECL((int) NETDEV_F_100MB_FD   == OFPPF_100MB_FD); /* bit 3 */
373
BUILD_ASSERT_DECL((int) NETDEV_F_1GB_HD     == OFPPF_1GB_HD);   /* bit 4 */
374
BUILD_ASSERT_DECL((int) NETDEV_F_1GB_FD     == OFPPF_1GB_FD);   /* bit 5 */
375
BUILD_ASSERT_DECL((int) NETDEV_F_10GB_FD    == OFPPF_10GB_FD);  /* bit 6 */
376
377
/* NETDEV_F_ bits 11...15 are OFPPF10_ bits 7...11: */
378
BUILD_ASSERT_DECL((int) NETDEV_F_COPPER == (OFPPF10_COPPER << 4));
379
BUILD_ASSERT_DECL((int) NETDEV_F_FIBER == (OFPPF10_FIBER << 4));
380
BUILD_ASSERT_DECL((int) NETDEV_F_AUTONEG == (OFPPF10_AUTONEG << 4));
381
BUILD_ASSERT_DECL((int) NETDEV_F_PAUSE == (OFPPF10_PAUSE << 4));
382
BUILD_ASSERT_DECL((int) NETDEV_F_PAUSE_ASYM == (OFPPF10_PAUSE_ASYM << 4));
383
384
static enum netdev_features
385
netdev_port_features_from_ofp10(ovs_be32 ofp10_)
386
0
{
387
0
    uint32_t ofp10 = ntohl(ofp10_);
388
0
    return (ofp10 & 0x7f) | ((ofp10 & 0xf80) << 4);
389
0
}
390
391
static ovs_be32
392
netdev_port_features_to_ofp10(enum netdev_features features)
393
0
{
394
0
    return htonl((features & 0x7f) | ((features & 0xf800) >> 4));
395
0
}
396
397
BUILD_ASSERT_DECL((int) NETDEV_F_10MB_HD    == OFPPF_10MB_HD);     /* bit 0 */
398
BUILD_ASSERT_DECL((int) NETDEV_F_10MB_FD    == OFPPF_10MB_FD);     /* bit 1 */
399
BUILD_ASSERT_DECL((int) NETDEV_F_100MB_HD   == OFPPF_100MB_HD);    /* bit 2 */
400
BUILD_ASSERT_DECL((int) NETDEV_F_100MB_FD   == OFPPF_100MB_FD);    /* bit 3 */
401
BUILD_ASSERT_DECL((int) NETDEV_F_1GB_HD     == OFPPF_1GB_HD);      /* bit 4 */
402
BUILD_ASSERT_DECL((int) NETDEV_F_1GB_FD     == OFPPF_1GB_FD);      /* bit 5 */
403
BUILD_ASSERT_DECL((int) NETDEV_F_10GB_FD    == OFPPF_10GB_FD);     /* bit 6 */
404
BUILD_ASSERT_DECL((int) NETDEV_F_40GB_FD    == OFPPF11_40GB_FD);   /* bit 7 */
405
BUILD_ASSERT_DECL((int) NETDEV_F_100GB_FD   == OFPPF11_100GB_FD);  /* bit 8 */
406
BUILD_ASSERT_DECL((int) NETDEV_F_1TB_FD     == OFPPF11_1TB_FD);    /* bit 9 */
407
BUILD_ASSERT_DECL((int) NETDEV_F_OTHER      == OFPPF11_OTHER);     /* bit 10 */
408
BUILD_ASSERT_DECL((int) NETDEV_F_COPPER     == OFPPF11_COPPER);    /* bit 11 */
409
BUILD_ASSERT_DECL((int) NETDEV_F_FIBER      == OFPPF11_FIBER);     /* bit 12 */
410
BUILD_ASSERT_DECL((int) NETDEV_F_AUTONEG    == OFPPF11_AUTONEG);   /* bit 13 */
411
BUILD_ASSERT_DECL((int) NETDEV_F_PAUSE      == OFPPF11_PAUSE);     /* bit 14 */
412
BUILD_ASSERT_DECL((int) NETDEV_F_PAUSE_ASYM == OFPPF11_PAUSE_ASYM);/* bit 15 */
413
414
static enum netdev_features
415
netdev_port_features_from_ofp11(ovs_be32 ofp11)
416
0
{
417
0
    return ntohl(ofp11) & 0xffff;
418
0
}
419
420
static ovs_be32
421
netdev_port_features_to_ofp11(enum netdev_features features)
422
0
{
423
0
    return htonl(features & 0xffff);
424
0
}
425
426
static enum ofperr
427
ofputil_decode_ofp10_phy_port(struct ofputil_phy_port *pp,
428
                              const struct ofp10_phy_port *opp)
429
0
{
430
0
    pp->port_no = u16_to_ofp(ntohs(opp->port_no));
431
0
    pp->hw_addr = opp->hw_addr;
432
0
    ovs_strlcpy_arrays(pp->name, opp->name);
433
434
0
    pp->config = ntohl(opp->config) & OFPPC10_ALL;
435
0
    pp->state = ntohl(opp->state) & OFPPS10_ALL;
436
437
0
    pp->curr = netdev_port_features_from_ofp10(opp->curr);
438
0
    pp->advertised = netdev_port_features_from_ofp10(opp->advertised);
439
0
    pp->supported = netdev_port_features_from_ofp10(opp->supported);
440
0
    pp->peer = netdev_port_features_from_ofp10(opp->peer);
441
442
0
    pp->curr_speed = netdev_features_to_bps(pp->curr, 0) / 1000;
443
0
    pp->max_speed = netdev_features_to_bps(pp->supported, 0) / 1000;
444
445
0
    return 0;
446
0
}
447
448
static enum ofperr
449
ofputil_decode_ofp11_port(struct ofputil_phy_port *pp,
450
                          const struct ofp11_port *op)
451
0
{
452
0
    enum ofperr error;
453
454
0
    error = ofputil_port_from_ofp11(op->port_no, &pp->port_no);
455
0
    if (error) {
456
0
        return error;
457
0
    }
458
0
    pp->hw_addr = op->hw_addr;
459
0
    ovs_strlcpy_arrays(pp->name, op->name);
460
461
0
    pp->config = ntohl(op->config) & OFPPC11_ALL;
462
0
    pp->state = ntohl(op->state) & OFPPS11_ALL;
463
464
0
    pp->curr = netdev_port_features_from_ofp11(op->curr);
465
0
    pp->advertised = netdev_port_features_from_ofp11(op->advertised);
466
0
    pp->supported = netdev_port_features_from_ofp11(op->supported);
467
0
    pp->peer = netdev_port_features_from_ofp11(op->peer);
468
469
0
    pp->curr_speed = ntohl(op->curr_speed);
470
0
    pp->max_speed = ntohl(op->max_speed);
471
472
0
    return 0;
473
0
}
474
475
static enum ofperr
476
parse_ofp14_port_ethernet_property(const struct ofpbuf *payload,
477
                                   struct ofputil_phy_port *pp)
478
0
{
479
0
    struct ofp14_port_desc_prop_ethernet *eth = payload->data;
480
481
0
    if (payload->size != sizeof *eth) {
482
0
        return OFPERR_OFPBPC_BAD_LEN;
483
0
    }
484
485
0
    pp->curr = netdev_port_features_from_ofp11(eth->curr);
486
0
    pp->advertised = netdev_port_features_from_ofp11(eth->advertised);
487
0
    pp->supported = netdev_port_features_from_ofp11(eth->supported);
488
0
    pp->peer = netdev_port_features_from_ofp11(eth->peer);
489
490
0
    pp->curr_speed = ntohl(eth->curr_speed);
491
0
    pp->max_speed = ntohl(eth->max_speed);
492
493
0
    return 0;
494
0
}
495
496
static enum ofperr
497
ofputil_pull_ofp14_port_properties(const void *props, size_t len,
498
                                   struct ofputil_phy_port *pp)
499
0
{
500
0
    struct ofpbuf properties = ofpbuf_const_initializer(props, len);
501
0
    while (properties.size > 0) {
502
0
        struct ofpbuf payload;
503
0
        enum ofperr error;
504
0
        uint64_t type;
505
506
0
        error = ofpprop_pull(&properties, &payload, &type);
507
0
        if (error) {
508
0
            return error;
509
0
        }
510
511
0
        switch (type) {
512
0
        case OFPPDPT14_ETHERNET:
513
0
            error = parse_ofp14_port_ethernet_property(&payload, pp);
514
0
            break;
515
516
0
        default:
517
0
            error = OFPPROP_UNKNOWN(true, "port", type);
518
0
            break;
519
0
        }
520
521
0
        if (error) {
522
0
            return error;
523
0
        }
524
0
    }
525
526
0
    return 0;
527
0
}
528
529
static enum ofperr
530
ofputil_pull_ofp14_port(struct ofputil_phy_port *pp, struct ofpbuf *msg)
531
0
{
532
0
    const struct ofp14_port *op = ofpbuf_try_pull(msg, sizeof *op);
533
0
    if (!op) {
534
0
        return OFPERR_OFPBRC_BAD_LEN;
535
0
    }
536
537
0
    size_t len = ntohs(op->length);
538
0
    if (len < sizeof *op || len - sizeof *op > msg->size) {
539
0
        return OFPERR_OFPBRC_BAD_LEN;
540
0
    }
541
0
    len -= sizeof *op;
542
543
0
    enum ofperr error = ofputil_port_from_ofp11(op->port_no, &pp->port_no);
544
0
    if (error) {
545
0
        return error;
546
0
    }
547
0
    pp->hw_addr = op->hw_addr;
548
0
    ovs_strlcpy_arrays(pp->name, op->name);
549
550
0
    pp->config = ntohl(op->config) & OFPPC11_ALL;
551
0
    pp->state = ntohl(op->state) & OFPPS11_ALL;
552
553
0
    return ofputil_pull_ofp14_port_properties(ofpbuf_pull(msg, len), len, pp);
554
0
}
555
556
static void
557
ofputil_encode_ofp10_phy_port(const struct ofputil_phy_port *pp,
558
                              struct ofp10_phy_port *opp)
559
0
{
560
0
    memset(opp, 0, sizeof *opp);
561
562
0
    opp->port_no = htons(ofp_to_u16(pp->port_no));
563
0
    opp->hw_addr = pp->hw_addr;
564
0
    ovs_strlcpy_arrays(opp->name, pp->name);
565
566
0
    opp->config = htonl(pp->config & OFPPC10_ALL);
567
0
    opp->state = htonl(pp->state & OFPPS10_ALL);
568
569
0
    opp->curr = netdev_port_features_to_ofp10(pp->curr);
570
0
    opp->advertised = netdev_port_features_to_ofp10(pp->advertised);
571
0
    opp->supported = netdev_port_features_to_ofp10(pp->supported);
572
0
    opp->peer = netdev_port_features_to_ofp10(pp->peer);
573
0
}
574
575
static void
576
ofputil_encode_ofp11_port(const struct ofputil_phy_port *pp,
577
                          struct ofp11_port *op)
578
0
{
579
0
    memset(op, 0, sizeof *op);
580
581
0
    op->port_no = ofputil_port_to_ofp11(pp->port_no);
582
0
    op->hw_addr = pp->hw_addr;
583
0
    ovs_strlcpy_arrays(op->name, pp->name);
584
585
0
    op->config = htonl(pp->config & OFPPC11_ALL);
586
0
    op->state = htonl(pp->state & OFPPS11_ALL);
587
588
0
    op->curr = netdev_port_features_to_ofp11(pp->curr);
589
0
    op->advertised = netdev_port_features_to_ofp11(pp->advertised);
590
0
    op->supported = netdev_port_features_to_ofp11(pp->supported);
591
0
    op->peer = netdev_port_features_to_ofp11(pp->peer);
592
593
0
    op->curr_speed = htonl(pp->curr_speed);
594
0
    op->max_speed = htonl(pp->max_speed);
595
0
}
596
597
static void
598
ofputil_encode_ofp14_port_ethernet_prop(
599
    const struct ofputil_phy_port *pp,
600
    struct ofp14_port_desc_prop_ethernet *eth)
601
0
{
602
0
    eth->curr = netdev_port_features_to_ofp11(pp->curr);
603
0
    eth->advertised = netdev_port_features_to_ofp11(pp->advertised);
604
0
    eth->supported = netdev_port_features_to_ofp11(pp->supported);
605
0
    eth->peer = netdev_port_features_to_ofp11(pp->peer);
606
0
    eth->curr_speed = htonl(pp->curr_speed);
607
0
    eth->max_speed = htonl(pp->max_speed);
608
0
}
609
610
static void
611
ofputil_put_ofp14_port(const struct ofputil_phy_port *pp, struct ofpbuf *b)
612
0
{
613
0
    struct ofp14_port *op;
614
0
    struct ofp14_port_desc_prop_ethernet *eth;
615
616
0
    ofpbuf_prealloc_tailroom(b, sizeof *op + sizeof *eth);
617
618
0
    op = ofpbuf_put_zeros(b, sizeof *op);
619
0
    op->port_no = ofputil_port_to_ofp11(pp->port_no);
620
0
    op->length = htons(sizeof *op + sizeof *eth);
621
0
    op->hw_addr = pp->hw_addr;
622
0
    ovs_strlcpy_arrays(op->name, pp->name);
623
0
    op->config = htonl(pp->config & OFPPC11_ALL);
624
0
    op->state = htonl(pp->state & OFPPS11_ALL);
625
626
0
    eth = ofpprop_put_zeros(b, OFPPDPT14_ETHERNET, sizeof *eth);
627
0
    ofputil_encode_ofp14_port_ethernet_prop(pp, eth);
628
0
}
629
630
void
631
ofputil_put_phy_port(enum ofp_version ofp_version,
632
                     const struct ofputil_phy_port *pp, struct ofpbuf *b)
633
0
{
634
0
    switch (ofp_version) {
635
0
    case OFP10_VERSION: {
636
0
        struct ofp10_phy_port *opp = ofpbuf_put_uninit(b, sizeof *opp);
637
0
        ofputil_encode_ofp10_phy_port(pp, opp);
638
0
        break;
639
0
    }
640
641
0
    case OFP11_VERSION:
642
0
    case OFP12_VERSION:
643
0
    case OFP13_VERSION: {
644
0
        struct ofp11_port *op = ofpbuf_put_uninit(b, sizeof *op);
645
0
        ofputil_encode_ofp11_port(pp, op);
646
0
        break;
647
0
    }
648
649
0
    case OFP14_VERSION:
650
0
    case OFP15_VERSION:
651
0
        ofputil_put_ofp14_port(pp, b);
652
0
        break;
653
654
0
    default:
655
0
        OVS_NOT_REACHED();
656
0
    }
657
0
}
658
659
enum ofperr
660
ofputil_decode_port_desc_stats_request(const struct ofp_header *request,
661
                                       ofp_port_t *port)
662
0
{
663
0
    struct ofpbuf b = ofpbuf_const_initializer(request,
664
0
                                               ntohs(request->length));
665
0
    enum ofpraw raw = ofpraw_pull_assert(&b);
666
0
    if (raw == OFPRAW_OFPST10_PORT_DESC_REQUEST) {
667
0
        *port = OFPP_ANY;
668
0
        return 0;
669
0
    } else if (raw == OFPRAW_OFPST15_PORT_DESC_REQUEST) {
670
0
        ovs_be32 *ofp11_port;
671
672
0
        ofp11_port = ofpbuf_pull(&b, sizeof *ofp11_port);
673
0
        return ofputil_port_from_ofp11(*ofp11_port, port);
674
0
    } else {
675
0
        OVS_NOT_REACHED();
676
0
    }
677
0
}
678
679
struct ofpbuf *
680
ofputil_encode_port_desc_stats_request(enum ofp_version ofp_version,
681
                                       ofp_port_t port)
682
0
{
683
0
    struct ofpbuf *request;
684
685
0
    switch (ofp_version) {
686
0
    case OFP10_VERSION:
687
0
    case OFP11_VERSION:
688
0
    case OFP12_VERSION:
689
0
    case OFP13_VERSION:
690
0
    case OFP14_VERSION:
691
0
        request = ofpraw_alloc(OFPRAW_OFPST10_PORT_DESC_REQUEST,
692
0
                               ofp_version, 0);
693
0
        break;
694
0
    case OFP15_VERSION: {
695
0
        struct ofp15_port_desc_request *req;
696
0
        request = ofpraw_alloc(OFPRAW_OFPST15_PORT_DESC_REQUEST,
697
0
                               ofp_version, 0);
698
0
        req = ofpbuf_put_zeros(request, sizeof *req);
699
0
        req->port_no = ofputil_port_to_ofp11(port);
700
0
        break;
701
0
    }
702
0
    default:
703
0
        OVS_NOT_REACHED();
704
0
    }
705
706
0
    return request;
707
0
}
708
709
void
710
ofputil_append_port_desc_stats_reply(const struct ofputil_phy_port *pp,
711
                                     struct ovs_list *replies)
712
0
{
713
0
    struct ofpbuf *reply = ofpbuf_from_list(ovs_list_back(replies));
714
0
    size_t start_ofs = reply->size;
715
716
0
    ofputil_put_phy_port(ofpmp_version(replies), pp, reply);
717
0
    ofpmp_postappend(replies, start_ofs);
718
0
}
719
720
/* Given a buffer 'b' that contains an array of OpenFlow ports of type
721
 * 'ofp_version', tries to pull the first element from the array.  If
722
 * successful, initializes '*pp' with an abstract representation of the
723
 * port and returns 0.  If no ports remain to be decoded, returns EOF.
724
 * On an error, returns a positive OFPERR_* value. */
725
int
726
ofputil_pull_phy_port(enum ofp_version ofp_version, struct ofpbuf *b,
727
                      struct ofputil_phy_port *pp)
728
0
{
729
0
    memset(pp, 0, sizeof *pp);
730
731
0
    switch (ofp_version) {
732
0
    case OFP10_VERSION: {
733
0
        const struct ofp10_phy_port *opp = ofpbuf_try_pull(b, sizeof *opp);
734
0
        return opp ? ofputil_decode_ofp10_phy_port(pp, opp) : EOF;
735
0
    }
736
0
    case OFP11_VERSION:
737
0
    case OFP12_VERSION:
738
0
    case OFP13_VERSION: {
739
0
        const struct ofp11_port *op = ofpbuf_try_pull(b, sizeof *op);
740
0
        return op ? ofputil_decode_ofp11_port(pp, op) : EOF;
741
0
    }
742
0
    case OFP14_VERSION:
743
0
    case OFP15_VERSION:
744
0
        return b->size ? ofputil_pull_ofp14_port(pp, b) : EOF;
745
0
    default:
746
0
        OVS_NOT_REACHED();
747
0
    }
748
0
}
749
750
void
751
ofputil_phy_port_format(struct ds *s, const struct ofputil_phy_port *port)
752
0
{
753
0
    char name[sizeof port->name];
754
0
    int j;
755
756
0
    memcpy(name, port->name, sizeof name);
757
0
    for (j = 0; j < sizeof name - 1; j++) {
758
0
        if (!isprint((unsigned char) name[j])) {
759
0
            break;
760
0
        }
761
0
    }
762
0
    name[j] = '\0';
763
764
0
    ds_put_char(s, ' ');
765
0
    ofputil_format_port(port->port_no, NULL, s);
766
0
    ds_put_format(s, "(%s): addr:"ETH_ADDR_FMT"\n",
767
0
                  name, ETH_ADDR_ARGS(port->hw_addr));
768
769
0
    ds_put_cstr(s, "     config:     ");
770
0
    ofputil_port_config_format(s, port->config);
771
772
0
    ds_put_cstr(s, "     state:      ");
773
0
    ofputil_port_state_format(s, port->state);
774
775
0
    if (port->curr) {
776
0
        ds_put_format(s, "     current:    ");
777
0
        netdev_features_format(s, port->curr);
778
0
    }
779
0
    if (port->advertised) {
780
0
        ds_put_format(s, "     advertised: ");
781
0
        netdev_features_format(s, port->advertised);
782
0
    }
783
0
    if (port->supported) {
784
0
        ds_put_format(s, "     supported:  ");
785
0
        netdev_features_format(s, port->supported);
786
0
    }
787
0
    if (port->peer) {
788
0
        ds_put_format(s, "     peer:       ");
789
0
        netdev_features_format(s, port->peer);
790
0
    }
791
0
    ds_put_format(s, "     speed: %"PRIu32" Mbps now, "
792
0
                  "%"PRIu32" Mbps max\n",
793
0
                  port->curr_speed / UINT32_C(1000),
794
0
                  port->max_speed / UINT32_C(1000));
795
0
}
796
797
/* qsort comparison function. */
798
static int
799
compare_ports(const void *a_, const void *b_)
800
0
{
801
0
    const struct ofputil_phy_port *a = a_;
802
0
    const struct ofputil_phy_port *b = b_;
803
0
    uint16_t ap = ofp_to_u16(a->port_no);
804
0
    uint16_t bp = ofp_to_u16(b->port_no);
805
806
0
    return ap < bp ? -1 : ap > bp;
807
0
}
808
809
/* Given a buffer 'b' that contains an array of OpenFlow ports of type
810
 * 'ofp_version', writes a detailed description of each port into 'string'. */
811
enum ofperr
812
ofputil_phy_ports_format(struct ds *string, uint8_t ofp_version,
813
                         struct ofpbuf *b)
814
0
{
815
0
    struct ofputil_phy_port *ports;
816
0
    size_t allocated_ports, n_ports;
817
0
    int retval;
818
0
    size_t i;
819
820
0
    ports = NULL;
821
0
    allocated_ports = 0;
822
0
    for (n_ports = 0; ; n_ports++) {
823
0
        if (n_ports >= allocated_ports) {
824
0
            ports = x2nrealloc(ports, &allocated_ports, sizeof *ports);
825
0
        }
826
827
0
        retval = ofputil_pull_phy_port(ofp_version, b, &ports[n_ports]);
828
0
        if (retval) {
829
0
            break;
830
0
        }
831
0
    }
832
833
0
    qsort(ports, n_ports, sizeof *ports, compare_ports);
834
0
    for (i = 0; i < n_ports; i++) {
835
0
        ofputil_phy_port_format(string, &ports[i]);
836
0
    }
837
0
    free(ports);
838
839
0
    return retval != EOF ? retval : 0;
840
0
}
841

842
/* ofputil_port_status */
843
844
/* Decodes the OpenFlow "port status" message in '*ops' into an abstract form
845
 * in '*ps'.  Returns 0 if successful, otherwise an OFPERR_* value. */
846
enum ofperr
847
ofputil_decode_port_status(const struct ofp_header *oh,
848
                           struct ofputil_port_status *ps)
849
0
{
850
0
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
851
0
    ofpraw_pull_assert(&b);
852
853
0
    const struct ofp_port_status *ops = ofpbuf_pull(&b, sizeof *ops);
854
0
    if (ops->reason != OFPPR_ADD &&
855
0
        ops->reason != OFPPR_DELETE &&
856
0
        ops->reason != OFPPR_MODIFY) {
857
0
        return OFPERR_NXBRC_BAD_REASON;
858
0
    }
859
0
    ps->reason = ops->reason;
860
861
0
    int retval = ofputil_pull_phy_port(oh->version, &b, &ps->desc);
862
0
    ovs_assert(retval != EOF);
863
0
    return retval;
864
0
}
865
866
/* Converts the abstract form of a "port status" message in '*ps' into an
867
 * OpenFlow message suitable for 'protocol', and returns that encoded form in
868
 * a buffer owned by the caller. */
869
struct ofpbuf *
870
ofputil_encode_port_status(const struct ofputil_port_status *ps,
871
                           enum ofputil_protocol protocol)
872
0
{
873
0
    struct ofp_port_status *ops;
874
0
    struct ofpbuf *b;
875
0
    enum ofp_version version;
876
0
    enum ofpraw raw;
877
878
0
    version = ofputil_protocol_to_ofp_version(protocol);
879
0
    switch (version) {
880
0
    case OFP10_VERSION:
881
0
        raw = OFPRAW_OFPT10_PORT_STATUS;
882
0
        break;
883
884
0
    case OFP11_VERSION:
885
0
    case OFP12_VERSION:
886
0
    case OFP13_VERSION:
887
0
        raw = OFPRAW_OFPT11_PORT_STATUS;
888
0
        break;
889
890
0
    case OFP14_VERSION:
891
0
    case OFP15_VERSION:
892
0
        raw = OFPRAW_OFPT14_PORT_STATUS;
893
0
        break;
894
895
0
    default:
896
0
        OVS_NOT_REACHED();
897
0
    }
898
899
0
    b = ofpraw_alloc_xid(raw, version, htonl(0), 0);
900
0
    ops = ofpbuf_put_zeros(b, sizeof *ops);
901
0
    ops->reason = ps->reason;
902
0
    ofputil_put_phy_port(version, &ps->desc, b);
903
0
    ofpmsg_update_length(b);
904
0
    return b;
905
0
}
906
907
void
908
ofputil_port_status_format(struct ds *s,
909
                           const struct ofputil_port_status *ps)
910
0
{
911
0
    if (ps->reason == OFPPR_ADD) {
912
0
        ds_put_format(s, " ADD:");
913
0
    } else if (ps->reason == OFPPR_DELETE) {
914
0
        ds_put_format(s, " DEL:");
915
0
    } else if (ps->reason == OFPPR_MODIFY) {
916
0
        ds_put_format(s, " MOD:");
917
0
    }
918
919
0
    ofputil_phy_port_format(s, &ps->desc);
920
0
}
921

922
/* ofputil_port_mod */
923
924
static enum ofperr
925
parse_port_mod_ethernet_property(struct ofpbuf *property,
926
                                 struct ofputil_port_mod *pm)
927
0
{
928
0
    ovs_be32 advertise;
929
0
    enum ofperr error;
930
931
0
    error = ofpprop_parse_be32(property, &advertise);
932
0
    if (!error) {
933
0
        pm->advertise = netdev_port_features_from_ofp11(advertise);
934
0
    }
935
0
    return error;
936
0
}
937
938
static enum ofperr
939
ofputil_decode_ofp10_port_mod(const struct ofp10_port_mod *opm,
940
                              struct ofputil_port_mod *pm)
941
0
{
942
0
    pm->port_no = u16_to_ofp(ntohs(opm->port_no));
943
0
    pm->hw_addr = opm->hw_addr;
944
0
    pm->config = ntohl(opm->config) & OFPPC10_ALL;
945
0
    pm->mask = ntohl(opm->mask) & OFPPC10_ALL;
946
0
    pm->advertise = netdev_port_features_from_ofp10(opm->advertise);
947
0
    return 0;
948
0
}
949
950
static enum ofperr
951
ofputil_decode_ofp11_port_mod(const struct ofp11_port_mod *opm,
952
                              struct ofputil_port_mod *pm)
953
0
{
954
0
    enum ofperr error;
955
956
0
    error = ofputil_port_from_ofp11(opm->port_no, &pm->port_no);
957
0
    if (error) {
958
0
        return error;
959
0
    }
960
961
0
    pm->hw_addr = opm->hw_addr;
962
0
    pm->config = ntohl(opm->config) & OFPPC11_ALL;
963
0
    pm->mask = ntohl(opm->mask) & OFPPC11_ALL;
964
0
    pm->advertise = netdev_port_features_from_ofp11(opm->advertise);
965
966
0
    return 0;
967
0
}
968
969
static enum ofperr
970
ofputil_decode_ofp14_port_mod_properties(struct ofpbuf *b, bool loose,
971
                                         struct ofputil_port_mod *pm)
972
0
{
973
0
    while (b->size > 0) {
974
0
        struct ofpbuf property;
975
0
        enum ofperr error;
976
0
        uint64_t type;
977
978
0
        error = ofpprop_pull(b, &property, &type);
979
0
        if (error) {
980
0
            return error;
981
0
        }
982
983
0
        switch (type) {
984
0
        case OFPPMPT14_ETHERNET:
985
0
            error = parse_port_mod_ethernet_property(&property, pm);
986
0
            break;
987
988
0
        default:
989
0
            error = OFPPROP_UNKNOWN(loose, "port_mod", type);
990
0
            break;
991
0
        }
992
993
0
        if (error) {
994
0
            return error;
995
0
        }
996
0
    }
997
0
    return 0;
998
0
}
999
1000
static enum ofperr
1001
ofputil_decode_ofp14_port_mod(struct ofpbuf *b, bool loose,
1002
                              struct ofputil_port_mod *pm)
1003
0
{
1004
0
    const struct ofp14_port_mod *opm = ofpbuf_pull(b, sizeof *opm);
1005
0
    enum ofperr error = ofputil_port_from_ofp11(opm->port_no, &pm->port_no);
1006
0
    if (error) {
1007
0
        return error;
1008
0
    }
1009
1010
0
    pm->hw_addr = opm->hw_addr;
1011
0
    pm->config = ntohl(opm->config) & OFPPC11_ALL;
1012
0
    pm->mask = ntohl(opm->mask) & OFPPC11_ALL;
1013
1014
0
    return ofputil_decode_ofp14_port_mod_properties(b, loose, pm);
1015
0
}
1016
1017
/* Decodes the OpenFlow "port mod" message in '*oh' into an abstract form in
1018
 * '*pm'.  Returns 0 if successful, otherwise an OFPERR_* value. */
1019
enum ofperr
1020
ofputil_decode_port_mod(const struct ofp_header *oh,
1021
                        struct ofputil_port_mod *pm, bool loose)
1022
0
{
1023
0
    memset(pm, 0, sizeof *pm);
1024
1025
0
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
1026
0
    enum ofpraw raw = ofpraw_pull_assert(&b);
1027
1028
0
    enum ofperr error;
1029
0
    if (raw == OFPRAW_OFPT10_PORT_MOD) {
1030
0
        error = ofputil_decode_ofp10_port_mod(b.data, pm);
1031
0
    } else if (raw == OFPRAW_OFPT11_PORT_MOD) {
1032
0
        error = ofputil_decode_ofp11_port_mod(b.data, pm);
1033
0
    } else if (raw == OFPRAW_OFPT14_PORT_MOD) {
1034
0
        error = ofputil_decode_ofp14_port_mod(&b, loose, pm);
1035
0
    } else {
1036
0
        error = OFPERR_OFPBRC_BAD_TYPE;
1037
0
    }
1038
1039
0
    pm->config &= pm->mask;
1040
0
    return error;
1041
0
}
1042
1043
/* Converts the abstract form of a "port mod" message in '*pm' into an OpenFlow
1044
 * message suitable for 'protocol', and returns that encoded form in a buffer
1045
 * owned by the caller. */
1046
struct ofpbuf *
1047
ofputil_encode_port_mod(const struct ofputil_port_mod *pm,
1048
                        enum ofputil_protocol protocol)
1049
0
{
1050
0
    enum ofp_version ofp_version = ofputil_protocol_to_ofp_version(protocol);
1051
0
    struct ofpbuf *b;
1052
1053
0
    switch (ofp_version) {
1054
0
    case OFP10_VERSION: {
1055
0
        struct ofp10_port_mod *opm;
1056
1057
0
        b = ofpraw_alloc(OFPRAW_OFPT10_PORT_MOD, ofp_version, 0);
1058
0
        opm = ofpbuf_put_zeros(b, sizeof *opm);
1059
0
        opm->port_no = htons(ofp_to_u16(pm->port_no));
1060
0
        opm->hw_addr = pm->hw_addr;
1061
0
        opm->config = htonl(pm->config & OFPPC10_ALL);
1062
0
        opm->mask = htonl(pm->mask & OFPPC10_ALL);
1063
0
        opm->advertise = netdev_port_features_to_ofp10(pm->advertise);
1064
0
        break;
1065
0
    }
1066
1067
0
    case OFP11_VERSION:
1068
0
    case OFP12_VERSION:
1069
0
    case OFP13_VERSION: {
1070
0
        struct ofp11_port_mod *opm;
1071
1072
0
        b = ofpraw_alloc(OFPRAW_OFPT11_PORT_MOD, ofp_version, 0);
1073
0
        opm = ofpbuf_put_zeros(b, sizeof *opm);
1074
0
        opm->port_no = ofputil_port_to_ofp11(pm->port_no);
1075
0
        opm->hw_addr = pm->hw_addr;
1076
0
        opm->config = htonl(pm->config & OFPPC11_ALL);
1077
0
        opm->mask = htonl(pm->mask & OFPPC11_ALL);
1078
0
        opm->advertise = netdev_port_features_to_ofp11(pm->advertise);
1079
0
        break;
1080
0
    }
1081
0
    case OFP14_VERSION:
1082
0
    case OFP15_VERSION: {
1083
0
        struct ofp14_port_mod *opm;
1084
1085
0
        b = ofpraw_alloc(OFPRAW_OFPT14_PORT_MOD, ofp_version, 0);
1086
0
        opm = ofpbuf_put_zeros(b, sizeof *opm);
1087
0
        opm->port_no = ofputil_port_to_ofp11(pm->port_no);
1088
0
        opm->hw_addr = pm->hw_addr;
1089
0
        opm->config = htonl(pm->config & OFPPC11_ALL);
1090
0
        opm->mask = htonl(pm->mask & OFPPC11_ALL);
1091
1092
0
        if (pm->advertise) {
1093
0
            ofpprop_put_be32(b, OFPPMPT14_ETHERNET,
1094
0
                             netdev_port_features_to_ofp11(pm->advertise));
1095
0
        }
1096
0
        break;
1097
0
    }
1098
0
    default:
1099
0
        OVS_NOT_REACHED();
1100
0
    }
1101
1102
0
    return b;
1103
0
}
1104
1105
void
1106
ofputil_port_mod_format(struct ds *s, const struct ofputil_port_mod *pm,
1107
                        const struct ofputil_port_map *port_map)
1108
0
{
1109
0
    ds_put_cstr(s, " port: ");
1110
0
    ofputil_format_port(pm->port_no, port_map, s);
1111
0
    ds_put_format(s, ": addr:"ETH_ADDR_FMT"\n",
1112
0
                  ETH_ADDR_ARGS(pm->hw_addr));
1113
1114
0
    ds_put_cstr(s, "     config: ");
1115
0
    ofputil_port_config_format(s, pm->config);
1116
1117
0
    ds_put_cstr(s, "     mask:   ");
1118
0
    ofputil_port_config_format(s, pm->mask);
1119
1120
0
    ds_put_cstr(s, "     advertise: ");
1121
0
    if (pm->advertise) {
1122
0
        netdev_features_format(s, pm->advertise);
1123
0
    } else {
1124
0
        ds_put_cstr(s, "UNCHANGED\n");
1125
0
    }
1126
0
}
1127

1128
/* Encode a dump ports request for 'port', the encoded message
1129
 * will be for OpenFlow version 'ofp_version'. Returns message
1130
 * as a struct ofpbuf. Returns encoded message on success, NULL on error */
1131
struct ofpbuf *
1132
ofputil_encode_dump_ports_request(enum ofp_version ofp_version,
1133
                                  ofp_port_t port)
1134
0
{
1135
0
    struct ofpbuf *request;
1136
1137
0
    switch (ofp_version) {
1138
0
    case OFP10_VERSION: {
1139
0
        struct ofp10_port_stats_request *req;
1140
0
        request = ofpraw_alloc(OFPRAW_OFPST10_PORT_REQUEST, ofp_version, 0);
1141
0
        req = ofpbuf_put_zeros(request, sizeof *req);
1142
0
        req->port_no = htons(ofp_to_u16(port));
1143
0
        break;
1144
0
    }
1145
0
    case OFP11_VERSION:
1146
0
    case OFP12_VERSION:
1147
0
    case OFP13_VERSION:
1148
0
    case OFP14_VERSION:
1149
0
    case OFP15_VERSION: {
1150
0
        struct ofp11_port_stats_request *req;
1151
0
        request = ofpraw_alloc(OFPRAW_OFPST11_PORT_REQUEST, ofp_version, 0);
1152
0
        req = ofpbuf_put_zeros(request, sizeof *req);
1153
0
        req->port_no = ofputil_port_to_ofp11(port);
1154
0
        break;
1155
0
    }
1156
0
    default:
1157
0
        OVS_NOT_REACHED();
1158
0
    }
1159
1160
0
    return request;
1161
0
}
1162
1163
static void
1164
ofputil_port_stats_to_ofp10(const struct ofputil_port_stats *ops,
1165
                            struct ofp10_port_stats *ps10)
1166
0
{
1167
0
    ps10->port_no = htons(ofp_to_u16(ops->port_no));
1168
0
    memset(ps10->pad, 0, sizeof ps10->pad);
1169
0
    put_32aligned_be64(&ps10->rx_packets, htonll(ops->stats.rx_packets));
1170
0
    put_32aligned_be64(&ps10->tx_packets, htonll(ops->stats.tx_packets));
1171
0
    put_32aligned_be64(&ps10->rx_bytes, htonll(ops->stats.rx_bytes));
1172
0
    put_32aligned_be64(&ps10->tx_bytes, htonll(ops->stats.tx_bytes));
1173
0
    put_32aligned_be64(&ps10->rx_dropped, htonll(ops->stats.rx_dropped));
1174
0
    put_32aligned_be64(&ps10->tx_dropped, htonll(ops->stats.tx_dropped));
1175
0
    put_32aligned_be64(&ps10->rx_errors, htonll(ops->stats.rx_errors));
1176
0
    put_32aligned_be64(&ps10->tx_errors, htonll(ops->stats.tx_errors));
1177
0
    put_32aligned_be64(&ps10->rx_frame_err,
1178
0
                       htonll(ops->stats.rx_frame_errors));
1179
0
    put_32aligned_be64(&ps10->rx_over_err, htonll(ops->stats.rx_over_errors));
1180
0
    put_32aligned_be64(&ps10->rx_crc_err, htonll(ops->stats.rx_crc_errors));
1181
0
    put_32aligned_be64(&ps10->collisions, htonll(ops->stats.collisions));
1182
0
}
1183
1184
static void
1185
ofputil_port_stats_to_ofp11(const struct ofputil_port_stats *ops,
1186
                            struct ofp11_port_stats *ps11)
1187
0
{
1188
0
    ps11->port_no = ofputil_port_to_ofp11(ops->port_no);
1189
0
    memset(ps11->pad, 0, sizeof ps11->pad);
1190
0
    ps11->rx_packets = htonll(ops->stats.rx_packets);
1191
0
    ps11->tx_packets = htonll(ops->stats.tx_packets);
1192
0
    ps11->rx_bytes = htonll(ops->stats.rx_bytes);
1193
0
    ps11->tx_bytes = htonll(ops->stats.tx_bytes);
1194
0
    ps11->rx_dropped = htonll(ops->stats.rx_dropped);
1195
0
    ps11->tx_dropped = htonll(ops->stats.tx_dropped);
1196
0
    ps11->rx_errors = htonll(ops->stats.rx_errors);
1197
0
    ps11->tx_errors = htonll(ops->stats.tx_errors);
1198
0
    ps11->rx_frame_err = htonll(ops->stats.rx_frame_errors);
1199
0
    ps11->rx_over_err = htonll(ops->stats.rx_over_errors);
1200
0
    ps11->rx_crc_err = htonll(ops->stats.rx_crc_errors);
1201
0
    ps11->collisions = htonll(ops->stats.collisions);
1202
0
}
1203
1204
static void
1205
ofputil_port_stats_to_ofp13(const struct ofputil_port_stats *ops,
1206
                            struct ofp13_port_stats *ps13)
1207
0
{
1208
0
    ofputil_port_stats_to_ofp11(ops, &ps13->ps);
1209
0
    ps13->duration_sec = htonl(ops->duration_sec);
1210
0
    ps13->duration_nsec = htonl(ops->duration_nsec);
1211
0
}
1212
1213
static void
1214
ofputil_append_ofp14_port_stats(const struct ofputil_port_stats *ops,
1215
                                struct ovs_list *replies)
1216
0
{
1217
0
    struct ofp14_port_stats_prop_ethernet *eth;
1218
0
    struct intel_port_stats_rfc2819 *stats_rfc2819;
1219
0
    struct intel_port_custom_stats *stats_custom;
1220
0
    struct ofp14_port_stats *ps14;
1221
0
    struct ofpbuf *reply;
1222
0
    uint16_t i;
1223
0
    ovs_be64 counter_value;
1224
0
    size_t custom_stats_start, start_ofs;
1225
1226
0
    reply = ofpbuf_from_list(ovs_list_back(replies));
1227
0
    start_ofs = reply->size;
1228
1229
0
    ps14 = ofpbuf_put_uninit(reply, sizeof *ps14);
1230
1231
0
    memset(ps14->pad, 0, sizeof ps14->pad);
1232
0
    ps14->port_no = ofputil_port_to_ofp11(ops->port_no);
1233
0
    ps14->duration_sec = htonl(ops->duration_sec);
1234
0
    ps14->duration_nsec = htonl(ops->duration_nsec);
1235
0
    ps14->rx_packets = htonll(ops->stats.rx_packets);
1236
0
    ps14->tx_packets = htonll(ops->stats.tx_packets);
1237
0
    ps14->rx_bytes = htonll(ops->stats.rx_bytes);
1238
0
    ps14->tx_bytes = htonll(ops->stats.tx_bytes);
1239
0
    ps14->rx_dropped = htonll(ops->stats.rx_dropped);
1240
0
    ps14->tx_dropped = htonll(ops->stats.tx_dropped);
1241
0
    ps14->rx_errors = htonll(ops->stats.rx_errors);
1242
0
    ps14->tx_errors = htonll(ops->stats.tx_errors);
1243
1244
0
    eth = ofpprop_put_zeros(reply, OFPPSPT14_ETHERNET, sizeof *eth);
1245
0
    eth->rx_frame_err = htonll(ops->stats.rx_frame_errors);
1246
0
    eth->rx_over_err = htonll(ops->stats.rx_over_errors);
1247
0
    eth->rx_crc_err = htonll(ops->stats.rx_crc_errors);
1248
0
    eth->collisions = htonll(ops->stats.collisions);
1249
1250
0
    uint64_t prop_type_stats = OFPPROP_EXP(INTEL_VENDOR_ID,
1251
0
                                     INTEL_PORT_STATS_RFC2819);
1252
1253
0
    stats_rfc2819 = ofpprop_put_zeros(reply, prop_type_stats,
1254
0
                                      sizeof *stats_rfc2819);
1255
1256
0
    memset(stats_rfc2819->pad, 0, sizeof stats_rfc2819->pad);
1257
0
    stats_rfc2819->rx_1_to_64_packets = htonll(ops->stats.rx_1_to_64_packets);
1258
0
    stats_rfc2819->rx_65_to_127_packets =
1259
0
        htonll(ops->stats.rx_65_to_127_packets);
1260
0
    stats_rfc2819->rx_128_to_255_packets =
1261
0
        htonll(ops->stats.rx_128_to_255_packets);
1262
0
    stats_rfc2819->rx_256_to_511_packets =
1263
0
        htonll(ops->stats.rx_256_to_511_packets);
1264
0
    stats_rfc2819->rx_512_to_1023_packets =
1265
0
        htonll(ops->stats.rx_512_to_1023_packets);
1266
0
    stats_rfc2819->rx_1024_to_1522_packets =
1267
0
        htonll(ops->stats.rx_1024_to_1522_packets);
1268
0
    stats_rfc2819->rx_1523_to_max_packets =
1269
0
        htonll(ops->stats.rx_1523_to_max_packets);
1270
1271
0
    stats_rfc2819->tx_1_to_64_packets = htonll(ops->stats.tx_1_to_64_packets);
1272
0
    stats_rfc2819->tx_65_to_127_packets =
1273
0
        htonll(ops->stats.tx_65_to_127_packets);
1274
0
    stats_rfc2819->tx_128_to_255_packets =
1275
0
        htonll(ops->stats.tx_128_to_255_packets);
1276
0
    stats_rfc2819->tx_256_to_511_packets =
1277
0
        htonll(ops->stats.tx_256_to_511_packets);
1278
0
    stats_rfc2819->tx_512_to_1023_packets =
1279
0
        htonll(ops->stats.tx_512_to_1023_packets);
1280
0
    stats_rfc2819->tx_1024_to_1522_packets =
1281
0
        htonll(ops->stats.tx_1024_to_1522_packets);
1282
0
    stats_rfc2819->tx_1523_to_max_packets =
1283
0
        htonll(ops->stats.tx_1523_to_max_packets);
1284
1285
0
    stats_rfc2819->tx_multicast_packets =
1286
0
        htonll(ops->stats.tx_multicast_packets);
1287
0
    stats_rfc2819->rx_broadcast_packets =
1288
0
        htonll(ops->stats.rx_broadcast_packets);
1289
0
    stats_rfc2819->tx_broadcast_packets =
1290
0
        htonll(ops->stats.tx_broadcast_packets);
1291
0
    stats_rfc2819->rx_undersized_errors =
1292
0
        htonll(ops->stats.rx_undersized_errors);
1293
0
    stats_rfc2819->rx_oversize_errors =
1294
0
        htonll(ops->stats.rx_oversize_errors);
1295
0
    stats_rfc2819->rx_fragmented_errors =
1296
0
        htonll(ops->stats.rx_fragmented_errors);
1297
0
    stats_rfc2819->rx_jabber_errors =
1298
0
        htonll(ops->stats.rx_jabber_errors);
1299
1300
0
    if (ops->custom_stats.counters && ops->custom_stats.size) {
1301
0
        custom_stats_start = reply->size;
1302
1303
0
        uint64_t prop_type_custom = OFPPROP_EXP(INTEL_VENDOR_ID,
1304
0
                                                INTEL_PORT_STATS_CUSTOM);
1305
1306
0
        stats_custom = ofpprop_put_zeros(reply, prop_type_custom,
1307
0
                                         sizeof *stats_custom);
1308
1309
0
        stats_custom->stats_array_size = htons(ops->custom_stats.size);
1310
1311
0
        for (i = 0; i < ops->custom_stats.size; i++) {
1312
0
            uint8_t counter_size = strlen(ops->custom_stats.counters[i].name);
1313
            /* Counter name size */
1314
0
            ofpbuf_put(reply, &counter_size, sizeof(counter_size));
1315
            /* Counter name */
1316
0
            ofpbuf_put(reply, ops->custom_stats.counters[i].name,
1317
0
                       counter_size);
1318
            /* Counter value */
1319
0
            counter_value = htonll(ops->custom_stats.counters[i].value);
1320
0
            ofpbuf_put(reply, &counter_value,
1321
0
                       sizeof(ops->custom_stats.counters[i].value));
1322
0
        }
1323
1324
0
        ofpprop_end(reply, custom_stats_start);
1325
0
    }
1326
1327
0
    ps14 = ofpbuf_at_assert(reply, start_ofs, sizeof *ps14);
1328
0
    ps14->length = htons(reply->size - start_ofs);
1329
1330
0
    ofpmp_postappend(replies, start_ofs);
1331
0
}
1332
1333
/* Encode a ports stat for 'ops' and append it to 'replies'. */
1334
void
1335
ofputil_append_port_stat(struct ovs_list *replies,
1336
                         const struct ofputil_port_stats *ops)
1337
0
{
1338
0
    switch (ofpmp_version(replies)) {
1339
0
    case OFP13_VERSION: {
1340
0
        struct ofp13_port_stats *reply = ofpmp_append(replies, sizeof *reply);
1341
0
        ofputil_port_stats_to_ofp13(ops, reply);
1342
0
        break;
1343
0
    }
1344
0
    case OFP12_VERSION:
1345
0
    case OFP11_VERSION: {
1346
0
        struct ofp11_port_stats *reply = ofpmp_append(replies, sizeof *reply);
1347
0
        ofputil_port_stats_to_ofp11(ops, reply);
1348
0
        break;
1349
0
    }
1350
1351
0
    case OFP10_VERSION: {
1352
0
        struct ofp10_port_stats *reply = ofpmp_append(replies, sizeof *reply);
1353
0
        ofputil_port_stats_to_ofp10(ops, reply);
1354
0
        break;
1355
0
    }
1356
1357
0
    case OFP14_VERSION:
1358
0
    case OFP15_VERSION:
1359
0
        ofputil_append_ofp14_port_stats(ops, replies);
1360
0
        break;
1361
1362
0
    default:
1363
0
        OVS_NOT_REACHED();
1364
0
    }
1365
0
}
1366
1367
static enum ofperr
1368
ofputil_port_stats_from_ofp10(struct ofputil_port_stats *ops,
1369
                              const struct ofp10_port_stats *ps10)
1370
0
{
1371
1372
0
    ops->port_no = u16_to_ofp(ntohs(ps10->port_no));
1373
0
    ops->stats.rx_packets = ntohll(get_32aligned_be64(&ps10->rx_packets));
1374
0
    ops->stats.tx_packets = ntohll(get_32aligned_be64(&ps10->tx_packets));
1375
0
    ops->stats.rx_bytes = ntohll(get_32aligned_be64(&ps10->rx_bytes));
1376
0
    ops->stats.tx_bytes = ntohll(get_32aligned_be64(&ps10->tx_bytes));
1377
0
    ops->stats.rx_dropped = ntohll(get_32aligned_be64(&ps10->rx_dropped));
1378
0
    ops->stats.tx_dropped = ntohll(get_32aligned_be64(&ps10->tx_dropped));
1379
0
    ops->stats.rx_errors = ntohll(get_32aligned_be64(&ps10->rx_errors));
1380
0
    ops->stats.tx_errors = ntohll(get_32aligned_be64(&ps10->tx_errors));
1381
0
    ops->stats.rx_frame_errors =
1382
0
        ntohll(get_32aligned_be64(&ps10->rx_frame_err));
1383
0
    ops->stats.rx_over_errors = ntohll(get_32aligned_be64(&ps10->rx_over_err));
1384
0
    ops->stats.rx_crc_errors = ntohll(get_32aligned_be64(&ps10->rx_crc_err));
1385
0
    ops->stats.collisions = ntohll(get_32aligned_be64(&ps10->collisions));
1386
0
    ops->duration_sec = ops->duration_nsec = UINT32_MAX;
1387
1388
0
    return 0;
1389
0
}
1390
1391
static enum ofperr
1392
ofputil_port_stats_from_ofp11(struct ofputil_port_stats *ops,
1393
                              const struct ofp11_port_stats *ps11)
1394
0
{
1395
0
    enum ofperr error;
1396
1397
0
    error = ofputil_port_from_ofp11(ps11->port_no, &ops->port_no);
1398
0
    if (error) {
1399
0
        return error;
1400
0
    }
1401
1402
0
    ops->stats.rx_packets = ntohll(ps11->rx_packets);
1403
0
    ops->stats.tx_packets = ntohll(ps11->tx_packets);
1404
0
    ops->stats.rx_bytes = ntohll(ps11->rx_bytes);
1405
0
    ops->stats.tx_bytes = ntohll(ps11->tx_bytes);
1406
0
    ops->stats.rx_dropped = ntohll(ps11->rx_dropped);
1407
0
    ops->stats.tx_dropped = ntohll(ps11->tx_dropped);
1408
0
    ops->stats.rx_errors = ntohll(ps11->rx_errors);
1409
0
    ops->stats.tx_errors = ntohll(ps11->tx_errors);
1410
0
    ops->stats.rx_frame_errors = ntohll(ps11->rx_frame_err);
1411
0
    ops->stats.rx_over_errors = ntohll(ps11->rx_over_err);
1412
0
    ops->stats.rx_crc_errors = ntohll(ps11->rx_crc_err);
1413
0
    ops->stats.collisions = ntohll(ps11->collisions);
1414
0
    ops->duration_sec = ops->duration_nsec = UINT32_MAX;
1415
1416
0
    return 0;
1417
0
}
1418
1419
static enum ofperr
1420
ofputil_port_stats_from_ofp13(struct ofputil_port_stats *ops,
1421
                              const struct ofp13_port_stats *ps13)
1422
0
{
1423
0
    enum ofperr error = ofputil_port_stats_from_ofp11(ops, &ps13->ps);
1424
0
    if (!error) {
1425
0
        ops->duration_sec = ntohl(ps13->duration_sec);
1426
0
        ops->duration_nsec = ntohl(ps13->duration_nsec);
1427
0
    }
1428
0
    return error;
1429
0
}
1430
1431
static enum ofperr
1432
parse_ofp14_port_stats_ethernet_property(const struct ofpbuf *payload,
1433
                                         struct ofputil_port_stats *ops)
1434
0
{
1435
0
    const struct ofp14_port_stats_prop_ethernet *eth = payload->data;
1436
1437
0
    if (payload->size != sizeof *eth) {
1438
0
        return OFPERR_OFPBPC_BAD_LEN;
1439
0
    }
1440
1441
0
    ops->stats.rx_frame_errors = ntohll(eth->rx_frame_err);
1442
0
    ops->stats.rx_over_errors = ntohll(eth->rx_over_err);
1443
0
    ops->stats.rx_crc_errors = ntohll(eth->rx_crc_err);
1444
0
    ops->stats.collisions = ntohll(eth->collisions);
1445
1446
0
    return 0;
1447
0
}
1448
1449
static enum ofperr
1450
parse_intel_port_stats_rfc2819_property(const struct ofpbuf *payload,
1451
                                        struct ofputil_port_stats *ops)
1452
0
{
1453
0
    const struct intel_port_stats_rfc2819 *rfc2819 = payload->data;
1454
1455
0
    if (payload->size != sizeof *rfc2819) {
1456
0
        return OFPERR_OFPBPC_BAD_LEN;
1457
0
    }
1458
0
    ops->stats.rx_1_to_64_packets = ntohll(rfc2819->rx_1_to_64_packets);
1459
0
    ops->stats.rx_65_to_127_packets = ntohll(rfc2819->rx_65_to_127_packets);
1460
0
    ops->stats.rx_128_to_255_packets = ntohll(rfc2819->rx_128_to_255_packets);
1461
0
    ops->stats.rx_256_to_511_packets = ntohll(rfc2819->rx_256_to_511_packets);
1462
0
    ops->stats.rx_512_to_1023_packets =
1463
0
        ntohll(rfc2819->rx_512_to_1023_packets);
1464
0
    ops->stats.rx_1024_to_1522_packets =
1465
0
        ntohll(rfc2819->rx_1024_to_1522_packets);
1466
0
    ops->stats.rx_1523_to_max_packets =
1467
0
        ntohll(rfc2819->rx_1523_to_max_packets);
1468
1469
0
    ops->stats.tx_1_to_64_packets = ntohll(rfc2819->tx_1_to_64_packets);
1470
0
    ops->stats.tx_65_to_127_packets = ntohll(rfc2819->tx_65_to_127_packets);
1471
0
    ops->stats.tx_128_to_255_packets = ntohll(rfc2819->tx_128_to_255_packets);
1472
0
    ops->stats.tx_256_to_511_packets = ntohll(rfc2819->tx_256_to_511_packets);
1473
0
    ops->stats.tx_512_to_1023_packets =
1474
0
        ntohll(rfc2819->tx_512_to_1023_packets);
1475
0
    ops->stats.tx_1024_to_1522_packets =
1476
0
        ntohll(rfc2819->tx_1024_to_1522_packets);
1477
0
    ops->stats.tx_1523_to_max_packets =
1478
0
        ntohll(rfc2819->tx_1523_to_max_packets);
1479
1480
0
    ops->stats.tx_multicast_packets = ntohll(rfc2819->tx_multicast_packets);
1481
0
    ops->stats.rx_broadcast_packets = ntohll(rfc2819->rx_broadcast_packets);
1482
0
    ops->stats.tx_broadcast_packets = ntohll(rfc2819->tx_broadcast_packets);
1483
0
    ops->stats.rx_undersized_errors = ntohll(rfc2819->rx_undersized_errors);
1484
1485
0
    ops->stats.rx_oversize_errors = ntohll(rfc2819->rx_oversize_errors);
1486
0
    ops->stats.rx_fragmented_errors = ntohll(rfc2819->rx_fragmented_errors);
1487
0
    ops->stats.rx_jabber_errors = ntohll(rfc2819->rx_jabber_errors);
1488
1489
0
    return 0;
1490
0
}
1491
1492
static enum ofperr
1493
parse_intel_port_custom_property(struct ofpbuf *payload,
1494
                                 struct ofputil_port_stats *ops)
1495
0
{
1496
0
    const struct intel_port_custom_stats *custom_stats
1497
0
        = ofpbuf_try_pull(payload, sizeof *custom_stats);
1498
0
    if (!custom_stats) {
1499
0
        return OFPERR_OFPBPC_BAD_LEN;
1500
0
    }
1501
1502
0
    ops->custom_stats.size = ntohs(custom_stats->stats_array_size);
1503
1504
0
    netdev_free_custom_stats_counters(&ops->custom_stats);
1505
0
    ops->custom_stats.counters = xcalloc(ops->custom_stats.size,
1506
0
                                         sizeof *ops->custom_stats.counters);
1507
1508
0
    for (int i = 0; i < ops->custom_stats.size; i++) {
1509
0
        struct netdev_custom_counter *c = &ops->custom_stats.counters[i];
1510
1511
        /* Counter name. */
1512
0
        uint8_t *name_len = ofpbuf_try_pull(payload, sizeof *name_len);
1513
0
        char *name = name_len ? ofpbuf_try_pull(payload, *name_len) : NULL;
1514
0
        if (!name_len || !name) {
1515
0
            netdev_free_custom_stats_counters(&ops->custom_stats);
1516
0
            return OFPERR_OFPBPC_BAD_LEN;
1517
0
        }
1518
1519
0
        size_t len = MIN(*name_len, sizeof c->name - 1);
1520
0
        memcpy(c->name, name, len);
1521
0
        c->name[len] = '\0';
1522
1523
        /* Counter value. */
1524
0
        ovs_be64 *value = ofpbuf_try_pull(payload, sizeof *value);
1525
0
        if (!value) {
1526
0
            netdev_free_custom_stats_counters(&ops->custom_stats);
1527
0
            return OFPERR_OFPBPC_BAD_LEN;
1528
0
        }
1529
0
        c->value = ntohll(get_unaligned_be64(value));
1530
0
    }
1531
1532
0
    return 0;
1533
0
}
1534
1535
static enum ofperr
1536
ofputil_pull_ofp14_port_stats(struct ofputil_port_stats *ops,
1537
                              struct ofpbuf *msg)
1538
0
{
1539
0
    const struct ofp14_port_stats *ps14 = ofpbuf_try_pull(msg, sizeof *ps14);
1540
0
    if (!ps14) {
1541
0
        return OFPERR_OFPBRC_BAD_LEN;
1542
0
    }
1543
1544
0
    size_t len = ntohs(ps14->length);
1545
0
    if (len < sizeof *ps14 || len - sizeof *ps14 > msg->size) {
1546
0
        return OFPERR_OFPBRC_BAD_LEN;
1547
0
    }
1548
0
    len -= sizeof *ps14;
1549
1550
0
    enum ofperr error = ofputil_port_from_ofp11(ps14->port_no, &ops->port_no);
1551
0
    if (error) {
1552
0
        return error;
1553
0
    }
1554
1555
0
    ops->duration_sec = ntohl(ps14->duration_sec);
1556
0
    ops->duration_nsec = ntohl(ps14->duration_nsec);
1557
0
    ops->stats.rx_packets = ntohll(ps14->rx_packets);
1558
0
    ops->stats.tx_packets = ntohll(ps14->tx_packets);
1559
0
    ops->stats.rx_bytes = ntohll(ps14->rx_bytes);
1560
0
    ops->stats.tx_bytes = ntohll(ps14->tx_bytes);
1561
0
    ops->stats.rx_dropped = ntohll(ps14->rx_dropped);
1562
0
    ops->stats.tx_dropped = ntohll(ps14->tx_dropped);
1563
0
    ops->stats.rx_errors = ntohll(ps14->rx_errors);
1564
0
    ops->stats.tx_errors = ntohll(ps14->tx_errors);
1565
1566
1567
0
    struct ofpbuf properties = ofpbuf_const_initializer(ofpbuf_pull(msg, len),
1568
0
                                                        len);
1569
0
    while (properties.size > 0) {
1570
0
        struct ofpbuf payload;
1571
0
        uint64_t type = 0;
1572
1573
0
        error = ofpprop_pull(&properties, &payload, &type);
1574
0
        if (error) {
1575
0
            netdev_free_custom_stats_counters(&ops->custom_stats);
1576
0
            return error;
1577
0
        }
1578
0
        switch (type) {
1579
0
        case OFPPSPT14_ETHERNET:
1580
0
            error = parse_ofp14_port_stats_ethernet_property(&payload, ops);
1581
0
            break;
1582
0
        case OFPPROP_EXP(INTEL_VENDOR_ID, INTEL_PORT_STATS_RFC2819):
1583
0
            error = parse_intel_port_stats_rfc2819_property(&payload, ops);
1584
0
            break;
1585
0
        case OFPPROP_EXP(INTEL_VENDOR_ID, INTEL_PORT_STATS_CUSTOM):
1586
0
            error = parse_intel_port_custom_property(&payload, ops);
1587
0
            break;
1588
0
        default:
1589
0
            error = OFPPROP_UNKNOWN(true, "port stats", type);
1590
0
            break;
1591
0
        }
1592
1593
0
        if (error) {
1594
0
            netdev_free_custom_stats_counters(&ops->custom_stats);
1595
0
            return error;
1596
0
        }
1597
0
    }
1598
1599
0
    return 0;
1600
0
}
1601
1602
/* Returns the number of port stats elements in OFPTYPE_PORT_STATS_REPLY
1603
 * message 'oh'. */
1604
size_t
1605
ofputil_count_port_stats(const struct ofp_header *oh)
1606
0
{
1607
0
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
1608
0
    ofpraw_pull_assert(&b);
1609
1610
0
    for (size_t n = 0; ; n++) {
1611
0
        struct ofputil_port_stats ps;
1612
0
        if (ofputil_decode_port_stats(&ps, &b)) {
1613
0
            return n;
1614
0
        }
1615
0
        netdev_free_custom_stats_counters(&ps.custom_stats);
1616
0
    }
1617
0
}
1618
1619
/* Converts an OFPST_PORT_STATS reply in 'msg' into an abstract
1620
 * ofputil_port_stats in 'ps'.
1621
 *
1622
 * Multiple OFPST_PORT_STATS replies can be packed into a single OpenFlow
1623
 * message.  Calling this function multiple times for a single 'msg' iterates
1624
 * through the replies.  The caller must initially leave 'msg''s layer pointers
1625
 * null and not modify them between calls.
1626
 *
1627
 * Returns 0 if successful, EOF if no replies were left in this 'msg',
1628
 * otherwise a positive errno value.
1629
 *
1630
 * On success, the caller must eventually free ps->custom_stats.counters,
1631
 * with netdev_free_custom_stats_counters(&ps->custom_stats). */
1632
int
1633
ofputil_decode_port_stats(struct ofputil_port_stats *ps, struct ofpbuf *msg)
1634
0
{
1635
0
    enum ofperr error;
1636
0
    enum ofpraw raw;
1637
1638
0
    memset(&(ps->stats), 0xFF, sizeof (ps->stats));
1639
0
    memset(&(ps->custom_stats), 0, sizeof (ps->custom_stats));
1640
1641
0
    error = (msg->header ? ofpraw_decode(&raw, msg->header)
1642
0
             : ofpraw_pull(&raw, msg));
1643
0
    if (error) {
1644
0
        return error;
1645
0
    }
1646
1647
0
    if (!msg->size) {
1648
0
        return EOF;
1649
0
    } else if (raw == OFPRAW_OFPST14_PORT_REPLY) {
1650
0
        return ofputil_pull_ofp14_port_stats(ps, msg);
1651
0
    } else if (raw == OFPRAW_OFPST13_PORT_REPLY) {
1652
0
        const struct ofp13_port_stats *ps13;
1653
0
        ps13 = ofpbuf_try_pull(msg, sizeof *ps13);
1654
0
        if (!ps13) {
1655
0
            goto bad_len;
1656
0
        }
1657
0
        return ofputil_port_stats_from_ofp13(ps, ps13);
1658
0
    } else if (raw == OFPRAW_OFPST11_PORT_REPLY) {
1659
0
        const struct ofp11_port_stats *ps11;
1660
1661
0
        ps11 = ofpbuf_try_pull(msg, sizeof *ps11);
1662
0
        if (!ps11) {
1663
0
            goto bad_len;
1664
0
        }
1665
0
        return ofputil_port_stats_from_ofp11(ps, ps11);
1666
0
    } else if (raw == OFPRAW_OFPST10_PORT_REPLY) {
1667
0
        const struct ofp10_port_stats *ps10;
1668
1669
0
        ps10 = ofpbuf_try_pull(msg, sizeof *ps10);
1670
0
        if (!ps10) {
1671
0
            goto bad_len;
1672
0
        }
1673
0
        return ofputil_port_stats_from_ofp10(ps, ps10);
1674
0
    } else {
1675
0
        OVS_NOT_REACHED();
1676
0
    }
1677
1678
0
 bad_len:
1679
0
    VLOG_WARN_RL(&rl, "OFPST_PORT reply has %"PRIu32" leftover "
1680
0
                 "bytes at end", msg->size);
1681
0
    return OFPERR_OFPBRC_BAD_LEN;
1682
0
}
1683
1684
static void
1685
print_port_stat(struct ds *string, const char *leader, uint64_t stat, int more)
1686
0
{
1687
0
    ds_put_cstr(string, leader);
1688
0
    if (stat != UINT64_MAX) {
1689
0
        ds_put_format(string, "%"PRIu64, stat);
1690
0
    } else {
1691
0
        ds_put_char(string, '?');
1692
0
    }
1693
0
    if (more) {
1694
0
        ds_put_cstr(string, ", ");
1695
0
    } else {
1696
0
        ds_put_cstr(string, "\n");
1697
0
    }
1698
0
}
1699
1700
static void
1701
print_port_stat_cond(struct ds *string, const char *leader, uint64_t stat)
1702
0
{
1703
0
    if (stat != UINT64_MAX) {
1704
0
        ds_put_format(string, "%s%"PRIu64", ", leader, stat);
1705
0
    }
1706
0
}
1707
1708
void
1709
ofputil_format_port_stats(struct ds *string,
1710
                          const struct ofputil_port_stats *ps,
1711
                          const struct ofputil_port_map *port_map)
1712
0
{
1713
0
    ds_put_cstr(string, "  port ");
1714
0
    if (ofp_to_u16(ps->port_no) < 10) {
1715
0
        ds_put_char(string, ' ');
1716
0
    }
1717
0
    ofputil_format_port(ps->port_no, port_map, string);
1718
1719
0
    ds_put_cstr(string, ": rx ");
1720
0
    print_port_stat(string, "pkts=", ps->stats.rx_packets, 1);
1721
0
    print_port_stat(string, "bytes=", ps->stats.rx_bytes, 1);
1722
0
    print_port_stat(string, "drop=", ps->stats.rx_dropped, 1);
1723
0
    print_port_stat(string, "errs=", ps->stats.rx_errors, 1);
1724
0
    print_port_stat(string, "frame=", ps->stats.rx_frame_errors, 1);
1725
0
    print_port_stat(string, "over=", ps->stats.rx_over_errors, 1);
1726
0
    print_port_stat(string, "crc=", ps->stats.rx_crc_errors, 0);
1727
1728
0
    ds_put_cstr(string, "           tx ");
1729
0
    print_port_stat(string, "pkts=", ps->stats.tx_packets, 1);
1730
0
    print_port_stat(string, "bytes=", ps->stats.tx_bytes, 1);
1731
0
    print_port_stat(string, "drop=", ps->stats.tx_dropped, 1);
1732
0
    print_port_stat(string, "errs=", ps->stats.tx_errors, 1);
1733
0
    print_port_stat(string, "coll=", ps->stats.collisions, 0);
1734
1735
0
    if (ps->duration_sec != UINT32_MAX) {
1736
0
        ds_put_cstr(string, "           duration=");
1737
0
        ofp_print_duration(string, ps->duration_sec, ps->duration_nsec);
1738
0
        ds_put_char(string, '\n');
1739
0
    }
1740
0
    struct ds string_ext_stats = DS_EMPTY_INITIALIZER;
1741
1742
0
    ds_init(&string_ext_stats);
1743
1744
0
    print_port_stat_cond(&string_ext_stats, "1_to_64_packets=",
1745
0
                         ps->stats.rx_1_to_64_packets);
1746
0
    print_port_stat_cond(&string_ext_stats, "65_to_127_packets=",
1747
0
                         ps->stats.rx_65_to_127_packets);
1748
0
    print_port_stat_cond(&string_ext_stats, "128_to_255_packets=",
1749
0
                         ps->stats.rx_128_to_255_packets);
1750
0
    print_port_stat_cond(&string_ext_stats, "256_to_511_packets=",
1751
0
                         ps->stats.rx_256_to_511_packets);
1752
0
    print_port_stat_cond(&string_ext_stats, "512_to_1023_packets=",
1753
0
                         ps->stats.rx_512_to_1023_packets);
1754
0
    print_port_stat_cond(&string_ext_stats, "1024_to_1522_packets=",
1755
0
                         ps->stats.rx_1024_to_1522_packets);
1756
0
    print_port_stat_cond(&string_ext_stats, "1523_to_max_packets=",
1757
0
                         ps->stats.rx_1523_to_max_packets);
1758
0
    print_port_stat_cond(&string_ext_stats, "broadcast_packets=",
1759
0
                         ps->stats.rx_broadcast_packets);
1760
0
    print_port_stat_cond(&string_ext_stats, "undersized_errors=",
1761
0
                         ps->stats.rx_undersized_errors);
1762
0
    print_port_stat_cond(&string_ext_stats, "oversize_errors=",
1763
0
                         ps->stats.rx_oversize_errors);
1764
0
    print_port_stat_cond(&string_ext_stats, "rx_fragmented_errors=",
1765
0
                         ps->stats.rx_fragmented_errors);
1766
0
    print_port_stat_cond(&string_ext_stats, "rx_jabber_errors=",
1767
0
                         ps->stats.rx_jabber_errors);
1768
1769
0
    if (string_ext_stats.length != 0) {
1770
        /* If at least one statistics counter is reported: */
1771
0
        ds_put_cstr(string, "           rx rfc2819 ");
1772
0
        ds_put_buffer(string, string_ext_stats.string,
1773
0
                      string_ext_stats.length);
1774
0
        ds_put_cstr(string, "\n");
1775
0
        ds_destroy(&string_ext_stats);
1776
0
    }
1777
1778
0
    ds_init(&string_ext_stats);
1779
1780
0
    print_port_stat_cond(&string_ext_stats, "1_to_64_packets=",
1781
0
                         ps->stats.tx_1_to_64_packets);
1782
0
    print_port_stat_cond(&string_ext_stats, "65_to_127_packets=",
1783
0
                         ps->stats.tx_65_to_127_packets);
1784
0
    print_port_stat_cond(&string_ext_stats, "128_to_255_packets=",
1785
0
                         ps->stats.tx_128_to_255_packets);
1786
0
    print_port_stat_cond(&string_ext_stats, "256_to_511_packets=",
1787
0
                         ps->stats.tx_256_to_511_packets);
1788
0
    print_port_stat_cond(&string_ext_stats, "512_to_1023_packets=",
1789
0
                         ps->stats.tx_512_to_1023_packets);
1790
0
    print_port_stat_cond(&string_ext_stats, "1024_to_1522_packets=",
1791
0
                         ps->stats.tx_1024_to_1522_packets);
1792
0
    print_port_stat_cond(&string_ext_stats, "1523_to_max_packets=",
1793
0
                         ps->stats.tx_1523_to_max_packets);
1794
0
    print_port_stat_cond(&string_ext_stats, "multicast_packets=",
1795
0
                         ps->stats.tx_multicast_packets);
1796
0
    print_port_stat_cond(&string_ext_stats, "broadcast_packets=",
1797
0
                         ps->stats.tx_broadcast_packets);
1798
1799
0
    if (string_ext_stats.length != 0) {
1800
        /* If at least one statistics counter is reported: */
1801
0
        ds_put_cstr(string, "           tx rfc2819 ");
1802
0
        ds_put_buffer(string, string_ext_stats.string,
1803
0
                      string_ext_stats.length);
1804
0
        ds_put_cstr(string, "\n");
1805
0
        ds_destroy(&string_ext_stats);
1806
0
    }
1807
1808
0
    if (ps->custom_stats.size) {
1809
0
        ds_put_cstr(string, "           CUSTOM Statistics");
1810
0
        for (int i = 0; i < ps->custom_stats.size; i++) {
1811
            /* 3 counters in the row */
1812
0
            if (ps->custom_stats.counters[i].name[0]) {
1813
0
                if (i % 3 == 0) {
1814
0
                    ds_put_cstr(string, "\n");
1815
0
                    ds_put_cstr(string, "                      ");
1816
0
                } else {
1817
0
                    ds_put_char(string, ' ');
1818
0
                }
1819
0
                ds_put_format(string, "%s=%"PRIu64",",
1820
0
                              ps->custom_stats.counters[i].name,
1821
0
                              ps->custom_stats.counters[i].value);
1822
0
            }
1823
0
        }
1824
0
        ds_put_cstr(string, "\n");
1825
0
    }
1826
0
}
1827
1828
1829
/* Parse a port status request message into a 16 bit OpenFlow 1.0
1830
 * port number and stores the latter in '*ofp10_port'.
1831
 * Returns 0 if successful, otherwise an OFPERR_* number. */
1832
enum ofperr
1833
ofputil_decode_port_stats_request(const struct ofp_header *request,
1834
                                  ofp_port_t *ofp10_port)
1835
0
{
1836
0
    switch ((enum ofp_version)request->version) {
1837
0
    case OFP15_VERSION:
1838
0
    case OFP14_VERSION:
1839
0
    case OFP13_VERSION:
1840
0
    case OFP12_VERSION:
1841
0
    case OFP11_VERSION: {
1842
0
        const struct ofp11_port_stats_request *psr11 = ofpmsg_body(request);
1843
0
        return ofputil_port_from_ofp11(psr11->port_no, ofp10_port);
1844
0
    }
1845
1846
0
    case OFP10_VERSION: {
1847
0
        const struct ofp10_port_stats_request *psr10 = ofpmsg_body(request);
1848
0
        *ofp10_port = u16_to_ofp(ntohs(psr10->port_no));
1849
0
        return 0;
1850
0
    }
1851
1852
0
    default:
1853
0
        OVS_NOT_REACHED();
1854
0
    }
1855
0
}
1856