Coverage Report

Created: 2026-04-10 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openvswitch/lib/ofp-port.c
Line
Count
Source
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
128k
{
54
128k
    struct namemap_node *node
55
128k
        = (map
56
128k
           ? namemap_find_by_number(&map->map, ofp_to_u16(ofp_port))
57
128k
           : NULL);
58
128k
    return node && !node->duplicate ? node->name : NULL;
59
128k
}
60
61
ofp_port_t
62
ofputil_port_map_get_number(const struct ofputil_port_map *map,
63
                            const char *name)
64
3.37k
{
65
3.37k
    struct namemap_node *node
66
3.37k
        = map ? namemap_find_by_name(&map->map, name) : NULL;
67
3.37k
    return node && !node->duplicate ? u16_to_ofp(node->number) : OFPP_NONE;
68
3.37k
}
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
156k
{
85
156k
    uint32_t ofp11_port_h = ntohl(ofp11_port);
86
87
156k
    if (ofp11_port_h < ofp_to_u16(OFPP_MAX)) {
88
95.8k
        *ofp10_port = u16_to_ofp(ofp11_port_h);
89
95.8k
        return 0;
90
95.8k
    } else if (ofp11_port_h >= ofp11_to_u32(OFPP11_MAX)) {
91
28.2k
        *ofp10_port = u16_to_ofp(ofp11_port_h - OFPP11_OFFSET);
92
28.2k
        return 0;
93
32.4k
    } else {
94
32.4k
        *ofp10_port = OFPP_NONE;
95
96
32.4k
        static struct vlog_rate_limit rll = VLOG_RATE_LIMIT_INIT(1, 5);
97
32.4k
        VLOG_WARN_RL(&rll, "port %"PRIu32" is outside the supported "
98
32.4k
                     "range 0 through %d or 0x%"PRIx32" through 0x%"PRIx32,
99
32.4k
                     ofp11_port_h, ofp_to_u16(OFPP_MAX) - 1,
100
32.4k
                     ofp11_to_u32(OFPP11_MAX), UINT32_MAX);
101
102
32.4k
        return OFPERR_OFPBAC_BAD_OUT_PORT;
103
32.4k
    }
104
156k
}
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
52.2k
{
113
52.2k
    return htonl(ofp_to_u16(ofp10_port) < ofp_to_u16(OFPP_MAX)
114
52.2k
                 ? ofp_to_u16(ofp10_port)
115
52.2k
                 : ofp_to_u16(ofp10_port) + OFPP11_OFFSET);
116
52.2k
}
117
118
#define OFPUTIL_NAMED_PORTS                     \
119
10.2k
        OFPUTIL_NAMED_PORT(IN_PORT)             \
120
10.0k
        OFPUTIL_NAMED_PORT(TABLE)               \
121
8.11k
        OFPUTIL_NAMED_PORT(NORMAL)              \
122
7.87k
        OFPUTIL_NAMED_PORT(FLOOD)               \
123
7.92k
        OFPUTIL_NAMED_PORT(ALL)                 \
124
9.05k
        OFPUTIL_NAMED_PORT(CONTROLLER)          \
125
7.71k
        OFPUTIL_NAMED_PORT(LOCAL)               \
126
25.1k
        OFPUTIL_NAMED_PORT(ANY)                 \
127
18.2k
        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
6.89k
        OFPUTIL_NAMED_PORTS                     \
132
6.89k
        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
172k
{
153
172k
    unsigned int port32; /* int is at least 32 bits wide. */
154
155
172k
    if (*s == '-') {
156
9
        VLOG_WARN("Negative value %s is not a valid port number.", s);
157
9
        return false;
158
9
    }
159
172k
    *portp = 0;
160
172k
    if (str_to_uint(s, 10, &port32)) {
161
165k
        if (port32 < ofp_to_u16(OFPP_MAX)) {
162
            /* Pass. */
163
160k
        } else if (port32 < ofp_to_u16(OFPP_FIRST_RESV)) {
164
234
            VLOG_WARN("port %u is a reserved OF1.0 port number that will "
165
234
                      "be translated to %u when talking to an OF1.1 or "
166
234
                      "later controller", port32, port32 + OFPP11_OFFSET);
167
4.17k
        } else if (port32 <= ofp_to_u16(OFPP_LAST_RESV)) {
168
3.90k
            char name[OFP_MAX_PORT_NAME_LEN];
169
170
3.90k
            ofputil_port_to_string(u16_to_ofp(port32), NULL,
171
3.90k
                                   name, sizeof name);
172
3.90k
            VLOG_WARN_ONCE("referring to port %s as %"PRIu32" is deprecated "
173
3.90k
                           "for compatibility with OpenFlow 1.1 and later",
174
3.90k
                           name, port32);
175
3.90k
        } else if (port32 < ofp11_to_u32(OFPP11_MAX)) {
176
64
            VLOG_WARN("port %u is outside the supported range 0 through "
177
64
                      "%x or 0x%x through 0x%"PRIx32, port32,
178
64
                      UINT16_MAX, ofp11_to_u32(OFPP11_MAX), UINT32_MAX);
179
64
            return false;
180
210
        } else {
181
210
            port32 -= OFPP11_OFFSET;
182
210
        }
183
184
165k
        *portp = u16_to_ofp(port32);
185
165k
        return true;
186
165k
    } else {
187
6.89k
        struct pair {
188
6.89k
            const char *name;
189
6.89k
            ofp_port_t value;
190
6.89k
        };
191
6.89k
        static const struct pair pairs[] = {
192
68.9k
#define OFPUTIL_NAMED_PORT(NAME) {#NAME, OFPP_##NAME},
193
6.89k
            OFPUTIL_NAMED_PORTS_WITH_NONE
194
6.89k
#undef OFPUTIL_NAMED_PORT
195
6.89k
        };
196
6.89k
        const struct pair *p;
197
198
48.9k
        for (p = pairs; p < &pairs[ARRAY_SIZE(pairs)]; p++) {
199
45.4k
            if (!strcasecmp(s, p->name)) {
200
3.47k
                *portp = p->value;
201
3.47k
                return true;
202
3.47k
            }
203
45.4k
        }
204
205
3.41k
        ofp_port_t ofp_port = OFPP_NONE;
206
3.41k
        if (s[0] != '"') {
207
3.35k
            ofp_port = ofputil_port_map_get_number(port_map, s);
208
3.35k
        } else {
209
64
            size_t length = strlen(s);
210
64
            char *name = NULL;
211
64
            if (length > 1
212
63
                && s[length - 1] == '"'
213
55
                && json_string_unescape(s + 1, length - 2, &name)) {
214
22
                ofp_port = ofputil_port_map_get_number(port_map, name);
215
22
            }
216
64
            free(name);
217
64
        }
218
3.41k
        if (ofp_port != OFPP_NONE) {
219
0
            *portp = ofp_port;
220
0
            return true;
221
0
        }
222
223
3.41k
        return false;
224
3.41k
    }
225
172k
}
226
227
const char *
228
ofputil_port_get_reserved_name(ofp_port_t port)
229
159k
{
230
159k
    switch (port) {
231
31.3k
#define OFPUTIL_NAMED_PORT(NAME) case OFPP_##NAME: return #NAME;
232
0
        OFPUTIL_NAMED_PORTS
233
0
#undef OFPUTIL_NAMED_PORT
234
235
128k
    default:
236
128k
        return NULL;
237
159k
    }
238
159k
}
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
155k
{
247
155k
    const char *reserved_name = ofputil_port_get_reserved_name(port);
248
155k
    if (reserved_name) {
249
27.4k
        ds_put_cstr(s, reserved_name);
250
27.4k
        return;
251
27.4k
    }
252
253
128k
    const char *port_name = ofputil_port_map_get_name(port_map, port);
254
128k
    if (port_name) {
255
0
        namemap_put_name(port_name, s);
256
0
        return;
257
0
    }
258
259
128k
    ds_put_format(s, "%"PRIu32, port);
260
128k
}
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
3.90k
{
271
3.90k
    const char *reserved_name = ofputil_port_get_reserved_name(port);
272
3.90k
    if (reserved_name) {
273
3.90k
        ovs_strlcpy(namebuf, reserved_name, bufsize);
274
3.90k
        return;
275
3.90k
    }
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
74.5k
{
294
74.5k
    enum ofputil_port_config pc = bit;
295
296
74.5k
    switch (pc) {
297
11.3k
    case OFPUTIL_PC_PORT_DOWN:    return "PORT_DOWN";
298
10.1k
    case OFPUTIL_PC_NO_STP:       return "NO_STP";
299
10.9k
    case OFPUTIL_PC_NO_RECV:      return "NO_RECV";
300
10.6k
    case OFPUTIL_PC_NO_RECV_STP:  return "NO_RECV_STP";
301
9.75k
    case OFPUTIL_PC_NO_FLOOD:     return "NO_FLOOD";
302
10.9k
    case OFPUTIL_PC_NO_FWD:       return "NO_FWD";
303
10.6k
    case OFPUTIL_PC_NO_PACKET_IN: return "NO_PACKET_IN";
304
74.5k
    }
305
306
0
    return NULL;
307
74.5k
}
308
309
void
310
ofputil_port_config_format(struct ds *s, enum ofputil_port_config config)
311
22.2k
{
312
22.2k
    ofp_print_bit_names(s, config, ofputil_port_config_to_name, ' ');
313
22.2k
    ds_put_char(s, '\n');
314
22.2k
}
315

316
/* ofputil_port_state */
317
318
static const char *
319
ofputil_port_state_to_name(uint32_t bit)
320
10.1k
{
321
10.1k
    enum ofputil_port_state ps = bit;
322
323
10.1k
    switch (ps) {
324
9.02k
    case OFPUTIL_PS_LINK_DOWN: return "LINK_DOWN";
325
571
    case OFPUTIL_PS_BLOCKED:   return "BLOCKED";
326
590
    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
10.1k
    }
335
336
0
    return NULL;
337
10.1k
}
338
339
void
340
ofputil_port_state_format(struct ds *s, enum ofputil_port_state state)
341
18.9k
{
342
18.9k
    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
18.9k
    stp_state = state & OFPUTIL_PS_STP_MASK;
352
18.9k
    if (stp_state) {
353
10.3k
        ds_put_cstr(s, (stp_state == OFPUTIL_PS_STP_LEARN ? "STP_LEARN"
354
10.3k
                        : stp_state == OFPUTIL_PS_STP_FORWARD ? "STP_FORWARD"
355
7.86k
                        : "STP_BLOCK"));
356
10.3k
        state &= ~OFPUTIL_PS_STP_MASK;
357
10.3k
        if (state) {
358
6.55k
            ofp_print_bit_names(s, state, ofputil_port_state_to_name, ' ');
359
6.55k
        }
360
10.3k
    } else {
361
8.60k
        ofp_print_bit_names(s, state, ofputil_port_state_to_name, ' ');
362
8.60k
    }
363
18.9k
    ds_put_char(s, '\n');
364
18.9k
}
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
73.9k
{
387
73.9k
    uint32_t ofp10 = ntohl(ofp10_);
388
73.9k
    return (ofp10 & 0x7f) | ((ofp10 & 0xf80) << 4);
389
73.9k
}
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
3.26k
{
417
3.26k
    return ntohl(ofp11) & 0xffff;
418
3.26k
}
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
18.1k
{
430
18.1k
    pp->port_no = u16_to_ofp(ntohs(opp->port_no));
431
18.1k
    pp->hw_addr = opp->hw_addr;
432
18.1k
    ovs_strlcpy_arrays(pp->name, opp->name);
433
434
18.1k
    pp->config = ntohl(opp->config) & OFPPC10_ALL;
435
18.1k
    pp->state = ntohl(opp->state) & OFPPS10_ALL;
436
437
18.1k
    pp->curr = netdev_port_features_from_ofp10(opp->curr);
438
18.1k
    pp->advertised = netdev_port_features_from_ofp10(opp->advertised);
439
18.1k
    pp->supported = netdev_port_features_from_ofp10(opp->supported);
440
18.1k
    pp->peer = netdev_port_features_from_ofp10(opp->peer);
441
442
18.1k
    pp->curr_speed = netdev_features_to_bps(pp->curr, 0) / 1000;
443
18.1k
    pp->max_speed = netdev_features_to_bps(pp->supported, 0) / 1000;
444
445
18.1k
    return 0;
446
18.1k
}
447
448
static enum ofperr
449
ofputil_decode_ofp11_port(struct ofputil_phy_port *pp,
450
                          const struct ofp11_port *op)
451
978
{
452
978
    enum ofperr error;
453
454
978
    error = ofputil_port_from_ofp11(op->port_no, &pp->port_no);
455
978
    if (error) {
456
273
        return error;
457
273
    }
458
705
    pp->hw_addr = op->hw_addr;
459
705
    ovs_strlcpy_arrays(pp->name, op->name);
460
461
705
    pp->config = ntohl(op->config) & OFPPC11_ALL;
462
705
    pp->state = ntohl(op->state) & OFPPS11_ALL;
463
464
705
    pp->curr = netdev_port_features_from_ofp11(op->curr);
465
705
    pp->advertised = netdev_port_features_from_ofp11(op->advertised);
466
705
    pp->supported = netdev_port_features_from_ofp11(op->supported);
467
705
    pp->peer = netdev_port_features_from_ofp11(op->peer);
468
469
705
    pp->curr_speed = ntohl(op->curr_speed);
470
705
    pp->max_speed = ntohl(op->max_speed);
471
472
705
    return 0;
473
978
}
474
475
static enum ofperr
476
parse_ofp14_port_ethernet_property(const struct ofpbuf *payload,
477
                                   struct ofputil_phy_port *pp)
478
485
{
479
485
    struct ofp14_port_desc_prop_ethernet *eth = payload->data;
480
481
485
    if (payload->size != sizeof *eth) {
482
473
        return OFPERR_OFPBPC_BAD_LEN;
483
473
    }
484
485
12
    pp->curr = netdev_port_features_from_ofp11(eth->curr);
486
12
    pp->advertised = netdev_port_features_from_ofp11(eth->advertised);
487
12
    pp->supported = netdev_port_features_from_ofp11(eth->supported);
488
12
    pp->peer = netdev_port_features_from_ofp11(eth->peer);
489
490
12
    pp->curr_speed = ntohl(eth->curr_speed);
491
12
    pp->max_speed = ntohl(eth->max_speed);
492
493
12
    return 0;
494
485
}
495
496
static enum ofperr
497
ofputil_pull_ofp14_port_properties(const void *props, size_t len,
498
                                   struct ofputil_phy_port *pp)
499
699
{
500
699
    struct ofpbuf properties = ofpbuf_const_initializer(props, len);
501
1.40k
    while (properties.size > 0) {
502
1.31k
        struct ofpbuf payload;
503
1.31k
        enum ofperr error;
504
1.31k
        uint64_t type;
505
506
1.31k
        error = ofpprop_pull(&properties, &payload, &type);
507
1.31k
        if (error) {
508
136
            return error;
509
136
        }
510
511
1.17k
        switch (type) {
512
485
        case OFPPDPT14_ETHERNET:
513
485
            error = parse_ofp14_port_ethernet_property(&payload, pp);
514
485
            break;
515
516
689
        default:
517
689
            error = OFPPROP_UNKNOWN(true, "port", type);
518
689
            break;
519
1.17k
        }
520
521
1.17k
        if (error) {
522
473
            return error;
523
473
        }
524
1.17k
    }
525
526
90
    return 0;
527
699
}
528
529
static enum ofperr
530
ofputil_pull_ofp14_port(struct ofputil_phy_port *pp, struct ofpbuf *msg)
531
1.72k
{
532
1.72k
    const struct ofp14_port *op = ofpbuf_try_pull(msg, sizeof *op);
533
1.72k
    if (!op) {
534
12
        return OFPERR_OFPBRC_BAD_LEN;
535
12
    }
536
537
1.70k
    size_t len = ntohs(op->length);
538
1.70k
    if (len < sizeof *op || len - sizeof *op > msg->size) {
539
613
        return OFPERR_OFPBRC_BAD_LEN;
540
613
    }
541
1.09k
    len -= sizeof *op;
542
543
1.09k
    enum ofperr error = ofputil_port_from_ofp11(op->port_no, &pp->port_no);
544
1.09k
    if (error) {
545
396
        return error;
546
396
    }
547
699
    pp->hw_addr = op->hw_addr;
548
699
    ovs_strlcpy_arrays(pp->name, op->name);
549
550
699
    pp->config = ntohl(op->config) & OFPPC11_ALL;
551
699
    pp->state = ntohl(op->state) & OFPPS11_ALL;
552
553
699
    return ofputil_pull_ofp14_port_properties(ofpbuf_pull(msg, len), len, pp);
554
1.09k
}
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
488
{
663
488
    struct ofpbuf b = ofpbuf_const_initializer(request,
664
488
                                               ntohs(request->length));
665
488
    enum ofpraw raw = ofpraw_pull_assert(&b);
666
488
    if (raw == OFPRAW_OFPST10_PORT_DESC_REQUEST) {
667
218
        *port = OFPP_ANY;
668
218
        return 0;
669
270
    } else if (raw == OFPRAW_OFPST15_PORT_DESC_REQUEST) {
670
270
        ovs_be32 *ofp11_port;
671
672
270
        ofp11_port = ofpbuf_pull(&b, sizeof *ofp11_port);
673
270
        return ofputil_port_from_ofp11(*ofp11_port, port);
674
270
    } else {
675
0
        OVS_NOT_REACHED();
676
0
    }
677
488
}
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
24.8k
{
729
24.8k
    memset(pp, 0, sizeof *pp);
730
731
24.8k
    switch (ofp_version) {
732
19.7k
    case OFP10_VERSION: {
733
19.7k
        const struct ofp10_phy_port *opp = ofpbuf_try_pull(b, sizeof *opp);
734
19.7k
        return opp ? ofputil_decode_ofp10_phy_port(pp, opp) : EOF;
735
0
    }
736
597
    case OFP11_VERSION:
737
1.19k
    case OFP12_VERSION:
738
1.37k
    case OFP13_VERSION: {
739
1.37k
        const struct ofp11_port *op = ofpbuf_try_pull(b, sizeof *op);
740
1.37k
        return op ? ofputil_decode_ofp11_port(pp, op) : EOF;
741
1.19k
    }
742
501
    case OFP14_VERSION:
743
3.68k
    case OFP15_VERSION:
744
3.68k
        return b->size ? ofputil_pull_ofp14_port(pp, b) : EOF;
745
0
    default:
746
0
        OVS_NOT_REACHED();
747
24.8k
    }
748
24.8k
}
749
750
void
751
ofputil_phy_port_format(struct ds *s, const struct ofputil_phy_port *port)
752
18.9k
{
753
18.9k
    char name[sizeof port->name];
754
18.9k
    int j;
755
756
18.9k
    memcpy(name, port->name, sizeof name);
757
34.7k
    for (j = 0; j < sizeof name - 1; j++) {
758
34.1k
        if (!isprint((unsigned char) name[j])) {
759
18.3k
            break;
760
18.3k
        }
761
34.1k
    }
762
18.9k
    name[j] = '\0';
763
764
18.9k
    ds_put_char(s, ' ');
765
18.9k
    ofputil_format_port(port->port_no, NULL, s);
766
18.9k
    ds_put_format(s, "(%s): addr:"ETH_ADDR_FMT"\n",
767
18.9k
                  name, ETH_ADDR_ARGS(port->hw_addr));
768
769
18.9k
    ds_put_cstr(s, "     config:     ");
770
18.9k
    ofputil_port_config_format(s, port->config);
771
772
18.9k
    ds_put_cstr(s, "     state:      ");
773
18.9k
    ofputil_port_state_format(s, port->state);
774
775
18.9k
    if (port->curr) {
776
15.8k
        ds_put_format(s, "     current:    ");
777
15.8k
        netdev_features_format(s, port->curr);
778
15.8k
    }
779
18.9k
    if (port->advertised) {
780
15.7k
        ds_put_format(s, "     advertised: ");
781
15.7k
        netdev_features_format(s, port->advertised);
782
15.7k
    }
783
18.9k
    if (port->supported) {
784
15.8k
        ds_put_format(s, "     supported:  ");
785
15.8k
        netdev_features_format(s, port->supported);
786
15.8k
    }
787
18.9k
    if (port->peer) {
788
16.1k
        ds_put_format(s, "     peer:       ");
789
16.1k
        netdev_features_format(s, port->peer);
790
16.1k
    }
791
18.9k
    ds_put_format(s, "     speed: %"PRIu32" Mbps now, "
792
18.9k
                  "%"PRIu32" Mbps max\n",
793
18.9k
                  port->curr_speed / UINT32_C(1000),
794
18.9k
                  port->max_speed / UINT32_C(1000));
795
18.9k
}
796
797
/* qsort comparison function. */
798
static int
799
compare_ports(const void *a_, const void *b_)
800
108k
{
801
108k
    const struct ofputil_phy_port *a = a_;
802
108k
    const struct ofputil_phy_port *b = b_;
803
108k
    uint16_t ap = ofp_to_u16(a->port_no);
804
108k
    uint16_t bp = ofp_to_u16(b->port_no);
805
806
108k
    return ap < bp ? -1 : ap > bp;
807
108k
}
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
5.40k
{
815
5.40k
    struct ofputil_phy_port *ports;
816
5.40k
    size_t allocated_ports, n_ports;
817
5.40k
    int retval;
818
5.40k
    size_t i;
819
820
5.40k
    ports = NULL;
821
5.40k
    allocated_ports = 0;
822
22.9k
    for (n_ports = 0; ; n_ports++) {
823
22.9k
        if (n_ports >= allocated_ports) {
824
6.73k
            ports = x2nrealloc(ports, &allocated_ports, sizeof *ports);
825
6.73k
        }
826
827
22.9k
        retval = ofputil_pull_phy_port(ofp_version, b, &ports[n_ports]);
828
22.9k
        if (retval) {
829
5.40k
            break;
830
5.40k
        }
831
22.9k
    }
832
833
5.40k
    qsort(ports, n_ports, sizeof *ports, compare_ports);
834
22.9k
    for (i = 0; i < n_ports; i++) {
835
17.5k
        ofputil_phy_port_format(string, &ports[i]);
836
17.5k
    }
837
5.40k
    free(ports);
838
839
5.40k
    return retval != EOF ? retval : 0;
840
5.40k
}
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
1.95k
{
850
1.95k
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
851
1.95k
    ofpraw_pull_assert(&b);
852
853
1.95k
    const struct ofp_port_status *ops = ofpbuf_pull(&b, sizeof *ops);
854
1.95k
    if (ops->reason != OFPPR_ADD &&
855
1.27k
        ops->reason != OFPPR_DELETE &&
856
348
        ops->reason != OFPPR_MODIFY) {
857
127
        return OFPERR_NXBRC_BAD_REASON;
858
127
    }
859
1.83k
    ps->reason = ops->reason;
860
861
1.83k
    int retval = ofputil_pull_phy_port(oh->version, &b, &ps->desc);
862
1.83k
    ovs_assert(retval != EOF);
863
1.83k
    return retval;
864
1.95k
}
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
1.40k
{
911
1.40k
    if (ps->reason == OFPPR_ADD) {
912
526
        ds_put_format(s, " ADD:");
913
882
    } else if (ps->reason == OFPPR_DELETE) {
914
838
        ds_put_format(s, " DEL:");
915
838
    } else if (ps->reason == OFPPR_MODIFY) {
916
44
        ds_put_format(s, " MOD:");
917
44
    }
918
919
1.40k
    ofputil_phy_port_format(s, &ps->desc);
920
1.40k
}
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
235
{
928
235
    ovs_be32 advertise;
929
235
    enum ofperr error;
930
931
235
    error = ofpprop_parse_be32(property, &advertise);
932
235
    if (!error) {
933
186
        pm->advertise = netdev_port_features_from_ofp11(advertise);
934
186
    }
935
235
    return error;
936
235
}
937
938
static enum ofperr
939
ofputil_decode_ofp10_port_mod(const struct ofp10_port_mod *opm,
940
                              struct ofputil_port_mod *pm)
941
1.21k
{
942
1.21k
    pm->port_no = u16_to_ofp(ntohs(opm->port_no));
943
1.21k
    pm->hw_addr = opm->hw_addr;
944
1.21k
    pm->config = ntohl(opm->config) & OFPPC10_ALL;
945
1.21k
    pm->mask = ntohl(opm->mask) & OFPPC10_ALL;
946
1.21k
    pm->advertise = netdev_port_features_from_ofp10(opm->advertise);
947
1.21k
    return 0;
948
1.21k
}
949
950
static enum ofperr
951
ofputil_decode_ofp11_port_mod(const struct ofp11_port_mod *opm,
952
                              struct ofputil_port_mod *pm)
953
260
{
954
260
    enum ofperr error;
955
956
260
    error = ofputil_port_from_ofp11(opm->port_no, &pm->port_no);
957
260
    if (error) {
958
54
        return error;
959
54
    }
960
961
206
    pm->hw_addr = opm->hw_addr;
962
206
    pm->config = ntohl(opm->config) & OFPPC11_ALL;
963
206
    pm->mask = ntohl(opm->mask) & OFPPC11_ALL;
964
206
    pm->advertise = netdev_port_features_from_ofp11(opm->advertise);
965
966
206
    return 0;
967
260
}
968
969
static enum ofperr
970
ofputil_decode_ofp14_port_mod_properties(struct ofpbuf *b, bool loose,
971
                                         struct ofputil_port_mod *pm)
972
994
{
973
1.44k
    while (b->size > 0) {
974
1.24k
        struct ofpbuf property;
975
1.24k
        enum ofperr error;
976
1.24k
        uint64_t type;
977
978
1.24k
        error = ofpprop_pull(b, &property, &type);
979
1.24k
        if (error) {
980
747
            return error;
981
747
        }
982
983
501
        switch (type) {
984
235
        case OFPPMPT14_ETHERNET:
985
235
            error = parse_port_mod_ethernet_property(&property, pm);
986
235
            break;
987
988
266
        default:
989
266
            error = OFPPROP_UNKNOWN(loose, "port_mod", type);
990
266
            break;
991
501
        }
992
993
501
        if (error) {
994
49
            return error;
995
49
        }
996
501
    }
997
198
    return 0;
998
994
}
999
1000
static enum ofperr
1001
ofputil_decode_ofp14_port_mod(struct ofpbuf *b, bool loose,
1002
                              struct ofputil_port_mod *pm)
1003
1.56k
{
1004
1.56k
    const struct ofp14_port_mod *opm = ofpbuf_pull(b, sizeof *opm);
1005
1.56k
    enum ofperr error = ofputil_port_from_ofp11(opm->port_no, &pm->port_no);
1006
1.56k
    if (error) {
1007
567
        return error;
1008
567
    }
1009
1010
994
    pm->hw_addr = opm->hw_addr;
1011
994
    pm->config = ntohl(opm->config) & OFPPC11_ALL;
1012
994
    pm->mask = ntohl(opm->mask) & OFPPC11_ALL;
1013
1014
994
    return ofputil_decode_ofp14_port_mod_properties(b, loose, pm);
1015
1.56k
}
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
3.03k
{
1023
3.03k
    memset(pm, 0, sizeof *pm);
1024
1025
3.03k
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
1026
3.03k
    enum ofpraw raw = ofpraw_pull_assert(&b);
1027
1028
3.03k
    enum ofperr error;
1029
3.03k
    if (raw == OFPRAW_OFPT10_PORT_MOD) {
1030
1.21k
        error = ofputil_decode_ofp10_port_mod(b.data, pm);
1031
1.82k
    } else if (raw == OFPRAW_OFPT11_PORT_MOD) {
1032
260
        error = ofputil_decode_ofp11_port_mod(b.data, pm);
1033
1.56k
    } else if (raw == OFPRAW_OFPT14_PORT_MOD) {
1034
1.56k
        error = ofputil_decode_ofp14_port_mod(&b, loose, pm);
1035
1.56k
    } else {
1036
0
        error = OFPERR_OFPBRC_BAD_TYPE;
1037
0
    }
1038
1039
3.03k
    pm->config &= pm->mask;
1040
3.03k
    return error;
1041
3.03k
}
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
1.62k
{
1109
1.62k
    ds_put_cstr(s, " port: ");
1110
1.62k
    ofputil_format_port(pm->port_no, port_map, s);
1111
1.62k
    ds_put_format(s, ": addr:"ETH_ADDR_FMT"\n",
1112
1.62k
                  ETH_ADDR_ARGS(pm->hw_addr));
1113
1114
1.62k
    ds_put_cstr(s, "     config: ");
1115
1.62k
    ofputil_port_config_format(s, pm->config);
1116
1117
1.62k
    ds_put_cstr(s, "     mask:   ");
1118
1.62k
    ofputil_port_config_format(s, pm->mask);
1119
1120
1.62k
    ds_put_cstr(s, "     advertise: ");
1121
1.62k
    if (pm->advertise) {
1122
1.29k
        netdev_features_format(s, pm->advertise);
1123
1.29k
    } else {
1124
324
        ds_put_cstr(s, "UNCHANGED\n");
1125
324
    }
1126
1.62k
}
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
11.8k
{
1371
1372
11.8k
    ops->port_no = u16_to_ofp(ntohs(ps10->port_no));
1373
11.8k
    ops->stats.rx_packets = ntohll(get_32aligned_be64(&ps10->rx_packets));
1374
11.8k
    ops->stats.tx_packets = ntohll(get_32aligned_be64(&ps10->tx_packets));
1375
11.8k
    ops->stats.rx_bytes = ntohll(get_32aligned_be64(&ps10->rx_bytes));
1376
11.8k
    ops->stats.tx_bytes = ntohll(get_32aligned_be64(&ps10->tx_bytes));
1377
11.8k
    ops->stats.rx_dropped = ntohll(get_32aligned_be64(&ps10->rx_dropped));
1378
11.8k
    ops->stats.tx_dropped = ntohll(get_32aligned_be64(&ps10->tx_dropped));
1379
11.8k
    ops->stats.rx_errors = ntohll(get_32aligned_be64(&ps10->rx_errors));
1380
11.8k
    ops->stats.tx_errors = ntohll(get_32aligned_be64(&ps10->tx_errors));
1381
11.8k
    ops->stats.rx_frame_errors =
1382
11.8k
        ntohll(get_32aligned_be64(&ps10->rx_frame_err));
1383
11.8k
    ops->stats.rx_over_errors = ntohll(get_32aligned_be64(&ps10->rx_over_err));
1384
11.8k
    ops->stats.rx_crc_errors = ntohll(get_32aligned_be64(&ps10->rx_crc_err));
1385
11.8k
    ops->stats.collisions = ntohll(get_32aligned_be64(&ps10->collisions));
1386
11.8k
    ops->duration_sec = ops->duration_nsec = UINT32_MAX;
1387
1388
11.8k
    return 0;
1389
11.8k
}
1390
1391
static enum ofperr
1392
ofputil_port_stats_from_ofp11(struct ofputil_port_stats *ops,
1393
                              const struct ofp11_port_stats *ps11)
1394
1.71k
{
1395
1.71k
    enum ofperr error;
1396
1397
1.71k
    error = ofputil_port_from_ofp11(ps11->port_no, &ops->port_no);
1398
1.71k
    if (error) {
1399
256
        return error;
1400
256
    }
1401
1402
1.45k
    ops->stats.rx_packets = ntohll(ps11->rx_packets);
1403
1.45k
    ops->stats.tx_packets = ntohll(ps11->tx_packets);
1404
1.45k
    ops->stats.rx_bytes = ntohll(ps11->rx_bytes);
1405
1.45k
    ops->stats.tx_bytes = ntohll(ps11->tx_bytes);
1406
1.45k
    ops->stats.rx_dropped = ntohll(ps11->rx_dropped);
1407
1.45k
    ops->stats.tx_dropped = ntohll(ps11->tx_dropped);
1408
1.45k
    ops->stats.rx_errors = ntohll(ps11->rx_errors);
1409
1.45k
    ops->stats.tx_errors = ntohll(ps11->tx_errors);
1410
1.45k
    ops->stats.rx_frame_errors = ntohll(ps11->rx_frame_err);
1411
1.45k
    ops->stats.rx_over_errors = ntohll(ps11->rx_over_err);
1412
1.45k
    ops->stats.rx_crc_errors = ntohll(ps11->rx_crc_err);
1413
1.45k
    ops->stats.collisions = ntohll(ps11->collisions);
1414
1.45k
    ops->duration_sec = ops->duration_nsec = UINT32_MAX;
1415
1416
1.45k
    return 0;
1417
1.71k
}
1418
1419
static enum ofperr
1420
ofputil_port_stats_from_ofp13(struct ofputil_port_stats *ops,
1421
                              const struct ofp13_port_stats *ps13)
1422
1.26k
{
1423
1.26k
    enum ofperr error = ofputil_port_stats_from_ofp11(ops, &ps13->ps);
1424
1.26k
    if (!error) {
1425
1.09k
        ops->duration_sec = ntohl(ps13->duration_sec);
1426
1.09k
        ops->duration_nsec = ntohl(ps13->duration_nsec);
1427
1.09k
    }
1428
1.26k
    return error;
1429
1.26k
}
1430
1431
static enum ofperr
1432
parse_ofp14_port_stats_ethernet_property(const struct ofpbuf *payload,
1433
                                         struct ofputil_port_stats *ops)
1434
106
{
1435
106
    const struct ofp14_port_stats_prop_ethernet *eth = payload->data;
1436
1437
106
    if (payload->size != sizeof *eth) {
1438
76
        return OFPERR_OFPBPC_BAD_LEN;
1439
76
    }
1440
1441
30
    ops->stats.rx_frame_errors = ntohll(eth->rx_frame_err);
1442
30
    ops->stats.rx_over_errors = ntohll(eth->rx_over_err);
1443
30
    ops->stats.rx_crc_errors = ntohll(eth->rx_crc_err);
1444
30
    ops->stats.collisions = ntohll(eth->collisions);
1445
1446
30
    return 0;
1447
106
}
1448
1449
static enum ofperr
1450
parse_intel_port_stats_rfc2819_property(const struct ofpbuf *payload,
1451
                                        struct ofputil_port_stats *ops)
1452
10
{
1453
10
    const struct intel_port_stats_rfc2819 *rfc2819 = payload->data;
1454
1455
10
    if (payload->size != sizeof *rfc2819) {
1456
10
        return OFPERR_OFPBPC_BAD_LEN;
1457
10
    }
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
10
}
1491
1492
static enum ofperr
1493
parse_intel_port_custom_property(struct ofpbuf *payload,
1494
                                 struct ofputil_port_stats *ops)
1495
6.02k
{
1496
6.02k
    const struct intel_port_custom_stats *custom_stats
1497
6.02k
        = ofpbuf_try_pull(payload, sizeof *custom_stats);
1498
6.02k
    if (!custom_stats) {
1499
6
        return OFPERR_OFPBPC_BAD_LEN;
1500
6
    }
1501
1502
6.01k
    ops->custom_stats.size = ntohs(custom_stats->stats_array_size);
1503
1504
6.01k
    netdev_free_custom_stats_counters(&ops->custom_stats);
1505
6.01k
    ops->custom_stats.counters = xcalloc(ops->custom_stats.size,
1506
6.01k
                                         sizeof *ops->custom_stats.counters);
1507
1508
37.5k
    for (int i = 0; i < ops->custom_stats.size; i++) {
1509
36.1k
        struct netdev_custom_counter *c = &ops->custom_stats.counters[i];
1510
1511
        /* Counter name. */
1512
36.1k
        uint8_t *name_len = ofpbuf_try_pull(payload, sizeof *name_len);
1513
36.1k
        char *name = name_len ? ofpbuf_try_pull(payload, *name_len) : NULL;
1514
36.1k
        if (!name_len || !name) {
1515
2.03k
            netdev_free_custom_stats_counters(&ops->custom_stats);
1516
2.03k
            return OFPERR_OFPBPC_BAD_LEN;
1517
2.03k
        }
1518
1519
34.1k
        size_t len = MIN(*name_len, sizeof c->name - 1);
1520
34.1k
        memcpy(c->name, name, len);
1521
34.1k
        c->name[len] = '\0';
1522
1523
        /* Counter value. */
1524
34.1k
        ovs_be64 *value = ofpbuf_try_pull(payload, sizeof *value);
1525
34.1k
        if (!value) {
1526
2.61k
            netdev_free_custom_stats_counters(&ops->custom_stats);
1527
2.61k
            return OFPERR_OFPBPC_BAD_LEN;
1528
2.61k
        }
1529
31.5k
        c->value = ntohll(get_unaligned_be64(value));
1530
31.5k
    }
1531
1532
1.36k
    return 0;
1533
6.01k
}
1534
1535
static enum ofperr
1536
ofputil_pull_ofp14_port_stats(struct ofputil_port_stats *ops,
1537
                              struct ofpbuf *msg)
1538
12.6k
{
1539
12.6k
    const struct ofp14_port_stats *ps14 = ofpbuf_try_pull(msg, sizeof *ps14);
1540
12.6k
    if (!ps14) {
1541
580
        return OFPERR_OFPBRC_BAD_LEN;
1542
580
    }
1543
1544
12.0k
    size_t len = ntohs(ps14->length);
1545
12.0k
    if (len < sizeof *ps14 || len - sizeof *ps14 > msg->size) {
1546
912
        return OFPERR_OFPBRC_BAD_LEN;
1547
912
    }
1548
11.1k
    len -= sizeof *ps14;
1549
1550
11.1k
    enum ofperr error = ofputil_port_from_ofp11(ps14->port_no, &ops->port_no);
1551
11.1k
    if (error) {
1552
522
        return error;
1553
522
    }
1554
1555
10.6k
    ops->duration_sec = ntohl(ps14->duration_sec);
1556
10.6k
    ops->duration_nsec = ntohl(ps14->duration_nsec);
1557
10.6k
    ops->stats.rx_packets = ntohll(ps14->rx_packets);
1558
10.6k
    ops->stats.tx_packets = ntohll(ps14->tx_packets);
1559
10.6k
    ops->stats.rx_bytes = ntohll(ps14->rx_bytes);
1560
10.6k
    ops->stats.tx_bytes = ntohll(ps14->tx_bytes);
1561
10.6k
    ops->stats.rx_dropped = ntohll(ps14->rx_dropped);
1562
10.6k
    ops->stats.tx_dropped = ntohll(ps14->tx_dropped);
1563
10.6k
    ops->stats.rx_errors = ntohll(ps14->rx_errors);
1564
10.6k
    ops->stats.tx_errors = ntohll(ps14->tx_errors);
1565
1566
1567
10.6k
    struct ofpbuf properties = ofpbuf_const_initializer(ofpbuf_pull(msg, len),
1568
10.6k
                                                        len);
1569
13.6k
    while (properties.size > 0) {
1570
9.09k
        struct ofpbuf payload;
1571
9.09k
        uint64_t type = 0;
1572
1573
9.09k
        error = ofpprop_pull(&properties, &payload, &type);
1574
9.09k
        if (error) {
1575
1.35k
            netdev_free_custom_stats_counters(&ops->custom_stats);
1576
1.35k
            return error;
1577
1.35k
        }
1578
7.74k
        switch (type) {
1579
106
        case OFPPSPT14_ETHERNET:
1580
106
            error = parse_ofp14_port_stats_ethernet_property(&payload, ops);
1581
106
            break;
1582
10
        case OFPPROP_EXP(INTEL_VENDOR_ID, INTEL_PORT_STATS_RFC2819):
1583
10
            error = parse_intel_port_stats_rfc2819_property(&payload, ops);
1584
10
            break;
1585
6.02k
        case OFPPROP_EXP(INTEL_VENDOR_ID, INTEL_PORT_STATS_CUSTOM):
1586
6.02k
            error = parse_intel_port_custom_property(&payload, ops);
1587
6.02k
            break;
1588
1.60k
        default:
1589
1.60k
            error = OFPPROP_UNKNOWN(true, "port stats", type);
1590
1.60k
            break;
1591
7.74k
        }
1592
1593
7.74k
        if (error) {
1594
4.74k
            netdev_free_custom_stats_counters(&ops->custom_stats);
1595
4.74k
            return error;
1596
4.74k
        }
1597
7.74k
    }
1598
1599
4.52k
    return 0;
1600
10.6k
}
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
7.55k
{
1607
7.55k
    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
1608
7.55k
    ofpraw_pull_assert(&b);
1609
1610
16.4k
    for (size_t n = 0; ; n++) {
1611
16.4k
        struct ofputil_port_stats ps;
1612
16.4k
        if (ofputil_decode_port_stats(&ps, &b)) {
1613
7.55k
            return n;
1614
7.55k
        }
1615
8.89k
        netdev_free_custom_stats_counters(&ps.custom_stats);
1616
8.89k
    }
1617
7.55k
}
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
32.8k
{
1635
32.8k
    enum ofperr error;
1636
32.8k
    enum ofpraw raw;
1637
1638
32.8k
    memset(&(ps->stats), 0xFF, sizeof (ps->stats));
1639
32.8k
    memset(&(ps->custom_stats), 0, sizeof (ps->custom_stats));
1640
1641
32.8k
    error = (msg->header ? ofpraw_decode(&raw, msg->header)
1642
32.8k
             : ofpraw_pull(&raw, msg));
1643
32.8k
    if (error) {
1644
0
        return error;
1645
0
    }
1646
1647
32.8k
    if (!msg->size) {
1648
6.74k
        return EOF;
1649
26.1k
    } else if (raw == OFPRAW_OFPST14_PORT_REPLY) {
1650
12.6k
        return ofputil_pull_ofp14_port_stats(ps, msg);
1651
13.5k
    } else if (raw == OFPRAW_OFPST13_PORT_REPLY) {
1652
1.26k
        const struct ofp13_port_stats *ps13;
1653
1.26k
        ps13 = ofpbuf_try_pull(msg, sizeof *ps13);
1654
1.26k
        if (!ps13) {
1655
0
            goto bad_len;
1656
0
        }
1657
1.26k
        return ofputil_port_stats_from_ofp13(ps, ps13);
1658
12.2k
    } else if (raw == OFPRAW_OFPST11_PORT_REPLY) {
1659
448
        const struct ofp11_port_stats *ps11;
1660
1661
448
        ps11 = ofpbuf_try_pull(msg, sizeof *ps11);
1662
448
        if (!ps11) {
1663
0
            goto bad_len;
1664
0
        }
1665
448
        return ofputil_port_stats_from_ofp11(ps, ps11);
1666
11.8k
    } else if (raw == OFPRAW_OFPST10_PORT_REPLY) {
1667
11.8k
        const struct ofp10_port_stats *ps10;
1668
1669
11.8k
        ps10 = ofpbuf_try_pull(msg, sizeof *ps10);
1670
11.8k
        if (!ps10) {
1671
0
            goto bad_len;
1672
0
        }
1673
11.8k
        return ofputil_port_stats_from_ofp10(ps, ps10);
1674
11.8k
    } 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
32.8k
}
1683
1684
static void
1685
print_port_stat(struct ds *string, const char *leader, uint64_t stat, int more)
1686
106k
{
1687
106k
    ds_put_cstr(string, leader);
1688
106k
    if (stat != UINT64_MAX) {
1689
62.9k
        ds_put_format(string, "%"PRIu64, stat);
1690
62.9k
    } else {
1691
43.7k
        ds_put_char(string, '?');
1692
43.7k
    }
1693
106k
    if (more) {
1694
88.9k
        ds_put_cstr(string, ", ");
1695
88.9k
    } else {
1696
17.7k
        ds_put_cstr(string, "\n");
1697
17.7k
    }
1698
106k
}
1699
1700
static void
1701
print_port_stat_cond(struct ds *string, const char *leader, uint64_t stat)
1702
186k
{
1703
186k
    if (stat != UINT64_MAX) {
1704
0
        ds_put_format(string, "%s%"PRIu64", ", leader, stat);
1705
0
    }
1706
186k
}
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
8.89k
{
1713
8.89k
    ds_put_cstr(string, "  port ");
1714
8.89k
    if (ofp_to_u16(ps->port_no) < 10) {
1715
1.22k
        ds_put_char(string, ' ');
1716
1.22k
    }
1717
8.89k
    ofputil_format_port(ps->port_no, port_map, string);
1718
1719
8.89k
    ds_put_cstr(string, ": rx ");
1720
8.89k
    print_port_stat(string, "pkts=", ps->stats.rx_packets, 1);
1721
8.89k
    print_port_stat(string, "bytes=", ps->stats.rx_bytes, 1);
1722
8.89k
    print_port_stat(string, "drop=", ps->stats.rx_dropped, 1);
1723
8.89k
    print_port_stat(string, "errs=", ps->stats.rx_errors, 1);
1724
8.89k
    print_port_stat(string, "frame=", ps->stats.rx_frame_errors, 1);
1725
8.89k
    print_port_stat(string, "over=", ps->stats.rx_over_errors, 1);
1726
8.89k
    print_port_stat(string, "crc=", ps->stats.rx_crc_errors, 0);
1727
1728
8.89k
    ds_put_cstr(string, "           tx ");
1729
8.89k
    print_port_stat(string, "pkts=", ps->stats.tx_packets, 1);
1730
8.89k
    print_port_stat(string, "bytes=", ps->stats.tx_bytes, 1);
1731
8.89k
    print_port_stat(string, "drop=", ps->stats.tx_dropped, 1);
1732
8.89k
    print_port_stat(string, "errs=", ps->stats.tx_errors, 1);
1733
8.89k
    print_port_stat(string, "coll=", ps->stats.collisions, 0);
1734
1735
8.89k
    if (ps->duration_sec != UINT32_MAX) {
1736
2.50k
        ds_put_cstr(string, "           duration=");
1737
2.50k
        ofp_print_duration(string, ps->duration_sec, ps->duration_nsec);
1738
2.50k
        ds_put_char(string, '\n');
1739
2.50k
    }
1740
8.89k
    struct ds string_ext_stats = DS_EMPTY_INITIALIZER;
1741
1742
8.89k
    ds_init(&string_ext_stats);
1743
1744
8.89k
    print_port_stat_cond(&string_ext_stats, "1_to_64_packets=",
1745
8.89k
                         ps->stats.rx_1_to_64_packets);
1746
8.89k
    print_port_stat_cond(&string_ext_stats, "65_to_127_packets=",
1747
8.89k
                         ps->stats.rx_65_to_127_packets);
1748
8.89k
    print_port_stat_cond(&string_ext_stats, "128_to_255_packets=",
1749
8.89k
                         ps->stats.rx_128_to_255_packets);
1750
8.89k
    print_port_stat_cond(&string_ext_stats, "256_to_511_packets=",
1751
8.89k
                         ps->stats.rx_256_to_511_packets);
1752
8.89k
    print_port_stat_cond(&string_ext_stats, "512_to_1023_packets=",
1753
8.89k
                         ps->stats.rx_512_to_1023_packets);
1754
8.89k
    print_port_stat_cond(&string_ext_stats, "1024_to_1522_packets=",
1755
8.89k
                         ps->stats.rx_1024_to_1522_packets);
1756
8.89k
    print_port_stat_cond(&string_ext_stats, "1523_to_max_packets=",
1757
8.89k
                         ps->stats.rx_1523_to_max_packets);
1758
8.89k
    print_port_stat_cond(&string_ext_stats, "broadcast_packets=",
1759
8.89k
                         ps->stats.rx_broadcast_packets);
1760
8.89k
    print_port_stat_cond(&string_ext_stats, "undersized_errors=",
1761
8.89k
                         ps->stats.rx_undersized_errors);
1762
8.89k
    print_port_stat_cond(&string_ext_stats, "oversize_errors=",
1763
8.89k
                         ps->stats.rx_oversize_errors);
1764
8.89k
    print_port_stat_cond(&string_ext_stats, "rx_fragmented_errors=",
1765
8.89k
                         ps->stats.rx_fragmented_errors);
1766
8.89k
    print_port_stat_cond(&string_ext_stats, "rx_jabber_errors=",
1767
8.89k
                         ps->stats.rx_jabber_errors);
1768
1769
8.89k
    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
8.89k
    ds_init(&string_ext_stats);
1779
1780
8.89k
    print_port_stat_cond(&string_ext_stats, "1_to_64_packets=",
1781
8.89k
                         ps->stats.tx_1_to_64_packets);
1782
8.89k
    print_port_stat_cond(&string_ext_stats, "65_to_127_packets=",
1783
8.89k
                         ps->stats.tx_65_to_127_packets);
1784
8.89k
    print_port_stat_cond(&string_ext_stats, "128_to_255_packets=",
1785
8.89k
                         ps->stats.tx_128_to_255_packets);
1786
8.89k
    print_port_stat_cond(&string_ext_stats, "256_to_511_packets=",
1787
8.89k
                         ps->stats.tx_256_to_511_packets);
1788
8.89k
    print_port_stat_cond(&string_ext_stats, "512_to_1023_packets=",
1789
8.89k
                         ps->stats.tx_512_to_1023_packets);
1790
8.89k
    print_port_stat_cond(&string_ext_stats, "1024_to_1522_packets=",
1791
8.89k
                         ps->stats.tx_1024_to_1522_packets);
1792
8.89k
    print_port_stat_cond(&string_ext_stats, "1523_to_max_packets=",
1793
8.89k
                         ps->stats.tx_1523_to_max_packets);
1794
8.89k
    print_port_stat_cond(&string_ext_stats, "multicast_packets=",
1795
8.89k
                         ps->stats.tx_multicast_packets);
1796
8.89k
    print_port_stat_cond(&string_ext_stats, "broadcast_packets=",
1797
8.89k
                         ps->stats.tx_broadcast_packets);
1798
1799
8.89k
    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
8.89k
    if (ps->custom_stats.size) {
1809
605
        ds_put_cstr(string, "           CUSTOM Statistics");
1810
6.44k
        for (int i = 0; i < ps->custom_stats.size; i++) {
1811
            /* 3 counters in the row */
1812
5.83k
            if (ps->custom_stats.counters[i].name[0]) {
1813
2.46k
                if (i % 3 == 0) {
1814
743
                    ds_put_cstr(string, "\n");
1815
743
                    ds_put_cstr(string, "                      ");
1816
1.71k
                } else {
1817
1.71k
                    ds_put_char(string, ' ');
1818
1.71k
                }
1819
2.46k
                ds_put_format(string, "%s=%"PRIu64",",
1820
2.46k
                              ps->custom_stats.counters[i].name,
1821
2.46k
                              ps->custom_stats.counters[i].value);
1822
2.46k
            }
1823
5.83k
        }
1824
605
        ds_put_cstr(string, "\n");
1825
605
    }
1826
8.89k
}
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
3.37k
{
1836
3.37k
    switch ((enum ofp_version)request->version) {
1837
226
    case OFP15_VERSION:
1838
345
    case OFP14_VERSION:
1839
423
    case OFP13_VERSION:
1840
1.60k
    case OFP12_VERSION:
1841
3.36k
    case OFP11_VERSION: {
1842
3.36k
        const struct ofp11_port_stats_request *psr11 = ofpmsg_body(request);
1843
3.36k
        return ofputil_port_from_ofp11(psr11->port_no, ofp10_port);
1844
1.60k
    }
1845
1846
10
    case OFP10_VERSION: {
1847
10
        const struct ofp10_port_stats_request *psr10 = ofpmsg_body(request);
1848
10
        *ofp10_port = u16_to_ofp(ntohs(psr10->port_no));
1849
10
        return 0;
1850
1.60k
    }
1851
1852
0
    default:
1853
0
        OVS_NOT_REACHED();
1854
3.37k
    }
1855
3.37k
}
1856