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